]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
⏪️ Temporarily revert "✨ Add support for Pydantic models in `Form` parameters" to...
authorSebastián Ramírez <tiangolo@gmail.com>
Thu, 5 Sep 2024 14:55:44 +0000 (16:55 +0200)
committerGitHub <noreply@github.com>
Thu, 5 Sep 2024 14:55:44 +0000 (16:55 +0200)
Revert "✨ Add support for Pydantic models in `Form` parameters (#12127)"

This reverts commit 0f3e65b00712a59d763cf9c7715cde353bb94b02.

13 files changed:
docs/en/docs/img/tutorial/request-form-models/image01.png [deleted file]
docs/en/docs/tutorial/request-form-models.md [deleted file]
docs/en/mkdocs.yml
docs_src/request_form_models/tutorial001.py [deleted file]
docs_src/request_form_models/tutorial001_an.py [deleted file]
docs_src/request_form_models/tutorial001_an_py39.py [deleted file]
fastapi/dependencies/utils.py
scripts/playwright/request_form_models/image01.py [deleted file]
tests/test_forms_single_model.py [deleted file]
tests/test_tutorial/test_request_form_models/__init__.py [deleted file]
tests/test_tutorial/test_request_form_models/test_tutorial001.py [deleted file]
tests/test_tutorial/test_request_form_models/test_tutorial001_an.py [deleted file]
tests/test_tutorial/test_request_form_models/test_tutorial001_an_py39.py [deleted file]

diff --git a/docs/en/docs/img/tutorial/request-form-models/image01.png b/docs/en/docs/img/tutorial/request-form-models/image01.png
deleted file mode 100644 (file)
index 3fe32c0..0000000
Binary files a/docs/en/docs/img/tutorial/request-form-models/image01.png and /dev/null differ
diff --git a/docs/en/docs/tutorial/request-form-models.md b/docs/en/docs/tutorial/request-form-models.md
deleted file mode 100644 (file)
index 8bb1ffb..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-# Form Models
-
-You can use Pydantic models to declare form fields in FastAPI.
-
-/// info
-
-To use forms, first install <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
-
-Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install it, for example:
-
-```console
-$ pip install python-multipart
-```
-
-///
-
-/// note
-
-This is supported since FastAPI version `0.113.0`. 🤓
-
-///
-
-## Pydantic Models for Forms
-
-You just need to declare a Pydantic model with the fields you want to receive as form fields, and then declare the parameter as `Form`:
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9-11  15"
-{!> ../../../docs_src/request_form_models/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8-10  14"
-{!> ../../../docs_src/request_form_models/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="7-9  13"
-{!> ../../../docs_src/request_form_models/tutorial001.py!}
-```
-
-////
-
-FastAPI will extract the data for each field from the form data in the request and give you the Pydantic model you defined.
-
-## Check the Docs
-
-You can verify it in the docs UI at `/docs`:
-
-<div class="screenshot">
-<img src="/img/tutorial/request-form-models/image01.png">
-</div>
index 7c810c2d7c212ff6d3826b0de2408d82a9134749..528c80b8e6b31b7d486dfd2c5b00522c2290d3ca 100644 (file)
@@ -129,7 +129,6 @@ nav:
     - tutorial/extra-models.md
     - tutorial/response-status-code.md
     - tutorial/request-forms.md
-    - tutorial/request-form-models.md
     - tutorial/request-files.md
     - tutorial/request-forms-and-files.md
     - tutorial/handling-errors.md
diff --git a/docs_src/request_form_models/tutorial001.py b/docs_src/request_form_models/tutorial001.py
deleted file mode 100644 (file)
index 98feff0..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-from fastapi import FastAPI, Form
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class FormData(BaseModel):
-    username: str
-    password: str
-
-
-@app.post("/login/")
-async def login(data: FormData = Form()):
-    return data
diff --git a/docs_src/request_form_models/tutorial001_an.py b/docs_src/request_form_models/tutorial001_an.py
deleted file mode 100644 (file)
index 30483d4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-from fastapi import FastAPI, Form
-from pydantic import BaseModel
-from typing_extensions import Annotated
-
-app = FastAPI()
-
-
-class FormData(BaseModel):
-    username: str
-    password: str
-
-
-@app.post("/login/")
-async def login(data: Annotated[FormData, Form()]):
-    return data
diff --git a/docs_src/request_form_models/tutorial001_an_py39.py b/docs_src/request_form_models/tutorial001_an_py39.py
deleted file mode 100644 (file)
index 7cc81aa..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-from typing import Annotated
-
-from fastapi import FastAPI, Form
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class FormData(BaseModel):
-    username: str
-    password: str
-
-
-@app.post("/login/")
-async def login(data: Annotated[FormData, Form()]):
-    return data
index 98ce17b55d9bab800b2c7163d6533b96576da4a1..7ac18d941cd8524425cd266f2536d108c1fc02d9 100644 (file)
@@ -33,7 +33,6 @@ from fastapi._compat import (
     field_annotation_is_scalar,
     get_annotation_from_field_info,
     get_missing_field_error,
-    get_model_fields,
     is_bytes_field,
     is_bytes_sequence_field,
     is_scalar_field,
@@ -57,7 +56,6 @@ from fastapi.security.base import SecurityBase
 from fastapi.security.oauth2 import OAuth2, SecurityScopes
 from fastapi.security.open_id_connect_url import OpenIdConnect
 from fastapi.utils import create_model_field, get_path_param_names
-from pydantic import BaseModel
 from pydantic.fields import FieldInfo
 from starlette.background import BackgroundTasks as StarletteBackgroundTasks
 from starlette.concurrency import run_in_threadpool
@@ -745,9 +743,7 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
         return True
     # If it's a Form (or File) field, it has to be a BaseModel to be top level
     # otherwise it has to be embedded, so that the key value pair can be extracted
-    if isinstance(first_field.field_info, params.Form) and not lenient_issubclass(
-        first_field.type_, BaseModel
-    ):
+    if isinstance(first_field.field_info, params.Form):
         return True
     return False
 
@@ -787,8 +783,7 @@ async def _extract_form_body(
                 for sub_value in value:
                     tg.start_soon(process_fn, sub_value.read)
             value = serialize_sequence_value(field=field, value=results)
-        if value is not None:
-            values[field.name] = value
+        values[field.name] = value
     return values
 
 
@@ -803,14 +798,8 @@ async def request_body_to_args(
     single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields
     first_field = body_fields[0]
     body_to_process = received_body
-
-    fields_to_extract: List[ModelField] = body_fields
-
-    if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
-        fields_to_extract = get_model_fields(first_field.type_)
-
     if isinstance(received_body, FormData):
-        body_to_process = await _extract_form_body(fields_to_extract, received_body)
+        body_to_process = await _extract_form_body(body_fields, received_body)
 
     if single_not_embedded_field:
         loc: Tuple[str, ...] = ("body",)
diff --git a/scripts/playwright/request_form_models/image01.py b/scripts/playwright/request_form_models/image01.py
deleted file mode 100644 (file)
index 15bd385..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import subprocess
-import time
-
-import httpx
-from playwright.sync_api import Playwright, sync_playwright
-
-
-# Run playwright codegen to generate the code below, copy paste the sections in run()
-def run(playwright: Playwright) -> None:
-    browser = playwright.chromium.launch(headless=False)
-    context = browser.new_context()
-    page = context.new_page()
-    page.goto("http://localhost:8000/docs")
-    page.get_by_role("button", name="POST /login/ Login").click()
-    page.get_by_role("button", name="Try it out").click()
-    page.screenshot(path="docs/en/docs/img/tutorial/request-form-models/image01.png")
-
-    # ---------------------
-    context.close()
-    browser.close()
-
-
-process = subprocess.Popen(
-    ["fastapi", "run", "docs_src/request_form_models/tutorial001.py"]
-)
-try:
-    for _ in range(3):
-        try:
-            response = httpx.get("http://localhost:8000/docs")
-        except httpx.ConnectError:
-            time.sleep(1)
-            break
-    with sync_playwright() as playwright:
-        run(playwright)
-finally:
-    process.terminate()
diff --git a/tests/test_forms_single_model.py b/tests/test_forms_single_model.py
deleted file mode 100644 (file)
index 7ed3ba3..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-from typing import List, Optional
-
-from dirty_equals import IsDict
-from fastapi import FastAPI, Form
-from fastapi.testclient import TestClient
-from pydantic import BaseModel
-from typing_extensions import Annotated
-
-app = FastAPI()
-
-
-class FormModel(BaseModel):
-    username: str
-    lastname: str
-    age: Optional[int] = None
-    tags: List[str] = ["foo", "bar"]
-
-
-@app.post("/form/")
-def post_form(user: Annotated[FormModel, Form()]):
-    return user
-
-
-client = TestClient(app)
-
-
-def test_send_all_data():
-    response = client.post(
-        "/form/",
-        data={
-            "username": "Rick",
-            "lastname": "Sanchez",
-            "age": "70",
-            "tags": ["plumbus", "citadel"],
-        },
-    )
-    assert response.status_code == 200, response.text
-    assert response.json() == {
-        "username": "Rick",
-        "lastname": "Sanchez",
-        "age": 70,
-        "tags": ["plumbus", "citadel"],
-    }
-
-
-def test_defaults():
-    response = client.post("/form/", data={"username": "Rick", "lastname": "Sanchez"})
-    assert response.status_code == 200, response.text
-    assert response.json() == {
-        "username": "Rick",
-        "lastname": "Sanchez",
-        "age": None,
-        "tags": ["foo", "bar"],
-    }
-
-
-def test_invalid_data():
-    response = client.post(
-        "/form/",
-        data={
-            "username": "Rick",
-            "lastname": "Sanchez",
-            "age": "seventy",
-            "tags": ["plumbus", "citadel"],
-        },
-    )
-    assert response.status_code == 422, response.text
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "int_parsing",
-                    "loc": ["body", "age"],
-                    "msg": "Input should be a valid integer, unable to parse string as an integer",
-                    "input": "seventy",
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "age"],
-                    "msg": "value is not a valid integer",
-                    "type": "type_error.integer",
-                }
-            ]
-        }
-    )
-
-
-def test_no_data():
-    response = client.post("/form/")
-    assert response.status_code == 422, response.text
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {"tags": ["foo", "bar"]},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "lastname"],
-                    "msg": "Field required",
-                    "input": {"tags": ["foo", "bar"]},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "lastname"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
diff --git a/tests/test_tutorial/test_request_form_models/__init__.py b/tests/test_tutorial/test_request_form_models/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001.py b/tests/test_tutorial/test_request_form_models/test_tutorial001.py
deleted file mode 100644 (file)
index 46c130e..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-import pytest
-from dirty_equals import IsDict
-from fastapi.testclient import TestClient
-
-
-@pytest.fixture(name="client")
-def get_client():
-    from docs_src.request_form_models.tutorial001 import app
-
-    client = TestClient(app)
-    return client
-
-
-def test_post_body_form(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo", "password": "secret"})
-    assert response.status_code == 200
-    assert response.json() == {"username": "Foo", "password": "secret"}
-
-
-def test_post_body_form_no_password(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {"username": "Foo"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-def test_post_body_form_no_username(client: TestClient):
-    response = client.post("/login/", data={"password": "secret"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {"password": "secret"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-def test_post_body_form_no_data(client: TestClient):
-    response = client.post("/login/")
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-def test_post_body_json(client: TestClient):
-    response = client.post("/login/", json={"username": "Foo", "password": "secret"})
-    assert response.status_code == 422, response.text
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-def test_openapi_schema(client: TestClient):
-    response = client.get("/openapi.json")
-    assert response.status_code == 200, response.text
-    assert response.json() == {
-        "openapi": "3.1.0",
-        "info": {"title": "FastAPI", "version": "0.1.0"},
-        "paths": {
-            "/login/": {
-                "post": {
-                    "responses": {
-                        "200": {
-                            "description": "Successful Response",
-                            "content": {"application/json": {"schema": {}}},
-                        },
-                        "422": {
-                            "description": "Validation Error",
-                            "content": {
-                                "application/json": {
-                                    "schema": {
-                                        "$ref": "#/components/schemas/HTTPValidationError"
-                                    }
-                                }
-                            },
-                        },
-                    },
-                    "summary": "Login",
-                    "operationId": "login_login__post",
-                    "requestBody": {
-                        "content": {
-                            "application/x-www-form-urlencoded": {
-                                "schema": {"$ref": "#/components/schemas/FormData"}
-                            }
-                        },
-                        "required": True,
-                    },
-                }
-            }
-        },
-        "components": {
-            "schemas": {
-                "FormData": {
-                    "properties": {
-                        "username": {"type": "string", "title": "Username"},
-                        "password": {"type": "string", "title": "Password"},
-                    },
-                    "type": "object",
-                    "required": ["username", "password"],
-                    "title": "FormData",
-                },
-                "ValidationError": {
-                    "title": "ValidationError",
-                    "required": ["loc", "msg", "type"],
-                    "type": "object",
-                    "properties": {
-                        "loc": {
-                            "title": "Location",
-                            "type": "array",
-                            "items": {
-                                "anyOf": [{"type": "string"}, {"type": "integer"}]
-                            },
-                        },
-                        "msg": {"title": "Message", "type": "string"},
-                        "type": {"title": "Error Type", "type": "string"},
-                    },
-                },
-                "HTTPValidationError": {
-                    "title": "HTTPValidationError",
-                    "type": "object",
-                    "properties": {
-                        "detail": {
-                            "title": "Detail",
-                            "type": "array",
-                            "items": {"$ref": "#/components/schemas/ValidationError"},
-                        }
-                    },
-                },
-            }
-        },
-    }
diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001_an.py b/tests/test_tutorial/test_request_form_models/test_tutorial001_an.py
deleted file mode 100644 (file)
index 4e14d89..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-import pytest
-from dirty_equals import IsDict
-from fastapi.testclient import TestClient
-
-
-@pytest.fixture(name="client")
-def get_client():
-    from docs_src.request_form_models.tutorial001_an import app
-
-    client = TestClient(app)
-    return client
-
-
-def test_post_body_form(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo", "password": "secret"})
-    assert response.status_code == 200
-    assert response.json() == {"username": "Foo", "password": "secret"}
-
-
-def test_post_body_form_no_password(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {"username": "Foo"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-def test_post_body_form_no_username(client: TestClient):
-    response = client.post("/login/", data={"password": "secret"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {"password": "secret"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-def test_post_body_form_no_data(client: TestClient):
-    response = client.post("/login/")
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-def test_post_body_json(client: TestClient):
-    response = client.post("/login/", json={"username": "Foo", "password": "secret"})
-    assert response.status_code == 422, response.text
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-def test_openapi_schema(client: TestClient):
-    response = client.get("/openapi.json")
-    assert response.status_code == 200, response.text
-    assert response.json() == {
-        "openapi": "3.1.0",
-        "info": {"title": "FastAPI", "version": "0.1.0"},
-        "paths": {
-            "/login/": {
-                "post": {
-                    "responses": {
-                        "200": {
-                            "description": "Successful Response",
-                            "content": {"application/json": {"schema": {}}},
-                        },
-                        "422": {
-                            "description": "Validation Error",
-                            "content": {
-                                "application/json": {
-                                    "schema": {
-                                        "$ref": "#/components/schemas/HTTPValidationError"
-                                    }
-                                }
-                            },
-                        },
-                    },
-                    "summary": "Login",
-                    "operationId": "login_login__post",
-                    "requestBody": {
-                        "content": {
-                            "application/x-www-form-urlencoded": {
-                                "schema": {"$ref": "#/components/schemas/FormData"}
-                            }
-                        },
-                        "required": True,
-                    },
-                }
-            }
-        },
-        "components": {
-            "schemas": {
-                "FormData": {
-                    "properties": {
-                        "username": {"type": "string", "title": "Username"},
-                        "password": {"type": "string", "title": "Password"},
-                    },
-                    "type": "object",
-                    "required": ["username", "password"],
-                    "title": "FormData",
-                },
-                "ValidationError": {
-                    "title": "ValidationError",
-                    "required": ["loc", "msg", "type"],
-                    "type": "object",
-                    "properties": {
-                        "loc": {
-                            "title": "Location",
-                            "type": "array",
-                            "items": {
-                                "anyOf": [{"type": "string"}, {"type": "integer"}]
-                            },
-                        },
-                        "msg": {"title": "Message", "type": "string"},
-                        "type": {"title": "Error Type", "type": "string"},
-                    },
-                },
-                "HTTPValidationError": {
-                    "title": "HTTPValidationError",
-                    "type": "object",
-                    "properties": {
-                        "detail": {
-                            "title": "Detail",
-                            "type": "array",
-                            "items": {"$ref": "#/components/schemas/ValidationError"},
-                        }
-                    },
-                },
-            }
-        },
-    }
diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_form_models/test_tutorial001_an_py39.py
deleted file mode 100644 (file)
index 2e6426a..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-import pytest
-from dirty_equals import IsDict
-from fastapi.testclient import TestClient
-
-from tests.utils import needs_py39
-
-
-@pytest.fixture(name="client")
-def get_client():
-    from docs_src.request_form_models.tutorial001_an_py39 import app
-
-    client = TestClient(app)
-    return client
-
-
-@needs_py39
-def test_post_body_form(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo", "password": "secret"})
-    assert response.status_code == 200
-    assert response.json() == {"username": "Foo", "password": "secret"}
-
-
-@needs_py39
-def test_post_body_form_no_password(client: TestClient):
-    response = client.post("/login/", data={"username": "Foo"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {"username": "Foo"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-@needs_py39
-def test_post_body_form_no_username(client: TestClient):
-    response = client.post("/login/", data={"password": "secret"})
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {"password": "secret"},
-                }
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                }
-            ]
-        }
-    )
-
-
-@needs_py39
-def test_post_body_form_no_data(client: TestClient):
-    response = client.post("/login/")
-    assert response.status_code == 422
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-@needs_py39
-def test_post_body_json(client: TestClient):
-    response = client.post("/login/", json={"username": "Foo", "password": "secret"})
-    assert response.status_code == 422, response.text
-    assert response.json() == IsDict(
-        {
-            "detail": [
-                {
-                    "type": "missing",
-                    "loc": ["body", "username"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-                {
-                    "type": "missing",
-                    "loc": ["body", "password"],
-                    "msg": "Field required",
-                    "input": {},
-                },
-            ]
-        }
-    ) | IsDict(
-        # TODO: remove when deprecating Pydantic v1
-        {
-            "detail": [
-                {
-                    "loc": ["body", "username"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-                {
-                    "loc": ["body", "password"],
-                    "msg": "field required",
-                    "type": "value_error.missing",
-                },
-            ]
-        }
-    )
-
-
-@needs_py39
-def test_openapi_schema(client: TestClient):
-    response = client.get("/openapi.json")
-    assert response.status_code == 200, response.text
-    assert response.json() == {
-        "openapi": "3.1.0",
-        "info": {"title": "FastAPI", "version": "0.1.0"},
-        "paths": {
-            "/login/": {
-                "post": {
-                    "responses": {
-                        "200": {
-                            "description": "Successful Response",
-                            "content": {"application/json": {"schema": {}}},
-                        },
-                        "422": {
-                            "description": "Validation Error",
-                            "content": {
-                                "application/json": {
-                                    "schema": {
-                                        "$ref": "#/components/schemas/HTTPValidationError"
-                                    }
-                                }
-                            },
-                        },
-                    },
-                    "summary": "Login",
-                    "operationId": "login_login__post",
-                    "requestBody": {
-                        "content": {
-                            "application/x-www-form-urlencoded": {
-                                "schema": {"$ref": "#/components/schemas/FormData"}
-                            }
-                        },
-                        "required": True,
-                    },
-                }
-            }
-        },
-        "components": {
-            "schemas": {
-                "FormData": {
-                    "properties": {
-                        "username": {"type": "string", "title": "Username"},
-                        "password": {"type": "string", "title": "Password"},
-                    },
-                    "type": "object",
-                    "required": ["username", "password"],
-                    "title": "FormData",
-                },
-                "ValidationError": {
-                    "title": "ValidationError",
-                    "required": ["loc", "msg", "type"],
-                    "type": "object",
-                    "properties": {
-                        "loc": {
-                            "title": "Location",
-                            "type": "array",
-                            "items": {
-                                "anyOf": [{"type": "string"}, {"type": "integer"}]
-                            },
-                        },
-                        "msg": {"title": "Message", "type": "string"},
-                        "type": {"title": "Error Type", "type": "string"},
-                    },
-                },
-                "HTTPValidationError": {
-                    "title": "HTTPValidationError",
-                    "type": "object",
-                    "properties": {
-                        "detail": {
-                            "title": "Detail",
-                            "type": "array",
-                            "items": {"$ref": "#/components/schemas/ValidationError"},
-                        }
-                    },
-                },
-            }
-        },
-    }