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