Commit 98da4089 authored by Markus Holtermann's avatar Markus Holtermann Committed by Tim Graham
Browse files

Fixed #23670 -- Prevented partial import state during module autodiscovery

Thanks kostko for the report.
parent c0c1bb9e
Loading
Loading
Loading
Loading
+18 −18
Original line number Diff line number Diff line
@@ -64,23 +64,23 @@ def autodiscover_modules(*args, **kwargs):

    register_to = kwargs.get('register_to')
    for app_config in apps.get_app_configs():
        for module_to_search in args:
            # Attempt to import the app's module.
            try:
                if register_to:
                    before_import_registry = copy.copy(register_to._registry)

            for module_to_search in args:
                import_module('%s.%s' % (app_config.name, module_to_search))
            except:
            # Reset the model registry to the state before the last import as
            # this import will have to reoccur on the next request and this
            # could raise NotRegistered and AlreadyRegistered exceptions
            # (see #8245).
                # Reset the registry to the state before the last import
                # as this import will have to reoccur on the next request and
                # this could raise NotRegistered and AlreadyRegistered
                # exceptions (see #8245).
                if register_to:
                    register_to._registry = before_import_registry

                # Decide whether to bubble up this error. If the app just
            # doesn't have an admin module, we can ignore the error
                # doesn't have the module in question, we can ignore the error
                # attempting to import it, otherwise we want it to bubble up.
                if module_has_submodule(app_config.module, module_to_search):
                    raise
+5 −0
Original line number Diff line number Diff line
from . import site
content = 'Another Good Module'

site._registry.update({
    'lorem': 'ipsum',
})
+25 −0
Original line number Diff line number Diff line
@@ -155,6 +155,15 @@ class ModuleImportTestCase(IgnoreDeprecationWarningsMixin, unittest.TestCase):
@modify_settings(INSTALLED_APPS={'append': 'utils_tests.test_module'})
class AutodiscoverModulesTestCase(SimpleTestCase):

    def tearDown(self):
        sys.path_importer_cache.clear()

        sys.modules.pop('utils_tests.test_module.another_bad_module', None)
        sys.modules.pop('utils_tests.test_module.another_good_module', None)
        sys.modules.pop('utils_tests.test_module.bad_module', None)
        sys.modules.pop('utils_tests.test_module.good_module', None)
        sys.modules.pop('utils_tests.test_module', None)

    def test_autodiscover_modules_found(self):
        autodiscover_modules('good_module')

@@ -172,12 +181,28 @@ class AutodiscoverModulesTestCase(SimpleTestCase):
    def test_autodiscover_modules_several_found(self):
        autodiscover_modules('good_module', 'another_good_module')

    def test_autodiscover_modules_several_found_with_registry(self):
        from .test_module import site
        autodiscover_modules('good_module', 'another_good_module', register_to=site)
        self.assertEqual(site._registry, {'lorem': 'ipsum'})

    def test_validate_registry_keeps_intact(self):
        from .test_module import site
        with six.assertRaisesRegex(self, Exception, "Some random exception."):
            autodiscover_modules('another_bad_module', register_to=site)
        self.assertEqual(site._registry, {})

    def test_validate_registry_resets_after_erroneous_module(self):
        from .test_module import site
        with six.assertRaisesRegex(self, Exception, "Some random exception."):
            autodiscover_modules('another_good_module', 'another_bad_module', register_to=site)
        self.assertEqual(site._registry, {'lorem': 'ipsum'})

    def test_validate_registry_resets_after_missing_module(self):
        from .test_module import site
        autodiscover_modules('does_not_exist', 'another_good_module', 'does_not_exist2', register_to=site)
        self.assertEqual(site._registry, {'lorem': 'ipsum'})


class ProxyFinder(object):
    def __init__(self):