Source code for app_enabler.enable

import json
import sys
import warnings
from importlib import import_module
from pathlib import Path
from types import ModuleType
from typing import Any, Dict, List

import django.conf

from .django import get_settings_path, get_urlconf_path, load_addon
from .errors import messages
from .patcher import setup_django, update_setting, update_urlconf


def _verify_settings(imported: ModuleType, application_config: Dict[str, Any]) -> bool:
    """
    Check that addon config has been properly set in patched settings.

    :param ModuleType imported:  Update settings module
    :param dict application_config: addon configuration
    """

    def _validate_setting(key: str, value: Any):
        """
        Validate the given value for a single setting.

        It's aware of the possible structures of the application config setting (either a literal or a dict with the
        precedence information).
        """
        passed = True
        if isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    real_item = item["value"]
                    passed = passed and (real_item in getattr(imported, key))
                    if not passed:  # pragma: no cover
                        warnings.warn(f"Configuration error for {key}", RuntimeWarning)
                else:
                    passed = passed and (item in getattr(imported, key))
                    if not passed:  # pragma: no cover
                        warnings.warn(f"Configuration error for {key}", RuntimeWarning)
        else:
            passed = passed and getattr(imported, key) == value
            if not passed:  # pragma: no cover
                warnings.warn(f"Configuration error for {key}", RuntimeWarning)
        return passed

    test_passed = _validate_setting("INSTALLED_APPS", application_config.get("installed-apps", []))
    for setting_name, setting_value in application_config.get("settings", {}).items():
        test_passed = test_passed and _validate_setting(setting_name, setting_value)
    return test_passed


def _verify_urlconf(imported: ModuleType, application_config: Dict[str, Any]) -> bool:
    """
    Check that addon urlconf has been properly added in patched urlconf.


    :param ModuleType imported: Update ``ROOT_URLCONF`` module
    :param dict application_config: addon configuration
    """
    # include function is added by our patcher, soo we must ensure it is available
    test_passed = bool(imported.include)
    included_urls = [url[1] for url in application_config.get("urls", [])]
    # as we want to make sure urlpatterns is really tested, we check both that an existing module of the correct type
    # is the module from addon config, and that the assert is reached for real
    urlpatterns_checked = not included_urls
    if included_urls:
        for urlpattern in imported.urlpatterns:
            try:
                if isinstance(urlpattern.urlconf_name, ModuleType):
                    urlpatterns_checked = True
                    test_passed = test_passed and urlpattern.urlconf_name.__name__ in included_urls
            except AttributeError:
                pass
    return test_passed and urlpatterns_checked


[docs] def verify_installation(settings: django.conf.LazySettings, application_config: Dict[str, Any]) -> bool: """ Verify that package installation has been successful. :param django.conf.LazySettings settings: Path to settings file :param dict application_config: addon configuration """ try: del sys.modules[settings.SETTINGS_MODULE] except KeyError: # pragma: no cover pass try: del sys.modules[settings.ROOT_URLCONF] except KeyError: # pragma: no cover pass imported_settings = import_module(settings.SETTINGS_MODULE) imported_urlconf = import_module(settings.ROOT_URLCONF) test_passed = _verify_settings(imported_settings, application_config) test_passed = test_passed and _verify_urlconf(imported_urlconf, application_config) return test_passed
[docs] def output_message(message: str): """ Print the given message to stdout. :param str message: Success message to display """ if message: sys.stdout.write(message)
[docs] def apply_configuration(application_config: Dict[str, Any]): """ Enable django application in the current project :param dict application_config: addon configuration """ setting_file = get_settings_path(django.conf.settings) urlconf_file = get_urlconf_path(django.conf.settings) update_setting(setting_file, application_config) update_urlconf(urlconf_file, application_config) if verify_installation(django.conf.settings, application_config): output_message(application_config.get("message", "")) else: output_message(messages["verify_error"].format(package=application_config.get("package-name")))
[docs] def enable_application(application: str, verbose: bool = False): """ Enable django application in the current project :param str application: python module name to enable. It must be the name of a Django application. :param bool verbose: Verbose output (currently unused) """ setup_django() application_config = load_addon(application) if application_config: apply_configuration(application_config)
[docs] def apply_configuration_set(config_set: List[Path], verbose: bool = False): """ Apply settings from the list of input files. :param list config_set: list of paths to addon configuration to load and apply :param bool verbose: Verbose output (currently unused) """ setup_django() for config_path in config_set: try: config_data = json.loads(config_path.read_text()) except OSError: config_data = [] if config_data: if not isinstance(config_data, list): config_data = [config_data] for item in config_data: apply_configuration(item)