imports.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # -*- coding: utf-8 -*-
  2. """Utilities related to importing modules and symbols by name."""
  3. from __future__ import absolute_import, unicode_literals
  4. import imp as _imp
  5. import importlib
  6. import os
  7. import sys
  8. import warnings
  9. from contextlib import contextmanager
  10. from kombu.utils.imports import symbol_by_name
  11. from celery.five import reload
  12. #: Billiard sets this when execv is enabled.
  13. #: We use it to find out the name of the original ``__main__``
  14. #: module, so that we can properly rewrite the name of the
  15. #: task to be that of ``App.main``.
  16. MP_MAIN_FILE = os.environ.get('MP_MAIN_FILE')
  17. __all__ = [
  18. 'NotAPackage', 'qualname', 'instantiate', 'symbol_by_name',
  19. 'cwd_in_path', 'find_module', 'import_from_cwd',
  20. 'reload_from_cwd', 'module_file', 'gen_task_name',
  21. ]
  22. class NotAPackage(Exception):
  23. """Raised when importing a package, but it's not a package."""
  24. if sys.version_info > (3, 3): # pragma: no cover
  25. def qualname(obj):
  26. """Return object name."""
  27. if not hasattr(obj, '__name__') and hasattr(obj, '__class__'):
  28. obj = obj.__class__
  29. q = getattr(obj, '__qualname__', None)
  30. if '.' not in q:
  31. q = '.'.join((obj.__module__, q))
  32. return q
  33. else:
  34. def qualname(obj): # noqa
  35. """Return object name."""
  36. if not hasattr(obj, '__name__') and hasattr(obj, '__class__'):
  37. obj = obj.__class__
  38. return '.'.join((obj.__module__, obj.__name__))
  39. def instantiate(name, *args, **kwargs):
  40. """Instantiate class by name.
  41. See Also:
  42. :func:`symbol_by_name`.
  43. """
  44. return symbol_by_name(name)(*args, **kwargs)
  45. @contextmanager
  46. def cwd_in_path():
  47. """Context adding the current working directory to sys.path."""
  48. cwd = os.getcwd()
  49. if cwd in sys.path:
  50. yield
  51. else:
  52. sys.path.insert(0, cwd)
  53. try:
  54. yield cwd
  55. finally:
  56. try:
  57. sys.path.remove(cwd)
  58. except ValueError: # pragma: no cover
  59. pass
  60. def find_module(module, path=None, imp=None):
  61. """Version of :func:`imp.find_module` supporting dots."""
  62. if imp is None:
  63. imp = importlib.import_module
  64. with cwd_in_path():
  65. if '.' in module:
  66. last = None
  67. parts = module.split('.')
  68. for i, part in enumerate(parts[:-1]):
  69. mpart = imp('.'.join(parts[:i + 1]))
  70. try:
  71. path = mpart.__path__
  72. except AttributeError:
  73. raise NotAPackage(module)
  74. last = _imp.find_module(parts[i + 1], path)
  75. return last
  76. return _imp.find_module(module)
  77. def import_from_cwd(module, imp=None, package=None):
  78. """Import module, temporarily including modules in the current directory.
  79. Modules located in the current directory has
  80. precedence over modules located in `sys.path`.
  81. """
  82. if imp is None:
  83. imp = importlib.import_module
  84. with cwd_in_path():
  85. return imp(module, package=package)
  86. def reload_from_cwd(module, reloader=None):
  87. """Reload module (ensuring that CWD is in sys.path)."""
  88. if reloader is None:
  89. reloader = reload
  90. with cwd_in_path():
  91. return reloader(module)
  92. def module_file(module):
  93. """Return the correct original file name of a module."""
  94. name = module.__file__
  95. return name[:-1] if name.endswith('.pyc') else name
  96. def gen_task_name(app, name, module_name):
  97. """Generate task name from name/module pair."""
  98. module_name = module_name or '__main__'
  99. try:
  100. module = sys.modules[module_name]
  101. except KeyError:
  102. # Fix for manage.py shell_plus (Issue #366)
  103. module = None
  104. if module is not None:
  105. module_name = module.__name__
  106. # - If the task module is used as the __main__ script
  107. # - we need to rewrite the module part of the task name
  108. # - to match App.main.
  109. if MP_MAIN_FILE and module.__file__ == MP_MAIN_FILE:
  110. # - see comment about :envvar:`MP_MAIN_FILE` above.
  111. module_name = '__main__'
  112. if module_name == '__main__' and app.main:
  113. return '.'.join([app.main, name])
  114. return '.'.join(p for p in (module_name, name) if p)
  115. def load_extension_class_names(namespace):
  116. try:
  117. from pkg_resources import iter_entry_points
  118. except ImportError: # pragma: no cover
  119. return
  120. for ep in iter_entry_points(namespace):
  121. yield ep.name, ':'.join([ep.module_name, ep.attrs[0]])
  122. def load_extension_classes(namespace):
  123. for name, class_name in load_extension_class_names(namespace):
  124. try:
  125. cls = symbol_by_name(class_name)
  126. except (ImportError, SyntaxError) as exc:
  127. warnings.warn(
  128. 'Cannot load {0} extension {1!r}: {2!r}'.format(
  129. namespace, class_name, exc))
  130. else:
  131. yield name, cls