__init__.py 2.4 KB

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