📄 modulegraph.py
字号:
self.msgout(2, "raise ImportError: Bad magic number", pathname) raise ImportError, "Bad magic number in %s" % pathname fp.read(4) co = marshal.load(fp) cls = CompiledModule elif typ == imp.C_BUILTIN: cls = BuiltinModule co = None else: cls = Extension co = None m = self.createNode(cls, fqname) m.filename = pathname if co: if self.replace_paths: co = self.replace_paths_in_code(co) m.code = co self.scan_code(co, m) self.msgout(2, "load_module ->", m) return m def _safe_import_hook(self, name, caller, fromlist): # wrapper for self.import_hook() that won't raise ImportError try: m = self.import_hook(name, caller).pop() except ImportError, msg: self.msg(2, "ImportError:", str(msg)) m = self.createNode(MissingModule, name) subs = set([m]) for sub in set(fromlist or ()): if sub in m: subs.add(m[sub]) continue fullname = name + '.' + sub sm = self.findNode(fullname) if sm is None: try: sm = self.import_hook(name, caller, [sub]) except ImportError, msg: self.msg(2, "ImportError:", str(msg)) sm = self.createNode(MissingModule, fullname) else: sm = self.findNode(fullname) m[sub] = sm if sm is not None: self.createReference(sm, m) subs.add(sm) return subs def scan_code(self, co, m): code = co.co_code n = len(code) i = 0 fromlist = None while i < n: c = code[i] i = i+1 op = ord(c) if op >= dis.HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i+1])*256 i = i+2 if op == LOAD_CONST: # An IMPORT_NAME is always preceded by a LOAD_CONST, it's # a tuple of "from" names, or None for a regular import. # The tuple may contain "*" for "from <mod> import *" fromlist = co.co_consts[oparg] elif op == IMPORT_NAME: assert fromlist is None or type(fromlist) is tuple name = co.co_names[oparg] have_star = False if fromlist is not None: fromlist = set(fromlist) if '*' in fromlist: fromlist.remove('*') have_star = True self._safe_import_hook(name, m, fromlist) if have_star: # We've encountered an "import *". If it is a Python module, # the code has already been parsed and we can suck out the # global names. mm = None if m.packagepath: # At this point we don't know whether 'name' is a # submodule of 'm' or a global module. Let's just try # the full name first. mm = self.findNode(m.identifier + '.' + name) if mm is None: mm = self.findNode(name) if mm is not None: m.globalnames.update(mm.globalnames) m.starimports.update(mm.starimports) if mm.code is None: m.starimports.add(name) else: m.starimports.add(name) elif op in STORE_OPS: # keep track of all global names that are assigned to name = co.co_names[oparg] m.globalnames.add(name) for c in co.co_consts: if isinstance(c, type(co)): self.scan_code(c, m) def load_package(self, fqname, pathname): self.msgin(2, "load_package", fqname, pathname) newname = replacePackageMap.get(fqname) if newname: fqname = newname m = self.createNode(Package, fqname) m.filename = pathname m.packagepath = [pathname] # As per comment at top of file, simulate runtime packagepath additions. m.packagepath = m.packagepath + packagePathMap.get(fqname, []) fp, buf, stuff = self.find_module("__init__", m.packagepath) self.load_module(fqname, fp, buf, stuff) self.msgout(2, "load_package ->", m) return m def find_module(self, name, path, parent=None): if parent is not None: # assert path is not None fullname = parent.identifier+'.'+name else: fullname = name node = self.findNode(fullname) if node is not None: self.msgout(3, "find_module -> already included?", node) raise ImportError, name if path is None: if name in sys.builtin_module_names: return (None, None, ("", "", imp.C_BUILTIN)) path = self.path fp, buf, stuff = imp.find_module(name, path) if buf: buf = os.path.realpath(buf) return (fp, buf, stuff) def itergraphreport(self, name='G', flatpackages=()): nodes = map(self.graph.describe_node, self.graph.iterdfs(self)) describe_edge = self.graph.describe_edge edges = deque() packagenodes = set() packageidents = {} nodetoident = {} inpackages = {} mainedges = set() # XXX - implement flatpackages = dict(flatpackages) def nodevisitor(node, data, outgoing, incoming): if not isinstance(data, Node): return {'label': str(node)} #if isinstance(d, (ExcludedModule, MissingModule, BadModule)): # return None s = '<f0> ' + type(data).__name__ for i,v in izip(count(1), data.infoTuple()[:1]): s += '| <f%d> %s' % (i,v) return {'label':s, 'shape':'record'} def edgevisitor(edge, data, head, tail): if data == 'orphan': return {'style':'dashed'} elif data == 'pkgref': return {'style':'dotted'} return {} yield 'digraph %s {\n' % (name,) attr = dict(rankdir='LR', concentrate='true') cpatt = '%s="%s"' for item in attr.iteritems(): yield '\t%s;\n' % (cpatt % item,) # find all packages (subgraphs) for (node, data, outgoing, incoming) in nodes: nodetoident[node] = getattr(data, 'identifier', None) if isinstance(data, Package): packageidents[data.identifier] = node inpackages[node] = set([node]) packagenodes.add(node) # create sets for subgraph, write out descriptions for (node, data, outgoing, incoming) in nodes: # update edges for edge in imap(describe_edge, outgoing): edges.append(edge) # describe node yield '\t"%s" [%s];\n' % ( node, ','.join([ (cpatt % item) for item in nodevisitor(node, data, outgoing, incoming).iteritems() ]), ) inside = inpackages.get(node) if inside is None: inside = inpackages[node] = set() ident = nodetoident[node] if ident is None: continue pkgnode = packageidents.get(ident[:ident.rfind('.')]) if pkgnode is not None: inside.add(pkgnode) graph = [] subgraphs = {} for key in packagenodes: subgraphs[key] = [] while edges: edge, data, head, tail = edges.popleft() if ((head, tail)) in mainedges: continue mainedges.add((head, tail)) tailpkgs = inpackages[tail] common = inpackages[head] & tailpkgs if not common and tailpkgs: usepkgs = sorted(tailpkgs) if len(usepkgs) != 1 or usepkgs[0] != tail: edges.append((edge, data, head, usepkgs[0])) edges.append((edge, 'pkgref', usepkgs[-1], tail)) continue if common: common = common.pop() if tail == common: edges.append((edge, data, tail, head)) elif head == common: subgraphs[common].append((edge, 'pkgref', head, tail)) else: edges.append((edge, data, common, head)) edges.append((edge, data, common, tail)) else: graph.append((edge, data, head, tail)) def do_graph(edges, tabs): edgestr = tabs + '"%s" -> "%s" [%s];\n' # describe edge for (edge, data, head, tail) in edges: attribs = edgevisitor(edge, data, head, tail) yield edgestr % ( head, tail, ','.join([(cpatt % item) for item in attribs.iteritems()]), ) for g, edges in subgraphs.iteritems(): yield '\tsubgraph "cluster_%s" {\n' % (g,) yield '\t\tlabel="%s";\n' % (nodetoident[g],) for s in do_graph(edges, '\t\t'): yield s yield '\t}\n' for s in do_graph(graph, '\t'): yield s yield '}\n' def graphreport(self, fileobj=None, flatpackages=()): if fileobj is None: fileobj = sys.stdout fileobj.writelines(self.itergraphreport(flatpackages=flatpackages)) def report(self): """Print a report to stdout, listing the found modules with their paths, as well as modules that are missing, or seem to be missing. """ print print "%-15s %-25s %s" % ("Class", "Name", "File") print "%-15s %-25s %s" % ("----", "----", "----") # Print modules found sorted = [(os.path.basename(mod.identifier), mod) for mod in self.flatten()] sorted.sort() for (name, m) in sorted: print "%-15s %-25s %s" % (type(m).__name__, name, m.filename or "") def replace_paths_in_code(self, co): new_filename = original_filename = os.path.normpath(co.co_filename) for f, r in self.replace_paths: f = os.path.join(f, '') r = os.path.join(r, '') if original_filename.startswith(f): new_filename = r + original_filename[len(f):] break consts = list(co.co_consts) for i in range(len(consts)): if isinstance(consts[i], type(co)): consts[i] = self.replace_paths_in_code(consts[i]) return new.code(co.co_argcount, co.co_nlocals, co.co_stacksize, co.co_flags, co.co_code, tuple(consts), co.co_names, co.co_varnames, new_filename, co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars, co.co_cellvars)def main(): # Parse command line import getopt try: opts, args = getopt.getopt(sys.argv[1:], "dgmp:qx:") except getopt.error, msg: print msg return # Process options debug = 1 domods = 0 dodot = False addpath = [] exclude = [] for o, a in opts: if o == '-d': debug = debug + 1 if o == '-m': domods = 1 if o == '-p': addpath = addpath + a.split(os.pathsep) if o == '-q': debug = 0 if o == '-x': exclude.append(a) if o == '-g': dodot = True # Provide default arguments if not args: script = "hello.py" else: script = args[0] # Set the path based on sys.path and the script directory path = sys.path[:] path[0] = os.path.dirname(script) path = addpath + path if debug > 1: print "path:" for item in path: print " ", repr(item) # Create the module finder and turn its crank mf = ModuleGraph(path, debug, exclude) for arg in args[1:]: if arg == '-m': domods = 1 continue if domods: if arg[-2:] == '.*': mf.import_hook(arg[:-2], None, ["*"]) else: mf.import_hook(arg) else: mf.run_script(arg) mf.run_script(script) if dodot: mf.graphreport() else: mf.report() return mf # for -i debuggingif __name__ == '__main__': try: mf = main() except KeyboardInterrupt: print "\n[interrupt]"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -