From a13a9b65d9e709f5cfebbda49c2c81cf16528338 Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Sun, 20 Dec 2020 06:16:04 +0100 Subject: [PATCH] Add support for message addon config parameter --- app_enabler/django.py | 4 +-- app_enabler/enable.py | 72 ++++++++++++++++++++++++++++++++++++++++--- changes/11.feature | 1 + tests/test_enable.py | 28 ++++++++--------- tests/test_patcher.py | 33 ++------------------ 5 files changed, 87 insertions(+), 51 deletions(-) create mode 100644 changes/11.feature diff --git a/app_enabler/django.py b/app_enabler/django.py index 597db0e..3f6e0d0 100644 --- a/app_enabler/django.py +++ b/app_enabler/django.py @@ -1,12 +1,12 @@ import json from importlib import import_module -from typing import Optional +from typing import Any, Dict, Optional import django.conf from pkg_resources import resource_stream -def load_addon(module_name: str) -> Optional[dict]: +def load_addon(module_name: str) -> Optional[Dict[str, Any]]: """ Load addon configuration from json file stored in package resources. diff --git a/app_enabler/enable.py b/app_enabler/enable.py index 2cc8514..d0dd610 100644 --- a/app_enabler/enable.py +++ b/app_enabler/enable.py @@ -1,21 +1,85 @@ -from django.conf import settings +import sys +from importlib import import_module +from types import ModuleType +from typing import Any, Dict + +import django.conf from .django import get_settings_path, get_urlconf_path, load_addon 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.""" + test_passed = True + for app in application_config["installed-apps"]: + test_passed = test_passed and app in imported.INSTALLED_APPS + for key, value in application_config["settings"].items(): + if isinstance(value, list): + for item in value: + test_passed = test_passed and item in getattr(imported, key) + else: + test_passed = test_passed and getattr(imported, key) == 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.""" + + # 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 = False + # include function is added by our patcher, soo we must ensure it is available + test_passed = bool(imported.include) + for urlpattern in imported.urlpatterns: + if isinstance(urlpattern.urlconf_name, ModuleType): + urlpatterns_checked = True + test_passed = test_passed and urlpattern.urlconf_name.__name__ == "djangocms_blog.taggit_urls" + return test_passed and urlpatterns_checked + + +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 str application_config: addon configuration + """ + if settings.SETTINGS_MODULE in sys.modules: + del sys.modules[settings.SETTINGS_MODULE] + if settings.ROOT_URLCONF in sys.modules: + del sys.modules[settings.ROOT_URLCONF] + 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 + + +def output_message(message: str): + """ + Print the given message to stdout. + + :param str message: Success message to display + """ + sys.stdout.write(message) + + def enable(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 + :param bool verbose: Verbose output (currently unused) """ + setup_django() - setting_file = get_settings_path(settings) - urlconf_file = get_urlconf_path(settings) + setting_file = get_settings_path(django.conf.settings) + urlconf_file = get_urlconf_path(django.conf.settings) application_config = load_addon(application) if application_config: update_setting(setting_file, application_config) update_urlconf(urlconf_file, application_config) + if verify_installation(django.conf.settings, application_config): + output_message(application_config["message"]) diff --git a/changes/11.feature b/changes/11.feature new file mode 100644 index 0000000..81c0352 --- /dev/null +++ b/changes/11.feature @@ -0,0 +1 @@ +Add support for message addon config parameter diff --git a/tests/test_enable.py b/tests/test_enable.py index c27a70a..4366f44 100644 --- a/tests/test_enable.py +++ b/tests/test_enable.py @@ -4,32 +4,30 @@ from types import ModuleType from unittest.mock import patch -from app_enabler.enable import enable -from tests.test_patcher import check_settings_patched, check_urlconf_patched +from app_enabler.enable import _verify_settings, _verify_urlconf, enable from tests.utils import working_directory -def test_enable(pytester, project_dir, addon_config, teardown_django): +def test_enable(capsys, pytester, project_dir, addon_config, teardown_django): """Executing setup_django will setup the corresponding django project.""" with working_directory(project_dir), patch("app_enabler.enable.load_addon") as load_addon: load_addon.return_value = addon_config os.environ["DJANGO_SETTINGS_MODULE"] = "test_project.settings" - if "test_project.settings" in sys.modules: - del sys.modules["test_project.settings"] - if "test_project.urls" in sys.modules: - del sys.modules["test_project.urls"] enable("djangocms_blog") - if "test_project.settings" in sys.modules: - del sys.modules["test_project.settings"] + + captured = capsys.readouterr() + assert addon_config["message"] in captured.out + if os.environ["DJANGO_SETTINGS_MODULE"] in sys.modules: + del sys.modules[os.environ["DJANGO_SETTINGS_MODULE"]] if "test_project.urls" in sys.modules: del sys.modules["test_project.urls"] - imported = import_module("test_project.settings") - check_settings_patched(imported, addon_config) + imported = import_module(os.environ["DJANGO_SETTINGS_MODULE"]) + assert _verify_settings(imported, addon_config) imported = import_module("test_project.urls") - check_urlconf_patched(imported, addon_config) + assert _verify_urlconf(imported, addon_config) def test_enable_no_application(pytester, project_dir, addon_config, teardown_django): @@ -40,11 +38,11 @@ def test_enable_no_application(pytester, project_dir, addon_config, teardown_dja os.environ["DJANGO_SETTINGS_MODULE"] = "test_project.settings" enable("djangocms_blog") - if "test_project.settings" in sys.modules: - del sys.modules["test_project.settings"] + if os.environ["DJANGO_SETTINGS_MODULE"] in sys.modules: + del sys.modules[os.environ["DJANGO_SETTINGS_MODULE"]] if "test_project.urls" in sys.modules: del sys.modules["test_project.urls"] - imported = import_module("test_project.settings") + imported = import_module(os.environ["DJANGO_SETTINGS_MODULE"]) assert "djangocms_blog" not in imported.INSTALLED_APPS assert "django.middleware.gzip.GZipMiddleware" not in imported.MIDDLEWARE diff --git a/tests/test_patcher.py b/tests/test_patcher.py index 0cde628..6270643 100644 --- a/tests/test_patcher.py +++ b/tests/test_patcher.py @@ -1,42 +1,15 @@ import os import sys from importlib import import_module -from types import ModuleType -from typing import Any, Dict import pytest -from django.conf import LazySettings +from app_enabler.enable import _verify_settings, _verify_urlconf from app_enabler.errors import messages from app_enabler.patcher import setup_django, update_setting, update_urlconf from tests.utils import working_directory -def check_settings_patched(imported: LazySettings, addon_config: Dict[str, Any]): - """Assert that addon config has been properly set in patched settings.""" - - for app in addon_config["installed-apps"]: - assert app in imported.INSTALLED_APPS - assert imported.META_SITE_PROTOCOL == "https" - assert imported.META_USE_SITES is True - assert "django.middleware.gzip.GZipMiddleware" in imported.MIDDLEWARE - - -def check_urlconf_patched(imported: ModuleType, addon_config: Dict[str, Any]): - """Assert that addon urlconf has been properly added in patched urlconf.""" - - # 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 = False - # include function is added by our patcher, soo we must ensure it is available - assert imported.include - for urlpattern in imported.urlpatterns: - if isinstance(urlpattern.urlconf_name, ModuleType): - urlpatterns_checked = True - assert urlpattern.urlconf_name.__name__ == "djangocms_blog.taggit_urls" - assert urlpatterns_checked - - def test_setup_django_no_manage(capsys, project_dir, teardown_django): """Executing setup_django outside a project root raise a specific exception.""" from django.apps import apps @@ -73,7 +46,7 @@ def test_update_setting(pytester, project_dir, addon_config): update_setting(settings_file, addon_config) sys.path.insert(0, str(settings_file.parent)) imported = import_module("settings") - check_settings_patched(imported, addon_config) + assert _verify_settings(imported, addon_config) def test_update_urlconf(pytester, django_setup, project_dir, addon_config): @@ -83,4 +56,4 @@ def test_update_urlconf(pytester, django_setup, project_dir, addon_config): update_urlconf(urlconf_file, addon_config) sys.path.insert(0, str(urlconf_file.parent)) imported = import_module("urls") - check_urlconf_patched(imported, addon_config) + assert _verify_urlconf(imported, addon_config)