diff --git a/django/test/utils.py b/django/test/utils.py index d205f5c9fb..7f47d29844 100644 --- a/django/test/utils.py +++ b/django/test/utils.py @@ -526,3 +526,15 @@ class TransRealMixin(object): requires_tz_support = skipUnless(TZ_SUPPORT, "This test relies on the ability to run a program in an arbitrary " "time zone, but your operating system isn't able to do that.") + + + +@contextmanager +def extend_sys_path(*paths): + """Context manager to temporarily add paths to sys.path.""" + _orig_sys_path = sys.path[:] + sys.path.extend(paths) + try: + yield + finally: + sys.path = _orig_sys_path diff --git a/tests/app_loading/tests.py b/tests/app_loading/tests.py index 63f47fa5fa..71f1a49b63 100644 --- a/tests/app_loading/tests.py +++ b/tests/app_loading/tests.py @@ -1,10 +1,10 @@ from __future__ import unicode_literals import os -import sys from django.apps import apps from django.test import TestCase +from django.test.utils import extend_sys_path from django.utils._os import upath from django.utils import six @@ -12,56 +12,54 @@ from django.utils import six class EggLoadingTest(TestCase): def setUp(self): - self.old_path = sys.path[:] self.egg_dir = '%s/eggs' % os.path.dirname(upath(__file__)) def tearDown(self): apps.clear_cache() - sys.path = self.old_path def test_egg1(self): """Models module can be loaded from an app in an egg""" egg_name = '%s/modelapp.egg' % self.egg_dir - sys.path.append(egg_name) - with self.settings(INSTALLED_APPS=['app_with_models']): - models_module = apps.get_app_config('app_with_models').models_module - self.assertIsNotNone(models_module) + with extend_sys_path(egg_name): + with self.settings(INSTALLED_APPS=['app_with_models']): + models_module = apps.get_app_config('app_with_models').models_module + self.assertIsNotNone(models_module) del apps.all_models['app_with_models'] def test_egg2(self): """Loading an app from an egg that has no models returns no models (and no error)""" egg_name = '%s/nomodelapp.egg' % self.egg_dir - sys.path.append(egg_name) - with self.settings(INSTALLED_APPS=['app_no_models']): - models_module = apps.get_app_config('app_no_models').models_module - self.assertIsNone(models_module) + with extend_sys_path(egg_name): + with self.settings(INSTALLED_APPS=['app_no_models']): + models_module = apps.get_app_config('app_no_models').models_module + self.assertIsNone(models_module) del apps.all_models['app_no_models'] def test_egg3(self): """Models module can be loaded from an app located under an egg's top-level package""" egg_name = '%s/omelet.egg' % self.egg_dir - sys.path.append(egg_name) - with self.settings(INSTALLED_APPS=['omelet.app_with_models']): - models_module = apps.get_app_config('app_with_models').models_module - self.assertIsNotNone(models_module) + with extend_sys_path(egg_name): + with self.settings(INSTALLED_APPS=['omelet.app_with_models']): + models_module = apps.get_app_config('app_with_models').models_module + self.assertIsNotNone(models_module) del apps.all_models['app_with_models'] def test_egg4(self): """Loading an app with no models from under the top-level egg package generates no error""" egg_name = '%s/omelet.egg' % self.egg_dir - sys.path.append(egg_name) - with self.settings(INSTALLED_APPS=['omelet.app_no_models']): - models_module = apps.get_app_config('app_no_models').models_module - self.assertIsNone(models_module) + with extend_sys_path(egg_name): + with self.settings(INSTALLED_APPS=['omelet.app_no_models']): + models_module = apps.get_app_config('app_no_models').models_module + self.assertIsNone(models_module) del apps.all_models['app_no_models'] def test_egg5(self): """Loading an app from an egg that has an import error in its models module raises that error""" egg_name = '%s/brokenapp.egg' % self.egg_dir - sys.path.append(egg_name) - with six.assertRaisesRegex(self, ImportError, 'modelz'): - with self.settings(INSTALLED_APPS=['broken_app']): - pass + with extend_sys_path(egg_name): + with six.assertRaisesRegex(self, ImportError, 'modelz'): + with self.settings(INSTALLED_APPS=['broken_app']): + pass class GetModelsTest(TestCase): diff --git a/tests/apps/tests.py b/tests/apps/tests.py index 21dd8a1204..6a345760ee 100644 --- a/tests/apps/tests.py +++ b/tests/apps/tests.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, unicode_literals -from contextlib import contextmanager import os import sys from unittest import skipUnless @@ -10,6 +9,7 @@ from django.apps.registry import Apps from django.core.exceptions import ImproperlyConfigured from django.db import models from django.test import TestCase, override_settings +from django.test.utils import extend_sys_path from django.utils._os import upath from django.utils import six @@ -189,21 +189,11 @@ class NamespacePackageAppTests(TestCase): other_location = os.path.join(HERE, 'namespace_package_other_base') app_path = os.path.join(base_location, 'nsapp') - @contextmanager - def add_to_path(self, *paths): - """Context manager to temporarily add paths to sys.path.""" - _orig_sys_path = sys.path[:] - sys.path.extend(paths) - try: - yield - finally: - sys.path = _orig_sys_path - def test_single_path(self): """ A Py3.3+ namespace package can be an app if it has only one path. """ - with self.add_to_path(self.base_location): + with extend_sys_path(self.base_location): with self.settings(INSTALLED_APPS=['nsapp']): app_config = apps.get_app_config('nsapp') self.assertEqual(app_config.path, upath(self.app_path)) @@ -218,7 +208,7 @@ class NamespacePackageAppTests(TestCase): """ # Temporarily add two directories to sys.path that both contain # components of the "nsapp" package. - with self.add_to_path(self.base_location, self.other_location): + with extend_sys_path(self.base_location, self.other_location): with self.assertRaises(ImproperlyConfigured): with self.settings(INSTALLED_APPS=['nsapp']): pass @@ -229,7 +219,7 @@ class NamespacePackageAppTests(TestCase): """ # Temporarily add two directories to sys.path that both contain # components of the "nsapp" package. - with self.add_to_path(self.base_location, self.other_location): + with extend_sys_path(self.base_location, self.other_location): with self.settings(INSTALLED_APPS=['nsapp.apps.NSAppConfig']): app_config = apps.get_app_config('nsapp') self.assertEqual(app_config.path, upath(self.app_path)) diff --git a/tests/proxy_model_inheritance/tests.py b/tests/proxy_model_inheritance/tests.py index 11acbd216d..ec9e4c5a78 100644 --- a/tests/proxy_model_inheritance/tests.py +++ b/tests/proxy_model_inheritance/tests.py @@ -1,11 +1,10 @@ from __future__ import absolute_import, unicode_literals import os -import sys from django.core.management import call_command from django.test import TestCase, TransactionTestCase -from django.test.utils import override_system_checks +from django.test.utils import override_system_checks, extend_sys_path from django.utils._os import upath from .models import (ConcreteModel, ConcreteModelSubclass, @@ -20,23 +19,17 @@ class ProxyModelInheritanceTests(TransactionTestCase): """ available_apps = [] - def setUp(self): - self.old_sys_path = sys.path[:] - sys.path.append(os.path.dirname(os.path.abspath(upath(__file__)))) - - def tearDown(self): - sys.path = self.old_sys_path - # `auth` app is imported, but not installed in this test, so we need to # exclude checks registered by this app. @override_system_checks([]) def test_table_exists(self): - with self.modify_settings(INSTALLED_APPS={'append': ['app1', 'app2']}): - call_command('migrate', verbosity=0) - from app1.models import ProxyModel - from app2.models import NiceModel - self.assertEqual(NiceModel.objects.all().count(), 0) - self.assertEqual(ProxyModel.objects.all().count(), 0) + with extend_sys_path(os.path.dirname(os.path.abspath(upath(__file__)))): + with self.modify_settings(INSTALLED_APPS={'append': ['app1', 'app2']}): + call_command('migrate', verbosity=0) + from app1.models import ProxyModel + from app2.models import NiceModel + self.assertEqual(NiceModel.objects.all().count(), 0) + self.assertEqual(ProxyModel.objects.all().count(), 0) class MultiTableInheritanceProxyTest(TestCase): diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index ddcad693a6..b5b9bdf5b1 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -22,7 +22,8 @@ from django.template import (base as template_base, loader, Context, from django.template.loaders import app_directories, filesystem, cached from django.test import RequestFactory, TestCase from django.test.utils import (setup_test_template_loader, - restore_template_loaders, override_settings, TransRealMixin) + restore_template_loaders, override_settings, TransRealMixin, + extend_sys_path) from django.utils.encoding import python_2_unicode_compatible from django.utils.formats import date_format from django.utils._os import upath @@ -1857,13 +1858,11 @@ class TemplateTests(TransRealMixin, TestCase): class TemplateTagLoading(TestCase): def setUp(self): - self.old_path = sys.path[:] self.egg_dir = '%s/eggs' % os.path.dirname(upath(__file__)) self.old_tag_modules = template_base.templatetags_modules template_base.templatetags_modules = [] def tearDown(self): - sys.path = self.old_path template_base.templatetags_modules = self.old_tag_modules def test_load_error(self): @@ -1878,23 +1877,23 @@ class TemplateTagLoading(TestCase): def test_load_error_egg(self): ttext = "{% load broken_egg %}" egg_name = '%s/tagsegg.egg' % self.egg_dir - sys.path.append(egg_name) - with self.assertRaises(template.TemplateSyntaxError): - with self.settings(INSTALLED_APPS=['tagsegg']): - template.Template(ttext) - try: - with self.settings(INSTALLED_APPS=['tagsegg']): - template.Template(ttext) - except template.TemplateSyntaxError as e: - self.assertTrue('ImportError' in e.args[0]) - self.assertTrue('Xtemplate' in e.args[0]) + with extend_sys_path(egg_name): + with self.assertRaises(template.TemplateSyntaxError): + with self.settings(INSTALLED_APPS=['tagsegg']): + template.Template(ttext) + try: + with self.settings(INSTALLED_APPS=['tagsegg']): + template.Template(ttext) + except template.TemplateSyntaxError as e: + self.assertTrue('ImportError' in e.args[0]) + self.assertTrue('Xtemplate' in e.args[0]) def test_load_working_egg(self): ttext = "{% load working_egg %}" egg_name = '%s/tagsegg.egg' % self.egg_dir - sys.path.append(egg_name) - with self.settings(INSTALLED_APPS=['tagsegg']): - template.Template(ttext) + with extend_sys_path(egg_name): + with self.settings(INSTALLED_APPS=['tagsegg']): + template.Template(ttext) class RequestContextTests(unittest.TestCase): diff --git a/tests/utils_tests/test_module_loading.py b/tests/utils_tests/test_module_loading.py index 0bba98e8c2..905163b1b9 100644 --- a/tests/utils_tests/test_module_loading.py +++ b/tests/utils_tests/test_module_loading.py @@ -7,6 +7,7 @@ from zipimport import zipimporter from django.core.exceptions import ImproperlyConfigured from django.test import SimpleTestCase, modify_settings +from django.test.utils import extend_sys_path from django.utils import six from django.utils.module_loading import autodiscover_modules, import_by_path, module_has_submodule from django.utils._os import upath @@ -54,11 +55,9 @@ class DefaultLoader(unittest.TestCase): class EggLoader(unittest.TestCase): def setUp(self): - self.old_path = sys.path[:] self.egg_dir = '%s/eggs' % os.path.dirname(upath(__file__)) def tearDown(self): - sys.path = self.old_path sys.path_importer_cache.clear() sys.modules.pop('egg_module.sub1.sub2.bad_module', None) @@ -72,40 +71,40 @@ class EggLoader(unittest.TestCase): def test_shallow_loader(self): "Module existence can be tested inside eggs" egg_name = '%s/test_egg.egg' % self.egg_dir - sys.path.append(egg_name) - egg_module = import_module('egg_module') + with extend_sys_path(egg_name): + egg_module = import_module('egg_module') - # An importable child - self.assertTrue(module_has_submodule(egg_module, 'good_module')) - mod = import_module('egg_module.good_module') - self.assertEqual(mod.content, 'Good Module') + # An importable child + self.assertTrue(module_has_submodule(egg_module, 'good_module')) + mod = import_module('egg_module.good_module') + self.assertEqual(mod.content, 'Good Module') - # A child that exists, but will generate an import error if loaded - self.assertTrue(module_has_submodule(egg_module, 'bad_module')) - self.assertRaises(ImportError, import_module, 'egg_module.bad_module') + # A child that exists, but will generate an import error if loaded + self.assertTrue(module_has_submodule(egg_module, 'bad_module')) + self.assertRaises(ImportError, import_module, 'egg_module.bad_module') - # A child that doesn't exist - self.assertFalse(module_has_submodule(egg_module, 'no_such_module')) - self.assertRaises(ImportError, import_module, 'egg_module.no_such_module') + # A child that doesn't exist + self.assertFalse(module_has_submodule(egg_module, 'no_such_module')) + self.assertRaises(ImportError, import_module, 'egg_module.no_such_module') def test_deep_loader(self): "Modules deep inside an egg can still be tested for existence" egg_name = '%s/test_egg.egg' % self.egg_dir - sys.path.append(egg_name) - egg_module = import_module('egg_module.sub1.sub2') + with extend_sys_path(egg_name): + egg_module = import_module('egg_module.sub1.sub2') - # An importable child - self.assertTrue(module_has_submodule(egg_module, 'good_module')) - mod = import_module('egg_module.sub1.sub2.good_module') - self.assertEqual(mod.content, 'Deep Good Module') + # An importable child + self.assertTrue(module_has_submodule(egg_module, 'good_module')) + mod = import_module('egg_module.sub1.sub2.good_module') + self.assertEqual(mod.content, 'Deep Good Module') - # A child that exists, but will generate an import error if loaded - self.assertTrue(module_has_submodule(egg_module, 'bad_module')) - self.assertRaises(ImportError, import_module, 'egg_module.sub1.sub2.bad_module') + # A child that exists, but will generate an import error if loaded + self.assertTrue(module_has_submodule(egg_module, 'bad_module')) + self.assertRaises(ImportError, import_module, 'egg_module.sub1.sub2.bad_module') - # A child that doesn't exist - self.assertFalse(module_has_submodule(egg_module, 'no_such_module')) - self.assertRaises(ImportError, import_module, 'egg_module.sub1.sub2.no_such_module') + # A child that doesn't exist + self.assertFalse(module_has_submodule(egg_module, 'no_such_module')) + self.assertRaises(ImportError, import_module, 'egg_module.sub1.sub2.no_such_module') class ModuleImportTestCase(unittest.TestCase):