From bcbf4416c321acddbcf49273a668c3a52b646a23 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 9 Jul 2023 21:13:56 +0200 Subject: [PATCH] Raise `ImportError` on circular import (#2040) Co-authored-by: Michael Jones <4087139+mikeedjones@users.noreply.github.com> --- tests/importer/circular_import_a.py | 4 ++++ tests/importer/circular_import_b.py | 4 ++++ tests/importer/test_importer.py | 10 ++++++++++ uvicorn/importer.py | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/importer/circular_import_a.py create mode 100644 tests/importer/circular_import_b.py diff --git a/tests/importer/circular_import_a.py b/tests/importer/circular_import_a.py new file mode 100644 index 000000000..7d68ad8d0 --- /dev/null +++ b/tests/importer/circular_import_a.py @@ -0,0 +1,4 @@ +# Used by test_importer.py +from .circular_import_b import foo # noqa + +bar = 123 diff --git a/tests/importer/circular_import_b.py b/tests/importer/circular_import_b.py new file mode 100644 index 000000000..4854a80ee --- /dev/null +++ b/tests/importer/circular_import_b.py @@ -0,0 +1,4 @@ +# Used by test_importer.py +from .circular_import_a import bar # noqa + +foo = 123 diff --git a/tests/importer/test_importer.py b/tests/importer/test_importer.py index d9eb3a86b..371fdcaf9 100644 --- a/tests/importer/test_importer.py +++ b/tests/importer/test_importer.py @@ -41,3 +41,13 @@ def test_no_import_needed() -> None: instance = import_from_string(TemporaryFile) assert instance == TemporaryFile + + +def test_circular_import_error() -> None: + with pytest.raises(ImportError) as exc_info: + import_from_string("tests.importer.circular_import_a:bar") + expected = ( + "cannot import name 'bar' from partially initialized module " + "'tests.importer.circular_import_a' (most likely due to a circular import)" + ) + assert expected in str(exc_info.value) diff --git a/uvicorn/importer.py b/uvicorn/importer.py index e612bf134..338eba25c 100644 --- a/uvicorn/importer.py +++ b/uvicorn/importer.py @@ -19,7 +19,7 @@ def import_from_string(import_str: Any) -> Any: try: module = importlib.import_module(module_str) - except ImportError as exc: + except ModuleNotFoundError as exc: if exc.name != module_str: raise exc from None message = 'Could not import module "{module_str}".'