diff --git a/dav_base/config/apps.py b/dav_base/config/apps.py index b57f220..93cd081 100644 --- a/dav_base/config/apps.py +++ b/dav_base/config/apps.py @@ -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) diff --git a/dav_base/config/modules.py b/dav_base/config/modules.py index e360462..2ff177c 100644 --- a/dav_base/config/modules.py +++ b/dav_base/config/modules.py @@ -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 = {} diff --git a/dav_base/console_scripts/admin.py b/dav_base/console_scripts/admin.py index 291d9e8..67fda81 100644 --- a/dav_base/console_scripts/admin.py +++ b/dav_base/console_scripts/admin.py @@ -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 diff --git a/dav_base/constants.py b/dav_base/constants.py new file mode 100644 index 0000000..d54e335 --- /dev/null +++ b/dav_base/constants.py @@ -0,0 +1,3 @@ +DJANGO_MAIN_MODULE = 'main' +MODULES_CONFIG_FILE_NAME = 'module_config.json' +MODULE_APP_SETTINGS_PREFIX = 'settings-' \ No newline at end of file diff --git a/dav_base/management/commands/enable_module.py b/dav_base/management/commands/enable_module.py index 3625fc3..1ee31b7 100644 --- a/dav_base/management/commands/enable_module.py +++ b/dav_base/management/commands/enable_module.py @@ -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) diff --git a/dav_base/tests/test_config_modules.py b/dav_base/tests/test_config_modules.py index 41a3dd3..e5cdf28 100644 --- a/dav_base/tests/test_config_modules.py +++ b/dav_base/tests/test_config_modules.py @@ -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') diff --git a/dav_base/tests/test_views.py b/dav_base/tests/test_views.py index 1b0efa3..6ac4f0c 100644 --- a/dav_base/tests/test_views.py +++ b/dav_base/tests/test_views.py @@ -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({})): diff --git a/dav_base/views.py b/dav_base/views.py index d07fd7c..37b2df1 100644 --- a/dav_base/views.py +++ b/dav_base/views.py @@ -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))