forked from Nuitka/Nuitka
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathModuleRegistry.py
210 lines (139 loc) · 5.47 KB
/
ModuleRegistry.py
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# Copyright 2020, Kay Hayen, mailto:[email protected]
#
# Part of "Nuitka", an optimizing Python compiler that is compatible and
# integrates with CPython, but also works on its own.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
""" This to keep track of used modules.
There is a set of root modules, which are user specified, and must be
processed. As they go, they add more modules to active modules list
and move done modules out of it.
That process can be restarted and modules will be fetched back from
the existing set of modules.
"""
import os
from nuitka.containers.oset import OrderedSet
from nuitka.PythonVersions import python_version
from nuitka.utils.FileOperations import areSamePaths
# One or more root modules, i.e. entry points that must be there.
root_modules = OrderedSet()
# To be traversed modules
active_modules = OrderedSet()
# Already traversed modules
done_modules = set()
# Uncompiled modules
uncompiled_modules = set()
def addRootModule(module):
root_modules.add(module)
def getRootModules():
return root_modules
def getRootTopModule():
top_module = next(iter(root_modules))
assert top_module.isTopModule()
return top_module
def hasRootModule(module_name):
for module in root_modules:
if module.getFullName() == module_name:
return True
return False
def replaceRootModule(old, new):
# Using global here, as this is really a singleton, in the form of a module,
# pylint: disable=global-statement
global root_modules
new_root_modules = OrderedSet()
for module in root_modules:
new_root_modules.add(module if module is not old else new)
root_modules = new_root_modules
def addUncompiledModule(module):
uncompiled_modules.add(module)
def getUncompiledModules():
return sorted(uncompiled_modules, key=lambda module: module.getFullName())
def getUncompiledTechnicalModules():
result = [module for module in uncompiled_modules if module.isTechnical()]
return sorted(result, key=lambda module: module.getFullName())
def getUncompiledNonTechnicalModules():
result = [module for module in uncompiled_modules if not module.isTechnical()]
return sorted(result, key=lambda module: module.getFullName())
def _normalizeModuleFilename(filename):
if python_version >= 0x300:
filename = filename.replace("__pycache__", "")
suffix = ".cpython-%d.pyc" % (python_version // 10)
if filename.endswith(suffix):
filename = filename[: -len(suffix)] + ".py"
else:
if filename.endswith(".pyc"):
filename = filename[:-3] + ".py"
if os.path.basename(filename) == "__init__.py":
filename = os.path.dirname(filename)
return filename
def getUncompiledModule(module_name, module_filename):
for uncompiled_module in uncompiled_modules:
if module_name == uncompiled_module.getFullName():
if areSamePaths(
_normalizeModuleFilename(module_filename),
_normalizeModuleFilename(uncompiled_module.filename),
):
return uncompiled_module
return None
def removeUncompiledModule(module):
uncompiled_modules.remove(module)
def startTraversal():
# Using global here, as this is really a singleton, in the form of a module,
# pylint: disable=global-statement
global active_modules, done_modules
active_modules = OrderedSet(root_modules)
done_modules = set()
for active_module in active_modules:
active_module.startTraversal()
def addUsedModule(module):
if module not in done_modules and module not in active_modules:
active_modules.add(module)
module.startTraversal()
def nextModule():
if active_modules:
result = active_modules.pop()
done_modules.add(result)
return result
else:
return None
def remainingCount():
return len(active_modules)
def getDoneModules():
return sorted(done_modules, key=lambda module: module.getFullName())
def removeDoneModule(module):
done_modules.remove(module)
def getModuleFromCodeName(code_name):
# TODO: We need something to just load modules.
for module in root_modules:
if module.getCodeName() == code_name:
return module
assert False, code_name
def getOwnerFromCodeName(code_name):
if "$$$" in code_name:
module_code_name, _function_code_name = code_name.split("$$$", 1)
module = getModuleFromCodeName(module_code_name)
return module.getFunctionFromCodeName(code_name)
else:
return getModuleFromCodeName(code_name)
def getModuleByName(module_name):
for module in active_modules:
if module.getFullName() == module_name:
return module
for module in done_modules:
if module.getFullName() == module_name:
return module
for module in uncompiled_modules:
if module.getFullName() == module_name:
return module
return None