1
|
1 |
# Copyright (C) 2005, Giovanni Bajo
|
|
2 |
# Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
|
|
3 |
#
|
|
4 |
# This program is free software; you can redistribute it and/or
|
|
5 |
# modify it under the terms of the GNU General Public License
|
|
6 |
# as published by the Free Software Foundation; either version 2
|
|
7 |
# of the License, or (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
17 |
import sys, string, os, imp, marshal
|
|
18 |
|
|
19 |
#=======================Owners==========================#
|
|
20 |
# An Owner does imports from a particular piece of turf
|
|
21 |
# That is, there's an Owner for each thing on sys.path
|
|
22 |
# There are owners for directories and .pyz files.
|
|
23 |
# There could be owners for zip files, or even URLs.
|
|
24 |
# Note that they replace the string in sys.path,
|
|
25 |
# but str(sys.path[n]) should yield the original string.
|
|
26 |
|
|
27 |
STRINGTYPE = type('')
|
|
28 |
|
|
29 |
class Owner:
|
|
30 |
def __init__(self, path):
|
|
31 |
self.path = path
|
|
32 |
def __str__(self):
|
|
33 |
return self.path
|
|
34 |
def getmod(self, nm):
|
|
35 |
return None
|
|
36 |
|
|
37 |
class DirOwner(Owner):
|
|
38 |
def __init__(self, path):
|
|
39 |
if path == '':
|
|
40 |
path = os.getcwd()
|
|
41 |
if not os.path.isdir(path):
|
|
42 |
raise ValueError, "%s is not a directory" % path
|
|
43 |
Owner.__init__(self, path)
|
|
44 |
def getmod(self, nm, getsuffixes=imp.get_suffixes, loadco=marshal.loads):
|
|
45 |
pth = os.path.join(self.path, nm)
|
|
46 |
possibles = [(pth, 0, None)]
|
|
47 |
if os.path.isdir(pth):
|
|
48 |
possibles.insert(0, (os.path.join(pth, '__init__'), 1, pth))
|
|
49 |
py = pyc = None
|
|
50 |
for pth, ispkg, pkgpth in possibles:
|
|
51 |
for ext, mode, typ in getsuffixes():
|
|
52 |
attempt = pth+ext
|
|
53 |
try:
|
|
54 |
st = os.stat(attempt)
|
|
55 |
except:
|
|
56 |
pass
|
|
57 |
else:
|
|
58 |
if typ == imp.C_EXTENSION:
|
|
59 |
return ExtensionModule(nm, attempt)
|
|
60 |
elif typ == imp.PY_SOURCE:
|
|
61 |
py = (attempt, st)
|
|
62 |
else:
|
|
63 |
pyc = (attempt, st)
|
|
64 |
if py or pyc:
|
|
65 |
break
|
|
66 |
if py is None and pyc is None:
|
|
67 |
return None
|
|
68 |
while 1:
|
|
69 |
if pyc is None or py and pyc[1][8] < py[1][8]:
|
|
70 |
try:
|
|
71 |
co = compile(open(py[0], 'r').read()+'\n', py[0], 'exec')
|
|
72 |
if __debug__:
|
|
73 |
pth = py[0] + 'c'
|
|
74 |
else:
|
|
75 |
pth = py[0] + 'o'
|
|
76 |
break
|
|
77 |
except SyntaxError, e:
|
|
78 |
print "Syntax error in", py[0]
|
|
79 |
print e.args
|
|
80 |
raise
|
|
81 |
elif pyc:
|
|
82 |
stuff = open(pyc[0], 'rb').read()
|
|
83 |
try:
|
|
84 |
co = loadco(stuff[8:])
|
|
85 |
pth = pyc[0]
|
|
86 |
break
|
|
87 |
except (ValueError, EOFError):
|
|
88 |
print "W: bad .pyc found (%s)" % pyc[0]
|
|
89 |
pyc = None
|
|
90 |
else:
|
|
91 |
return None
|
|
92 |
if not os.path.isabs(pth):
|
|
93 |
pth = os.path.abspath(pth)
|
|
94 |
if ispkg:
|
|
95 |
mod = PkgModule(nm, pth, co)
|
|
96 |
else:
|
|
97 |
mod = PyModule(nm, pth, co)
|
|
98 |
return mod
|
|
99 |
|
|
100 |
class PYZOwner(Owner):
|
|
101 |
def __init__(self, path):
|
|
102 |
import archive
|
|
103 |
self.pyz = archive.ZlibArchive(path)
|
|
104 |
Owner.__init__(self, path)
|
|
105 |
def getmod(self, nm):
|
|
106 |
rslt = self.pyz.extract(nm)
|
|
107 |
if rslt:
|
|
108 |
ispkg, co = rslt
|
|
109 |
if ispkg:
|
|
110 |
return PkgInPYZModule(nm, co, self)
|
|
111 |
return PyModule(nm, self.path, co)
|
|
112 |
|
|
113 |
_globalownertypes = [
|
|
114 |
DirOwner,
|
|
115 |
PYZOwner,
|
|
116 |
Owner,
|
|
117 |
]
|
|
118 |
|
|
119 |
#===================Import Directors====================================#
|
|
120 |
# ImportDirectors live on the metapath
|
|
121 |
# There's one for builtins, one for frozen modules, and one for sys.path
|
|
122 |
# Windows gets one for modules gotten from the Registry
|
|
123 |
# There should be one for Frozen modules
|
|
124 |
# Mac would have them for PY_RESOURCE modules etc.
|
|
125 |
# A generalization of Owner - their concept of "turf" is broader
|
|
126 |
|
|
127 |
class ImportDirector(Owner):
|
|
128 |
pass
|
|
129 |
class BuiltinImportDirector(ImportDirector):
|
|
130 |
def __init__(self):
|
|
131 |
self.path = 'Builtins'
|
|
132 |
def getmod(self, nm, isbuiltin=imp.is_builtin):
|
|
133 |
if isbuiltin(nm):
|
|
134 |
return BuiltinModule(nm)
|
|
135 |
return None
|
|
136 |
class FrozenImportDirector(ImportDirector):
|
|
137 |
def __init__(self):
|
|
138 |
self.path = 'FrozenModules'
|
|
139 |
def getmod(self, nm, isfrozen=imp.is_frozen):
|
|
140 |
if isfrozen(nm):
|
|
141 |
return FrozenModule(nm)
|
|
142 |
return None
|
|
143 |
class RegistryImportDirector(ImportDirector):
|
|
144 |
# for Windows only
|
|
145 |
def __init__(self):
|
|
146 |
self.path = "WindowsRegistry"
|
|
147 |
self.map = {}
|
|
148 |
try:
|
|
149 |
import win32api
|
|
150 |
import win32con
|
|
151 |
except ImportError:
|
|
152 |
pass
|
|
153 |
else:
|
|
154 |
subkey = r"Software\Python\PythonCore\%s\Modules" % sys.winver
|
|
155 |
for root in (win32con.HKEY_CURRENT_USER, win32con.HKEY_LOCAL_MACHINE):
|
|
156 |
try:
|
|
157 |
#hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_ALL_ACCESS)
|
|
158 |
hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_READ)
|
|
159 |
except:
|
|
160 |
pass
|
|
161 |
else:
|
|
162 |
numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey)
|
|
163 |
for i in range(numsubkeys):
|
|
164 |
subkeyname = win32api.RegEnumKey(hkey, i)
|
|
165 |
#hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, win32con.KEY_ALL_ACCESS)
|
|
166 |
hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, win32con.KEY_READ)
|
|
167 |
val = win32api.RegQueryValueEx(hskey, '')
|
|
168 |
desc = getDescr(val[0])
|
|
169 |
#print " RegistryImportDirector got %s %s" % (val[0], desc) #XXX
|
|
170 |
self.map[subkeyname] = (val[0], desc)
|
|
171 |
hskey.Close()
|
|
172 |
hkey.Close()
|
|
173 |
break
|
|
174 |
def getmod(self, nm):
|
|
175 |
stuff = self.map.get(nm)
|
|
176 |
if stuff:
|
|
177 |
fnm, (suffix, mode, typ) = stuff
|
|
178 |
if typ == imp.C_EXTENSION:
|
|
179 |
return ExtensionModule(nm, fnm)
|
|
180 |
elif typ == imp.PY_SOURCE:
|
|
181 |
try:
|
|
182 |
co = compile(open(fnm, 'r').read()+'\n', fnm, 'exec')
|
|
183 |
except SyntaxError, e:
|
|
184 |
print "Invalid syntax in %s" % py[0]
|
|
185 |
print e.args
|
|
186 |
raise
|
|
187 |
else:
|
|
188 |
stuff = open(fnm, 'rb').read()
|
|
189 |
co = loadco(stuff[8:])
|
|
190 |
return PyModule(nm, fnm, co)
|
|
191 |
return None
|
|
192 |
class PathImportDirector(ImportDirector):
|
|
193 |
def __init__(self, pathlist=None, importers=None, ownertypes=None):
|
|
194 |
if pathlist is None:
|
|
195 |
self.path = sys.path
|
|
196 |
else:
|
|
197 |
self.path = pathlist
|
|
198 |
if ownertypes == None:
|
|
199 |
self.ownertypes = _globalownertypes
|
|
200 |
else:
|
|
201 |
self.ownertypes = ownertypes
|
|
202 |
if importers:
|
|
203 |
self.shadowpath = importers
|
|
204 |
else:
|
|
205 |
self.shadowpath = {}
|
|
206 |
self.inMakeOwner = 0
|
|
207 |
self.building = {}
|
|
208 |
def getmod(self, nm):
|
|
209 |
mod = None
|
|
210 |
for thing in self.path:
|
|
211 |
if type(thing) is STRINGTYPE:
|
|
212 |
owner = self.shadowpath.get(thing, -1)
|
|
213 |
if owner == -1:
|
|
214 |
owner = self.shadowpath[thing] = self.makeOwner(thing)
|
|
215 |
if owner:
|
|
216 |
mod = owner.getmod(nm)
|
|
217 |
else:
|
|
218 |
mod = thing.getmod(nm)
|
|
219 |
if mod:
|
|
220 |
break
|
|
221 |
return mod
|
|
222 |
def makeOwner(self, path):
|
|
223 |
if self.building.get(path):
|
|
224 |
return None
|
|
225 |
self.building[path] = 1
|
|
226 |
owner = None
|
|
227 |
for klass in self.ownertypes:
|
|
228 |
try:
|
|
229 |
# this may cause an import, which may cause recursion
|
|
230 |
# hence the protection
|
|
231 |
owner = klass(path)
|
|
232 |
except:
|
|
233 |
pass
|
|
234 |
else:
|
|
235 |
break
|
|
236 |
del self.building[path]
|
|
237 |
return owner
|
|
238 |
|
|
239 |
|
|
240 |
def getDescr(fnm):
|
|
241 |
ext = os.path.splitext(fnm)[1]
|
|
242 |
for (suffix, mode, typ) in imp.get_suffixes():
|
|
243 |
if suffix == ext:
|
|
244 |
return (suffix, mode, typ)
|
|
245 |
|
|
246 |
#=================Import Tracker============================#
|
|
247 |
# This one doesn't really import, just analyzes
|
|
248 |
# If it *were* importing, it would be the one-and-only ImportManager
|
|
249 |
# ie, the builtin import
|
|
250 |
UNTRIED = -1
|
|
251 |
|
|
252 |
imptyps = ['top-level', 'conditional', 'delayed', 'delayed, conditional']
|
|
253 |
import hooks
|
|
254 |
|
|
255 |
class ImportTracker:
|
|
256 |
# really the equivalent of builtin import
|
|
257 |
def __init__(self, xpath=None, hookspath=None, excludes=None):
|
|
258 |
self.path = []
|
|
259 |
self.warnings = {}
|
|
260 |
if xpath:
|
|
261 |
self.path = xpath
|
|
262 |
self.path.extend(sys.path)
|
|
263 |
self.modules = {}
|
|
264 |
self.metapath = [
|
|
265 |
BuiltinImportDirector(),
|
|
266 |
FrozenImportDirector(),
|
|
267 |
RegistryImportDirector(),
|
|
268 |
PathImportDirector(self.path)
|
|
269 |
]
|
|
270 |
if hookspath:
|
|
271 |
hooks.__path__.extend(hookspath)
|
|
272 |
self.excludes = excludes
|
|
273 |
if excludes is None:
|
|
274 |
self.excludes = []
|
|
275 |
def analyze_r(self, nm, importernm=None):
|
|
276 |
importer = importernm
|
|
277 |
if importer is None:
|
|
278 |
importer = '__main__'
|
|
279 |
seen = {}
|
|
280 |
nms = self.analyze_one(nm, importernm)
|
|
281 |
nms = map(None, nms, [importer]*len(nms))
|
|
282 |
i = 0
|
|
283 |
while i < len(nms):
|
|
284 |
nm, importer = nms[i]
|
|
285 |
if seen.get(nm,0):
|
|
286 |
del nms[i]
|
|
287 |
mod = self.modules[nm]
|
|
288 |
if mod:
|
|
289 |
mod.xref(importer)
|
|
290 |
else:
|
|
291 |
i = i + 1
|
|
292 |
seen[nm] = 1
|
|
293 |
j = i
|
|
294 |
mod = self.modules[nm]
|
|
295 |
if mod:
|
|
296 |
mod.xref(importer)
|
|
297 |
for name, isdelayed, isconditional in mod.imports:
|
|
298 |
imptyp = isdelayed * 2 + isconditional
|
|
299 |
newnms = self.analyze_one(name, nm, imptyp)
|
|
300 |
newnms = map(None, newnms, [nm]*len(newnms))
|
|
301 |
nms[j:j] = newnms
|
|
302 |
j = j + len(newnms)
|
|
303 |
return map(lambda a: a[0], nms)
|
|
304 |
def analyze_one(self, nm, importernm=None, imptyp=0):
|
|
305 |
# first see if we could be importing a relative name
|
|
306 |
contexts = [None]
|
|
307 |
_all = None
|
|
308 |
if importernm:
|
|
309 |
if self.ispackage(importernm):
|
|
310 |
contexts.insert(0,importernm)
|
|
311 |
else:
|
|
312 |
pkgnm = string.join(string.split(importernm, '.')[:-1], '.')
|
|
313 |
if pkgnm:
|
|
314 |
contexts.insert(0,pkgnm)
|
|
315 |
# so contexts is [pkgnm, None] or just [None]
|
|
316 |
# now break the name being imported up so we get:
|
|
317 |
# a.b.c -> [a, b, c]
|
|
318 |
nmparts = string.split(nm, '.')
|
|
319 |
if nmparts[-1] == '*':
|
|
320 |
del nmparts[-1]
|
|
321 |
_all = []
|
|
322 |
nms = []
|
|
323 |
for context in contexts:
|
|
324 |
ctx = context
|
|
325 |
for i in range(len(nmparts)):
|
|
326 |
nm = nmparts[i]
|
|
327 |
if ctx:
|
|
328 |
fqname = ctx + '.' + nm
|
|
329 |
else:
|
|
330 |
fqname = nm
|
|
331 |
mod = self.modules.get(fqname, UNTRIED)
|
|
332 |
if mod is UNTRIED:
|
|
333 |
mod = self.doimport(nm, ctx, fqname)
|
|
334 |
if mod:
|
|
335 |
nms.append(mod.__name__)
|
|
336 |
ctx = fqname
|
|
337 |
else:
|
|
338 |
break
|
|
339 |
else:
|
|
340 |
# no break, point i beyond end
|
|
341 |
i = i + 1
|
|
342 |
if i:
|
|
343 |
break
|
|
344 |
# now nms is the list of modules that went into sys.modules
|
|
345 |
# just as result of the structure of the name being imported
|
|
346 |
# however, each mod has been scanned and that list is in mod.imports
|
|
347 |
if i<len(nmparts):
|
|
348 |
if ctx:
|
|
349 |
if hasattr(self.modules[ctx], nmparts[i]):
|
|
350 |
return nms
|
|
351 |
if not self.ispackage(ctx):
|
|
352 |
return nms
|
|
353 |
self.warnings["W: no module named %s (%s import by %s)" % (fqname, imptyps[imptyp], importernm or "__main__")] = 1
|
|
354 |
if self.modules.has_key(fqname):
|
|
355 |
del self.modules[fqname]
|
|
356 |
return nms
|
|
357 |
if _all is None:
|
|
358 |
return nms
|
|
359 |
bottommod = self.modules[ctx]
|
|
360 |
if bottommod.ispackage():
|
|
361 |
for nm in bottommod._all:
|
|
362 |
if not hasattr(bottommod, nm):
|
|
363 |
mod = self.doimport(nm, ctx, ctx+'.'+nm)
|
|
364 |
if mod:
|
|
365 |
nms.append(mod.__name__)
|
|
366 |
else:
|
|
367 |
bottommod.warnings.append("W: name %s not found" % nm)
|
|
368 |
return nms
|
|
369 |
|
|
370 |
def analyze_script(self, fnm):
|
|
371 |
try:
|
|
372 |
co = compile(open(fnm, 'r').read()+'\n', fnm, 'exec')
|
|
373 |
except SyntaxError, e:
|
|
374 |
print "Invalid syntax in %s" % fnm
|
|
375 |
print e.args
|
|
376 |
raise
|
|
377 |
mod = PyScript(fnm, co)
|
|
378 |
self.modules['__main__'] = mod
|
|
379 |
return self.analyze_r('__main__')
|
|
380 |
|
|
381 |
|
|
382 |
def ispackage(self, nm):
|
|
383 |
return self.modules[nm].ispackage()
|
|
384 |
|
|
385 |
def doimport(self, nm, parentnm, fqname):
|
|
386 |
# Not that nm is NEVER a dotted name at this point
|
|
387 |
if fqname in self.excludes:
|
|
388 |
return None
|
|
389 |
if parentnm:
|
|
390 |
parent = self.modules[parentnm]
|
|
391 |
if parent.ispackage():
|
|
392 |
mod = parent.doimport(nm)
|
|
393 |
if mod:
|
|
394 |
setattr(parent, nm, mod)
|
|
395 |
else:
|
|
396 |
return None
|
|
397 |
else:
|
|
398 |
# now we're dealing with an absolute import
|
|
399 |
for director in self.metapath:
|
|
400 |
mod = director.getmod(nm)
|
|
401 |
if mod:
|
|
402 |
break
|
|
403 |
if mod:
|
|
404 |
mod.__name__ = fqname
|
|
405 |
self.modules[fqname] = mod
|
|
406 |
# now look for hooks
|
|
407 |
# this (and scan_code) are instead of doing "exec co in mod.__dict__"
|
|
408 |
try:
|
|
409 |
hookmodnm = 'hook-'+fqname
|
|
410 |
hooks = __import__('hooks', globals(), locals(), [hookmodnm])
|
|
411 |
hook = getattr(hooks, hookmodnm)
|
|
412 |
#print `hook`
|
|
413 |
except (ImportError, AttributeError):
|
|
414 |
pass
|
|
415 |
else:
|
|
416 |
# rearranged so that hook() has a chance to mess with hiddenimports & attrs
|
|
417 |
if hasattr(hook, 'hook'):
|
|
418 |
mod = hook.hook(mod)
|
|
419 |
if hasattr(hook, 'hiddenimports'):
|
|
420 |
for impnm in hook.hiddenimports:
|
|
421 |
mod.imports.append((impnm, 0, 0))
|
|
422 |
if hasattr(hook, 'attrs'):
|
|
423 |
for attr, val in hook.attrs:
|
|
424 |
setattr(mod, attr, val)
|
|
425 |
|
|
426 |
if fqname != mod.__name__:
|
|
427 |
print "W: %s is changing it's name to %s" % (fqname, mod.__name__)
|
|
428 |
self.modules[mod.__name__] = mod
|
|
429 |
else:
|
|
430 |
self.modules[fqname] = None
|
|
431 |
return mod
|
|
432 |
def getwarnings(self):
|
|
433 |
warnings = self.warnings.keys()
|
|
434 |
for nm,mod in self.modules.items():
|
|
435 |
if mod:
|
|
436 |
for w in mod.warnings:
|
|
437 |
warnings.append(w+' - %s (%s)' % (mod.__name__, mod.__file__))
|
|
438 |
return warnings
|
|
439 |
def getxref(self):
|
|
440 |
mods = self.modules.items() # (nm, mod)
|
|
441 |
mods.sort()
|
|
442 |
rslt = []
|
|
443 |
for nm, mod in mods:
|
|
444 |
if mod:
|
|
445 |
importers = mod._xref.keys()
|
|
446 |
importers.sort()
|
|
447 |
rslt.append((nm, importers))
|
|
448 |
return rslt
|
|
449 |
|
|
450 |
#====================Modules============================#
|
|
451 |
# All we're doing here is tracking, not importing
|
|
452 |
# If we were importing, these would be hooked to the real module objects
|
|
453 |
|
|
454 |
class Module:
|
|
455 |
_ispkg = 0
|
|
456 |
typ = 'UNKNOWN'
|
|
457 |
def __init__(self, nm):
|
|
458 |
self.__name__ = nm
|
|
459 |
self._all = []
|
|
460 |
self.imports = []
|
|
461 |
self.warnings = []
|
|
462 |
self._xref = {}
|
|
463 |
def ispackage(self):
|
|
464 |
return self._ispkg
|
|
465 |
def doimport(self, nm):
|
|
466 |
pass
|
|
467 |
def xref(self, nm):
|
|
468 |
self._xref[nm] = 1
|
|
469 |
|
|
470 |
class BuiltinModule(Module):
|
|
471 |
typ = 'BUILTIN'
|
|
472 |
def __init__(self, nm):
|
|
473 |
Module.__init__(self, nm)
|
|
474 |
|
|
475 |
class ExtensionModule(Module):
|
|
476 |
typ = 'EXTENSION'
|
|
477 |
def __init__(self, nm, pth):
|
|
478 |
Module.__init__(self, nm)
|
|
479 |
self.__file__ = pth
|
|
480 |
|
|
481 |
class PyModule(Module):
|
|
482 |
typ = 'PYMODULE'
|
|
483 |
def __init__(self, nm, pth, co):
|
|
484 |
Module.__init__(self, nm)
|
|
485 |
self.co = co
|
|
486 |
self.__file__ = pth
|
|
487 |
if os.path.splitext(self.__file__)[1] == '.py':
|
|
488 |
if __debug__:
|
|
489 |
self.__file__ = self.__file__ + 'c'
|
|
490 |
else:
|
|
491 |
self.__file__ = self.__file__ + 'o'
|
|
492 |
self.scancode()
|
|
493 |
def scancode(self):
|
|
494 |
self.imports, self.warnings, allnms = scan_code(self.co)
|
|
495 |
if allnms:
|
|
496 |
self._all = allnms
|
|
497 |
|
|
498 |
class PyScript(PyModule):
|
|
499 |
typ = 'PYSOURCE'
|
|
500 |
def __init__(self, pth, co):
|
|
501 |
Module.__init__(self, '__main__')
|
|
502 |
self.co = co
|
|
503 |
self.__file__ = pth
|
|
504 |
self.scancode()
|
|
505 |
|
|
506 |
class PkgModule(PyModule):
|
|
507 |
typ = 'PYMODULE'
|
|
508 |
def __init__(self, nm, pth, co):
|
|
509 |
PyModule.__init__(self, nm, pth, co)
|
|
510 |
self._ispkg = 1
|
|
511 |
pth = os.path.dirname(pth)
|
|
512 |
self.__path__ = [ pth ]
|
|
513 |
self.subimporter = PathImportDirector(self.__path__)
|
|
514 |
def doimport(self, nm):
|
|
515 |
mod = self.subimporter.getmod(nm)
|
|
516 |
if mod:
|
|
517 |
mod.__name__ = self.__name__ + '.' + mod.__name__
|
|
518 |
return mod
|
|
519 |
|
|
520 |
class PkgInPYZModule(PyModule):
|
|
521 |
def __init__(self, nm, co, pyzowner):
|
|
522 |
PyModule.__init__(self, nm, co.co_filename, co)
|
|
523 |
self._ispkg = 1
|
|
524 |
self.__path__ = [ str(pyzowner) ]
|
|
525 |
self.owner = pyzowner
|
|
526 |
def doimport(self, nm):
|
|
527 |
mod = self.owner.getmod(self.__name__ + '.' + nm)
|
|
528 |
return mod
|
|
529 |
|
|
530 |
#======================== Utility ================================#
|
|
531 |
# Scan the code object for imports, __all__ and wierd stuff
|
|
532 |
|
|
533 |
import dis
|
|
534 |
IMPORT_NAME = dis.opname.index('IMPORT_NAME')
|
|
535 |
IMPORT_FROM = dis.opname.index('IMPORT_FROM')
|
|
536 |
try:
|
|
537 |
IMPORT_STAR = dis.opname.index('IMPORT_STAR')
|
|
538 |
except:
|
|
539 |
IMPORT_STAR = 999
|
|
540 |
STORE_NAME = dis.opname.index('STORE_NAME')
|
|
541 |
STORE_FAST = dis.opname.index('STORE_FAST')
|
|
542 |
STORE_GLOBAL = dis.opname.index('STORE_GLOBAL')
|
|
543 |
LOAD_GLOBAL = dis.opname.index('LOAD_GLOBAL')
|
|
544 |
EXEC_STMT = dis.opname.index('EXEC_STMT')
|
|
545 |
try:
|
|
546 |
SET_LINENO = dis.opname.index('SET_LINENO')
|
|
547 |
except ValueError:
|
|
548 |
SET_LINENO = 999
|
|
549 |
BUILD_LIST = dis.opname.index('BUILD_LIST')
|
|
550 |
LOAD_CONST = dis.opname.index('LOAD_CONST')
|
|
551 |
JUMP_IF_FALSE = dis.opname.index('JUMP_IF_FALSE')
|
|
552 |
JUMP_IF_TRUE = dis.opname.index('JUMP_IF_TRUE')
|
|
553 |
JUMP_FORWARD = dis.opname.index('JUMP_FORWARD')
|
|
554 |
try:
|
|
555 |
STORE_DEREF = dis.opname.index('STORE_DEREF')
|
|
556 |
except ValueError:
|
|
557 |
STORE_DEREF = 999
|
|
558 |
COND_OPS = [JUMP_IF_TRUE, JUMP_IF_FALSE]
|
|
559 |
STORE_OPS = [STORE_NAME, STORE_FAST, STORE_GLOBAL, STORE_DEREF]
|
|
560 |
#IMPORT_STAR -> IMPORT_NAME mod ; IMPORT_STAR
|
|
561 |
#JUMP_IF_FALSE / JUMP_IF_TRUE / JUMP_FORWARD
|
|
562 |
|
|
563 |
def pass1(code):
|
|
564 |
instrs = []
|
|
565 |
i = 0
|
|
566 |
n = len(code)
|
|
567 |
curline = 0
|
|
568 |
incondition = 0
|
|
569 |
out = 0
|
|
570 |
while i < n:
|
|
571 |
if i >= out:
|
|
572 |
incondition = 0
|
|
573 |
c = code[i]
|
|
574 |
i = i+1
|
|
575 |
op = ord(c)
|
|
576 |
if op >= dis.HAVE_ARGUMENT:
|
|
577 |
oparg = ord(code[i]) + ord(code[i+1])*256
|
|
578 |
i = i+2
|
|
579 |
else:
|
|
580 |
oparg = None
|
|
581 |
if not incondition and op in COND_OPS:
|
|
582 |
incondition = 1
|
|
583 |
out = i + oparg
|
|
584 |
elif incondition and op == JUMP_FORWARD:
|
|
585 |
out = max(out, i + oparg)
|
|
586 |
if op == SET_LINENO:
|
|
587 |
curline = oparg
|
|
588 |
else:
|
|
589 |
instrs.append((op, oparg, incondition, curline))
|
|
590 |
return instrs
|
|
591 |
|
|
592 |
def scan_code(co, m=None, w=None, nested=0):
|
|
593 |
instrs = pass1(co.co_code)
|
|
594 |
if m is None:
|
|
595 |
m = []
|
|
596 |
if w is None:
|
|
597 |
w = []
|
|
598 |
all = None
|
|
599 |
lastname = None
|
|
600 |
for i in range(len(instrs)):
|
|
601 |
op, oparg, conditional, curline = instrs[i]
|
|
602 |
if op == IMPORT_NAME:
|
|
603 |
name = lastname = co.co_names[oparg]
|
|
604 |
m.append((name, nested, conditional))
|
|
605 |
elif op == IMPORT_FROM:
|
|
606 |
name = co.co_names[oparg]
|
|
607 |
m.append((lastname+'.'+name, nested, conditional))
|
|
608 |
assert lastname is not None
|
|
609 |
elif op == IMPORT_STAR:
|
|
610 |
m.append((lastname+'.*', nested, conditional))
|
|
611 |
elif op == STORE_NAME:
|
|
612 |
if co.co_names[oparg] == "__all__":
|
|
613 |
j = i - 1
|
|
614 |
pop, poparg, pcondtl, pline = instrs[j]
|
|
615 |
if pop != BUILD_LIST:
|
|
616 |
w.append("W: __all__ is built strangely at line %s" % pline)
|
|
617 |
else:
|
|
618 |
all = []
|
|
619 |
while j > 0:
|
|
620 |
j = j - 1
|
|
621 |
pop, poparg, pcondtl, pline = instrs[j]
|
|
622 |
if pop == LOAD_CONST:
|
|
623 |
all.append(co.co_consts[poparg])
|
|
624 |
else:
|
|
625 |
break
|
|
626 |
elif op in STORE_OPS:
|
|
627 |
pass
|
|
628 |
elif op == LOAD_GLOBAL:
|
|
629 |
name = co.co_names[oparg]
|
|
630 |
cndtl = ['', 'conditional'][conditional]
|
|
631 |
lvl = ['top-level', 'delayed'][nested]
|
|
632 |
if name == "__import__":
|
|
633 |
w.append("W: %s %s __import__ hack detected at line %s" % (lvl, cndtl, curline))
|
|
634 |
elif name == "eval":
|
|
635 |
w.append("W: %s %s eval hack detected at line %s" % (lvl, cndtl, curline))
|
|
636 |
elif op == EXEC_STMT:
|
|
637 |
cndtl = ['', 'conditional'][conditional]
|
|
638 |
lvl = ['top-level', 'delayed'][nested]
|
|
639 |
w.append("W: %s %s exec statement detected at line %s" % (lvl, cndtl, curline))
|
|
640 |
else:
|
|
641 |
lastname = None
|
|
642 |
for c in co.co_consts:
|
|
643 |
if isinstance(c, type(co)):
|
|
644 |
scan_code(c, m, w, 1)
|
|
645 |
return m, w, all
|