1import sys 2 3 4class VendorImporter: 5 """ 6 A PEP 302 meta path importer for finding optionally-vendored 7 or otherwise naturally-installed packages from root_name. 8 """ 9 10 def __init__(self, root_name, vendored_names=(), vendor_pkg=None): 11 self.root_name = root_name 12 self.vendored_names = set(vendored_names) 13 self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') 14 15 @property 16 def search_path(self): 17 """ 18 Search first the vendor package then as a natural package. 19 """ 20 yield self.vendor_pkg + '.' 21 yield '' 22 23 def find_module(self, fullname, path=None): 24 """ 25 Return self when fullname starts with root_name and the 26 target module is one vendored through this importer. 27 """ 28 root, base, target = fullname.partition(self.root_name + '.') 29 if root: 30 return 31 if not any(map(target.startswith, self.vendored_names)): 32 return 33 return self 34 35 def load_module(self, fullname): 36 """ 37 Iterate over the search path to locate and load fullname. 38 """ 39 root, base, target = fullname.partition(self.root_name + '.') 40 for prefix in self.search_path: 41 try: 42 extant = prefix + target 43 __import__(extant) 44 mod = sys.modules[extant] 45 sys.modules[fullname] = mod 46 # mysterious hack: 47 # Remove the reference to the extant package/module 48 # on later Python versions to cause relative imports 49 # in the vendor package to resolve the same modules 50 # as those going through this importer. 51 if sys.version_info > (3, 3): 52 del sys.modules[extant] 53 return mod 54 except ImportError: 55 pass 56 else: 57 raise ImportError( 58 "The '{target}' package is required; " 59 "normally this is bundled with this package so if you get " 60 "this warning, consult the packager of your " 61 "distribution.".format(**locals()) 62 ) 63 64 def install(self): 65 """ 66 Install this importer into sys.meta_path if not already present. 67 """ 68 if self not in sys.meta_path: 69 sys.meta_path.append(self) 70 71 72names = 'packaging', 'pyparsing', 'six', 'appdirs' 73VendorImporter(__name__, names).install() 74