import json import os import pkg_resources from django.conf import settings from django.urls import re_path, include DJANGO_MAIN_MODULE = 'main' MODULE_CONFIG_FILE_NAME = 'module_config.json' class ModuleConfigError(Exception): pass class ModuleMeta: _json_file = 'module.json' _root_url_name = 'root' def __init__(self, package_name): self._package_name = package_name self._app_config = None self._additional_apps = [] self._url_prefix = None self._load_from_package() def __str__(self): t = '- {}'.format(self._package_name) return t @property def package(self): return self._package_name @property def app(self): if self._app_config: app = self._app_config if app.startswith('.'): app = self._package_name + app else: app = self._package_name return app @property def additional_apps(self): return self._additional_apps @property def url_prefix(self): if self._url_prefix is None: return self._package_name else: return self._url_prefix @property def url_namespace(self): return self._package_name.replace('.', '_') @property def url_conf_pattern(self): url_pattern = '^{}/'.format(self.url_prefix) url_conf = self._package_name + '.urls' return re_path(url_pattern, include(url_conf, self.url_namespace)) def _load_from_package(self): package_name = self._package_name json_text = pkg_resources.resource_string(package_name, self._json_file) meta_dict = json.loads(json_text) meta_dict['package'] = package_name self.load_from_dict(meta_dict) def load_from_dict(self, meta_dict): self._package_name = meta_dict.get('package', None) self._app_config = meta_dict.get('app_config', None) self._additional_apps = meta_dict.get('additional_apps', []) self._url_prefix = meta_dict.get('url_prefix', None) def dump_as_dict(self): d = { 'package': self._package_name, } if self._app_config: d['app_config'] = self._app_config if self._additional_apps: d['additional_apps'] = self._additional_apps if self._url_prefix: d['url_prefix'] = self._url_prefix return d class ModuleConfig: _lazy_load = True def __init__(self, config_file_path=None, django_base_dir=None): 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) self._config_file_path = config_file_path self._modules = {} self._loaded = False if not self._lazy_load: self._load() def _lazy_init(self): if not self._loaded: self._load() def _load(self): path = self._config_file_path self._modules = {} if os.path.exists(path): with open(path, 'r', encoding='ascii') as f: data = json.load(f) else: data = {} if 'modules' in data: for meta_dict in data['modules']: module_name = meta_dict['package'] self._modules[module_name] = ModuleMeta(module_name) self._modules[module_name].load_from_dict(meta_dict) self._loaded = True @property def modules(self): self._lazy_init() return self._modules def save(self): path = self._config_file_path if os.path.exists(path): self._lazy_init() else: self._loaded = True data = { 'modules': [], } for meta_obj in self._modules.values(): data['modules'].append(meta_obj.dump_as_dict()) with open(path, 'w', encoding='ascii') as f: json.dump(data, f, indent=4)