1*cda5da8dSAndroid Build Coastguard Worker"""Find modules used by a script, using introspection.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport dis 4*cda5da8dSAndroid Build Coastguard Workerimport importlib._bootstrap_external 5*cda5da8dSAndroid Build Coastguard Workerimport importlib.machinery 6*cda5da8dSAndroid Build Coastguard Workerimport marshal 7*cda5da8dSAndroid Build Coastguard Workerimport os 8*cda5da8dSAndroid Build Coastguard Workerimport io 9*cda5da8dSAndroid Build Coastguard Workerimport sys 10*cda5da8dSAndroid Build Coastguard Worker 11*cda5da8dSAndroid Build Coastguard Worker# Old imp constants: 12*cda5da8dSAndroid Build Coastguard Worker 13*cda5da8dSAndroid Build Coastguard Worker_SEARCH_ERROR = 0 14*cda5da8dSAndroid Build Coastguard Worker_PY_SOURCE = 1 15*cda5da8dSAndroid Build Coastguard Worker_PY_COMPILED = 2 16*cda5da8dSAndroid Build Coastguard Worker_C_EXTENSION = 3 17*cda5da8dSAndroid Build Coastguard Worker_PKG_DIRECTORY = 5 18*cda5da8dSAndroid Build Coastguard Worker_C_BUILTIN = 6 19*cda5da8dSAndroid Build Coastguard Worker_PY_FROZEN = 7 20*cda5da8dSAndroid Build Coastguard Worker 21*cda5da8dSAndroid Build Coastguard Worker# Modulefinder does a good job at simulating Python's, but it can not 22*cda5da8dSAndroid Build Coastguard Worker# handle __path__ modifications packages make at runtime. Therefore there 23*cda5da8dSAndroid Build Coastguard Worker# is a mechanism whereby you can register extra paths in this map for a 24*cda5da8dSAndroid Build Coastguard Worker# package, and it will be honored. 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker# Note this is a mapping is lists of paths. 27*cda5da8dSAndroid Build Coastguard WorkerpackagePathMap = {} 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker# A Public interface 30*cda5da8dSAndroid Build Coastguard Workerdef AddPackagePath(packagename, path): 31*cda5da8dSAndroid Build Coastguard Worker packagePathMap.setdefault(packagename, []).append(path) 32*cda5da8dSAndroid Build Coastguard Worker 33*cda5da8dSAndroid Build Coastguard WorkerreplacePackageMap = {} 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard Worker# This ReplacePackage mechanism allows modulefinder to work around 36*cda5da8dSAndroid Build Coastguard Worker# situations in which a package injects itself under the name 37*cda5da8dSAndroid Build Coastguard Worker# of another package into sys.modules at runtime by calling 38*cda5da8dSAndroid Build Coastguard Worker# ReplacePackage("real_package_name", "faked_package_name") 39*cda5da8dSAndroid Build Coastguard Worker# before running ModuleFinder. 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Workerdef ReplacePackage(oldname, newname): 42*cda5da8dSAndroid Build Coastguard Worker replacePackageMap[oldname] = newname 43*cda5da8dSAndroid Build Coastguard Worker 44*cda5da8dSAndroid Build Coastguard Worker 45*cda5da8dSAndroid Build Coastguard Workerdef _find_module(name, path=None): 46*cda5da8dSAndroid Build Coastguard Worker """An importlib reimplementation of imp.find_module (for our purposes).""" 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Worker # It's necessary to clear the caches for our Finder first, in case any 49*cda5da8dSAndroid Build Coastguard Worker # modules are being added/deleted/modified at runtime. In particular, 50*cda5da8dSAndroid Build Coastguard Worker # test_modulefinder.py changes file tree contents in a cache-breaking way: 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker importlib.machinery.PathFinder.invalidate_caches() 53*cda5da8dSAndroid Build Coastguard Worker 54*cda5da8dSAndroid Build Coastguard Worker spec = importlib.machinery.PathFinder.find_spec(name, path) 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Worker if spec is None: 57*cda5da8dSAndroid Build Coastguard Worker raise ImportError("No module named {name!r}".format(name=name), name=name) 58*cda5da8dSAndroid Build Coastguard Worker 59*cda5da8dSAndroid Build Coastguard Worker # Some special cases: 60*cda5da8dSAndroid Build Coastguard Worker 61*cda5da8dSAndroid Build Coastguard Worker if spec.loader is importlib.machinery.BuiltinImporter: 62*cda5da8dSAndroid Build Coastguard Worker return None, None, ("", "", _C_BUILTIN) 63*cda5da8dSAndroid Build Coastguard Worker 64*cda5da8dSAndroid Build Coastguard Worker if spec.loader is importlib.machinery.FrozenImporter: 65*cda5da8dSAndroid Build Coastguard Worker return None, None, ("", "", _PY_FROZEN) 66*cda5da8dSAndroid Build Coastguard Worker 67*cda5da8dSAndroid Build Coastguard Worker file_path = spec.origin 68*cda5da8dSAndroid Build Coastguard Worker 69*cda5da8dSAndroid Build Coastguard Worker if spec.loader.is_package(name): 70*cda5da8dSAndroid Build Coastguard Worker return None, os.path.dirname(file_path), ("", "", _PKG_DIRECTORY) 71*cda5da8dSAndroid Build Coastguard Worker 72*cda5da8dSAndroid Build Coastguard Worker if isinstance(spec.loader, importlib.machinery.SourceFileLoader): 73*cda5da8dSAndroid Build Coastguard Worker kind = _PY_SOURCE 74*cda5da8dSAndroid Build Coastguard Worker 75*cda5da8dSAndroid Build Coastguard Worker elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader): 76*cda5da8dSAndroid Build Coastguard Worker kind = _C_EXTENSION 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader): 79*cda5da8dSAndroid Build Coastguard Worker kind = _PY_COMPILED 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Worker else: # Should never happen. 82*cda5da8dSAndroid Build Coastguard Worker return None, None, ("", "", _SEARCH_ERROR) 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker file = io.open_code(file_path) 85*cda5da8dSAndroid Build Coastguard Worker suffix = os.path.splitext(file_path)[-1] 86*cda5da8dSAndroid Build Coastguard Worker 87*cda5da8dSAndroid Build Coastguard Worker return file, file_path, (suffix, "rb", kind) 88*cda5da8dSAndroid Build Coastguard Worker 89*cda5da8dSAndroid Build Coastguard Worker 90*cda5da8dSAndroid Build Coastguard Workerclass Module: 91*cda5da8dSAndroid Build Coastguard Worker 92*cda5da8dSAndroid Build Coastguard Worker def __init__(self, name, file=None, path=None): 93*cda5da8dSAndroid Build Coastguard Worker self.__name__ = name 94*cda5da8dSAndroid Build Coastguard Worker self.__file__ = file 95*cda5da8dSAndroid Build Coastguard Worker self.__path__ = path 96*cda5da8dSAndroid Build Coastguard Worker self.__code__ = None 97*cda5da8dSAndroid Build Coastguard Worker # The set of global names that are assigned to in the module. 98*cda5da8dSAndroid Build Coastguard Worker # This includes those names imported through starimports of 99*cda5da8dSAndroid Build Coastguard Worker # Python modules. 100*cda5da8dSAndroid Build Coastguard Worker self.globalnames = {} 101*cda5da8dSAndroid Build Coastguard Worker # The set of starimports this module did that could not be 102*cda5da8dSAndroid Build Coastguard Worker # resolved, ie. a starimport from a non-Python module. 103*cda5da8dSAndroid Build Coastguard Worker self.starimports = {} 104*cda5da8dSAndroid Build Coastguard Worker 105*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 106*cda5da8dSAndroid Build Coastguard Worker s = "Module(%r" % (self.__name__,) 107*cda5da8dSAndroid Build Coastguard Worker if self.__file__ is not None: 108*cda5da8dSAndroid Build Coastguard Worker s = s + ", %r" % (self.__file__,) 109*cda5da8dSAndroid Build Coastguard Worker if self.__path__ is not None: 110*cda5da8dSAndroid Build Coastguard Worker s = s + ", %r" % (self.__path__,) 111*cda5da8dSAndroid Build Coastguard Worker s = s + ")" 112*cda5da8dSAndroid Build Coastguard Worker return s 113*cda5da8dSAndroid Build Coastguard Worker 114*cda5da8dSAndroid Build Coastguard Workerclass ModuleFinder: 115*cda5da8dSAndroid Build Coastguard Worker 116*cda5da8dSAndroid Build Coastguard Worker def __init__(self, path=None, debug=0, excludes=None, replace_paths=None): 117*cda5da8dSAndroid Build Coastguard Worker if path is None: 118*cda5da8dSAndroid Build Coastguard Worker path = sys.path 119*cda5da8dSAndroid Build Coastguard Worker self.path = path 120*cda5da8dSAndroid Build Coastguard Worker self.modules = {} 121*cda5da8dSAndroid Build Coastguard Worker self.badmodules = {} 122*cda5da8dSAndroid Build Coastguard Worker self.debug = debug 123*cda5da8dSAndroid Build Coastguard Worker self.indent = 0 124*cda5da8dSAndroid Build Coastguard Worker self.excludes = excludes if excludes is not None else [] 125*cda5da8dSAndroid Build Coastguard Worker self.replace_paths = replace_paths if replace_paths is not None else [] 126*cda5da8dSAndroid Build Coastguard Worker self.processed_paths = [] # Used in debugging only 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker def msg(self, level, str, *args): 129*cda5da8dSAndroid Build Coastguard Worker if level <= self.debug: 130*cda5da8dSAndroid Build Coastguard Worker for i in range(self.indent): 131*cda5da8dSAndroid Build Coastguard Worker print(" ", end=' ') 132*cda5da8dSAndroid Build Coastguard Worker print(str, end=' ') 133*cda5da8dSAndroid Build Coastguard Worker for arg in args: 134*cda5da8dSAndroid Build Coastguard Worker print(repr(arg), end=' ') 135*cda5da8dSAndroid Build Coastguard Worker print() 136*cda5da8dSAndroid Build Coastguard Worker 137*cda5da8dSAndroid Build Coastguard Worker def msgin(self, *args): 138*cda5da8dSAndroid Build Coastguard Worker level = args[0] 139*cda5da8dSAndroid Build Coastguard Worker if level <= self.debug: 140*cda5da8dSAndroid Build Coastguard Worker self.indent = self.indent + 1 141*cda5da8dSAndroid Build Coastguard Worker self.msg(*args) 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Worker def msgout(self, *args): 144*cda5da8dSAndroid Build Coastguard Worker level = args[0] 145*cda5da8dSAndroid Build Coastguard Worker if level <= self.debug: 146*cda5da8dSAndroid Build Coastguard Worker self.indent = self.indent - 1 147*cda5da8dSAndroid Build Coastguard Worker self.msg(*args) 148*cda5da8dSAndroid Build Coastguard Worker 149*cda5da8dSAndroid Build Coastguard Worker def run_script(self, pathname): 150*cda5da8dSAndroid Build Coastguard Worker self.msg(2, "run_script", pathname) 151*cda5da8dSAndroid Build Coastguard Worker with io.open_code(pathname) as fp: 152*cda5da8dSAndroid Build Coastguard Worker stuff = ("", "rb", _PY_SOURCE) 153*cda5da8dSAndroid Build Coastguard Worker self.load_module('__main__', fp, pathname, stuff) 154*cda5da8dSAndroid Build Coastguard Worker 155*cda5da8dSAndroid Build Coastguard Worker def load_file(self, pathname): 156*cda5da8dSAndroid Build Coastguard Worker dir, name = os.path.split(pathname) 157*cda5da8dSAndroid Build Coastguard Worker name, ext = os.path.splitext(name) 158*cda5da8dSAndroid Build Coastguard Worker with io.open_code(pathname) as fp: 159*cda5da8dSAndroid Build Coastguard Worker stuff = (ext, "rb", _PY_SOURCE) 160*cda5da8dSAndroid Build Coastguard Worker self.load_module(name, fp, pathname, stuff) 161*cda5da8dSAndroid Build Coastguard Worker 162*cda5da8dSAndroid Build Coastguard Worker def import_hook(self, name, caller=None, fromlist=None, level=-1): 163*cda5da8dSAndroid Build Coastguard Worker self.msg(3, "import_hook", name, caller, fromlist, level) 164*cda5da8dSAndroid Build Coastguard Worker parent = self.determine_parent(caller, level=level) 165*cda5da8dSAndroid Build Coastguard Worker q, tail = self.find_head_package(parent, name) 166*cda5da8dSAndroid Build Coastguard Worker m = self.load_tail(q, tail) 167*cda5da8dSAndroid Build Coastguard Worker if not fromlist: 168*cda5da8dSAndroid Build Coastguard Worker return q 169*cda5da8dSAndroid Build Coastguard Worker if m.__path__: 170*cda5da8dSAndroid Build Coastguard Worker self.ensure_fromlist(m, fromlist) 171*cda5da8dSAndroid Build Coastguard Worker return None 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker def determine_parent(self, caller, level=-1): 174*cda5da8dSAndroid Build Coastguard Worker self.msgin(4, "determine_parent", caller, level) 175*cda5da8dSAndroid Build Coastguard Worker if not caller or level == 0: 176*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent -> None") 177*cda5da8dSAndroid Build Coastguard Worker return None 178*cda5da8dSAndroid Build Coastguard Worker pname = caller.__name__ 179*cda5da8dSAndroid Build Coastguard Worker if level >= 1: # relative import 180*cda5da8dSAndroid Build Coastguard Worker if caller.__path__: 181*cda5da8dSAndroid Build Coastguard Worker level -= 1 182*cda5da8dSAndroid Build Coastguard Worker if level == 0: 183*cda5da8dSAndroid Build Coastguard Worker parent = self.modules[pname] 184*cda5da8dSAndroid Build Coastguard Worker assert parent is caller 185*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent ->", parent) 186*cda5da8dSAndroid Build Coastguard Worker return parent 187*cda5da8dSAndroid Build Coastguard Worker if pname.count(".") < level: 188*cda5da8dSAndroid Build Coastguard Worker raise ImportError("relative importpath too deep") 189*cda5da8dSAndroid Build Coastguard Worker pname = ".".join(pname.split(".")[:-level]) 190*cda5da8dSAndroid Build Coastguard Worker parent = self.modules[pname] 191*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent ->", parent) 192*cda5da8dSAndroid Build Coastguard Worker return parent 193*cda5da8dSAndroid Build Coastguard Worker if caller.__path__: 194*cda5da8dSAndroid Build Coastguard Worker parent = self.modules[pname] 195*cda5da8dSAndroid Build Coastguard Worker assert caller is parent 196*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent ->", parent) 197*cda5da8dSAndroid Build Coastguard Worker return parent 198*cda5da8dSAndroid Build Coastguard Worker if '.' in pname: 199*cda5da8dSAndroid Build Coastguard Worker i = pname.rfind('.') 200*cda5da8dSAndroid Build Coastguard Worker pname = pname[:i] 201*cda5da8dSAndroid Build Coastguard Worker parent = self.modules[pname] 202*cda5da8dSAndroid Build Coastguard Worker assert parent.__name__ == pname 203*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent ->", parent) 204*cda5da8dSAndroid Build Coastguard Worker return parent 205*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "determine_parent -> None") 206*cda5da8dSAndroid Build Coastguard Worker return None 207*cda5da8dSAndroid Build Coastguard Worker 208*cda5da8dSAndroid Build Coastguard Worker def find_head_package(self, parent, name): 209*cda5da8dSAndroid Build Coastguard Worker self.msgin(4, "find_head_package", parent, name) 210*cda5da8dSAndroid Build Coastguard Worker if '.' in name: 211*cda5da8dSAndroid Build Coastguard Worker i = name.find('.') 212*cda5da8dSAndroid Build Coastguard Worker head = name[:i] 213*cda5da8dSAndroid Build Coastguard Worker tail = name[i+1:] 214*cda5da8dSAndroid Build Coastguard Worker else: 215*cda5da8dSAndroid Build Coastguard Worker head = name 216*cda5da8dSAndroid Build Coastguard Worker tail = "" 217*cda5da8dSAndroid Build Coastguard Worker if parent: 218*cda5da8dSAndroid Build Coastguard Worker qname = "%s.%s" % (parent.__name__, head) 219*cda5da8dSAndroid Build Coastguard Worker else: 220*cda5da8dSAndroid Build Coastguard Worker qname = head 221*cda5da8dSAndroid Build Coastguard Worker q = self.import_module(head, qname, parent) 222*cda5da8dSAndroid Build Coastguard Worker if q: 223*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "find_head_package ->", (q, tail)) 224*cda5da8dSAndroid Build Coastguard Worker return q, tail 225*cda5da8dSAndroid Build Coastguard Worker if parent: 226*cda5da8dSAndroid Build Coastguard Worker qname = head 227*cda5da8dSAndroid Build Coastguard Worker parent = None 228*cda5da8dSAndroid Build Coastguard Worker q = self.import_module(head, qname, parent) 229*cda5da8dSAndroid Build Coastguard Worker if q: 230*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "find_head_package ->", (q, tail)) 231*cda5da8dSAndroid Build Coastguard Worker return q, tail 232*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "raise ImportError: No module named", qname) 233*cda5da8dSAndroid Build Coastguard Worker raise ImportError("No module named " + qname) 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker def load_tail(self, q, tail): 236*cda5da8dSAndroid Build Coastguard Worker self.msgin(4, "load_tail", q, tail) 237*cda5da8dSAndroid Build Coastguard Worker m = q 238*cda5da8dSAndroid Build Coastguard Worker while tail: 239*cda5da8dSAndroid Build Coastguard Worker i = tail.find('.') 240*cda5da8dSAndroid Build Coastguard Worker if i < 0: i = len(tail) 241*cda5da8dSAndroid Build Coastguard Worker head, tail = tail[:i], tail[i+1:] 242*cda5da8dSAndroid Build Coastguard Worker mname = "%s.%s" % (m.__name__, head) 243*cda5da8dSAndroid Build Coastguard Worker m = self.import_module(head, mname, m) 244*cda5da8dSAndroid Build Coastguard Worker if not m: 245*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "raise ImportError: No module named", mname) 246*cda5da8dSAndroid Build Coastguard Worker raise ImportError("No module named " + mname) 247*cda5da8dSAndroid Build Coastguard Worker self.msgout(4, "load_tail ->", m) 248*cda5da8dSAndroid Build Coastguard Worker return m 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker def ensure_fromlist(self, m, fromlist, recursive=0): 251*cda5da8dSAndroid Build Coastguard Worker self.msg(4, "ensure_fromlist", m, fromlist, recursive) 252*cda5da8dSAndroid Build Coastguard Worker for sub in fromlist: 253*cda5da8dSAndroid Build Coastguard Worker if sub == "*": 254*cda5da8dSAndroid Build Coastguard Worker if not recursive: 255*cda5da8dSAndroid Build Coastguard Worker all = self.find_all_submodules(m) 256*cda5da8dSAndroid Build Coastguard Worker if all: 257*cda5da8dSAndroid Build Coastguard Worker self.ensure_fromlist(m, all, 1) 258*cda5da8dSAndroid Build Coastguard Worker elif not hasattr(m, sub): 259*cda5da8dSAndroid Build Coastguard Worker subname = "%s.%s" % (m.__name__, sub) 260*cda5da8dSAndroid Build Coastguard Worker submod = self.import_module(sub, subname, m) 261*cda5da8dSAndroid Build Coastguard Worker if not submod: 262*cda5da8dSAndroid Build Coastguard Worker raise ImportError("No module named " + subname) 263*cda5da8dSAndroid Build Coastguard Worker 264*cda5da8dSAndroid Build Coastguard Worker def find_all_submodules(self, m): 265*cda5da8dSAndroid Build Coastguard Worker if not m.__path__: 266*cda5da8dSAndroid Build Coastguard Worker return 267*cda5da8dSAndroid Build Coastguard Worker modules = {} 268*cda5da8dSAndroid Build Coastguard Worker # 'suffixes' used to be a list hardcoded to [".py", ".pyc"]. 269*cda5da8dSAndroid Build Coastguard Worker # But we must also collect Python extension modules - although 270*cda5da8dSAndroid Build Coastguard Worker # we cannot separate normal dlls from Python extensions. 271*cda5da8dSAndroid Build Coastguard Worker suffixes = [] 272*cda5da8dSAndroid Build Coastguard Worker suffixes += importlib.machinery.EXTENSION_SUFFIXES[:] 273*cda5da8dSAndroid Build Coastguard Worker suffixes += importlib.machinery.SOURCE_SUFFIXES[:] 274*cda5da8dSAndroid Build Coastguard Worker suffixes += importlib.machinery.BYTECODE_SUFFIXES[:] 275*cda5da8dSAndroid Build Coastguard Worker for dir in m.__path__: 276*cda5da8dSAndroid Build Coastguard Worker try: 277*cda5da8dSAndroid Build Coastguard Worker names = os.listdir(dir) 278*cda5da8dSAndroid Build Coastguard Worker except OSError: 279*cda5da8dSAndroid Build Coastguard Worker self.msg(2, "can't list directory", dir) 280*cda5da8dSAndroid Build Coastguard Worker continue 281*cda5da8dSAndroid Build Coastguard Worker for name in names: 282*cda5da8dSAndroid Build Coastguard Worker mod = None 283*cda5da8dSAndroid Build Coastguard Worker for suff in suffixes: 284*cda5da8dSAndroid Build Coastguard Worker n = len(suff) 285*cda5da8dSAndroid Build Coastguard Worker if name[-n:] == suff: 286*cda5da8dSAndroid Build Coastguard Worker mod = name[:-n] 287*cda5da8dSAndroid Build Coastguard Worker break 288*cda5da8dSAndroid Build Coastguard Worker if mod and mod != "__init__": 289*cda5da8dSAndroid Build Coastguard Worker modules[mod] = mod 290*cda5da8dSAndroid Build Coastguard Worker return modules.keys() 291*cda5da8dSAndroid Build Coastguard Worker 292*cda5da8dSAndroid Build Coastguard Worker def import_module(self, partname, fqname, parent): 293*cda5da8dSAndroid Build Coastguard Worker self.msgin(3, "import_module", partname, fqname, parent) 294*cda5da8dSAndroid Build Coastguard Worker try: 295*cda5da8dSAndroid Build Coastguard Worker m = self.modules[fqname] 296*cda5da8dSAndroid Build Coastguard Worker except KeyError: 297*cda5da8dSAndroid Build Coastguard Worker pass 298*cda5da8dSAndroid Build Coastguard Worker else: 299*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "import_module ->", m) 300*cda5da8dSAndroid Build Coastguard Worker return m 301*cda5da8dSAndroid Build Coastguard Worker if fqname in self.badmodules: 302*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "import_module -> None") 303*cda5da8dSAndroid Build Coastguard Worker return None 304*cda5da8dSAndroid Build Coastguard Worker if parent and parent.__path__ is None: 305*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "import_module -> None") 306*cda5da8dSAndroid Build Coastguard Worker return None 307*cda5da8dSAndroid Build Coastguard Worker try: 308*cda5da8dSAndroid Build Coastguard Worker fp, pathname, stuff = self.find_module(partname, 309*cda5da8dSAndroid Build Coastguard Worker parent and parent.__path__, parent) 310*cda5da8dSAndroid Build Coastguard Worker except ImportError: 311*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "import_module ->", None) 312*cda5da8dSAndroid Build Coastguard Worker return None 313*cda5da8dSAndroid Build Coastguard Worker 314*cda5da8dSAndroid Build Coastguard Worker try: 315*cda5da8dSAndroid Build Coastguard Worker m = self.load_module(fqname, fp, pathname, stuff) 316*cda5da8dSAndroid Build Coastguard Worker finally: 317*cda5da8dSAndroid Build Coastguard Worker if fp: 318*cda5da8dSAndroid Build Coastguard Worker fp.close() 319*cda5da8dSAndroid Build Coastguard Worker if parent: 320*cda5da8dSAndroid Build Coastguard Worker setattr(parent, partname, m) 321*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "import_module ->", m) 322*cda5da8dSAndroid Build Coastguard Worker return m 323*cda5da8dSAndroid Build Coastguard Worker 324*cda5da8dSAndroid Build Coastguard Worker def load_module(self, fqname, fp, pathname, file_info): 325*cda5da8dSAndroid Build Coastguard Worker suffix, mode, type = file_info 326*cda5da8dSAndroid Build Coastguard Worker self.msgin(2, "load_module", fqname, fp and "fp", pathname) 327*cda5da8dSAndroid Build Coastguard Worker if type == _PKG_DIRECTORY: 328*cda5da8dSAndroid Build Coastguard Worker m = self.load_package(fqname, pathname) 329*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "load_module ->", m) 330*cda5da8dSAndroid Build Coastguard Worker return m 331*cda5da8dSAndroid Build Coastguard Worker if type == _PY_SOURCE: 332*cda5da8dSAndroid Build Coastguard Worker co = compile(fp.read(), pathname, 'exec') 333*cda5da8dSAndroid Build Coastguard Worker elif type == _PY_COMPILED: 334*cda5da8dSAndroid Build Coastguard Worker try: 335*cda5da8dSAndroid Build Coastguard Worker data = fp.read() 336*cda5da8dSAndroid Build Coastguard Worker importlib._bootstrap_external._classify_pyc(data, fqname, {}) 337*cda5da8dSAndroid Build Coastguard Worker except ImportError as exc: 338*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "raise ImportError: " + str(exc), pathname) 339*cda5da8dSAndroid Build Coastguard Worker raise 340*cda5da8dSAndroid Build Coastguard Worker co = marshal.loads(memoryview(data)[16:]) 341*cda5da8dSAndroid Build Coastguard Worker else: 342*cda5da8dSAndroid Build Coastguard Worker co = None 343*cda5da8dSAndroid Build Coastguard Worker m = self.add_module(fqname) 344*cda5da8dSAndroid Build Coastguard Worker m.__file__ = pathname 345*cda5da8dSAndroid Build Coastguard Worker if co: 346*cda5da8dSAndroid Build Coastguard Worker if self.replace_paths: 347*cda5da8dSAndroid Build Coastguard Worker co = self.replace_paths_in_code(co) 348*cda5da8dSAndroid Build Coastguard Worker m.__code__ = co 349*cda5da8dSAndroid Build Coastguard Worker self.scan_code(co, m) 350*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "load_module ->", m) 351*cda5da8dSAndroid Build Coastguard Worker return m 352*cda5da8dSAndroid Build Coastguard Worker 353*cda5da8dSAndroid Build Coastguard Worker def _add_badmodule(self, name, caller): 354*cda5da8dSAndroid Build Coastguard Worker if name not in self.badmodules: 355*cda5da8dSAndroid Build Coastguard Worker self.badmodules[name] = {} 356*cda5da8dSAndroid Build Coastguard Worker if caller: 357*cda5da8dSAndroid Build Coastguard Worker self.badmodules[name][caller.__name__] = 1 358*cda5da8dSAndroid Build Coastguard Worker else: 359*cda5da8dSAndroid Build Coastguard Worker self.badmodules[name]["-"] = 1 360*cda5da8dSAndroid Build Coastguard Worker 361*cda5da8dSAndroid Build Coastguard Worker def _safe_import_hook(self, name, caller, fromlist, level=-1): 362*cda5da8dSAndroid Build Coastguard Worker # wrapper for self.import_hook() that won't raise ImportError 363*cda5da8dSAndroid Build Coastguard Worker if name in self.badmodules: 364*cda5da8dSAndroid Build Coastguard Worker self._add_badmodule(name, caller) 365*cda5da8dSAndroid Build Coastguard Worker return 366*cda5da8dSAndroid Build Coastguard Worker try: 367*cda5da8dSAndroid Build Coastguard Worker self.import_hook(name, caller, level=level) 368*cda5da8dSAndroid Build Coastguard Worker except ImportError as msg: 369*cda5da8dSAndroid Build Coastguard Worker self.msg(2, "ImportError:", str(msg)) 370*cda5da8dSAndroid Build Coastguard Worker self._add_badmodule(name, caller) 371*cda5da8dSAndroid Build Coastguard Worker except SyntaxError as msg: 372*cda5da8dSAndroid Build Coastguard Worker self.msg(2, "SyntaxError:", str(msg)) 373*cda5da8dSAndroid Build Coastguard Worker self._add_badmodule(name, caller) 374*cda5da8dSAndroid Build Coastguard Worker else: 375*cda5da8dSAndroid Build Coastguard Worker if fromlist: 376*cda5da8dSAndroid Build Coastguard Worker for sub in fromlist: 377*cda5da8dSAndroid Build Coastguard Worker fullname = name + "." + sub 378*cda5da8dSAndroid Build Coastguard Worker if fullname in self.badmodules: 379*cda5da8dSAndroid Build Coastguard Worker self._add_badmodule(fullname, caller) 380*cda5da8dSAndroid Build Coastguard Worker continue 381*cda5da8dSAndroid Build Coastguard Worker try: 382*cda5da8dSAndroid Build Coastguard Worker self.import_hook(name, caller, [sub], level=level) 383*cda5da8dSAndroid Build Coastguard Worker except ImportError as msg: 384*cda5da8dSAndroid Build Coastguard Worker self.msg(2, "ImportError:", str(msg)) 385*cda5da8dSAndroid Build Coastguard Worker self._add_badmodule(fullname, caller) 386*cda5da8dSAndroid Build Coastguard Worker 387*cda5da8dSAndroid Build Coastguard Worker def scan_opcodes(self, co): 388*cda5da8dSAndroid Build Coastguard Worker # Scan the code, and yield 'interesting' opcode combinations 389*cda5da8dSAndroid Build Coastguard Worker for name in dis._find_store_names(co): 390*cda5da8dSAndroid Build Coastguard Worker yield "store", (name,) 391*cda5da8dSAndroid Build Coastguard Worker for name, level, fromlist in dis._find_imports(co): 392*cda5da8dSAndroid Build Coastguard Worker if level == 0: # absolute import 393*cda5da8dSAndroid Build Coastguard Worker yield "absolute_import", (fromlist, name) 394*cda5da8dSAndroid Build Coastguard Worker else: # relative import 395*cda5da8dSAndroid Build Coastguard Worker yield "relative_import", (level, fromlist, name) 396*cda5da8dSAndroid Build Coastguard Worker 397*cda5da8dSAndroid Build Coastguard Worker def scan_code(self, co, m): 398*cda5da8dSAndroid Build Coastguard Worker code = co.co_code 399*cda5da8dSAndroid Build Coastguard Worker scanner = self.scan_opcodes 400*cda5da8dSAndroid Build Coastguard Worker for what, args in scanner(co): 401*cda5da8dSAndroid Build Coastguard Worker if what == "store": 402*cda5da8dSAndroid Build Coastguard Worker name, = args 403*cda5da8dSAndroid Build Coastguard Worker m.globalnames[name] = 1 404*cda5da8dSAndroid Build Coastguard Worker elif what == "absolute_import": 405*cda5da8dSAndroid Build Coastguard Worker fromlist, name = args 406*cda5da8dSAndroid Build Coastguard Worker have_star = 0 407*cda5da8dSAndroid Build Coastguard Worker if fromlist is not None: 408*cda5da8dSAndroid Build Coastguard Worker if "*" in fromlist: 409*cda5da8dSAndroid Build Coastguard Worker have_star = 1 410*cda5da8dSAndroid Build Coastguard Worker fromlist = [f for f in fromlist if f != "*"] 411*cda5da8dSAndroid Build Coastguard Worker self._safe_import_hook(name, m, fromlist, level=0) 412*cda5da8dSAndroid Build Coastguard Worker if have_star: 413*cda5da8dSAndroid Build Coastguard Worker # We've encountered an "import *". If it is a Python module, 414*cda5da8dSAndroid Build Coastguard Worker # the code has already been parsed and we can suck out the 415*cda5da8dSAndroid Build Coastguard Worker # global names. 416*cda5da8dSAndroid Build Coastguard Worker mm = None 417*cda5da8dSAndroid Build Coastguard Worker if m.__path__: 418*cda5da8dSAndroid Build Coastguard Worker # At this point we don't know whether 'name' is a 419*cda5da8dSAndroid Build Coastguard Worker # submodule of 'm' or a global module. Let's just try 420*cda5da8dSAndroid Build Coastguard Worker # the full name first. 421*cda5da8dSAndroid Build Coastguard Worker mm = self.modules.get(m.__name__ + "." + name) 422*cda5da8dSAndroid Build Coastguard Worker if mm is None: 423*cda5da8dSAndroid Build Coastguard Worker mm = self.modules.get(name) 424*cda5da8dSAndroid Build Coastguard Worker if mm is not None: 425*cda5da8dSAndroid Build Coastguard Worker m.globalnames.update(mm.globalnames) 426*cda5da8dSAndroid Build Coastguard Worker m.starimports.update(mm.starimports) 427*cda5da8dSAndroid Build Coastguard Worker if mm.__code__ is None: 428*cda5da8dSAndroid Build Coastguard Worker m.starimports[name] = 1 429*cda5da8dSAndroid Build Coastguard Worker else: 430*cda5da8dSAndroid Build Coastguard Worker m.starimports[name] = 1 431*cda5da8dSAndroid Build Coastguard Worker elif what == "relative_import": 432*cda5da8dSAndroid Build Coastguard Worker level, fromlist, name = args 433*cda5da8dSAndroid Build Coastguard Worker if name: 434*cda5da8dSAndroid Build Coastguard Worker self._safe_import_hook(name, m, fromlist, level=level) 435*cda5da8dSAndroid Build Coastguard Worker else: 436*cda5da8dSAndroid Build Coastguard Worker parent = self.determine_parent(m, level=level) 437*cda5da8dSAndroid Build Coastguard Worker self._safe_import_hook(parent.__name__, None, fromlist, level=0) 438*cda5da8dSAndroid Build Coastguard Worker else: 439*cda5da8dSAndroid Build Coastguard Worker # We don't expect anything else from the generator. 440*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError(what) 441*cda5da8dSAndroid Build Coastguard Worker 442*cda5da8dSAndroid Build Coastguard Worker for c in co.co_consts: 443*cda5da8dSAndroid Build Coastguard Worker if isinstance(c, type(co)): 444*cda5da8dSAndroid Build Coastguard Worker self.scan_code(c, m) 445*cda5da8dSAndroid Build Coastguard Worker 446*cda5da8dSAndroid Build Coastguard Worker def load_package(self, fqname, pathname): 447*cda5da8dSAndroid Build Coastguard Worker self.msgin(2, "load_package", fqname, pathname) 448*cda5da8dSAndroid Build Coastguard Worker newname = replacePackageMap.get(fqname) 449*cda5da8dSAndroid Build Coastguard Worker if newname: 450*cda5da8dSAndroid Build Coastguard Worker fqname = newname 451*cda5da8dSAndroid Build Coastguard Worker m = self.add_module(fqname) 452*cda5da8dSAndroid Build Coastguard Worker m.__file__ = pathname 453*cda5da8dSAndroid Build Coastguard Worker m.__path__ = [pathname] 454*cda5da8dSAndroid Build Coastguard Worker 455*cda5da8dSAndroid Build Coastguard Worker # As per comment at top of file, simulate runtime __path__ additions. 456*cda5da8dSAndroid Build Coastguard Worker m.__path__ = m.__path__ + packagePathMap.get(fqname, []) 457*cda5da8dSAndroid Build Coastguard Worker 458*cda5da8dSAndroid Build Coastguard Worker fp, buf, stuff = self.find_module("__init__", m.__path__) 459*cda5da8dSAndroid Build Coastguard Worker try: 460*cda5da8dSAndroid Build Coastguard Worker self.load_module(fqname, fp, buf, stuff) 461*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "load_package ->", m) 462*cda5da8dSAndroid Build Coastguard Worker return m 463*cda5da8dSAndroid Build Coastguard Worker finally: 464*cda5da8dSAndroid Build Coastguard Worker if fp: 465*cda5da8dSAndroid Build Coastguard Worker fp.close() 466*cda5da8dSAndroid Build Coastguard Worker 467*cda5da8dSAndroid Build Coastguard Worker def add_module(self, fqname): 468*cda5da8dSAndroid Build Coastguard Worker if fqname in self.modules: 469*cda5da8dSAndroid Build Coastguard Worker return self.modules[fqname] 470*cda5da8dSAndroid Build Coastguard Worker self.modules[fqname] = m = Module(fqname) 471*cda5da8dSAndroid Build Coastguard Worker return m 472*cda5da8dSAndroid Build Coastguard Worker 473*cda5da8dSAndroid Build Coastguard Worker def find_module(self, name, path, parent=None): 474*cda5da8dSAndroid Build Coastguard Worker if parent is not None: 475*cda5da8dSAndroid Build Coastguard Worker # assert path is not None 476*cda5da8dSAndroid Build Coastguard Worker fullname = parent.__name__+'.'+name 477*cda5da8dSAndroid Build Coastguard Worker else: 478*cda5da8dSAndroid Build Coastguard Worker fullname = name 479*cda5da8dSAndroid Build Coastguard Worker if fullname in self.excludes: 480*cda5da8dSAndroid Build Coastguard Worker self.msgout(3, "find_module -> Excluded", fullname) 481*cda5da8dSAndroid Build Coastguard Worker raise ImportError(name) 482*cda5da8dSAndroid Build Coastguard Worker 483*cda5da8dSAndroid Build Coastguard Worker if path is None: 484*cda5da8dSAndroid Build Coastguard Worker if name in sys.builtin_module_names: 485*cda5da8dSAndroid Build Coastguard Worker return (None, None, ("", "", _C_BUILTIN)) 486*cda5da8dSAndroid Build Coastguard Worker 487*cda5da8dSAndroid Build Coastguard Worker path = self.path 488*cda5da8dSAndroid Build Coastguard Worker 489*cda5da8dSAndroid Build Coastguard Worker return _find_module(name, path) 490*cda5da8dSAndroid Build Coastguard Worker 491*cda5da8dSAndroid Build Coastguard Worker def report(self): 492*cda5da8dSAndroid Build Coastguard Worker """Print a report to stdout, listing the found modules with their 493*cda5da8dSAndroid Build Coastguard Worker paths, as well as modules that are missing, or seem to be missing. 494*cda5da8dSAndroid Build Coastguard Worker """ 495*cda5da8dSAndroid Build Coastguard Worker print() 496*cda5da8dSAndroid Build Coastguard Worker print(" %-25s %s" % ("Name", "File")) 497*cda5da8dSAndroid Build Coastguard Worker print(" %-25s %s" % ("----", "----")) 498*cda5da8dSAndroid Build Coastguard Worker # Print modules found 499*cda5da8dSAndroid Build Coastguard Worker keys = sorted(self.modules.keys()) 500*cda5da8dSAndroid Build Coastguard Worker for key in keys: 501*cda5da8dSAndroid Build Coastguard Worker m = self.modules[key] 502*cda5da8dSAndroid Build Coastguard Worker if m.__path__: 503*cda5da8dSAndroid Build Coastguard Worker print("P", end=' ') 504*cda5da8dSAndroid Build Coastguard Worker else: 505*cda5da8dSAndroid Build Coastguard Worker print("m", end=' ') 506*cda5da8dSAndroid Build Coastguard Worker print("%-25s" % key, m.__file__ or "") 507*cda5da8dSAndroid Build Coastguard Worker 508*cda5da8dSAndroid Build Coastguard Worker # Print missing modules 509*cda5da8dSAndroid Build Coastguard Worker missing, maybe = self.any_missing_maybe() 510*cda5da8dSAndroid Build Coastguard Worker if missing: 511*cda5da8dSAndroid Build Coastguard Worker print() 512*cda5da8dSAndroid Build Coastguard Worker print("Missing modules:") 513*cda5da8dSAndroid Build Coastguard Worker for name in missing: 514*cda5da8dSAndroid Build Coastguard Worker mods = sorted(self.badmodules[name].keys()) 515*cda5da8dSAndroid Build Coastguard Worker print("?", name, "imported from", ', '.join(mods)) 516*cda5da8dSAndroid Build Coastguard Worker # Print modules that may be missing, but then again, maybe not... 517*cda5da8dSAndroid Build Coastguard Worker if maybe: 518*cda5da8dSAndroid Build Coastguard Worker print() 519*cda5da8dSAndroid Build Coastguard Worker print("Submodules that appear to be missing, but could also be", end=' ') 520*cda5da8dSAndroid Build Coastguard Worker print("global names in the parent package:") 521*cda5da8dSAndroid Build Coastguard Worker for name in maybe: 522*cda5da8dSAndroid Build Coastguard Worker mods = sorted(self.badmodules[name].keys()) 523*cda5da8dSAndroid Build Coastguard Worker print("?", name, "imported from", ', '.join(mods)) 524*cda5da8dSAndroid Build Coastguard Worker 525*cda5da8dSAndroid Build Coastguard Worker def any_missing(self): 526*cda5da8dSAndroid Build Coastguard Worker """Return a list of modules that appear to be missing. Use 527*cda5da8dSAndroid Build Coastguard Worker any_missing_maybe() if you want to know which modules are 528*cda5da8dSAndroid Build Coastguard Worker certain to be missing, and which *may* be missing. 529*cda5da8dSAndroid Build Coastguard Worker """ 530*cda5da8dSAndroid Build Coastguard Worker missing, maybe = self.any_missing_maybe() 531*cda5da8dSAndroid Build Coastguard Worker return missing + maybe 532*cda5da8dSAndroid Build Coastguard Worker 533*cda5da8dSAndroid Build Coastguard Worker def any_missing_maybe(self): 534*cda5da8dSAndroid Build Coastguard Worker """Return two lists, one with modules that are certainly missing 535*cda5da8dSAndroid Build Coastguard Worker and one with modules that *may* be missing. The latter names could 536*cda5da8dSAndroid Build Coastguard Worker either be submodules *or* just global names in the package. 537*cda5da8dSAndroid Build Coastguard Worker 538*cda5da8dSAndroid Build Coastguard Worker The reason it can't always be determined is that it's impossible to 539*cda5da8dSAndroid Build Coastguard Worker tell which names are imported when "from module import *" is done 540*cda5da8dSAndroid Build Coastguard Worker with an extension module, short of actually importing it. 541*cda5da8dSAndroid Build Coastguard Worker """ 542*cda5da8dSAndroid Build Coastguard Worker missing = [] 543*cda5da8dSAndroid Build Coastguard Worker maybe = [] 544*cda5da8dSAndroid Build Coastguard Worker for name in self.badmodules: 545*cda5da8dSAndroid Build Coastguard Worker if name in self.excludes: 546*cda5da8dSAndroid Build Coastguard Worker continue 547*cda5da8dSAndroid Build Coastguard Worker i = name.rfind(".") 548*cda5da8dSAndroid Build Coastguard Worker if i < 0: 549*cda5da8dSAndroid Build Coastguard Worker missing.append(name) 550*cda5da8dSAndroid Build Coastguard Worker continue 551*cda5da8dSAndroid Build Coastguard Worker subname = name[i+1:] 552*cda5da8dSAndroid Build Coastguard Worker pkgname = name[:i] 553*cda5da8dSAndroid Build Coastguard Worker pkg = self.modules.get(pkgname) 554*cda5da8dSAndroid Build Coastguard Worker if pkg is not None: 555*cda5da8dSAndroid Build Coastguard Worker if pkgname in self.badmodules[name]: 556*cda5da8dSAndroid Build Coastguard Worker # The package tried to import this module itself and 557*cda5da8dSAndroid Build Coastguard Worker # failed. It's definitely missing. 558*cda5da8dSAndroid Build Coastguard Worker missing.append(name) 559*cda5da8dSAndroid Build Coastguard Worker elif subname in pkg.globalnames: 560*cda5da8dSAndroid Build Coastguard Worker # It's a global in the package: definitely not missing. 561*cda5da8dSAndroid Build Coastguard Worker pass 562*cda5da8dSAndroid Build Coastguard Worker elif pkg.starimports: 563*cda5da8dSAndroid Build Coastguard Worker # It could be missing, but the package did an "import *" 564*cda5da8dSAndroid Build Coastguard Worker # from a non-Python module, so we simply can't be sure. 565*cda5da8dSAndroid Build Coastguard Worker maybe.append(name) 566*cda5da8dSAndroid Build Coastguard Worker else: 567*cda5da8dSAndroid Build Coastguard Worker # It's not a global in the package, the package didn't 568*cda5da8dSAndroid Build Coastguard Worker # do funny star imports, it's very likely to be missing. 569*cda5da8dSAndroid Build Coastguard Worker # The symbol could be inserted into the package from the 570*cda5da8dSAndroid Build Coastguard Worker # outside, but since that's not good style we simply list 571*cda5da8dSAndroid Build Coastguard Worker # it missing. 572*cda5da8dSAndroid Build Coastguard Worker missing.append(name) 573*cda5da8dSAndroid Build Coastguard Worker else: 574*cda5da8dSAndroid Build Coastguard Worker missing.append(name) 575*cda5da8dSAndroid Build Coastguard Worker missing.sort() 576*cda5da8dSAndroid Build Coastguard Worker maybe.sort() 577*cda5da8dSAndroid Build Coastguard Worker return missing, maybe 578*cda5da8dSAndroid Build Coastguard Worker 579*cda5da8dSAndroid Build Coastguard Worker def replace_paths_in_code(self, co): 580*cda5da8dSAndroid Build Coastguard Worker new_filename = original_filename = os.path.normpath(co.co_filename) 581*cda5da8dSAndroid Build Coastguard Worker for f, r in self.replace_paths: 582*cda5da8dSAndroid Build Coastguard Worker if original_filename.startswith(f): 583*cda5da8dSAndroid Build Coastguard Worker new_filename = r + original_filename[len(f):] 584*cda5da8dSAndroid Build Coastguard Worker break 585*cda5da8dSAndroid Build Coastguard Worker 586*cda5da8dSAndroid Build Coastguard Worker if self.debug and original_filename not in self.processed_paths: 587*cda5da8dSAndroid Build Coastguard Worker if new_filename != original_filename: 588*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "co_filename %r changed to %r" \ 589*cda5da8dSAndroid Build Coastguard Worker % (original_filename,new_filename,)) 590*cda5da8dSAndroid Build Coastguard Worker else: 591*cda5da8dSAndroid Build Coastguard Worker self.msgout(2, "co_filename %r remains unchanged" \ 592*cda5da8dSAndroid Build Coastguard Worker % (original_filename,)) 593*cda5da8dSAndroid Build Coastguard Worker self.processed_paths.append(original_filename) 594*cda5da8dSAndroid Build Coastguard Worker 595*cda5da8dSAndroid Build Coastguard Worker consts = list(co.co_consts) 596*cda5da8dSAndroid Build Coastguard Worker for i in range(len(consts)): 597*cda5da8dSAndroid Build Coastguard Worker if isinstance(consts[i], type(co)): 598*cda5da8dSAndroid Build Coastguard Worker consts[i] = self.replace_paths_in_code(consts[i]) 599*cda5da8dSAndroid Build Coastguard Worker 600*cda5da8dSAndroid Build Coastguard Worker return co.replace(co_consts=tuple(consts), co_filename=new_filename) 601*cda5da8dSAndroid Build Coastguard Worker 602*cda5da8dSAndroid Build Coastguard Worker 603*cda5da8dSAndroid Build Coastguard Workerdef test(): 604*cda5da8dSAndroid Build Coastguard Worker # Parse command line 605*cda5da8dSAndroid Build Coastguard Worker import getopt 606*cda5da8dSAndroid Build Coastguard Worker try: 607*cda5da8dSAndroid Build Coastguard Worker opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:") 608*cda5da8dSAndroid Build Coastguard Worker except getopt.error as msg: 609*cda5da8dSAndroid Build Coastguard Worker print(msg) 610*cda5da8dSAndroid Build Coastguard Worker return 611*cda5da8dSAndroid Build Coastguard Worker 612*cda5da8dSAndroid Build Coastguard Worker # Process options 613*cda5da8dSAndroid Build Coastguard Worker debug = 1 614*cda5da8dSAndroid Build Coastguard Worker domods = 0 615*cda5da8dSAndroid Build Coastguard Worker addpath = [] 616*cda5da8dSAndroid Build Coastguard Worker exclude = [] 617*cda5da8dSAndroid Build Coastguard Worker for o, a in opts: 618*cda5da8dSAndroid Build Coastguard Worker if o == '-d': 619*cda5da8dSAndroid Build Coastguard Worker debug = debug + 1 620*cda5da8dSAndroid Build Coastguard Worker if o == '-m': 621*cda5da8dSAndroid Build Coastguard Worker domods = 1 622*cda5da8dSAndroid Build Coastguard Worker if o == '-p': 623*cda5da8dSAndroid Build Coastguard Worker addpath = addpath + a.split(os.pathsep) 624*cda5da8dSAndroid Build Coastguard Worker if o == '-q': 625*cda5da8dSAndroid Build Coastguard Worker debug = 0 626*cda5da8dSAndroid Build Coastguard Worker if o == '-x': 627*cda5da8dSAndroid Build Coastguard Worker exclude.append(a) 628*cda5da8dSAndroid Build Coastguard Worker 629*cda5da8dSAndroid Build Coastguard Worker # Provide default arguments 630*cda5da8dSAndroid Build Coastguard Worker if not args: 631*cda5da8dSAndroid Build Coastguard Worker script = "hello.py" 632*cda5da8dSAndroid Build Coastguard Worker else: 633*cda5da8dSAndroid Build Coastguard Worker script = args[0] 634*cda5da8dSAndroid Build Coastguard Worker 635*cda5da8dSAndroid Build Coastguard Worker # Set the path based on sys.path and the script directory 636*cda5da8dSAndroid Build Coastguard Worker path = sys.path[:] 637*cda5da8dSAndroid Build Coastguard Worker path[0] = os.path.dirname(script) 638*cda5da8dSAndroid Build Coastguard Worker path = addpath + path 639*cda5da8dSAndroid Build Coastguard Worker if debug > 1: 640*cda5da8dSAndroid Build Coastguard Worker print("path:") 641*cda5da8dSAndroid Build Coastguard Worker for item in path: 642*cda5da8dSAndroid Build Coastguard Worker print(" ", repr(item)) 643*cda5da8dSAndroid Build Coastguard Worker 644*cda5da8dSAndroid Build Coastguard Worker # Create the module finder and turn its crank 645*cda5da8dSAndroid Build Coastguard Worker mf = ModuleFinder(path, debug, exclude) 646*cda5da8dSAndroid Build Coastguard Worker for arg in args[1:]: 647*cda5da8dSAndroid Build Coastguard Worker if arg == '-m': 648*cda5da8dSAndroid Build Coastguard Worker domods = 1 649*cda5da8dSAndroid Build Coastguard Worker continue 650*cda5da8dSAndroid Build Coastguard Worker if domods: 651*cda5da8dSAndroid Build Coastguard Worker if arg[-2:] == '.*': 652*cda5da8dSAndroid Build Coastguard Worker mf.import_hook(arg[:-2], None, ["*"]) 653*cda5da8dSAndroid Build Coastguard Worker else: 654*cda5da8dSAndroid Build Coastguard Worker mf.import_hook(arg) 655*cda5da8dSAndroid Build Coastguard Worker else: 656*cda5da8dSAndroid Build Coastguard Worker mf.load_file(arg) 657*cda5da8dSAndroid Build Coastguard Worker mf.run_script(script) 658*cda5da8dSAndroid Build Coastguard Worker mf.report() 659*cda5da8dSAndroid Build Coastguard Worker return mf # for -i debugging 660*cda5da8dSAndroid Build Coastguard Worker 661*cda5da8dSAndroid Build Coastguard Worker 662*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__': 663*cda5da8dSAndroid Build Coastguard Worker try: 664*cda5da8dSAndroid Build Coastguard Worker mf = test() 665*cda5da8dSAndroid Build Coastguard Worker except KeyboardInterrupt: 666*cda5da8dSAndroid Build Coastguard Worker print("\n[interrupted]") 667