diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py index f3617764ef..c0a1208eb2 100644 --- a/django/db/migrations/loader.py +++ b/django/db/migrations/loader.py @@ -64,6 +64,13 @@ class MigrationLoader(object): self.unmigrated_apps.add(app_label) continue raise + else: + # PY3 will happily import empty dirs as namespaces. + if not hasattr(module, '__file__'): + continue + # Module is not a package (e.g. migrations.py). + if not hasattr(module, '__path__'): + continue self.migrated_apps.add(app_label) directory = os.path.dirname(module.__file__) # Scan for .py[c|o] files diff --git a/tests/migrations/faulty_migrations/__init__.py b/tests/migrations/faulty_migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/faulty_migrations/file.py b/tests/migrations/faulty_migrations/file.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/faulty_migrations/namespace/foo/__init__.py b/tests/migrations/faulty_migrations/namespace/foo/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/test_loader.py b/tests/migrations/test_loader.py index 6810089603..c7fe16cf9a 100644 --- a/tests/migrations/test_loader.py +++ b/tests/migrations/test_loader.py @@ -1,8 +1,11 @@ +from unittest import skipIf + from django.test import TestCase from django.test.utils import override_settings from django.db import connection from django.db.migrations.loader import MigrationLoader, AmbiguityError from django.db.migrations.recorder import MigrationRecorder +from django.utils import six class RecorderTests(TestCase): @@ -84,3 +87,16 @@ class LoaderTests(TestCase): with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.import_error"}): with self.assertRaises(ImportError): migration_loader.load_disk() + + def test_load_module_file(self): + migration_loader = MigrationLoader(connection) + + with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.file"}): + migration_loader.load_disk() + + @skipIf(six.PY2, "PY2 doesn't load empty dirs.") + def test_load_empty_dir(self): + migration_loader = MigrationLoader(connection) + + with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.namespace"}): + migration_loader.load_disk()