You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import sys
  2. import traceback
  3. from django.conf import settings
  4. from django.core.exceptions import ImproperlyConfigured
  5. from django.db.models import get_model
  6. class AppNotFoundError(Exception):
  7. pass
  8. class ClassNotFoundError(Exception):
  9. pass
  10. def get_class(module_label, classname):
  11. return get_classes(module_label, [classname])[0]
  12. def get_classes(module_label, classnames):
  13. """
  14. For dynamically importing classes from a module.
  15. Eg. calling get_classes('catalogue.models', ['Product']) will search
  16. INSTALLED_APPS for the relevant product app (default is
  17. 'oscar.apps.catalogue') and then import the classes from there. If the
  18. class can't be found in the overriding module, then we attempt to import it
  19. from within oscar.
  20. This is very similar to django.db.models.get_model although that is only
  21. for loading models while this method will load any class.
  22. """
  23. app_module_path = _get_app_module_path(module_label)
  24. if not app_module_path:
  25. raise AppNotFoundError("No app found matching '%s'" % module_label)
  26. # Check if app is in oscar
  27. if app_module_path.split('.')[0] == 'oscar':
  28. # Using core oscar class
  29. module_path = 'oscar.apps.%s' % module_label
  30. imported_module = __import__(module_path, fromlist=classnames)
  31. return _pluck_classes([imported_module], classnames)
  32. # App must be local - check if module is in local app (it could be in
  33. # oscar's)
  34. app_label = module_label.split('.')[0]
  35. if '.' in app_module_path:
  36. base_package = app_module_path.rsplit('.' + app_label, 1)[0]
  37. local_app = "%s.%s" % (base_package, module_label)
  38. else:
  39. local_app = module_label
  40. try:
  41. imported_local_module = __import__(local_app, fromlist=classnames)
  42. except ImportError:
  43. # There are 2 reasons why there is ImportError:
  44. # 1. local_app does not exist
  45. # 2. local_app exists but is corrupted (ImportError inside of the app)
  46. #
  47. # Obviously, for the reason #1 we want to fail back to use Oscar app.
  48. # For the reason #2 we want to propagate error (the dev obviously wants
  49. # to override app and not use Oscar app)
  50. #
  51. # ImportError does not provide easy way to distinguish those two cases.
  52. # Fortunatelly, the traceback of the ImportError starts at __import__
  53. # statement. If the traceback has more than one frame, it means that
  54. # application was found and ImportError originates within the local app
  55. __, __, exc_traceback = sys.exc_info()
  56. frames = traceback.extract_tb(exc_traceback)
  57. if len(frames) > 1:
  58. raise
  59. # Module not in local app
  60. imported_local_module = {}
  61. oscar_app = "oscar.apps.%s" % module_label
  62. imported_oscar_module = __import__(oscar_app, fromlist=classnames)
  63. return _pluck_classes([imported_local_module, imported_oscar_module],
  64. classnames)
  65. def _pluck_classes(modules, classnames):
  66. klasses = []
  67. for classname in classnames:
  68. klass = None
  69. for module in modules:
  70. if hasattr(module, classname):
  71. klass = getattr(module, classname)
  72. break
  73. if not klass:
  74. packages = [m.__name__ for m in modules]
  75. raise ClassNotFoundError("No class '%s' found in %s" % (
  76. classname, ", ".join(packages)))
  77. klasses.append(klass)
  78. return klasses
  79. def _get_app_module_path(module_label):
  80. app_name = module_label.rsplit(".", 1)[0]
  81. for installed_app in settings.INSTALLED_APPS:
  82. if installed_app.endswith(app_name):
  83. return installed_app
  84. return None
  85. def get_profile_class():
  86. """
  87. Return the profile model class
  88. """
  89. setting = getattr(settings, 'AUTH_PROFILE_MODULE', None)
  90. if setting is None:
  91. return None
  92. app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
  93. profile_class = get_model(app_label, model_name)
  94. if not profile_class:
  95. raise ImproperlyConfigured("Can't import profile model")
  96. return profile_class
  97. def feature_hidden(feature_name):
  98. """
  99. Test if a certain Oscar feature is disabled.
  100. """
  101. return (feature_name is not None and
  102. feature_name in settings.OSCAR_HIDDEN_FEATURES)