imports.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # -*- coding: utf-8 -*-
  2. """
  3. celery.utils.import
  4. ~~~~~~~~~~~~~~~~~~~
  5. Utilities related to importing modules and symbols by name.
  6. """
  7. from __future__ import absolute_import
  8. from __future__ import with_statement
  9. import imp as _imp
  10. import importlib
  11. import os
  12. import sys
  13. from contextlib import contextmanager
  14. from .compat import reload
  15. class NotAPackage(Exception):
  16. pass
  17. if sys.version_info >= (3, 3): # pragma: no cover
  18. def qualname(obj):
  19. return obj.__qualname__
  20. else:
  21. def qualname(obj): # noqa
  22. if not hasattr(obj, '__name__') and hasattr(obj, '__class__'):
  23. return qualname(obj.__class__)
  24. return '%s.%s' % (obj.__module__, obj.__name__)
  25. def symbol_by_name(name, aliases={}, imp=None, package=None,
  26. sep='.', default=None, **kwargs):
  27. """Get symbol by qualified name.
  28. The name should be the full dot-separated path to the class::
  29. modulename.ClassName
  30. Example::
  31. celery.concurrency.processes.TaskPool
  32. ^- class name
  33. or using ':' to separate module and symbol::
  34. celery.concurrency.processes:TaskPool
  35. If `aliases` is provided, a dict containing short name/long name
  36. mappings, the name is looked up in the aliases first.
  37. Examples:
  38. >>> symbol_by_name('celery.concurrency.processes.TaskPool')
  39. <class 'celery.concurrency.processes.TaskPool'>
  40. >>> symbol_by_name('default', {
  41. ... 'default': 'celery.concurrency.processes.TaskPool'})
  42. <class 'celery.concurrency.processes.TaskPool'>
  43. # Does not try to look up non-string names.
  44. >>> from celery.concurrency.processes import TaskPool
  45. >>> symbol_by_name(TaskPool) is TaskPool
  46. True
  47. """
  48. if imp is None:
  49. imp = importlib.import_module
  50. if not isinstance(name, basestring):
  51. return name # already a class
  52. name = aliases.get(name) or name
  53. sep = ':' if ':' in name else sep
  54. module_name, _, cls_name = name.rpartition(sep)
  55. if not module_name:
  56. cls_name, module_name = None, package if package else cls_name
  57. try:
  58. try:
  59. module = imp(module_name, package=package, **kwargs)
  60. except ValueError, exc:
  61. raise ValueError, ValueError(
  62. "Couldn't import %r: %s" % (name, exc)), sys.exc_info()[2]
  63. return getattr(module, cls_name) if cls_name else module
  64. except (ImportError, AttributeError):
  65. if default is None:
  66. raise
  67. return default
  68. def instantiate(name, *args, **kwargs):
  69. """Instantiate class by name.
  70. See :func:`symbol_by_name`.
  71. """
  72. return symbol_by_name(name)(*args, **kwargs)
  73. @contextmanager
  74. def cwd_in_path():
  75. cwd = os.getcwd()
  76. if cwd in sys.path:
  77. yield
  78. else:
  79. sys.path.insert(0, cwd)
  80. try:
  81. yield cwd
  82. finally:
  83. try:
  84. sys.path.remove(cwd)
  85. except ValueError: # pragma: no cover
  86. pass
  87. def find_module(module, path=None, imp=None):
  88. """Version of :func:`imp.find_module` supporting dots."""
  89. if imp is None:
  90. imp = importlib.import_module
  91. with cwd_in_path():
  92. if '.' in module:
  93. last = None
  94. parts = module.split('.')
  95. for i, part in enumerate(parts[:-1]):
  96. mpart = imp('.'.join(parts[:i + 1]))
  97. try:
  98. path = mpart.__path__
  99. except AttributeError:
  100. raise NotAPackage(module)
  101. last = _imp.find_module(parts[i + 1], path)
  102. return last
  103. return _imp.find_module(module)
  104. def import_from_cwd(module, imp=None, package=None):
  105. """Import module, but make sure it finds modules
  106. located in the current directory.
  107. Modules located in the current directory has
  108. precedence over modules located in `sys.path`.
  109. """
  110. if imp is None:
  111. imp = importlib.import_module
  112. with cwd_in_path():
  113. return imp(module, package=package)
  114. def reload_from_cwd(module, reloader=None):
  115. if reloader is None:
  116. reloader = reload
  117. with cwd_in_path():
  118. return reloader(module)
  119. def module_file(module):
  120. name = module.__file__
  121. return name[:-1] if name.endswith('.pyc') else name