File size: 6,575 Bytes
ba8d952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
'''
OpenCV Python binary extension loader
'''
import os
import importlib
import sys

__all__ = []

try:
    import numpy
    import numpy.core.multiarray
except ImportError:
    print('OpenCV bindings requires "numpy" package.')
    print('Install it via command:')
    print('    pip install numpy')
    raise

# TODO
# is_x64 = sys.maxsize > 2**32


def __load_extra_py_code_for_module(base, name, enable_debug_print=False):
    module_name = "{}.{}".format(__name__, name)
    export_module_name = "{}.{}".format(base, name)
    native_module = sys.modules.pop(module_name, None)
    try:
        py_module = importlib.import_module(module_name)
    except ImportError as err:
        if enable_debug_print:
            print("Can't load Python code for module:", module_name,
                  ". Reason:", err)
        # Extension doesn't contain extra py code
        return False

    if not hasattr(base, name):
        setattr(sys.modules[base], name, py_module)
    sys.modules[export_module_name] = py_module
    # If it is C extension module it is already loaded by cv2 package
    if native_module:
        setattr(py_module, "_native", native_module)
        for k, v in filter(lambda kv: not hasattr(py_module, kv[0]),
                           native_module.__dict__.items()):
            if enable_debug_print: print('    symbol({}): {} = {}'.format(name, k, v))
            setattr(py_module, k, v)
    return True


def __collect_extra_submodules(enable_debug_print=False):
    def modules_filter(module):
        return all((
             # module is not internal
             not module.startswith("_"),
             not module.startswith("python-"),
             # it is not a file
             os.path.isdir(os.path.join(_extra_submodules_init_path, module))
        ))
    if sys.version_info[0] < 3:
        if enable_debug_print:
            print("Extra submodules is loaded only for Python 3")
        return []

    __INIT_FILE_PATH = os.path.abspath(__file__)
    _extra_submodules_init_path = os.path.dirname(__INIT_FILE_PATH)
    return filter(modules_filter, os.listdir(_extra_submodules_init_path))


def bootstrap():
    import sys

    import copy
    save_sys_path = copy.copy(sys.path)

    if hasattr(sys, 'OpenCV_LOADER'):
        print(sys.path)
        raise ImportError('ERROR: recursion is detected during loading of "cv2" binary extensions. Check OpenCV installation.')
    sys.OpenCV_LOADER = True

    DEBUG = False
    if hasattr(sys, 'OpenCV_LOADER_DEBUG'):
        DEBUG = True

    import platform
    if DEBUG: print('OpenCV loader: os.name="{}"  platform.system()="{}"'.format(os.name, str(platform.system())))

    LOADER_DIR = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))

    PYTHON_EXTENSIONS_PATHS = []
    BINARIES_PATHS = []

    g_vars = globals()
    l_vars = locals().copy()

    if sys.version_info[:2] < (3, 0):
        from . load_config_py2 import exec_file_wrapper
    else:
        from . load_config_py3 import exec_file_wrapper

    def load_first_config(fnames, required=True):
        for fname in fnames:
            fpath = os.path.join(LOADER_DIR, fname)
            if not os.path.exists(fpath):
                if DEBUG: print('OpenCV loader: config not found, skip: {}'.format(fpath))
                continue
            if DEBUG: print('OpenCV loader: loading config: {}'.format(fpath))
            exec_file_wrapper(fpath, g_vars, l_vars)
            return True
        if required:
            raise ImportError('OpenCV loader: missing configuration file: {}. Check OpenCV installation.'.format(fnames))

    load_first_config(['config.py'], True)
    load_first_config([
        'config-{}.{}.py'.format(sys.version_info[0], sys.version_info[1]),
        'config-{}.py'.format(sys.version_info[0])
    ], True)

    if DEBUG: print('OpenCV loader: PYTHON_EXTENSIONS_PATHS={}'.format(str(l_vars['PYTHON_EXTENSIONS_PATHS'])))
    if DEBUG: print('OpenCV loader: BINARIES_PATHS={}'.format(str(l_vars['BINARIES_PATHS'])))

    applySysPathWorkaround = False
    if hasattr(sys, 'OpenCV_REPLACE_SYS_PATH_0'):
        applySysPathWorkaround = True
    else:
        try:
            BASE_DIR = os.path.dirname(LOADER_DIR)
            if sys.path[0] == BASE_DIR or os.path.realpath(sys.path[0]) == BASE_DIR:
                applySysPathWorkaround = True
        except:
            if DEBUG: print('OpenCV loader: exception during checking workaround for sys.path[0]')
            pass  # applySysPathWorkaround is False

    for p in reversed(l_vars['PYTHON_EXTENSIONS_PATHS']):
        sys.path.insert(1 if not applySysPathWorkaround else 0, p)

    if os.name == 'nt':
        if sys.version_info[:2] >= (3, 8):  # https://github.com/python/cpython/pull/12302
            for p in l_vars['BINARIES_PATHS']:
                try:
                    os.add_dll_directory(p)
                except Exception as e:
                    if DEBUG: print('Failed os.add_dll_directory(): '+ str(e))
                    pass
        os.environ['PATH'] = ';'.join(l_vars['BINARIES_PATHS']) + ';' + os.environ.get('PATH', '')
        if DEBUG: print('OpenCV loader: PATH={}'.format(str(os.environ['PATH'])))
    else:
        # amending of LD_LIBRARY_PATH works for sub-processes only
        os.environ['LD_LIBRARY_PATH'] = ':'.join(l_vars['BINARIES_PATHS']) + ':' + os.environ.get('LD_LIBRARY_PATH', '')

    if DEBUG: print("Relink everything from native cv2 module to cv2 package")

    py_module = sys.modules.pop("cv2")

    native_module = importlib.import_module("cv2")

    sys.modules["cv2"] = py_module
    setattr(py_module, "_native", native_module)

    for item_name, item in filter(lambda kv: kv[0] not in ("__file__", "__loader__", "__spec__",
                                                           "__name__", "__package__"),
                                  native_module.__dict__.items()):
        if item_name not in g_vars:
            g_vars[item_name] = item

    sys.path = save_sys_path  # multiprocessing should start from bootstrap code (https://github.com/opencv/opencv/issues/18502)

    try:
        del sys.OpenCV_LOADER
    except Exception as e:
        if DEBUG:
            print("Exception during delete OpenCV_LOADER:", e)

    if DEBUG: print('OpenCV loader: binary extension... OK')

    for submodule in __collect_extra_submodules(DEBUG):
        if __load_extra_py_code_for_module("cv2", submodule, DEBUG):
            if DEBUG: print("Extra Python code for", submodule, "is loaded")

    if DEBUG: print('OpenCV loader: DONE')


bootstrap()