This commit is contained in:
+13
-8
@@ -4,6 +4,8 @@ import re
|
||||
from django.apps import AppConfig as _AppConfig
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from ..constants import DJANGO_MAIN_MODULE, MODULE_APP_SETTINGS_PREFIX
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -18,18 +20,21 @@ class DefaultSetting: # pylint: disable=too-few-public-methods
|
||||
self.validator = validator
|
||||
|
||||
def validate(self, value):
|
||||
if hasattr(self, 'validator') and self.validator is not None:
|
||||
if callable(self.validator):
|
||||
if not self.validator(value):
|
||||
raise ImproperlyConfigured('Validator callback {clb} returned False'.format(clb=self.validator))
|
||||
else:
|
||||
if not re.search(self.validator, value):
|
||||
raise ImproperlyConfigured('Does not match /{re}/'.format(re=self.validator))
|
||||
if self.validator is None:
|
||||
return
|
||||
if callable(self.validator):
|
||||
if not self.validator(value):
|
||||
raise ImproperlyConfigured('Validator callback {clb} returned False'.format(clb=self.validator))
|
||||
else:
|
||||
if not re.search(self.validator, value):
|
||||
raise ImproperlyConfigured('Does not match /{re}/'.format(re=self.validator))
|
||||
|
||||
|
||||
class AppSettings: # pylint: disable=too-few-public-methods
|
||||
def __init__(self, app_name, defaults):
|
||||
settings_name = 'main.settings-' + app_name
|
||||
settings_name = '{main_module}.{prefix}{app_name}'.format(main_module=DJANGO_MAIN_MODULE,
|
||||
prefix=MODULE_APP_SETTINGS_PREFIX,
|
||||
app_name=app_name)
|
||||
|
||||
try:
|
||||
settings_module = importlib.import_module(settings_name)
|
||||
|
||||
@@ -5,8 +5,7 @@ from importlib.resources import files as resource_files
|
||||
from django.conf import settings
|
||||
from django.urls import re_path, include
|
||||
|
||||
DJANGO_MAIN_MODULE = 'main'
|
||||
MODULE_CONFIG_FILE_NAME = 'module_config.json'
|
||||
from ..constants import DJANGO_MAIN_MODULE, MODULES_CONFIG_FILE_NAME
|
||||
|
||||
|
||||
class ModuleConfigError(Exception):
|
||||
@@ -64,6 +63,12 @@ class ModuleMeta:
|
||||
url_conf = self._package_name + '.urls'
|
||||
return re_path(url_pattern, include(url_conf, self.url_namespace))
|
||||
|
||||
@property
|
||||
def root_url_name(self):
|
||||
if self.url_namespace:
|
||||
return '{}:{}'.format(self.url_namespace, self._root_url_name)
|
||||
return self._root_url_name
|
||||
|
||||
def _load_from_package(self):
|
||||
package_name = self._package_name
|
||||
json_text = resource_files(package_name).joinpath(self._json_file).read_bytes()
|
||||
@@ -97,7 +102,7 @@ class ModuleConfig:
|
||||
if config_file_path is None:
|
||||
if django_base_dir is None:
|
||||
django_base_dir = settings.BASE_DIR
|
||||
config_file_path = os.path.join(django_base_dir, DJANGO_MAIN_MODULE, MODULE_CONFIG_FILE_NAME)
|
||||
config_file_path = os.path.join(django_base_dir, DJANGO_MAIN_MODULE, MODULES_CONFIG_FILE_NAME)
|
||||
self._config_file_path = config_file_path
|
||||
|
||||
self._modules = {}
|
||||
|
||||
@@ -5,7 +5,8 @@ import sys
|
||||
from importlib.resources import files as resource_files
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
from dav_base.config.modules import DJANGO_MAIN_MODULE, ModuleConfig
|
||||
from dav_base.constants import DJANGO_MAIN_MODULE, MODULE_APP_SETTINGS_PREFIX
|
||||
from dav_base.config.modules import ModuleConfig
|
||||
|
||||
VERSION = '0.1'
|
||||
|
||||
@@ -94,46 +95,48 @@ class AdminCommand: # pylint: disable=too-few-public-methods
|
||||
config = ModuleConfig(django_base_dir=django_base_dir)
|
||||
config.save()
|
||||
|
||||
input_file = resource_files(__package__).joinpath('django_project_config', 'additional_settings.py')
|
||||
input_file = resource_files(__package__).joinpath('django_project_config',
|
||||
'additional_settings.py')
|
||||
output_file = os.path.join(django_base_dir, django_main_module, 'settings.py')
|
||||
with open(output_file, 'ab') as f:
|
||||
f.write(input_file.read_bytes())
|
||||
|
||||
input_file = resource_files(__package__).joinpath('django_project_config', 'urls.py')
|
||||
input_file = resource_files(__package__).joinpath('django_project_config',
|
||||
'urls.py')
|
||||
output_file = os.path.join(django_base_dir, django_main_module, 'urls.py')
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(input_file.read_bytes())
|
||||
|
||||
input_file = resource_files(__package__).joinpath('django_project_config', 'settings-dav_base.py')
|
||||
output_file = os.path.join(django_base_dir, django_main_module, 'settings-dav_base.py')
|
||||
input_file = resource_files(__package__).joinpath('django_project_config',
|
||||
'{prefix}dav_base.py'.format(prefix=MODULE_APP_SETTINGS_PREFIX))
|
||||
output_file = os.path.join(django_base_dir,
|
||||
django_main_module,
|
||||
'{prefix}dav_base.py'.format(prefix=MODULE_APP_SETTINGS_PREFIX))
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(input_file.read_bytes())
|
||||
|
||||
return posix.EX_OK
|
||||
|
||||
def _subcmd_enable_module(self, cmd_args):
|
||||
django_main_module = DJANGO_MAIN_MODULE
|
||||
django_base_dir = cmd_args.path
|
||||
module_name = cmd_args.module
|
||||
sys.path.append(django_base_dir)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(django_main_module)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(DJANGO_MAIN_MODULE)
|
||||
execute_from_command_line(['manage.py', 'enable_module', module_name])
|
||||
return posix.EX_OK
|
||||
|
||||
def _subcmd_disable_module(self, cmd_args):
|
||||
django_main_module = DJANGO_MAIN_MODULE
|
||||
django_base_dir = cmd_args.path
|
||||
module_name = cmd_args.module
|
||||
sys.path.append(django_base_dir)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(django_main_module)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(DJANGO_MAIN_MODULE)
|
||||
execute_from_command_line(['manage.py', 'disable_module', module_name])
|
||||
return posix.EX_OK
|
||||
|
||||
def _subcmd_list_modules(self, cmd_args):
|
||||
django_main_module = DJANGO_MAIN_MODULE
|
||||
django_base_dir = cmd_args.path
|
||||
sys.path.append(django_base_dir)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(django_main_module)
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(DJANGO_MAIN_MODULE)
|
||||
execute_from_command_line(['manage.py', 'list_modules'])
|
||||
return posix.EX_OK
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
DJANGO_MAIN_MODULE = 'main'
|
||||
MODULES_CONFIG_FILE_NAME = 'module_config.json'
|
||||
MODULE_APP_SETTINGS_PREFIX = 'settings-'
|
||||
@@ -3,7 +3,8 @@ from importlib.resources import files as resource_files
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from dav_base.config.modules import DJANGO_MAIN_MODULE, ModuleMeta
|
||||
from dav_base.constants import DJANGO_MAIN_MODULE, MODULE_APP_SETTINGS_PREFIX
|
||||
from dav_base.config.modules import ModuleMeta
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@@ -22,7 +23,9 @@ class Command(BaseCommand):
|
||||
if module_name in config.modules.keys():
|
||||
raise CommandError('Module \'{}\' is already enabled'.format(module_name))
|
||||
|
||||
settings_file_name = 'settings-{}.py'.format(module_name)
|
||||
settings_file_name = '{prefix}{module_name}.py'.format(prefix=MODULE_APP_SETTINGS_PREFIX,
|
||||
module_name=module_name)
|
||||
|
||||
input_file = resource_files(module_name).joinpath('django_project_config', settings_file_name)
|
||||
if input_file.is_file():
|
||||
output_file = os.path.join(django_base_dir, django_main_module, settings_file_name)
|
||||
|
||||
@@ -23,6 +23,7 @@ class ModuleMetaTestCase(SimpleTestCase):
|
||||
self.assertEqual(mm.additional_apps, [])
|
||||
self.assertEqual(mm.url_prefix, 'test')
|
||||
self.assertEqual(mm.url_namespace, 'dav_base_tests_fake_app1')
|
||||
self.assertEqual(mm.root_url_name, 'dav_base_tests_fake_app1:root')
|
||||
pattern = mm.url_conf_pattern
|
||||
self.assertIsInstance(pattern, URLResolver)
|
||||
self.assertEqual('^test/', str(pattern.pattern))
|
||||
@@ -33,10 +34,13 @@ class ModuleMetaTestCase(SimpleTestCase):
|
||||
|
||||
def test_init_without_load(self):
|
||||
app_name = 'dav_base.tests.non_existent_app'
|
||||
app_namespace = app_name.replace('.', '_')
|
||||
mm = ModuleMeta(app_name, load=False)
|
||||
self.assertEqual(mm.package, app_name)
|
||||
self.assertEqual(mm.app, app_name)
|
||||
self.assertEqual(mm.url_prefix, app_name)
|
||||
self.assertEqual(mm.url_namespace, app_namespace)
|
||||
self.assertEqual(mm.root_url_name, app_namespace + ':root')
|
||||
|
||||
def test_url_config_not_exists(self):
|
||||
mm = ModuleMeta('dav_base.tests.fake_app1')
|
||||
@@ -57,19 +61,24 @@ class ModuleMetaTestCase(SimpleTestCase):
|
||||
'additional_apps': ['test1', 'test2.subtest'],
|
||||
'url_prefix': 'test_url_prefix',
|
||||
}
|
||||
expected_namespace = dd['package'].replace('.', '_')
|
||||
mm.load_from_dict(dd)
|
||||
self.assertEqual(mm.package, dd['package'])
|
||||
self.assertEqual(mm.app, dd['app_config'])
|
||||
self.assertEqual(mm.additional_apps, dd['additional_apps'])
|
||||
self.assertEqual(mm.url_prefix, dd['url_prefix'])
|
||||
self.assertEqual(mm.url_namespace, dd['package'].replace('.', '_'))
|
||||
self.assertEqual(mm.url_namespace, expected_namespace)
|
||||
self.assertEqual(mm.root_url_name, expected_namespace + ':root')
|
||||
|
||||
dd = {'package': 'dav_base2.bar'}
|
||||
expected_namespace = dd['package'].replace('.', '_')
|
||||
mm.load_from_dict(dd)
|
||||
self.assertEqual(mm.url_prefix, dd['package'])
|
||||
self.assertEqual(mm.app, dd['package'])
|
||||
self.assertEqual(mm.additional_apps, [])
|
||||
self.assertEqual(mm.url_prefix, dd['package'])
|
||||
self.assertEqual(mm.url_namespace, expected_namespace)
|
||||
self.assertEqual(mm.root_url_name, expected_namespace + ':root')
|
||||
|
||||
def test_dump_as_dict(self):
|
||||
mm = ModuleMeta('dav_base.tests.fake_app1')
|
||||
|
||||
@@ -6,16 +6,12 @@ from ..views import RootView
|
||||
|
||||
|
||||
class DummyModuleMeta:
|
||||
def __init__(self, package, url_namespace=None):
|
||||
def __init__(self, package):
|
||||
self.package = package
|
||||
self.url_namespace = url_namespace
|
||||
|
||||
@property
|
||||
def url_name(self):
|
||||
if self.url_namespace:
|
||||
return self.url_namespace + ':root'
|
||||
else:
|
||||
return 'root'
|
||||
def root_url_name(self):
|
||||
return self.package.replace('.', '_') + ':root'
|
||||
|
||||
class DummyModuleConfig:
|
||||
def __init__(self, modules):
|
||||
@@ -30,17 +26,17 @@ class DummyModuleConfig:
|
||||
class ViewsTestCase(SimpleTestCase):
|
||||
def test_root(self):
|
||||
modules = {
|
||||
'module1': DummyModuleMeta('pkg1', url_namespace='ns1'),
|
||||
'module1': DummyModuleMeta('pkg1'),
|
||||
'module2': DummyModuleMeta('pkg2'),
|
||||
'moduleC': DummyModuleMeta('pkgC', url_namespace='nsC'),
|
||||
'moduleD': DummyModuleMeta('pkgD', url_namespace='nsD'),
|
||||
'moduleC': DummyModuleMeta('pkgC'),
|
||||
'moduleD': DummyModuleMeta('pkgD'),
|
||||
}
|
||||
expected_root_urls = [
|
||||
('pkg1', 'ns1:root'), ('pkg2', 'root'), ('pkgD', 'nsD:root')
|
||||
('pkg1', 'pkg1:root'), ('pkg2', 'pkg2:root'), ('pkgD', 'pkgD:root')
|
||||
]
|
||||
|
||||
def fake_reverse(name):
|
||||
if name == 'nsC:root':
|
||||
if name == 'pkgC:root':
|
||||
raise NoReverseMatch()
|
||||
return '/'
|
||||
|
||||
@@ -57,7 +53,7 @@ class ViewsTestCase(SimpleTestCase):
|
||||
called_names = [call.args[0] for call in mocked_reverse.call_args_list]
|
||||
self.assertEqual(len(called_names), len(modules))
|
||||
for m in modules.values():
|
||||
self.assertIn(m.url_name, called_names)
|
||||
self.assertIn(m.root_url_name, called_names)
|
||||
|
||||
def test_integrated_root(self):
|
||||
with override_settings(MODULE_CONFIG=DummyModuleConfig({})):
|
||||
|
||||
+1
-3
@@ -10,9 +10,7 @@ class RootView(generic.TemplateView):
|
||||
c = super().get_context_data(**kwargs)
|
||||
root_urls = []
|
||||
for module_meta_obj in settings.MODULE_CONFIG.modules.values():
|
||||
root_url_name = 'root'
|
||||
if module_meta_obj.url_namespace:
|
||||
root_url_name = '%s:%s' % (module_meta_obj.url_namespace, root_url_name)
|
||||
root_url_name = module_meta_obj.root_url_name
|
||||
try:
|
||||
reverse(root_url_name)
|
||||
root_urls.append((module_meta_obj.package, root_url_name))
|
||||
|
||||
Reference in New Issue
Block a user