From c3c0b66ff4544a2c97a7c4f414b869c3c0ddd8a5 Mon Sep 17 00:00:00 2001 From: Jens Kleineheismann Date: Thu, 14 Nov 2019 17:36:23 +0100 Subject: [PATCH] Close #1 We do things differently now :) --- src/django_deploy/__init__.py | 1 + src/django_deploy/config.py | 101 +++++++++ src/django_deploy/exceptions.py | 8 + src/django_deploy/program.py | 192 +++++++----------- .../tests/fake_app/django_settings.py | 4 - .../tests/{fake_app => fake_app1}/__init__.py | 0 .../tests/fake_app1/django_settings.py | 5 + .../tests/{fake_app => fake_app1}/urls.py | 0 src/django_deploy/tests/fake_app2/__init__.py | 0 .../tests/fake_app2/django_settings.py | 5 + src/django_deploy/tests/fake_app2/urls.py | 3 + src/django_deploy/tests/test_config.py | 54 +++++ src/django_deploy/tests/test_program.py | 152 +++++++++----- src/django_deploy/utils.py | 29 --- tox.ini | 2 +- 15 files changed, 349 insertions(+), 207 deletions(-) create mode 100644 src/django_deploy/exceptions.py delete mode 100644 src/django_deploy/tests/fake_app/django_settings.py rename src/django_deploy/tests/{fake_app => fake_app1}/__init__.py (100%) create mode 100644 src/django_deploy/tests/fake_app1/django_settings.py rename src/django_deploy/tests/{fake_app => fake_app1}/urls.py (100%) create mode 100644 src/django_deploy/tests/fake_app2/__init__.py create mode 100644 src/django_deploy/tests/fake_app2/django_settings.py create mode 100644 src/django_deploy/tests/fake_app2/urls.py create mode 100644 src/django_deploy/tests/test_config.py delete mode 100644 src/django_deploy/utils.py diff --git a/src/django_deploy/__init__.py b/src/django_deploy/__init__.py index c28a133..bb17839 100644 --- a/src/django_deploy/__init__.py +++ b/src/django_deploy/__init__.py @@ -1 +1,2 @@ +from .config import get_installed_apps, get_urlpatterns from .main import main diff --git a/src/django_deploy/config.py b/src/django_deploy/config.py index decb621..53291ec 100644 --- a/src/django_deploy/config.py +++ b/src/django_deploy/config.py @@ -1 +1,102 @@ +try: + from collections.abc import MutableMapping +except ImportError: # pragma: no cover + from collections import MutableMapping +import json +import os + +from django.conf.urls import url, include + DJANGO_SETTINGS_DIR = 'main' + + +class _BaseDict(MutableMapping): + def __init__(self, *args, **kwargs): + super(_BaseDict, self).__init__(*args, **kwargs) + self._store = dict() + self.update(dict(*args, **kwargs)) + + def __getitem__(self, key): + return self._store[self.__keytransform__(key)] + + def __setitem__(self, key, value): + self._store[self.__keytransform__(key)] = value + + def __delitem__(self, key): + del self._store[self.__keytransform__(key)] + + def __iter__(self): + return iter(self._store) + + def __len__(self): + return len(self._store) + + @staticmethod + def __keytransform__(key): + return key + + +class DeployedAppsConfig(_BaseDict): # pylint: disable=too-many-ancestors + def load(self, path=None): + if path is None: + path = self._json_file + if os.path.exists(path): + with open(path, 'r') as f: + self._store = json.load(f) + else: + self._store = dict() + + def write(self, path=None): + if path is None: + path = self._json_file + with open(path, 'w') as f: + json.dump(self._store, f, indent=4) + + def __init__(self, project_dir=None, settings_dir=None): + assert (project_dir or settings_dir), 'DeployedAppsConfig(): ' \ + 'Either keyword argument project_dir or settings_dir' \ + ' must be set.' + assert (not (project_dir and settings_dir)), 'DeployedAppsConfig(): ' \ + 'Keyword arguments project_dir and settings_dir' \ + ' are mutually exclusive.' + super(DeployedAppsConfig, self).__init__() + if project_dir is not None: + settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) + self._json_file = os.path.join(settings_dir, 'django_deploy.json') + self.load() + + +def get_installed_apps(file_path, installed_apps): + settings_dir = os.path.dirname(os.path.abspath(file_path)) + config = DeployedAppsConfig(settings_dir=settings_dir) + app_list = installed_apps[:] + for wanting_app in config: + wanted_apps = config[wanting_app].get('INSTALLED_APPS', []) + for wanted_app in wanted_apps: + if wanted_app not in app_list: + app_list.append(wanted_app) + return app_list + + +def get_urlpatterns(file_path, urlpatterns): + settings_dir = os.path.dirname(os.path.abspath(file_path)) + config = DeployedAppsConfig(settings_dir=settings_dir) + urls_list = urlpatterns[:] + patterns = [] + for url_obj in urls_list: + # Django 1 vs Django 2 + if url_obj.__class__.__name__.startswith('Regex'): # pragma: no cover + patterns.append(url_obj.regex.pattern) + else: # pragma: no cover + patterns.append(str(url_obj.pattern)) + for wanting_app in config: + wanted_urls = config[wanting_app].get('urlpatterns', []) + for wanted_url in wanted_urls: + pattern = wanted_url['pattern'] + if pattern in patterns: + continue + if wanted_url['type'] == 'include': + url_obj = url(pattern, include(wanted_url['module'])) + urls_list.append(url_obj) + patterns.append(pattern) + return urls_list diff --git a/src/django_deploy/exceptions.py b/src/django_deploy/exceptions.py new file mode 100644 index 0000000..229a4c1 --- /dev/null +++ b/src/django_deploy/exceptions.py @@ -0,0 +1,8 @@ +class FatalError(Exception): + def __init__(self, *args, **kwargs): + self._exitval = kwargs.pop('exitval', None) + super(FatalError, self).__init__(*args, **kwargs) + + @property + def exitval(self): + return self._exitval diff --git a/src/django_deploy/program.py b/src/django_deploy/program.py index 996788b..55043e8 100644 --- a/src/django_deploy/program.py +++ b/src/django_deploy/program.py @@ -1,11 +1,10 @@ import argparse -import datetime import importlib import os import sys -from .config import DJANGO_SETTINGS_DIR -from .utils import get_root_urlconf +from .config import DJANGO_SETTINGS_DIR, DeployedAppsConfig +from .exceptions import FatalError from .version import VERSION @@ -24,6 +23,10 @@ class Program(object): # pylint: disable=too-few-public-methods action='store_true', dest='create', help='Create the django project directory') + parser.add_argument('-e', '--enable', + action='store_true', dest='enable', + help='Enable django_deploy in an existing django project directory') + parser.add_argument('project_dir', metavar='PATH', help='The directory, where the django project is or will be installed.') @@ -37,22 +40,6 @@ class Program(object): # pylint: disable=too-few-public-methods return self._argparser.parse_args(argv) - @staticmethod - def _install_django_files(project_dir, overwrite=False): - if os.path.exists(project_dir): - if not overwrite: - sys.stderr.write('directory already exists: {}\n'.format(project_dir)) - return os.EX_NOPERM - else: - os.makedirs(project_dir) - - settings_module = DJANGO_SETTINGS_DIR - cmd = 'django-admin startproject {name} {path}'.format(name=settings_module, - path=project_dir) - sys.stdout.write('Installing django files to {path}\n'.format(path=project_dir)) - exitval = os.system(cmd) - return exitval - @staticmethod def _append_to_pythonfile(path, text): py2_cache = path + 'c' @@ -75,117 +62,72 @@ class Program(object): # pylint: disable=too-few-public-methods text = '\n' + comment + '\n' + code + '\n' return self._append_to_pythonfile(settings_file, text) - def _add_installed_apps_from_app(self, project_dir, app): - settings_from_app = importlib.import_module('{}.django_settings'.format(app)) - if hasattr(settings_from_app, 'ADD_INSTALLED_APPS'): - wanted_apps = settings_from_app.ADD_INSTALLED_APPS - else: - wanted_apps = [] - - if wanted_apps: - sys.stdout.write('{app}: wanted apps: {apps}\n'.format(app=app, apps=', '.join(wanted_apps))) - else: - return os.EX_OK + @staticmethod + def _install_django_files(project_dir, overwrite=False): + if not os.path.exists(project_dir): + os.makedirs(project_dir) settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) - sys.path.insert(0, settings_dir) - settings = importlib.import_module('settings') - sys.path.pop(0) + if os.path.exists(settings_dir) and not overwrite: + sys.stderr.write('directory already exists: {}\n'.format(settings_dir)) + raise FatalError(exitval=os.EX_NOPERM) - already_apps = [] - missing_apps = [] - for wanted_app in wanted_apps: - if wanted_app in settings.INSTALLED_APPS: - already_apps.append(wanted_app) - else: - missing_apps.append(wanted_app) + cmd = 'django-admin startproject {name} {path}'.format(name=DJANGO_SETTINGS_DIR, + path=project_dir) + sys.stdout.write('Installing django files to {path}\n'.format(path=project_dir)) + exitval = os.system(cmd) + if exitval != os.EX_OK: # pragma: no cover + raise FatalError(exitval=exitval) - if already_apps: - sys.stdout.write('{app}: already in settings.INSTALLED_APPS:' - ' {apps}\n'.format(app=app, apps=', '.join(already_apps))) + @staticmethod + def _install_django_deploy_files(project_dir, overwrite=False): + json_file = os.path.join(project_dir, DJANGO_SETTINGS_DIR, 'django_deploy.json') + if os.path.exists(json_file) and not overwrite: + sys.stderr.write('file already exists: {}\n'.format(json_file)) + raise FatalError(exitval=os.EX_NOPERM) - if missing_apps: - sys.stdout.write('{app}: adding to settings.INSTALLED_APPS:' - ' {apps}\n'.format(app=app, apps=', '.join(missing_apps))) - code = 'INSTALLED_APPS += [\n' - for missing_app in missing_apps: - code += ' \'{}\',\n'.format(missing_app) - code += ']\n' - timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - comment = '### {app}: added apps with django-deploy at {timestamp}'.format(app=app, - timestamp=timestamp) + config = DeployedAppsConfig(project_dir=project_dir) + config.write() - self._append_to_settings(project_dir, code, comment) - else: - sys.stdout.write('{app}: all wanted apps are already in settings.INSTALLED_APPS\n'.format(app=app)) + def _enable_django_deploy(self, project_dir): + settings_code = '' + settings_code += 'from django_deploy import get_installed_apps\n' + settings_code += 'INSTALLED_APPS = get_installed_apps(__file__, INSTALLED_APPS)\n' + settings_comment = '# django-deploy' + self._append_to_settings(project_dir, settings_code, settings_comment) + urlconf_code = '' + urlconf_code += 'from django_deploy import get_urlpatterns\n' + urlconf_code += 'urlpatterns = get_urlpatterns(__file__, urlpatterns)\n' + urlconf_comment = '# django-deploy' + self._append_to_urlconf(project_dir, urlconf_code, urlconf_comment) - return os.EX_OK - - def _add_urlpatterns_from_app(self, project_dir, app): # pylint: disable=too-many-locals,too-many-branches + @staticmethod + def _add_installed_apps_from_app(project_dir, app): settings_from_app = importlib.import_module('{}.django_settings'.format(app)) - if hasattr(settings_from_app, 'ADD_URLPATTERNS'): - wanted_urls = {} - for wanted in settings_from_app.ADD_URLPATTERNS: - wanted_urls[wanted['pattern']] = wanted - wanted_patterns = wanted_urls.keys() - else: - wanted_urls = {} - wanted_patterns = [] + wanted_apps = getattr(settings_from_app, 'ADD_INSTALLED_APPS', []) - if wanted_urls: - sys.stdout.write('{app}: wanted urlpatterns: {urls}\n'.format(app=app, urls=', '.join(wanted_patterns))) - else: - return os.EX_OK + config = DeployedAppsConfig(project_dir=project_dir) + if app not in config: + config[app] = {} - root_urlconf = get_root_urlconf(project_dir) + config[app]['INSTALLED_APPS'] = wanted_apps + config.write() - already_patterns = [] - for item in root_urlconf.urlpatterns: - if hasattr(item, 'pattern'): - pattern = str(item.pattern) - else: - pattern = item.regex.pattern - if pattern in wanted_patterns: - already_patterns.append(pattern) + @staticmethod + def _add_urlpatterns_from_app(project_dir, app): + settings_from_app = importlib.import_module('{}.django_settings'.format(app)) + wanted_urls = getattr(settings_from_app, 'ADD_URLPATTERNS', []) - missing_patterns = [pattern for pattern in wanted_patterns if pattern not in already_patterns] + config = DeployedAppsConfig(project_dir=project_dir) + if app not in config: # pragma: no cover + config[app] = {} - if already_patterns: - sys.stdout.write('{app}: already in urlpatterns:' - ' {urls}\n'.format(app=app, urls=', '.join(already_patterns))) - - if missing_patterns: - sys.stdout.write('{app}: adding to urlpatterns:' - ' {apps}\n'.format(app=app, apps=', '.join(missing_patterns))) - code = '' - if not hasattr(root_urlconf, 'url'): - code += 'from django.conf.urls import url\n' - if not hasattr(root_urlconf, 'include'): - code += 'from django.conf.urls import include\n' - code += 'urlpatterns += [\n' - for pattern in missing_patterns: - url = wanted_urls[pattern] - if url['type'] == 'include': - code += " url(r'{pattern}', include('{module}')),\n".format(pattern=pattern, - module=url['module']) - else: - sys.stderr.write('{app}: not a supported url type: {type}\n'.format(app=app, type=url['type'])) - code += ']\n' - timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - comment = '### {app}: added urlpatterns with django-deploy at {timestamp}'.format(app=app, - timestamp=timestamp) - self._append_to_urlconf(project_dir, code, comment) - else: - sys.stdout.write('{app}: all wanted patterns are already in urlconfig\n'.format(app=app)) - - return os.EX_OK + config[app]['urlpatterns'] = wanted_urls + config.write() def _merge_app(self, project_dir, app): - exitval = self._add_installed_apps_from_app(project_dir, app) - if exitval != os.EX_OK: - return exitval - exitval = self._add_urlpatterns_from_app(project_dir, app) - return exitval + self._add_installed_apps_from_app(project_dir, app) + self._add_urlpatterns_from_app(project_dir, app) def __init__(self): self._argparser = argparse.ArgumentParser() @@ -195,13 +137,15 @@ class Program(object): # pylint: disable=too-few-public-methods argv = kwargs.get('argv', None) cmd_args = self._parse_args(argv) exitval = os.EX_OK - if cmd_args.create: - exitval = self._install_django_files(cmd_args.project_dir) - if exitval != os.EX_OK: - return exitval - if cmd_args.merge_apps: - for app in cmd_args.merge_apps: - exitval = self._merge_app(cmd_args.project_dir, app) - if exitval != os.EX_OK: - return exitval + try: + if cmd_args.create: + self._install_django_files(cmd_args.project_dir) + if cmd_args.create or cmd_args.enable: + self._install_django_deploy_files(cmd_args.project_dir) + self._enable_django_deploy(cmd_args.project_dir) + if cmd_args.merge_apps: + for app in cmd_args.merge_apps: + self._merge_app(cmd_args.project_dir, app) + except FatalError as e: + exitval = e.exitval return exitval diff --git a/src/django_deploy/tests/fake_app/django_settings.py b/src/django_deploy/tests/fake_app/django_settings.py deleted file mode 100644 index 23e6a92..0000000 --- a/src/django_deploy/tests/fake_app/django_settings.py +++ /dev/null @@ -1,4 +0,0 @@ -ADD_INSTALLED_APPS = ['django_deploy.tests.fake_app'] -ADD_URLPATTERNS = [ - {'type': 'include', 'pattern': '^fake/', 'module': 'django_deploy.tests.fake_app.urls'}, -] diff --git a/src/django_deploy/tests/fake_app/__init__.py b/src/django_deploy/tests/fake_app1/__init__.py similarity index 100% rename from src/django_deploy/tests/fake_app/__init__.py rename to src/django_deploy/tests/fake_app1/__init__.py diff --git a/src/django_deploy/tests/fake_app1/django_settings.py b/src/django_deploy/tests/fake_app1/django_settings.py new file mode 100644 index 0000000..fffc431 --- /dev/null +++ b/src/django_deploy/tests/fake_app1/django_settings.py @@ -0,0 +1,5 @@ +ADD_INSTALLED_APPS = ['django_deploy.tests.fake_app1'] +ADD_URLPATTERNS = [ + {'type': 'include', 'pattern': '^fake1/', 'module': 'django_deploy.tests.fake_app1.urls'}, + {'type': 'invalid', 'pattern': '^invalid/'}, +] diff --git a/src/django_deploy/tests/fake_app/urls.py b/src/django_deploy/tests/fake_app1/urls.py similarity index 100% rename from src/django_deploy/tests/fake_app/urls.py rename to src/django_deploy/tests/fake_app1/urls.py diff --git a/src/django_deploy/tests/fake_app2/__init__.py b/src/django_deploy/tests/fake_app2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/django_deploy/tests/fake_app2/django_settings.py b/src/django_deploy/tests/fake_app2/django_settings.py new file mode 100644 index 0000000..5bbce39 --- /dev/null +++ b/src/django_deploy/tests/fake_app2/django_settings.py @@ -0,0 +1,5 @@ +ADD_INSTALLED_APPS = ['django_deploy.tests.fake_app1', 'django_deploy.tests.fake_app2'] +ADD_URLPATTERNS = [ + {'type': 'include', 'pattern': '^fake1/', 'module': 'django_deploy.tests.fake_app1.urls'}, + {'type': 'include', 'pattern': '^fake2/', 'module': 'django_deploy.tests.fake_app2.urls'}, +] diff --git a/src/django_deploy/tests/fake_app2/urls.py b/src/django_deploy/tests/fake_app2/urls.py new file mode 100644 index 0000000..3197708 --- /dev/null +++ b/src/django_deploy/tests/fake_app2/urls.py @@ -0,0 +1,3 @@ +# pylint: skip-file +app_name = 'fake2' +urlpatterns = [] diff --git a/src/django_deploy/tests/test_config.py b/src/django_deploy/tests/test_config.py new file mode 100644 index 0000000..8063bc4 --- /dev/null +++ b/src/django_deploy/tests/test_config.py @@ -0,0 +1,54 @@ +import unittest + +from django.conf.urls import url, include + +from ..config import get_installed_apps, get_urlpatterns, DeployedAppsConfig + + +class FunctionsTestCase(unittest.TestCase): + def test_get_installed_apps(self): + test_data_sets = [ + (__file__, ['fake_app1', 'fake_app2']), + ] + + for file_path, installed_apps in test_data_sets: + result = get_installed_apps(file_path, installed_apps) + self.assertEqual(installed_apps, result) + + def test_get_urlpatterns(self): + test_data_sets = [ + ( + __file__, + [ + url('/app1', include('django_deploy.tests.fake_app1.urls')), + url('/app2', include('django_deploy.tests.fake_app2.urls')), + ], + ), + ] + + for file_path, urlpatterns in test_data_sets: + result = get_urlpatterns(file_path, urlpatterns) + self.assertEqual(urlpatterns, result) + + +class DeployedAppsConfigTestCase(unittest.TestCase): + def test_init_parameters(self): + with self.assertRaises(AssertionError): + DeployedAppsConfig() + with self.assertRaises(AssertionError): + DeployedAppsConfig(project_dir='.', settings_dir='.') + + def test_len(self): + c = DeployedAppsConfig(settings_dir='.') + c['a'] = 'a' + c['b'] = 'b' + c['c'] = 'c' + self.assertEqual(3, len(c)) + + def test_del(self): + c = DeployedAppsConfig(settings_dir='.') + c['a'] = 'a' + c['b'] = 'b' + c['c'] = 'c' + del c['b'] + self.assertEqual(2, len(c)) diff --git a/src/django_deploy/tests/test_program.py b/src/django_deploy/tests/test_program.py index cfdc511..ae71d0f 100644 --- a/src/django_deploy/tests/test_program.py +++ b/src/django_deploy/tests/test_program.py @@ -2,65 +2,96 @@ import importlib import os import sys import unittest +import mock import pytest from ..config import DJANGO_SETTINGS_DIR from ..program import Program -from ..utils import get_root_urlconf -class MainTestCase(unittest.TestCase): +class ProgramTestCase(unittest.TestCase): @pytest.fixture(autouse=True) def tmpdir(self, tmpdir): # pylint: disable=method-hidden self.tmpdir = tmpdir + def _assert_django_project(self, project_dir): + self.assertTrue(os.path.isdir(project_dir), 'no directory: {}'.format(project_dir)) + settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) + self.assertTrue(os.path.isdir(settings_dir), 'no directory: {}'.format(settings_dir)) + settings_file = os.path.join(settings_dir, 'settings.py') + self.assertTrue(os.path.isfile(settings_file), 'no file: {}'.format(settings_file)) + manage_script = os.path.join(project_dir, 'manage.py') + self.assertTrue(os.path.isfile(manage_script), 'no file: {}'.format(manage_script)) + + def _assert_django_deploy_project(self, project_dir): + settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) + settings_file = os.path.join(settings_dir, 'settings.py') + urlconf_file = os.path.join(settings_dir, 'urls.py') + django_deploy_json = os.path.join(settings_dir, 'django_deploy.json') + + self.assertTrue(os.path.isfile(django_deploy_json), 'no file: {}'.format(django_deploy_json)) + + with open(settings_file, 'r') as f: + needle = 'from django_deploy import get_installed_apps' + haystack = f.read() + self.assertIn(needle, haystack) + + with open(urlconf_file, 'r') as f: + needle = 'from django_deploy import get_urlpatterns' + haystack = f.read() + self.assertIn(needle, haystack) + def setUp(self): self._program = Program() + self._project_dir = os.path.join(str(self.tmpdir), 'django') + self._program(argv=['--create', self._project_dir]) - def test_create(self): - tmpdir = self.tmpdir - project_dir = os.path.join(str(tmpdir), 'env', 'django') - + def test_create_new_dir(self): + project_dir = os.path.join(str(self.tmpdir), 'new_dir') exitval = self._program(argv=['-c', project_dir]) self.assertEqual(os.EX_OK, exitval, 'program() does not return os.EX_OK') - self.assertTrue(os.path.isdir(project_dir), 'project directory was not created') - settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) - self.assertTrue(os.path.isdir(settings_dir), 'settings directory was not created') - settings_file = os.path.join(settings_dir, 'settings.py') - self.assertTrue(os.path.isfile(settings_file), 'settings.py was not created') - manage_script = os.path.join(project_dir, 'manage.py') - self.assertTrue(os.path.isfile(manage_script), 'manage.py was not created') + self._assert_django_project(project_dir) + self._assert_django_deploy_project(project_dir) - def test_create_dont_overwrite(self): - tmpdir = self.tmpdir - project_dir = os.path.join(str(tmpdir), 'env', 'django') + def test_create_existing_empty_dir(self): + project_dir = os.path.join(str(self.tmpdir), 'empty_dir') + os.makedirs(project_dir) + exitval = self._program(argv=['-c', project_dir]) - self._program(argv=['--create', project_dir]) - exitval = self._program(argv=['--create', project_dir]) + self.assertEqual(os.EX_OK, exitval, 'program() does not return os.EX_OK') + self._assert_django_project(project_dir) + self._assert_django_deploy_project(project_dir) - self.assertEqual(os.EX_NOPERM, exitval, 'second call to program() does not exit with os.EX_NOPERM') + def test_create_existing_project_dir(self): + exitval = self._program(argv=['-c', self._project_dir]) + self.assertEqual(os.EX_NOPERM, exitval, 'program() does not return os.EX_NOPERM' + ' when project directory is not empty') + + def test_enable_django_deploy(self): + project_dir = os.path.join(str(self.tmpdir), 'pure_django') + os.makedirs(project_dir) + cmd = 'django-admin startproject {name} {path}'.format(name=DJANGO_SETTINGS_DIR, + path=project_dir) + os.system(cmd) + self._program(argv=['--enable', project_dir]) + self._assert_django_deploy_project(project_dir) + + def test_enable_django_deploy_twice(self): + exitval = self._program(argv=['-e', self._project_dir]) + self.assertEqual(os.EX_NOPERM, exitval, 'program() does not return os.EX_NOPERM' + ' when django_deploy is already enabled') def test_merge_installed_apps(self): - tmpdir = self.tmpdir - project_dir = os.path.join(str(tmpdir), 'env', 'django') + project_dir = self._project_dir - argv = ['-c', project_dir] + argv = [ + '-a', 'django_deploy', + '-a', 'django_deploy.tests.fake_app1', + '-a', 'django_deploy.tests.fake_app2', + project_dir] self._program(argv=argv) - argv = ['-a', 'django_deploy', '-a', 'django_deploy.tests.fake_app', project_dir] - self._program(argv=argv) - - expected_installed_apps = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django_deploy.tests.fake_app', - ] - settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) sys.path.insert(0, settings_dir) settings = importlib.import_module('settings') @@ -70,30 +101,52 @@ class MainTestCase(unittest.TestCase): importlib.reload(settings) # pylint: disable=no-member sys.path.pop(0) + expected_installed_apps = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django_deploy.tests.fake_app1', + 'django_deploy.tests.fake_app2', + ] + self.assertListEqual(expected_installed_apps, settings.INSTALLED_APPS) def test_merge_root_urlconf(self): - tmpdir = self.tmpdir - project_dir = os.path.join(str(tmpdir), 'env', 'django') + project_dir = self._project_dir - argv = ['-c', project_dir] + argv = [ + '-a', 'django_deploy', + '-a', 'django_deploy.tests.fake_app1', + '-a', 'django_deploy.tests.fake_app2', + project_dir] self._program(argv=argv) - argv = ['-a', 'django_deploy', '-a', 'django_deploy.tests.fake_app', project_dir] - self._program(argv=argv) + sys.modules['django.contrib'] = mock.MagicMock(name='django.contrib') - root_urlconf = get_root_urlconf(project_dir) + settings_dir = os.path.join(project_dir, DJANGO_SETTINGS_DIR) + sys.path.insert(0, settings_dir) + root_urlconf = importlib.import_module('urls') + if sys.version_info.major == 2: # pragma: no cover + reload(root_urlconf) # pylint: disable=undefined-variable + else: # pragma: no cover + importlib.reload(root_urlconf) # pylint: disable=no-member + sys.path.pop(0) - if hasattr(root_urlconf, 'path'): + # Django 2 vs Django 1 + if hasattr(root_urlconf, 'path'): # pragma: no cover expected_urlpatterns = [ ('URLPattern', 'admin/', 'django.contrib.admin.site.urls'), ] - else: + else: # pragma: no cover expected_urlpatterns = [ ('URLPattern', '^admin/', 'django.contrib.admin.site.urls'), ] expected_urlpatterns += [ - ('URLResolver', '^fake/', 'django_deploy.tests.fake_app.urls'), + ('URLResolver', '^fake1/', 'django_deploy.tests.fake_app1.urls'), + ('URLResolver', '^fake2/', 'django_deploy.tests.fake_app2.urls'), ] real_urlpatterns = root_urlconf.urlpatterns @@ -103,17 +156,18 @@ class MainTestCase(unittest.TestCase): real = real_urlpatterns[i] real_class_name = real.__class__.__name__ self.assertTrue(real_class_name.endswith(expected[0])) - if real_class_name == 'URLPattern': + # Django 2 vs. Django 1 + if real_class_name == 'URLPattern': # pragma: no cover self.assertEqual(expected[1], str(real.pattern)) self.assertTrue(real.callback.startswith("