mirror of
https://github.com/jazzband/django-configurations.git
synced 2026-03-16 22:20:27 +00:00
Merge pull request #386 from adamchainz/pep_451
Move to PEP-451 style loader
This commit is contained in:
commit
57b6827ae3
6 changed files with 99 additions and 67 deletions
|
|
@ -1,4 +1,3 @@
|
|||
import importlib.util
|
||||
from importlib.machinery import PathFinder
|
||||
import logging
|
||||
import os
|
||||
|
|
@ -47,12 +46,12 @@ def install(check_options=False):
|
|||
return parser
|
||||
|
||||
base.BaseCommand.create_parser = create_parser
|
||||
importer = ConfigurationImporter(check_options=check_options)
|
||||
importer = ConfigurationFinder(check_options=check_options)
|
||||
sys.meta_path.insert(0, importer)
|
||||
installed = True
|
||||
|
||||
|
||||
class ConfigurationImporter:
|
||||
class ConfigurationFinder(PathFinder):
|
||||
modvar = SETTINGS_ENVIRONMENT_VARIABLE
|
||||
namevar = CONFIGURATION_ENVIRONMENT_VARIABLE
|
||||
error_msg = ("Configuration cannot be imported, "
|
||||
|
|
@ -71,7 +70,7 @@ class ConfigurationImporter:
|
|||
self.announce()
|
||||
|
||||
def __repr__(self):
|
||||
return "<ConfigurationImporter for '{}.{}'>".format(self.module,
|
||||
return "<ConfigurationFinder for '{}.{}'>".format(self.module,
|
||||
self.name)
|
||||
|
||||
@property
|
||||
|
|
@ -129,36 +128,33 @@ class ConfigurationImporter:
|
|||
|
||||
def find_spec(self, fullname, path=None, target=None):
|
||||
if fullname is not None and fullname == self.module:
|
||||
spec = PathFinder.find_spec(fullname, path)
|
||||
spec = super().find_spec(fullname, path, target)
|
||||
if spec is not None:
|
||||
return importlib.machinery.ModuleSpec(spec.name,
|
||||
ConfigurationLoader(self.name, spec),
|
||||
origin=spec.origin)
|
||||
wrap_loader(spec.loader, self.name)
|
||||
return spec
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class ConfigurationLoader:
|
||||
def wrap_loader(loader, class_name):
|
||||
class ConfigurationLoader(loader.__class__):
|
||||
def exec_module(self, module):
|
||||
super().exec_module(module)
|
||||
|
||||
def __init__(self, name, spec):
|
||||
self.name = name
|
||||
self.spec = spec
|
||||
mod = module
|
||||
|
||||
def load_module(self, fullname):
|
||||
if fullname in sys.modules:
|
||||
mod = sys.modules[fullname] # pragma: no cover
|
||||
else:
|
||||
mod = importlib.util.module_from_spec(self.spec)
|
||||
sys.modules[fullname] = mod
|
||||
self.spec.loader.exec_module(mod)
|
||||
|
||||
cls_path = f'{mod.__name__}.{self.name}'
|
||||
cls_path = f'{mod.__name__}.{class_name}'
|
||||
|
||||
try:
|
||||
cls = getattr(mod, self.name)
|
||||
cls = getattr(mod, class_name)
|
||||
except AttributeError as err: # pragma: no cover
|
||||
reraise(err, "Couldn't find configuration '{}' "
|
||||
"in module '{}'".format(self.name,
|
||||
mod.__package__))
|
||||
reraise(
|
||||
err,
|
||||
(
|
||||
f"Couldn't find configuration '{class_name}' in "
|
||||
f"module '{mod.__package__}'"
|
||||
),
|
||||
)
|
||||
try:
|
||||
cls.pre_setup()
|
||||
cls.setup()
|
||||
|
|
@ -174,11 +170,11 @@ class ConfigurationLoader:
|
|||
continue
|
||||
setattr(mod, name, value)
|
||||
|
||||
setattr(mod, 'CONFIGURATION', '{}.{}'.format(fullname,
|
||||
self.name))
|
||||
setattr(mod, 'CONFIGURATION', '{0}.{1}'.format(module.__name__,
|
||||
class_name))
|
||||
cls.post_setup()
|
||||
|
||||
except Exception as err:
|
||||
reraise(err, f"Couldn't setup configuration '{cls_path}'")
|
||||
|
||||
return mod
|
||||
loader.__class__ = ConfigurationLoader
|
||||
|
|
|
|||
|
|
@ -6,3 +6,6 @@ class DotEnvConfiguration(Configuration):
|
|||
DOTENV = 'test_project/.env'
|
||||
|
||||
DOTENV_VALUE = values.Value()
|
||||
|
||||
def DOTENV_VALUE_METHOD(self):
|
||||
return values.Value(environ_name="DOTENV_VALUE")
|
||||
|
|
|
|||
8
tests/settings/error.py
Normal file
8
tests/settings/error.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from configurations import Configuration
|
||||
|
||||
|
||||
class ErrorConfiguration(Configuration):
|
||||
|
||||
@classmethod
|
||||
def pre_setup(cls):
|
||||
raise ValueError("Error in pre_setup")
|
||||
|
|
@ -11,4 +11,5 @@ class DotEnvLoadingTests(TestCase):
|
|||
def test_env_loaded(self):
|
||||
from tests.settings import dot_env
|
||||
self.assertEqual(dot_env.DOTENV_VALUE, 'is set')
|
||||
self.assertEqual(dot_env.DOTENV_VALUE_METHOD, 'is set')
|
||||
self.assertEqual(dot_env.DOTENV_LOADED, dot_env.DOTENV)
|
||||
|
|
|
|||
22
tests/test_error.py
Normal file
22
tests/test_error.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import os
|
||||
from django.test import TestCase
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
class ErrorTests(TestCase):
|
||||
|
||||
@patch.dict(os.environ, clear=True,
|
||||
DJANGO_CONFIGURATION='ErrorConfiguration',
|
||||
DJANGO_SETTINGS_MODULE='tests.settings.error')
|
||||
def test_env_loaded(self):
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
from tests.settings import error # noqa: F401
|
||||
|
||||
self.assertIsInstance(cm.exception, ValueError)
|
||||
self.assertEqual(
|
||||
cm.exception.args,
|
||||
(
|
||||
"Couldn't setup configuration "
|
||||
"'tests.settings.error.ErrorConfiguration': Error in pre_setup ",
|
||||
)
|
||||
)
|
||||
|
|
@ -7,7 +7,7 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
|
||||
from unittest.mock import patch
|
||||
|
||||
from configurations.importer import ConfigurationImporter
|
||||
from configurations.importer import ConfigurationFinder
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
TEST_PROJECT_DIR = os.path.join(ROOT_DIR, 'test_project')
|
||||
|
|
@ -42,12 +42,14 @@ class MainTests(TestCase):
|
|||
|
||||
@patch.dict(os.environ, clear=True, DJANGO_CONFIGURATION='Test')
|
||||
def test_empty_module_var(self):
|
||||
self.assertRaises(ImproperlyConfigured, ConfigurationImporter)
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
ConfigurationFinder()
|
||||
|
||||
@patch.dict(os.environ, clear=True,
|
||||
DJANGO_SETTINGS_MODULE='tests.settings.main')
|
||||
def test_empty_class_var(self):
|
||||
self.assertRaises(ImproperlyConfigured, ConfigurationImporter)
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
ConfigurationFinder()
|
||||
|
||||
def test_global_settings(self):
|
||||
from configurations.base import Configuration
|
||||
|
|
@ -70,21 +72,21 @@ class MainTests(TestCase):
|
|||
DJANGO_SETTINGS_MODULE='tests.settings.main',
|
||||
DJANGO_CONFIGURATION='Test')
|
||||
def test_initialization(self):
|
||||
importer = ConfigurationImporter()
|
||||
self.assertEqual(importer.module, 'tests.settings.main')
|
||||
self.assertEqual(importer.name, 'Test')
|
||||
finder = ConfigurationFinder()
|
||||
self.assertEqual(finder.module, 'tests.settings.main')
|
||||
self.assertEqual(finder.name, 'Test')
|
||||
self.assertEqual(
|
||||
repr(importer),
|
||||
"<ConfigurationImporter for 'tests.settings.main.Test'>")
|
||||
repr(finder),
|
||||
"<ConfigurationFinder for 'tests.settings.main.Test'>")
|
||||
|
||||
@patch.dict(os.environ, clear=True,
|
||||
DJANGO_SETTINGS_MODULE='tests.settings.inheritance',
|
||||
DJANGO_CONFIGURATION='Inheritance')
|
||||
def test_initialization_inheritance(self):
|
||||
importer = ConfigurationImporter()
|
||||
self.assertEqual(importer.module,
|
||||
finder = ConfigurationFinder()
|
||||
self.assertEqual(finder.module,
|
||||
'tests.settings.inheritance')
|
||||
self.assertEqual(importer.name, 'Inheritance')
|
||||
self.assertEqual(finder.name, 'Inheritance')
|
||||
|
||||
@patch.dict(os.environ, clear=True,
|
||||
DJANGO_SETTINGS_MODULE='tests.settings.main',
|
||||
|
|
@ -93,12 +95,12 @@ class MainTests(TestCase):
|
|||
'--settings=tests.settings.main',
|
||||
'--configuration=Test'])
|
||||
def test_configuration_option(self):
|
||||
importer = ConfigurationImporter(check_options=False)
|
||||
self.assertEqual(importer.module, 'tests.settings.main')
|
||||
self.assertEqual(importer.name, 'NonExisting')
|
||||
importer = ConfigurationImporter(check_options=True)
|
||||
self.assertEqual(importer.module, 'tests.settings.main')
|
||||
self.assertEqual(importer.name, 'Test')
|
||||
finder = ConfigurationFinder(check_options=False)
|
||||
self.assertEqual(finder.module, 'tests.settings.main')
|
||||
self.assertEqual(finder.name, 'NonExisting')
|
||||
finder = ConfigurationFinder(check_options=True)
|
||||
self.assertEqual(finder.module, 'tests.settings.main')
|
||||
self.assertEqual(finder.name, 'Test')
|
||||
|
||||
def test_configuration_argument_in_cli(self):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue