Permalink
Browse files

Fixed #17061 -- Factored out importing object from a dotted path

Thanks Carl Meyer for the report.
  • Loading branch information...
1 parent 3f1c7b7 commit 7c5b244826be636429791a8ca76b2adc678e82e7 @claudep claudep committed Feb 2, 2013
@@ -15,6 +15,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import LazyObject, empty
from django.utils import importlib
+from django.utils.module_loading import import_by_path
from django.utils import six
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
@@ -68,9 +69,7 @@ def _configure_logging(self):
if self.LOGGING_CONFIG:
from django.utils.log import DEFAULT_LOGGING
# First find the logging configuration function ...
- logging_config_path, logging_config_func_name = self.LOGGING_CONFIG.rsplit('.', 1)
- logging_config_module = importlib.import_module(logging_config_path)
- logging_config_func = getattr(logging_config_module, logging_config_func_name)
+ logging_config_func = import_by_path(self.LOGGING_CONFIG)
logging_config_func(DEFAULT_LOGGING)
@@ -1,5 +1,5 @@
from django.test import LiveServerTestCase
-from django.utils.importlib import import_module
+from django.utils.module_loading import import_by_path
from django.utils.unittest import SkipTest
from django.utils.translation import ugettext as _
@@ -9,11 +9,7 @@ class AdminSeleniumWebDriverTestCase(LiveServerTestCase):
@classmethod
def setUpClass(cls):
try:
- # Import and start the WebDriver class.
- module, attr = cls.webdriver_class.rsplit('.', 1)
- mod = import_module(module)
- WebDriver = getattr(mod, attr)
- cls.selenium = WebDriver()
+ cls.selenium = import_by_path(cls.webdriver_class)()
except Exception as e:
raise SkipTest('Selenium webdriver "%s" not installed or not '
'operational: %s' % (cls.webdriver_class, str(e)))
@@ -1,28 +1,16 @@
import re
-from django.core.exceptions import ImproperlyConfigured, PermissionDenied
-from django.utils.importlib import import_module
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
+from django.core.exceptions import ImproperlyConfigured, PermissionDenied
+from django.utils.module_loading import import_by_path
SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend'
REDIRECT_FIELD_NAME = 'next'
def load_backend(path):
- i = path.rfind('.')
- module, attr = path[:i], path[i + 1:]
- try:
- mod = import_module(module)
- except ImportError as e:
- raise ImproperlyConfigured('Error importing authentication backend %s: "%s"' % (path, e))
- except ValueError:
- raise ImproperlyConfigured('Error importing authentication backends. Is AUTHENTICATION_BACKENDS a correctly defined list or tuple?')
- try:
- cls = getattr(mod, attr)
- except AttributeError:
- raise ImproperlyConfigured('Module "%s" does not define a "%s" authentication backend' % (module, attr))
- return cls()
+ return import_by_path(path)()
def get_backends():
@@ -12,6 +12,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.crypto import (
pbkdf2, constant_time_compare, get_random_string)
+from django.utils.module_loading import import_by_path
from django.utils.translation import ugettext_noop as _
@@ -84,13 +85,7 @@ def load_hashers(password_hashers=None):
if not password_hashers:
password_hashers = settings.PASSWORD_HASHERS
for backend in password_hashers:
- try:
- mod_path, cls_name = backend.rsplit('.', 1)
- mod = importlib.import_module(mod_path)
- hasher_cls = getattr(mod, cls_name)
- except (AttributeError, ImportError, ValueError):
- raise ImproperlyConfigured("hasher not found: %s" % backend)
- hasher = hasher_cls()
+ hasher = import_by_path(backend)()
if not getattr(hasher, 'algorithm'):
raise ImproperlyConfigured("hasher doesn't specify an "
"algorithm name: %s" % backend)
@@ -1,8 +1,6 @@
from django.test import TestCase
-from django.contrib.formtools.wizard.storage import (get_storage,
- MissingStorageModule,
- MissingStorageClass)
+from django.contrib.formtools.wizard.storage import get_storage, MissingStorage
from django.contrib.formtools.wizard.storage.base import BaseStorage
@@ -12,11 +10,9 @@ def test_load_storage(self):
type(get_storage('django.contrib.formtools.wizard.storage.base.BaseStorage', 'wizard1')),
BaseStorage)
- def test_missing_module(self):
- self.assertRaises(MissingStorageModule, get_storage,
+ def test_missing_storage(self):
+ self.assertRaises(MissingStorage, get_storage,
'django.contrib.formtools.wizard.storage.idontexist.IDontExistStorage', 'wizard1')
-
- def test_missing_class(self):
- self.assertRaises(MissingStorageClass, get_storage,
+ self.assertRaises(MissingStorage, get_storage,
'django.contrib.formtools.wizard.storage.base.IDontExistStorage', 'wizard1')
@@ -1,22 +1,14 @@
-from django.utils.importlib import import_module
+from django.core.exceptions import ImproperlyConfigured
+from django.utils.module_loading import import_by_path
from django.contrib.formtools.wizard.storage.base import BaseStorage
from django.contrib.formtools.wizard.storage.exceptions import (
- MissingStorageModule, MissingStorageClass, NoFileStorageConfigured)
+ MissingStorage, NoFileStorageConfigured)
def get_storage(path, *args, **kwargs):
- i = path.rfind('.')
- module, attr = path[:i], path[i+1:]
try:
- mod = import_module(module)
- except ImportError as e:
- raise MissingStorageModule(
- 'Error loading storage %s: "%s"' % (module, e))
- try:
- storage_class = getattr(mod, attr)
- except AttributeError:
- raise MissingStorageClass(
- 'Module "%s" does not define a storage named "%s"' % (module, attr))
+ storage_class = import_by_path(path)
+ except ImproperlyConfigured as e:
+ raise MissingStorage('Error loading storage: %s' % e)
return storage_class(*args, **kwargs)
-
@@ -1,9 +1,6 @@
from django.core.exceptions import ImproperlyConfigured
-class MissingStorageModule(ImproperlyConfigured):
- pass
-
-class MissingStorageClass(ImproperlyConfigured):
+class MissingStorage(ImproperlyConfigured):
pass
class NoFileStorageConfigured(ImproperlyConfigured):
@@ -1,28 +1,5 @@
from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
-from django.utils.importlib import import_module
-
-
-def get_storage(import_path):
- """
- Imports the message storage class described by import_path, where
- import_path is the full Python path to the class.
- """
- try:
- dot = import_path.rindex('.')
- except ValueError:
- raise ImproperlyConfigured("%s isn't a Python path." % import_path)
- module, classname = import_path[:dot], import_path[dot + 1:]
- try:
- mod = import_module(module)
- except ImportError as e:
- raise ImproperlyConfigured('Error importing module %s: "%s"' %
- (module, e))
- try:
- return getattr(mod, classname)
- except AttributeError:
- raise ImproperlyConfigured('Module "%s" does not define a "%s" '
- 'class.' % (module, classname))
+from django.utils.module_loading import import_by_path as get_storage
# Callable with the same interface as the storage classes i.e. accepts a
@@ -4,7 +4,7 @@
from django.core.files.storage import default_storage, Storage, FileSystemStorage
from django.utils.datastructures import SortedDict
from django.utils.functional import empty, memoize, LazyObject
-from django.utils.importlib import import_module
+from django.utils.module_loading import import_by_path
from django.utils._os import safe_join
from django.utils import six
@@ -258,17 +258,7 @@ def _get_finder(import_path):
Imports the staticfiles finder class described by import_path, where
import_path is the full Python path to the class.
"""
- module, attr = import_path.rsplit('.', 1)
- try:
- mod = import_module(module)
- except ImportError as e:
- raise ImproperlyConfigured('Error importing module %s: "%s"' %
- (module, e))
- try:
- Finder = getattr(mod, attr)
- except AttributeError:
- raise ImproperlyConfigured('Module "%s" does not define a "%s" '
- 'class.' % (module, attr))
+ Finder = import_by_path(import_path)
if not issubclass(Finder, BaseFinder):
raise ImproperlyConfigured('Finder "%s" is not a subclass of "%s"' %
(Finder, BaseFinder))
@@ -25,6 +25,8 @@
InvalidCacheBackendError, CacheKeyWarning, BaseCache)
from django.core.exceptions import ImproperlyConfigured
from django.utils import importlib
+from django.utils.module_loading import import_by_path
+
__all__ = [
'get_cache', 'cache', 'DEFAULT_CACHE_ALIAS'
@@ -86,11 +88,10 @@ def parse_backend_conf(backend, **kwargs):
else:
try:
# Trying to import the given backend, in case it's a dotted path
- mod_path, cls_name = backend.rsplit('.', 1)
- mod = importlib.import_module(mod_path)
- backend_cls = getattr(mod, cls_name)
- except (AttributeError, ImportError, ValueError):
- raise InvalidCacheBackendError("Could not find backend '%s'" % backend)
+ backend_cls = import_by_path(backend)
+ except ImproperlyConfigured as e:
+ raise InvalidCacheBackendError("Could not find backend '%s': %s" % (
+ backend, e))
location = kwargs.pop('LOCATION', '')
return backend, location, kwargs
@@ -126,10 +127,8 @@ def get_cache(backend, **kwargs):
backend_cls = mod.CacheClass
else:
backend, location, params = parse_backend_conf(backend, **kwargs)
- mod_path, cls_name = backend.rsplit('.', 1)
- mod = importlib.import_module(mod_path)
- backend_cls = getattr(mod, cls_name)
- except (AttributeError, ImportError) as e:
+ backend_cls = import_by_path(backend)
+ except (AttributeError, ImportError, ImproperlyConfigured) as e:
raise InvalidCacheBackendError(
"Could not find backend '%s': %s" % (backend, e))
cache = backend_cls(location, params)
@@ -4,7 +4,7 @@
import warnings
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
-from django.utils.importlib import import_module
+from django.utils.module_loading import import_by_path
class InvalidCacheBackendError(ImproperlyConfigured):
@@ -40,9 +40,7 @@ def get_key_func(key_func):
if callable(key_func):
return key_func
else:
- key_func_module_path, key_func_name = key_func.rsplit('.', 1)
- key_func_module = import_module(key_func_module_path)
- return getattr(key_func_module, key_func_name)
+ return import_by_path(key_func)
return default_key_func
@@ -8,12 +8,12 @@
from datetime import datetime
from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
+from django.core.exceptions import SuspiciousOperation
from django.core.files import locks, File
from django.core.files.move import file_move_safe
from django.utils.encoding import force_text, filepath_to_uri
from django.utils.functional import LazyObject
-from django.utils.importlib import import_module
+from django.utils.module_loading import import_by_path
from django.utils.text import get_valid_filename
from django.utils._os import safe_join, abspathu
@@ -277,21 +277,7 @@ def modified_time(self, name):
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
def get_storage_class(import_path=None):
- if import_path is None:
- import_path = settings.DEFAULT_FILE_STORAGE
- try:
- dot = import_path.rindex('.')
- except ValueError:
- raise ImproperlyConfigured("%s isn't a storage module." % import_path)
- module, classname = import_path[:dot], import_path[dot+1:]
- try:
- mod = import_module(module)
- except ImportError as e:
- raise ImproperlyConfigured('Error importing storage module %s: "%s"' % (module, e))
- try:
- return getattr(mod, classname)
- except AttributeError:
- raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
+ return import_by_path(import_path or settings.DEFAULT_FILE_STORAGE)
class DefaultStorage(LazyObject):
def _setup(self):
@@ -7,10 +7,9 @@
from io import BytesIO
from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile
-from django.utils import importlib
from django.utils.encoding import python_2_unicode_compatible
+from django.utils.module_loading import import_by_path
__all__ = ['UploadFileException','StopUpload', 'SkipFile', 'FileUploadHandler',
'TemporaryFileUploadHandler', 'MemoryFileUploadHandler',
@@ -201,17 +200,4 @@ def load_handler(path, *args, **kwargs):
<TemporaryFileUploadHandler object at 0x...>
"""
- i = path.rfind('.')
- module, attr = path[:i], path[i+1:]
- try:
- mod = importlib.import_module(module)
- except ImportError as e:
- raise ImproperlyConfigured('Error importing upload handler module %s: "%s"' % (module, e))
- except ValueError:
- raise ImproperlyConfigured('Error importing upload handler module.'
- 'Is FILE_UPLOAD_HANDLERS a correctly defined list or tuple?')
- try:
- cls = getattr(mod, attr)
- except AttributeError:
- raise ImproperlyConfigured('Module "%s" does not define a "%s" upload handler backend' % (module, attr))
- return cls(*args, **kwargs)
+ return import_by_path(path)(*args, **kwargs)
@@ -9,8 +9,9 @@
from django.core import exceptions
from django.core import urlresolvers
from django.core import signals
+from django.core.exceptions import MiddlewareNotUsed, PermissionDenied
from django.utils.encoding import force_text
-from django.utils.importlib import import_module
+from django.utils.module_loading import import_by_path
from django.utils import six
from django.views import debug
@@ -43,21 +44,10 @@ def load_middleware(self):
request_middleware = []
for middleware_path in settings.MIDDLEWARE_CLASSES:
- try:
- mw_module, mw_classname = middleware_path.rsplit('.', 1)
- except ValueError:
- raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path)
- try:
- mod = import_module(mw_module)
- except ImportError as e:
- raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
- try:
- mw_class = getattr(mod, mw_classname)
- except AttributeError:
- raise exceptions.ImproperlyConfigured('Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname))
+ mw_class = import_by_path(middleware_path)
try:
mw_instance = mw_class()
- except exceptions.MiddlewareNotUsed:
+ except MiddlewareNotUsed:
continue
if hasattr(mw_instance, 'process_request'):
@@ -154,7 +144,7 @@ def get_response(self, request):
except:
signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
- except exceptions.PermissionDenied:
+ except PermissionDenied:
logger.warning(
'Forbidden (Permission denied): %s', request.path,
extra={
Oops, something went wrong.

5 comments on commit 7c5b244

@jezdez
Member
jezdez commented on 7c5b244 Feb 4, 2013

ZOMG YES!!!

@mjtamlyn
Member

Should (or could) this be considered a public API now?

@sebleblanc

Wow, what a cleanup!

@claudep
Member
claudep commented on 7c5b244 Feb 5, 2013

Should (or could) this be considered a public API now?

Not until it is documented on https://docs.djangoproject.com/en/dev/ref/utils/. However, feel free to open a Trac ticket requesting it to be documented (hence public API), if you think it's really useful.

@mjtamlyn
Member

I know of a lot of libraries which utilise this sort of functionality for their own settings. Opened https://code.djangoproject.com/ticket/19748

Please sign in to comment.