From 29dd5524b2c3fb0b113da2c1bb8f6bb5d9282b98 Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Sat, 22 Dec 2018 22:39:31 +0100 Subject: [PATCH] Improve settings patching --- HISTORY.rst | 1 + djangocms_installer/config/__init__.py | 2 +- djangocms_installer/config/ini.py | 2 +- djangocms_installer/django/__init__.py | 40 +++++++++++++++++--------- tests/config.py | 2 +- tests/django.py | 38 ++++++++++++++++++------ tests/main.py | 4 +-- 7 files changed, 63 insertions(+), 26 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 6000bcc..66b70f4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,6 +8,7 @@ History * Added support for django CMS 3.6 (as develop version until release) * Added detection of incompatible DJANGO_SETTINGS_MODULE environment variable +* Added detection of mismatched Django version between currently installed and declared one 1.0.2 (2018-11-21) ++++++++++++++++++ diff --git a/djangocms_installer/config/__init__.py b/djangocms_installer/config/__init__.py index 146efc2..ab8f94d 100644 --- a/djangocms_installer/config/__init__.py +++ b/djangocms_installer/config/__init__.py @@ -254,7 +254,7 @@ def parse(args): 'djangocms installer.\nPlease unset `DJANGO_SETTINGS_MODULE` and re-run the installer ' '\n'.format(env_settings) ) - sys.exit(7) + sys.exit(10) if not getattr(args, 'requirements_file'): requirements = [] diff --git a/djangocms_installer/config/ini.py b/djangocms_installer/config/ini.py index 842ddc1..00526b5 100644 --- a/djangocms_installer/config/ini.py +++ b/djangocms_installer/config/ini.py @@ -40,7 +40,7 @@ def parse_config_file(parser, stdin_args): config = ConfigParser() if not config.read(parsed_args.config_file): sys.stderr.write('Config file "{0}" doesn\'t exists\n'.format(parsed_args.config_file)) - sys.exit(7) # It isn't used anythere. + sys.exit(7) # It isn't used anywhere. config_args = _convert_config_to_stdin(config, parser) return config_args diff --git a/djangocms_installer/django/__init__.py b/djangocms_installer/django/__init__.py index e932346..aa5b67e 100644 --- a/djangocms_installer/django/__init__.py +++ b/djangocms_installer/django/__init__.py @@ -168,19 +168,34 @@ def patch_settings(config_data): :param config_data: configuration data """ - overridden_settings = ( - 'MIDDLEWARE_CLASSES', 'MIDDLEWARE', 'INSTALLED_APPS', 'TEMPLATE_LOADERS', - 'TEMPLATE_CONTEXT_PROCESSORS', 'TEMPLATE_DIRS', 'LANGUAGES' - ) - extra_settings = '' + import django + current_django_version = LooseVersion(django.__version__) + declared_django_version = LooseVersion(config_data.django_version) if not os.path.exists(config_data.settings_path): - sys.stdout.write( + sys.stderr.write( 'Error while creating target project, ' - 'please check the given configuration: {0}'.format(config_data.settings_path) + 'please check the given configuration: {0}\n'.format(config_data.settings_path) ) return sys.exit(5) + if current_django_version.version[:2] != declared_django_version.version[:2]: + sys.stderr.write( + 'Currently installed Django version {} differs from the declared {}. ' + 'Please check the given `--django-version` installer argument, your virtualenv ' + 'configuration and any package forcing a different Django version' + '\n'.format( + current_django_version, declared_django_version + ) + ) + return sys.exit(9) + + overridden_settings = ( + 'MIDDLEWARE_CLASSES', 'MIDDLEWARE', 'INSTALLED_APPS', 'TEMPLATE_LOADERS', + 'TEMPLATE_CONTEXT_PROCESSORS', 'TEMPLATE_DIRS', 'LANGUAGES' + ) + extra_settings = '' + with open(config_data.settings_path, 'r') as fd_original: original = fd_original.read() @@ -227,19 +242,18 @@ def patch_settings(config_data): 'LANGUAGE_CODE = \'en-us\'', 'LANGUAGE_CODE = \'{0}\''.format(config_data.languages[0]) ) if config_data.timezone: - # This is for Django 1.6 which changed the default timezone original = original.replace( 'TIME_ZONE = \'UTC\'', 'TIME_ZONE = \'{0}\''.format(config_data.timezone) ) for item in overridden_settings: - if LooseVersion(config_data.django_version) >= LooseVersion('1.9'): + if declared_django_version >= LooseVersion('1.9'): item_re = re.compile(r'{0} = [^\]]+\]'.format(item), re.DOTALL | re.MULTILINE) else: item_re = re.compile(r'{0} = [^\)]+\)'.format(item), re.DOTALL | re.MULTILINE) original = item_re.sub('', original) # TEMPLATES is special, so custom regexp needed - if LooseVersion(config_data.django_version) >= LooseVersion('2.0'): + if declared_django_version >= LooseVersion('2.0'): item_re = re.compile(r'TEMPLATES = .+\},\n\s+\},\n]$', re.DOTALL | re.MULTILINE) else: item_re = re.compile(r'TEMPLATES = .+\]$', re.DOTALL | re.MULTILINE) @@ -284,12 +298,12 @@ def _build_settings(config_data): )) if LooseVersion(config_data.django_version) >= LooseVersion('1.10'): - text.append('MIDDLEWARE = (\n{0}{1}\n)'.format( + text.append('MIDDLEWARE = [\n{0}{1}\n]'.format( spacer, (',\n' + spacer).join(['\'{0}\''.format(var) for var in vars.MIDDLEWARE_CLASSES]) )) else: - text.append('MIDDLEWARE_CLASSES = (\n{0}{1}\n)'.format( + text.append('MIDDLEWARE_CLASSES = [\n{0}{1}\n]'.format( spacer, (',\n' + spacer).join(["'{0}'".format(var) for var in vars.MIDDLEWARE_CLASSES]) )) @@ -306,7 +320,7 @@ def _build_settings(config_data): apps.extend(vars.ALDRYN_APPLICATIONS) if config_data.reversion and LooseVersion(config_data.cms_version) < LooseVersion('3.4'): apps.extend(vars.REVERSION_APPLICATIONS) - text.append('INSTALLED_APPS = (\n{0}{1}\n)'.format( + text.append('INSTALLED_APPS = [\n{0}{1}\n]'.format( spacer, (',\n' + spacer).join(['\'{0}\''.format(var) for var in apps] + ['\'{0}\''.format(config_data.project_name)]) )) diff --git a/tests/config.py b/tests/config.py index 1761a5d..f5d3e87 100644 --- a/tests/config.py +++ b/tests/config.py @@ -308,7 +308,7 @@ def test_invalid_django_settings_module(self): '--db=postgres://user:pwd@host/dbname', '-p'+self.project_dir, prj_dir]) - self.assertEqual(error.exception.code, 7) + self.assertEqual(error.exception.code, 10) self.assertTrue(self.stderr.getvalue().find('DJANGO_SETTINGS_MODULE') > -1) self.assertTrue(self.stderr.getvalue().find('some_module.settings') > -1) diff --git a/tests/django.py b/tests/django.py index 971f526..b8a2b90 100644 --- a/tests/django.py +++ b/tests/django.py @@ -7,6 +7,8 @@ import sys import textwrap +from mock import patch + from djangocms_installer import config, django, install from .base import IsolatedTestClass, dj_ver, unittest @@ -185,7 +187,7 @@ def test_patch_django_19_34(self): '--django-version=1.9', '--cms-version=3.4', '--timezone=Europe/Moscow', '-q', '-u', '-zno', '--i18n=no', - '-p' + self.project_dir, 'example_path_16']) + '-p' + self.project_dir, 'example_path_19']) install.requirements(config_data.requirements) django.create_project(config_data) @@ -200,12 +202,13 @@ def test_patch_django_19_34(self): project = __import__(config_data.project_name, globals(), locals(), [str('settings')]) # checking for django options - self.assertEqual(project.settings.MEDIA_ROOT, - os.path.join(config_data.project_directory, 'media')) + self.assertEqual( + project.settings.MEDIA_ROOT, os.path.join(config_data.project_directory, 'media') + ) self.assertEqual(project.settings.MEDIA_URL, '/media/') self.assertEqual(project.settings.TIME_ZONE, 'Europe/Moscow') - self.assertTrue('cmsplugin_filer_image'not in project.settings.INSTALLED_APPS) + self.assertTrue('cmsplugin_filer_image' not in project.settings.INSTALLED_APPS) self.assertTrue('cmsplugin_filer_file' not in project.settings.INSTALLED_APPS) self.assertTrue('cmsplugin_filer_folder' not in project.settings.INSTALLED_APPS) self.assertTrue('cmsplugin_filer_link' not in project.settings.INSTALLED_APPS) @@ -296,8 +299,8 @@ def test_patch_django_111_develop(self): project.settings.MIDDLEWARE ) - @unittest.skipIf(sys.version_info[:2] not in ((3, 4), (3, 5), (3, 6), (3, 7),), - reason='django 2.1 only supports python 3.4, 3.5, 3.6 and 3.7') + @unittest.skipIf(sys.version_info[:2] not in ((3, 5), (3, 6), (3, 7),), + reason='django 2.1 only supports python 3.5, 3.6 and 3.7') def test_patch_django_21_develop(self): extra_path = os.path.join(os.path.dirname(__file__), 'data', 'extra_settings.py') params = [ @@ -328,8 +331,8 @@ def test_patch_django_21_develop(self): project.settings.MIDDLEWARE ) - @unittest.skipIf(sys.version_info[:2] not in ((3, 4), (3, 5), (3, 6), (3, 7),), - reason='django 2.1 only supports python 3.4, 3.5, 3.6 and 3.7') + @unittest.skipIf(sys.version_info[:2] not in ((3, 4), (3, 5), (3, 6),), + reason='django 2.0 only supports python 3.4, 3.5, 3.6') def test_patch_django_20_develop(self): extra_path = os.path.join(os.path.dirname(__file__), 'data', 'extra_settings.py') params = [ @@ -559,6 +562,25 @@ def test_starting_page(self): row = query.fetchone() self.assertTrue('TextPlugin' in row) + @unittest.skipIf(sys.version_info[:2] not in ((2, 7), (3, 4), (3, 5), (3, 6), (3, 7),), + reason='django 1.8 only supports python 2.7, 3.4, 3.5, 3.6 and 3.7,') + def test_force_django(self): + config_data = config.parse(['--db=sqlite://localhost/test.db', + '-q', '-u', '--django-version=1.11', + '--cms-version=3.4', '--starting-page=yes', + '-p' + self.project_dir, 'cms_project']) + install.requirements(config_data.requirements) + install.requirements('django<1.9') + django.create_project(config_data) + with patch('sys.stdout', self.stdout): + with patch('sys.stderr', self.stderr): + with self.assertRaises(SystemExit) as error: + django.patch_settings(config_data) + self.assertEqual(error.exception.code, 9) + self.assertTrue(self.stderr.getvalue().find( + 'Currently installed Django version 1.8.19 differs from the declared 1.11' + ) > -1) + class TestBaseDjango(unittest.TestCase): def test_build_settings(self): diff --git a/tests/main.py b/tests/main.py index 2ac2d5c..9a6ff9b 100644 --- a/tests/main.py +++ b/tests/main.py @@ -133,8 +133,8 @@ def test_two_langs_invocation(self): # Checking we successfully completed the whole process self.assertTrue(('Get into "%s" directory and type "python manage.py runserver" to start your project' % self.project_dir) in self.stdout.getvalue()) - @unittest.skipIf(sys.version_info < (3.0,), - reason='django 2.1 does not support python 2.6') + @unittest.skipIf(sys.version_info < (3.5,), + reason='django 2.1 does not support python < 3.5') def test_develop(self): with patch('sys.stdout', self.stdout): with patch('sys.stderr', self.stderr):