|
| 1 | +from importlib import import_module |
| 2 | + |
| 3 | +from django.core.management.commands.shell import Command as BaseShellCommand |
| 4 | +from django.utils.module_loading import import_string |
| 5 | + |
| 6 | +from dojo.management.commands.shell import Command |
| 7 | + |
| 8 | +from .dojo_test_case import DojoTestCase |
| 9 | + |
| 10 | + |
| 11 | +class TestShellAutoImportFilter(DojoTestCase): |
| 12 | + |
| 13 | + """ |
| 14 | + The overridden ``shell`` command must drop non-importable auto-imports. |
| 15 | +
|
| 16 | + Django's stock shell lists dynamically generated Tagulous tag models and |
| 17 | + auditlog proxy models as "could not be automatically imported" on every |
| 18 | + launch. The override filters the auto-import list down to paths that |
| 19 | + actually import, so the banner is clean without losing real auto-imports. |
| 20 | + """ |
| 21 | + |
| 22 | + def _resolve(self, path): |
| 23 | + return import_string(path) if "." in path else import_module(path) |
| 24 | + |
| 25 | + def test_all_returned_paths_are_importable(self): |
| 26 | + paths = Command().get_auto_imports() |
| 27 | + self.assertTrue(paths, "expected a non-empty auto-import list") |
| 28 | + for path in paths: |
| 29 | + try: |
| 30 | + self._resolve(path) |
| 31 | + except ImportError: |
| 32 | + self.fail(f"get_auto_imports() returned a non-importable path: {path}") |
| 33 | + |
| 34 | + def test_real_models_are_kept(self): |
| 35 | + self.assertIn("dojo.finding.models.Finding", Command().get_auto_imports()) |
| 36 | + |
| 37 | + def test_only_non_importable_paths_are_dropped(self): |
| 38 | + base_paths = BaseShellCommand().get_auto_imports() |
| 39 | + kept = set(Command().get_auto_imports()) |
| 40 | + dropped = [path for path in base_paths if path not in kept] |
| 41 | + # The override must actually remove something (the environment has |
| 42 | + # dynamically generated / proxy models that Django cannot import). |
| 43 | + self.assertTrue(dropped, "expected the override to drop at least one non-importable path") |
| 44 | + # Everything it drops must genuinely be non-importable. |
| 45 | + for path in dropped: |
| 46 | + with self.assertRaises(ImportError, msg=f"{path} was dropped but is importable"): |
| 47 | + self._resolve(path) |
0 commit comments