]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
♻️ Update logic to import and check `python-multipart` for compatibility with newer...
authorSebastián Ramírez <tiangolo@gmail.com>
Sun, 27 Oct 2024 21:46:26 +0000 (22:46 +0100)
committerGitHub <noreply@github.com>
Sun, 27 Oct 2024 21:46:26 +0000 (21:46 +0000)
fastapi/dependencies/utils.py
tests/test_multipart_installation.py

index 87653c80df9789927cee546cd84064db0c8e889a..e2866b48894b794c9fe7029a2c128b1751ff2754 100644 (file)
@@ -90,21 +90,29 @@ multipart_incorrect_install_error = (
 
 def ensure_multipart_is_installed() -> None:
     try:
-        # __version__ is available in both multiparts, and can be mocked
-        from multipart import __version__
+        from python_multipart import __version__
 
-        assert __version__
+        # Import an attribute that can be mocked/deleted in testing
+        assert __version__ > "0.0.12"
+    except (ImportError, AssertionError):
         try:
-            # parse_options_header is only available in the right multipart
-            from multipart.multipart import parse_options_header
+            # __version__ is available in both multiparts, and can be mocked
+            from multipart import __version__  # type: ignore[no-redef,import-untyped]
 
-            assert parse_options_header  # type: ignore[truthy-function]
+            assert __version__
+            try:
+                # parse_options_header is only available in the right multipart
+                from multipart.multipart import (  # type: ignore[import-untyped]
+                    parse_options_header,
+                )
+
+                assert parse_options_header
+            except ImportError:
+                logger.error(multipart_incorrect_install_error)
+                raise RuntimeError(multipart_incorrect_install_error) from None
         except ImportError:
-            logger.error(multipart_incorrect_install_error)
-            raise RuntimeError(multipart_incorrect_install_error) from None
-    except ImportError:
-        logger.error(multipart_not_installed_error)
-        raise RuntimeError(multipart_not_installed_error) from None
+            logger.error(multipart_not_installed_error)
+            raise RuntimeError(multipart_not_installed_error) from None
 
 
 def get_param_sub_dependant(
index 788d9ef5afd30e4d289654a1cd4972c93462fcda..9c3e47c495990892f4a82165310534bdba6def0f 100644 (file)
@@ -1,3 +1,5 @@
+import warnings
+
 import pytest
 from fastapi import FastAPI, File, Form, UploadFile
 from fastapi.dependencies.utils import (
@@ -7,7 +9,10 @@ from fastapi.dependencies.utils import (
 
 
 def test_incorrect_multipart_installed_form(monkeypatch):
-    monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
     with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
         app = FastAPI()
 
@@ -17,7 +22,10 @@ def test_incorrect_multipart_installed_form(monkeypatch):
 
 
 def test_incorrect_multipart_installed_file_upload(monkeypatch):
-    monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
     with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
         app = FastAPI()
 
@@ -27,7 +35,10 @@ def test_incorrect_multipart_installed_file_upload(monkeypatch):
 
 
 def test_incorrect_multipart_installed_file_bytes(monkeypatch):
-    monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
     with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
         app = FastAPI()
 
@@ -37,7 +48,10 @@ def test_incorrect_multipart_installed_file_bytes(monkeypatch):
 
 
 def test_incorrect_multipart_installed_multi_form(monkeypatch):
-    monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
     with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
         app = FastAPI()
 
@@ -47,7 +61,10 @@ def test_incorrect_multipart_installed_multi_form(monkeypatch):
 
 
 def test_incorrect_multipart_installed_form_file(monkeypatch):
-    monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
     with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
         app = FastAPI()
 
@@ -57,50 +74,76 @@ def test_incorrect_multipart_installed_form_file(monkeypatch):
 
 
 def test_no_multipart_installed(monkeypatch):
-    monkeypatch.delattr("multipart.__version__", raising=False)
-    with pytest.raises(RuntimeError, match=multipart_not_installed_error):
-        app = FastAPI()
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.__version__", raising=False)
+        with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+            app = FastAPI()
 
-        @app.post("/")
-        async def root(username: str = Form()):
-            return username  # pragma: nocover
+            @app.post("/")
+            async def root(username: str = Form()):
+                return username  # pragma: nocover
 
 
 def test_no_multipart_installed_file(monkeypatch):
-    monkeypatch.delattr("multipart.__version__", raising=False)
-    with pytest.raises(RuntimeError, match=multipart_not_installed_error):
-        app = FastAPI()
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.__version__", raising=False)
+        with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+            app = FastAPI()
 
-        @app.post("/")
-        async def root(f: UploadFile = File()):
-            return f  # pragma: nocover
+            @app.post("/")
+            async def root(f: UploadFile = File()):
+                return f  # pragma: nocover
 
 
 def test_no_multipart_installed_file_bytes(monkeypatch):
-    monkeypatch.delattr("multipart.__version__", raising=False)
-    with pytest.raises(RuntimeError, match=multipart_not_installed_error):
-        app = FastAPI()
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.__version__", raising=False)
+        with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+            app = FastAPI()
 
-        @app.post("/")
-        async def root(f: bytes = File()):
-            return f  # pragma: nocover
+            @app.post("/")
+            async def root(f: bytes = File()):
+                return f  # pragma: nocover
 
 
 def test_no_multipart_installed_multi_form(monkeypatch):
-    monkeypatch.delattr("multipart.__version__", raising=False)
-    with pytest.raises(RuntimeError, match=multipart_not_installed_error):
-        app = FastAPI()
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.__version__", raising=False)
+        with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+            app = FastAPI()
 
-        @app.post("/")
-        async def root(username: str = Form(), password: str = Form()):
-            return username  # pragma: nocover
+            @app.post("/")
+            async def root(username: str = Form(), password: str = Form()):
+                return username  # pragma: nocover
 
 
 def test_no_multipart_installed_form_file(monkeypatch):
-    monkeypatch.delattr("multipart.__version__", raising=False)
-    with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
+        monkeypatch.delattr("multipart.__version__", raising=False)
+        with pytest.raises(RuntimeError, match=multipart_not_installed_error):
+            app = FastAPI()
+
+            @app.post("/")
+            async def root(username: str = Form(), f: UploadFile = File()):
+                return username  # pragma: nocover
+
+
+def test_old_multipart_installed(monkeypatch):
+    monkeypatch.setattr("python_multipart.__version__", "0.0.12")
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("always")
         app = FastAPI()
 
         @app.post("/")
-        async def root(username: str = Form(), f: UploadFile = File()):
+        async def root(username: str = Form()):
             return username  # pragma: nocover