srcanamdw/codescanner/pyinstaller/mf.py
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     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