Skip to content

Commit

Permalink
Add support for message addon config parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
yakky committed Dec 20, 2020
1 parent d76a244 commit a13a9b6
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 51 deletions.
4 changes: 2 additions & 2 deletions app_enabler/django.py
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
72 changes: 68 additions & 4 deletions app_enabler/enable.py
Original file line number Diff line number Diff line change
@@ -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"])
1 change: 1 addition & 0 deletions changes/11.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for message addon config parameter
28 changes: 13 additions & 15 deletions tests/test_enable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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

Expand Down
33 changes: 3 additions & 30 deletions tests/test_patcher.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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)

0 comments on commit a13a9b6

Please sign in to comment.