module_loading.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from __future__ import absolute_import # Avoid importing `importlib` from this package.
  2. import copy
  3. import imp
  4. from importlib import import_module
  5. import os
  6. import sys
  7. import warnings
  8. from django.core.exceptions import ImproperlyConfigured
  9. from django.utils import six
  10. from django.utils.deprecation import RemovedInDjango19Warning
  11. def import_string(dotted_path):
  12. """
  13. Import a dotted module path and return the attribute/class designated by the
  14. last name in the path. Raise ImportError if the import failed.
  15. """
  16. try:
  17. module_path, class_name = dotted_path.rsplit('.', 1)
  18. except ValueError:
  19. msg = "%s doesn't look like a module path" % dotted_path
  20. six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
  21. module = import_module(module_path)
  22. try:
  23. return getattr(module, class_name)
  24. except AttributeError:
  25. msg = 'Module "%s" does not define a "%s" attribute/class' % (
  26. dotted_path, class_name)
  27. six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
  28. def import_by_path(dotted_path, error_prefix=''):
  29. """
  30. Import a dotted module path and return the attribute/class designated by the
  31. last name in the path. Raise ImproperlyConfigured if something goes wrong.
  32. """
  33. warnings.warn(
  34. 'import_by_path() has been deprecated. Use import_string() instead.',
  35. RemovedInDjango19Warning, stacklevel=2)
  36. try:
  37. attr = import_string(dotted_path)
  38. except ImportError as e:
  39. msg = '%sError importing module %s: "%s"' % (
  40. error_prefix, dotted_path, e)
  41. six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
  42. sys.exc_info()[2])
  43. return attr
  44. def autodiscover_modules(*args, **kwargs):
  45. """
  46. Auto-discover INSTALLED_APPS modules and fail silently when
  47. not present. This forces an import on them to register any admin bits they
  48. may want.
  49. You may provide a register_to keyword parameter as a way to access a
  50. registry. This register_to object must have a _registry instance variable
  51. to access it.
  52. """
  53. from django.apps import apps
  54. register_to = kwargs.get('register_to')
  55. for app_config in apps.get_app_configs():
  56. # Attempt to import the app's module.
  57. try:
  58. if register_to:
  59. before_import_registry = copy.copy(register_to._registry)
  60. for module_to_search in args:
  61. import_module('%s.%s' % (app_config.name, module_to_search))
  62. except:
  63. # Reset the model registry to the state before the last import as
  64. # this import will have to reoccur on the next request and this
  65. # could raise NotRegistered and AlreadyRegistered exceptions
  66. # (see #8245).
  67. if register_to:
  68. register_to._registry = before_import_registry
  69. # Decide whether to bubble up this error. If the app just
  70. # doesn't have an admin module, we can ignore the error
  71. # attempting to import it, otherwise we want it to bubble up.
  72. if module_has_submodule(app_config.module, module_to_search):
  73. raise
  74. def module_has_submodule(package, module_name):
  75. """See if 'module' is in 'package'."""
  76. name = ".".join([package.__name__, module_name])
  77. try:
  78. # None indicates a cached miss; see mark_miss() in Python/import.c.
  79. return sys.modules[name] is not None
  80. except KeyError:
  81. pass
  82. try:
  83. package_path = package.__path__ # No __path__, then not a package.
  84. except AttributeError:
  85. # Since the remainder of this function assumes that we're dealing with
  86. # a package (module with a __path__), so if it's not, then bail here.
  87. return False
  88. for finder in sys.meta_path:
  89. if finder.find_module(name, package_path):
  90. return True
  91. for entry in package_path:
  92. try:
  93. # Try the cached finder.
  94. finder = sys.path_importer_cache[entry]
  95. if finder is None:
  96. # Implicit import machinery should be used.
  97. try:
  98. file_, _, _ = imp.find_module(module_name, [entry])
  99. if file_:
  100. file_.close()
  101. return True
  102. except ImportError:
  103. continue
  104. # Else see if the finder knows of a loader.
  105. elif finder.find_module(name):
  106. return True
  107. else:
  108. continue
  109. except KeyError:
  110. # No cached finder, so try and make one.
  111. for hook in sys.path_hooks:
  112. try:
  113. finder = hook(entry)
  114. # XXX Could cache in sys.path_importer_cache
  115. if finder.find_module(name):
  116. return True
  117. else:
  118. # Once a finder is found, stop the search.
  119. break
  120. except ImportError:
  121. # Continue the search for a finder.
  122. continue
  123. else:
  124. # No finder found.
  125. # Try the implicit import machinery if searching a directory.
  126. if os.path.isdir(entry):
  127. try:
  128. file_, _, _ = imp.find_module(module_name, [entry])
  129. if file_:
  130. file_.close()
  131. return True
  132. except ImportError:
  133. pass
  134. # XXX Could insert None or NullImporter
  135. else:
  136. # Exhausted the search, so the module cannot be found.
  137. return False