diff --git a/.gitignore b/.gitignore index 8164f19..e6bb967 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ /fastapi-0.85.0.tar.gz /fastapi-0.85.1.tar.gz /fastapi-0.85.2.tar.gz +/fastapi-0.86.0.tar.gz diff --git a/0001-Update-starlette-to-0.21.0.patch b/0001-Update-starlette-to-0.21.0.patch deleted file mode 100644 index 4c36cec..0000000 --- a/0001-Update-starlette-to-0.21.0.patch +++ /dev/null @@ -1,733 +0,0 @@ -From 68fad0b2fcebdfc55101ba1b31b515788c9fdfe7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pawe=C5=82=20Rubin?= -Date: Fri, 7 Oct 2022 11:33:16 +0200 -Subject: [PATCH] Update starlette to 0.21.0. - -- Adapt tests suite after breaking changes to the starlette's TestClient -- Fix issues found by mypy caused by more precise type annotations in starlette ---- - fastapi/security/api_key.py | 2 +- - fastapi/security/http.py | 8 ++++---- - fastapi/security/oauth2.py | 6 +++--- - fastapi/security/open_id_connect_url.py | 2 +- - fastapi/security/utils.py | 6 ++++-- - pyproject.toml | 2 +- - tests/test_enforce_once_required_parameter.py | 2 +- - tests/test_extra_routes.py | 2 +- - tests/test_get_request_body.py | 2 +- - tests/test_param_include_in_schema.py | 9 ++++++--- - tests/test_security_api_key_cookie.py | 7 ++++--- - .../test_security_api_key_cookie_description.py | 7 ++++--- - tests/test_security_api_key_cookie_optional.py | 7 ++++--- - tests/test_tuples.py | 6 +++--- - .../test_advanced_middleware/test_tutorial001.py | 2 +- - .../test_tutorial/test_body/test_tutorial001.py | 16 +++++++++------- - .../test_body/test_tutorial001_py310.py | 16 +++++++++------- - .../test_cookie_params/test_tutorial001.py | 5 ++--- - .../test_cookie_params/test_tutorial001_py310.py | 15 +++++---------- - .../test_tutorial001.py | 2 +- - .../test_custom_response/test_tutorial006.py | 2 +- - .../test_custom_response/test_tutorial006b.py | 2 +- - .../test_custom_response/test_tutorial006c.py | 2 +- - .../test_tutorial006.py | 2 +- - .../test_tutorial007.py | 6 +++--- - .../test_websockets/test_tutorial002.py | 12 +++++++----- - 26 files changed, 79 insertions(+), 71 deletions(-) - -diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py -index bca5c721..24ddbf48 100644 ---- a/fastapi/security/api_key.py -+++ b/fastapi/security/api_key.py -@@ -54,7 +54,7 @@ class APIKeyHeader(APIKeyBase): - self.auto_error = auto_error - - async def __call__(self, request: Request) -> Optional[str]: -- api_key: str = request.headers.get(self.model.name) -+ api_key = request.headers.get(self.model.name) - if not api_key: - if self.auto_error: - raise HTTPException( -diff --git a/fastapi/security/http.py b/fastapi/security/http.py -index 1b473c69..8b677299 100644 ---- a/fastapi/security/http.py -+++ b/fastapi/security/http.py -@@ -38,7 +38,7 @@ class HTTPBase(SecurityBase): - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: -@@ -67,7 +67,7 @@ class HTTPBasic(HTTPBase): - async def __call__( # type: ignore - self, request: Request - ) -> Optional[HTTPBasicCredentials]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if self.realm: - unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'} -@@ -113,7 +113,7 @@ class HTTPBearer(HTTPBase): - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: -@@ -148,7 +148,7 @@ class HTTPDigest(HTTPBase): - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: -diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py -index 653c3010..eb6b4277 100644 ---- a/fastapi/security/oauth2.py -+++ b/fastapi/security/oauth2.py -@@ -126,7 +126,7 @@ class OAuth2(SecurityBase): - self.auto_error = auto_error - - async def __call__(self, request: Request) -> Optional[str]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise HTTPException( -@@ -157,7 +157,7 @@ class OAuth2PasswordBearer(OAuth2): - ) - - async def __call__(self, request: Request) -> Optional[str]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: -@@ -200,7 +200,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): - ) - - async def __call__(self, request: Request) -> Optional[str]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: -diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py -index dfe9f7b2..393614f7 100644 ---- a/fastapi/security/open_id_connect_url.py -+++ b/fastapi/security/open_id_connect_url.py -@@ -23,7 +23,7 @@ class OpenIdConnect(SecurityBase): - self.auto_error = auto_error - - async def __call__(self, request: Request) -> Optional[str]: -- authorization: str = request.headers.get("Authorization") -+ authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise HTTPException( -diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py -index 2da0dd20..fa7a450b 100644 ---- a/fastapi/security/utils.py -+++ b/fastapi/security/utils.py -@@ -1,7 +1,9 @@ --from typing import Tuple -+from typing import Optional, Tuple - - --def get_authorization_scheme_param(authorization_header_value: str) -> Tuple[str, str]: -+def get_authorization_scheme_param( -+ authorization_header_value: Optional[str], -+) -> Tuple[str, str]: - if not authorization_header_value: - return "", "" - scheme, _, param = authorization_header_value.partition(" ") -diff --git a/pyproject.toml b/pyproject.toml -index 543ba15c..232c4380 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -38,7 +38,7 @@ classifiers = [ - "Topic :: Internet :: WWW/HTTP", - ] - dependencies = [ -- "starlette==0.20.4", -+ "starlette==0.21.0", - "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", - ] - dynamic = ["version"] -diff --git a/tests/test_enforce_once_required_parameter.py b/tests/test_enforce_once_required_parameter.py -index ba8c7353..bf05aa58 100644 ---- a/tests/test_enforce_once_required_parameter.py -+++ b/tests/test_enforce_once_required_parameter.py -@@ -101,7 +101,7 @@ def test_schema(): - - - def test_get_invalid(): -- response = client.get("/foo", params={"client_id": None}) -+ response = client.get("/foo") - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - -diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py -index 491ba61c..e979628a 100644 ---- a/tests/test_extra_routes.py -+++ b/tests/test_extra_routes.py -@@ -333,7 +333,7 @@ def test_get_api_route_not_decorated(): - - - def test_delete(): -- response = client.delete("/items/foo", json={"name": "Foo"}) -+ response = client.request("DELETE", "/items/foo", json={"name": "Foo"}) - assert response.status_code == 200, response.text - assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} - -diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py -index 88b9d839..52a052fa 100644 ---- a/tests/test_get_request_body.py -+++ b/tests/test_get_request_body.py -@@ -104,5 +104,5 @@ def test_openapi_schema(): - - def test_get_with_body(): - body = {"name": "Foo", "description": "Some description", "price": 5.5} -- response = client.get("/product", json=body) -+ response = client.request("GET", "/product", json=body) - assert response.json() == body -diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py -index 214f039b..cb182a1c 100644 ---- a/tests/test_param_include_in_schema.py -+++ b/tests/test_param_include_in_schema.py -@@ -33,8 +33,6 @@ async def hidden_query( - return {"hidden_query": hidden_query} - - --client = TestClient(app) -- - openapi_shema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, -@@ -161,6 +159,7 @@ openapi_shema = { - - - def test_openapi_schema(): -+ client = TestClient(app) - response = client.get("/openapi.json") - assert response.status_code == 200 - assert response.json() == openapi_shema -@@ -184,7 +183,8 @@ def test_openapi_schema(): - ], - ) - def test_hidden_cookie(path, cookies, expected_status, expected_response): -- response = client.get(path, cookies=cookies) -+ client = TestClient(app, cookies=cookies) -+ response = client.get(path) - assert response.status_code == expected_status - assert response.json() == expected_response - -@@ -207,12 +207,14 @@ def test_hidden_cookie(path, cookies, expected_status, expected_response): - ], - ) - def test_hidden_header(path, headers, expected_status, expected_response): -+ client = TestClient(app) - response = client.get(path, headers=headers) - assert response.status_code == expected_status - assert response.json() == expected_response - - - def test_hidden_path(): -+ client = TestClient(app) - response = client.get("/hidden_path/hidden_path") - assert response.status_code == 200 - assert response.json() == {"hidden_path": "hidden_path"} -@@ -234,6 +236,7 @@ def test_hidden_path(): - ], - ) - def test_hidden_query(path, expected_status, expected_response): -+ client = TestClient(app) - response = client.get(path) - assert response.status_code == expected_status - assert response.json() == expected_response -diff --git a/tests/test_security_api_key_cookie.py b/tests/test_security_api_key_cookie.py -index a5b2e44f..0bf4e9bb 100644 ---- a/tests/test_security_api_key_cookie.py -+++ b/tests/test_security_api_key_cookie.py -@@ -22,8 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): - return current_user - - --client = TestClient(app) -- - openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, -@@ -51,18 +49,21 @@ openapi_schema = { - - - def test_openapi_schema(): -+ client = TestClient(app) - response = client.get("/openapi.json") - assert response.status_code == 200, response.text - assert response.json() == openapi_schema - - - def test_security_api_key(): -- response = client.get("/users/me", cookies={"key": "secret"}) -+ client = TestClient(app, cookies={"key": "secret"}) -+ response = client.get("/users/me") - assert response.status_code == 200, response.text - assert response.json() == {"username": "secret"} - - - def test_security_api_key_no_key(): -+ client = TestClient(app) - response = client.get("/users/me") - assert response.status_code == 403, response.text - assert response.json() == {"detail": "Not authenticated"} -diff --git a/tests/test_security_api_key_cookie_description.py b/tests/test_security_api_key_cookie_description.py -index 2cd3565b..ed4e6523 100644 ---- a/tests/test_security_api_key_cookie_description.py -+++ b/tests/test_security_api_key_cookie_description.py -@@ -22,8 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): - return current_user - - --client = TestClient(app) -- - openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, -@@ -56,18 +54,21 @@ openapi_schema = { - - - def test_openapi_schema(): -+ client = TestClient(app) - response = client.get("/openapi.json") - assert response.status_code == 200, response.text - assert response.json() == openapi_schema - - - def test_security_api_key(): -- response = client.get("/users/me", cookies={"key": "secret"}) -+ client = TestClient(app, cookies={"key": "secret"}) -+ response = client.get("/users/me") - assert response.status_code == 200, response.text - assert response.json() == {"username": "secret"} - - - def test_security_api_key_no_key(): -+ client = TestClient(app) - response = client.get("/users/me") - assert response.status_code == 403, response.text - assert response.json() == {"detail": "Not authenticated"} -diff --git a/tests/test_security_api_key_cookie_optional.py b/tests/test_security_api_key_cookie_optional.py -index 96a64f09..3e7aa81c 100644 ---- a/tests/test_security_api_key_cookie_optional.py -+++ b/tests/test_security_api_key_cookie_optional.py -@@ -29,8 +29,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): - return current_user - - --client = TestClient(app) -- - openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, -@@ -58,18 +56,21 @@ openapi_schema = { - - - def test_openapi_schema(): -+ client = TestClient(app) - response = client.get("/openapi.json") - assert response.status_code == 200, response.text - assert response.json() == openapi_schema - - - def test_security_api_key(): -- response = client.get("/users/me", cookies={"key": "secret"}) -+ client = TestClient(app, cookies={"key": "secret"}) -+ response = client.get("/users/me") - assert response.status_code == 200, response.text - assert response.json() == {"username": "secret"} - - - def test_security_api_key_no_key(): -+ client = TestClient(app) - response = client.get("/users/me") - assert response.status_code == 200, response.text - assert response.json() == {"msg": "Create an account first"} -diff --git a/tests/test_tuples.py b/tests/test_tuples.py -index 18ec2d04..9fa65e1d 100644 ---- a/tests/test_tuples.py -+++ b/tests/test_tuples.py -@@ -252,16 +252,16 @@ def test_tuple_with_model_invalid(): - - - def test_tuple_form_valid(): -- response = client.post("/tuple-form/", data=[("values", "1"), ("values", "2")]) -+ response = client.post("/tuple-form/", data={"values": ("1", "2")}) - assert response.status_code == 200, response.text - assert response.json() == [1, 2] - - - def test_tuple_form_invalid(): - response = client.post( -- "/tuple-form/", data=[("values", "1"), ("values", "2"), ("values", "3")] -+ "/tuple-form/", content=[("values", "1"), ("values", "2"), ("values", "3")] - ) - assert response.status_code == 422, response.text - -- response = client.post("/tuple-form/", data=[("values", "1")]) -+ response = client.post("/tuple-form/", content=[("values", "1")]) - assert response.status_code == 422, response.text -diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py -index 17165c0f..157fa5ca 100644 ---- a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py -+++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py -@@ -9,6 +9,6 @@ def test_middleware(): - assert response.status_code == 200, response.text - - client = TestClient(app) -- response = client.get("/", allow_redirects=False) -+ response = client.get("/", follow_redirects=False) - assert response.status_code == 307, response.text - assert response.headers["location"] == "https://testserver/" -diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py -index 8dbaf15d..65cdc758 100644 ---- a/tests/test_tutorial/test_body/test_tutorial001.py -+++ b/tests/test_tutorial/test_body/test_tutorial001.py -@@ -176,7 +176,7 @@ def test_post_broken_body(): - response = client.post( - "/items/", - headers={"content-type": "application/json"}, -- data="{some broken json}", -+ content="{some broken json}", - ) - assert response.status_code == 422, response.text - assert response.json() == { -@@ -214,7 +214,7 @@ def test_post_form_for_json(): - def test_explicit_content_type(): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - headers={"Content-Type": "application/json"}, - ) - assert response.status_code == 200, response.text -@@ -223,7 +223,7 @@ def test_explicit_content_type(): - def test_geo_json(): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - headers={"Content-Type": "application/geo+json"}, - ) - assert response.status_code == 200, response.text -@@ -232,7 +232,7 @@ def test_geo_json(): - def test_no_content_type_is_json(): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - ) - assert response.status_code == 200, response.text - assert response.json() == { -@@ -255,17 +255,19 @@ def test_wrong_headers(): - ] - } - -- response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) -+ response = client.post( -+ "/items/", content=data, headers={"Content-Type": "text/plain"} -+ ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict - - response = client.post( -- "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} -+ "/items/", content=data, headers={"Content-Type": "application/geo+json-seq"} - ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict - response = client.post( -- "/items/", data=data, headers={"Content-Type": "application/not-really-json"} -+ "/items/", content=data, headers={"Content-Type": "application/not-really-json"} - ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict -diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py -index dd9d9911..83bcb68f 100644 ---- a/tests/test_tutorial/test_body/test_tutorial001_py310.py -+++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py -@@ -185,7 +185,7 @@ def test_post_broken_body(client: TestClient): - response = client.post( - "/items/", - headers={"content-type": "application/json"}, -- data="{some broken json}", -+ content="{some broken json}", - ) - assert response.status_code == 422, response.text - assert response.json() == { -@@ -225,7 +225,7 @@ def test_post_form_for_json(client: TestClient): - def test_explicit_content_type(client: TestClient): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - headers={"Content-Type": "application/json"}, - ) - assert response.status_code == 200, response.text -@@ -235,7 +235,7 @@ def test_explicit_content_type(client: TestClient): - def test_geo_json(client: TestClient): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - headers={"Content-Type": "application/geo+json"}, - ) - assert response.status_code == 200, response.text -@@ -245,7 +245,7 @@ def test_geo_json(client: TestClient): - def test_no_content_type_is_json(client: TestClient): - response = client.post( - "/items/", -- data='{"name": "Foo", "price": 50.5}', -+ content='{"name": "Foo", "price": 50.5}', - ) - assert response.status_code == 200, response.text - assert response.json() == { -@@ -269,17 +269,19 @@ def test_wrong_headers(client: TestClient): - ] - } - -- response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) -+ response = client.post( -+ "/items/", content=data, headers={"Content-Type": "text/plain"} -+ ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict - - response = client.post( -- "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} -+ "/items/", content=data, headers={"Content-Type": "application/geo+json-seq"} - ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict - response = client.post( -- "/items/", data=data, headers={"Content-Type": "application/not-really-json"} -+ "/items/", content=data, headers={"Content-Type": "application/not-really-json"} - ) - assert response.status_code == 422, response.text - assert response.json() == invalid_dict -diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py -index edccffec..38ae211d 100644 ---- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py -+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py -@@ -3,8 +3,6 @@ from fastapi.testclient import TestClient - - from docs_src.cookie_params.tutorial001 import app - --client = TestClient(app) -- - openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, -@@ -88,6 +86,7 @@ openapi_schema = { - ], - ) - def test(path, cookies, expected_status, expected_response): -- response = client.get(path, cookies=cookies) -+ client = TestClient(app, cookies=cookies) -+ response = client.get(path) - assert response.status_code == expected_status - assert response.json() == expected_response -diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py -index 5caa5c44..5ad52fb5 100644 ---- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py -+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py -@@ -70,14 +70,6 @@ openapi_schema = { - } - - --@pytest.fixture(name="client") --def get_client(): -- from docs_src.cookie_params.tutorial001_py310 import app -- -- client = TestClient(app) -- return client -- -- - @needs_py310 - @pytest.mark.parametrize( - "path,cookies,expected_status,expected_response", -@@ -94,7 +86,10 @@ def get_client(): - ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}), - ], - ) --def test(path, cookies, expected_status, expected_response, client: TestClient): -- response = client.get(path, cookies=cookies) -+def test(path, cookies, expected_status, expected_response): -+ from docs_src.cookie_params.tutorial001_py310 import app -+ -+ client = TestClient(app, cookies=cookies) -+ response = client.get(path) - assert response.status_code == expected_status - assert response.json() == expected_response -diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py -index 3eb5822e..e6da630e 100644 ---- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py -+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py -@@ -26,7 +26,7 @@ def test_gzip_request(compress): - data = gzip.compress(data) - headers["Content-Encoding"] = "gzip" - headers["Content-Type"] = "application/json" -- response = client.post("/sum", data=data, headers=headers) -+ response = client.post("/sum", content=data, headers=headers) - assert response.json() == {"sum": n} - - -diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py -index 72bbfd27..9b10916e 100644 ---- a/tests/test_tutorial/test_custom_response/test_tutorial006.py -+++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py -@@ -32,6 +32,6 @@ def test_openapi_schema(): - - - def test_get(): -- response = client.get("/typer", allow_redirects=False) -+ response = client.get("/typer", follow_redirects=False) - assert response.status_code == 307, response.text - assert response.headers["location"] == "https://typer.tiangolo.com" -diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py -index ac5a76d3..b3e60e86 100644 ---- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py -+++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py -@@ -27,6 +27,6 @@ def test_openapi_schema(): - - - def test_redirect_response_class(): -- response = client.get("/fastapi", allow_redirects=False) -+ response = client.get("/fastapi", follow_redirects=False) - assert response.status_code == 307 - assert response.headers["location"] == "https://fastapi.tiangolo.com" -diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py -index 009225e8..0cb6ddaa 100644 ---- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py -+++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py -@@ -27,6 +27,6 @@ def test_openapi_schema(): - - - def test_redirect_status_code(): -- response = client.get("/pydantic", allow_redirects=False) -+ response = client.get("/pydantic", follow_redirects=False) - assert response.status_code == 302 - assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/" -diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py -index 5533b295..330b4e2c 100644 ---- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py -+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py -@@ -47,7 +47,7 @@ def test_openapi_schema(): - - - def test_post(): -- response = client.post("/items/", data=b"this is actually not validated") -+ response = client.post("/items/", content=b"this is actually not validated") - assert response.status_code == 200, response.text - assert response.json() == { - "size": 30, -diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py -index cb5dbc8e..076f60b2 100644 ---- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py -+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py -@@ -58,7 +58,7 @@ def test_post(): - - x-men - - x-avengers - """ -- response = client.post("/items/", data=yaml_data) -+ response = client.post("/items/", content=yaml_data) - assert response.status_code == 200, response.text - assert response.json() == { - "name": "Deadpoolio", -@@ -74,7 +74,7 @@ def test_post_broken_yaml(): - x - x-men - x - x-avengers - """ -- response = client.post("/items/", data=yaml_data) -+ response = client.post("/items/", content=yaml_data) - assert response.status_code == 422, response.text - assert response.json() == {"detail": "Invalid YAML"} - -@@ -88,7 +88,7 @@ def test_post_invalid(): - - x-avengers - - sneaky: object - """ -- response = client.post("/items/", data=yaml_data) -+ response = client.post("/items/", content=yaml_data) - assert response.status_code == 422, response.text - assert response.json() == { - "detail": [ -diff --git a/tests/test_tutorial/test_websockets/test_tutorial002.py b/tests/test_tutorial/test_websockets/test_tutorial002.py -index a8523c9c..bb5ccbf8 100644 ---- a/tests/test_tutorial/test_websockets/test_tutorial002.py -+++ b/tests/test_tutorial/test_websockets/test_tutorial002.py -@@ -4,20 +4,18 @@ from fastapi.websockets import WebSocketDisconnect - - from docs_src.websockets.tutorial002 import app - --client = TestClient(app) -- - - def test_main(): -+ client = TestClient(app) - response = client.get("/") - assert response.status_code == 200, response.text - assert b"" in response.content - - - def test_websocket_with_cookie(): -+ client = TestClient(app, cookies={"session": "fakesession"}) - with pytest.raises(WebSocketDisconnect): -- with client.websocket_connect( -- "/items/foo/ws", cookies={"session": "fakesession"} -- ) as websocket: -+ with client.websocket_connect("/items/foo/ws") as websocket: - message = "Message one" - websocket.send_text(message) - data = websocket.receive_text() -@@ -33,6 +31,7 @@ def test_websocket_with_cookie(): - - - def test_websocket_with_header(): -+ client = TestClient(app) - with pytest.raises(WebSocketDisconnect): - with client.websocket_connect("/items/bar/ws?token=some-token") as websocket: - message = "Message one" -@@ -50,6 +49,7 @@ def test_websocket_with_header(): - - - def test_websocket_with_header_and_query(): -+ client = TestClient(app) - with pytest.raises(WebSocketDisconnect): - with client.websocket_connect("/items/2/ws?q=3&token=some-token") as websocket: - message = "Message one" -@@ -71,6 +71,7 @@ def test_websocket_with_header_and_query(): - - - def test_websocket_no_credentials(): -+ client = TestClient(app) - with pytest.raises(WebSocketDisconnect): - with client.websocket_connect("/items/foo/ws"): - pytest.fail( -@@ -79,6 +80,7 @@ def test_websocket_no_credentials(): - - - def test_websocket_invalid_data(): -+ client = TestClient(app) - with pytest.raises(WebSocketDisconnect): - with client.websocket_connect("/items/foo/ws?q=bar&token=some-token"): - pytest.fail( --- -2.37.3 - diff --git a/5471.patch b/5471.patch new file mode 100644 index 0000000..2ced3e5 --- /dev/null +++ b/5471.patch @@ -0,0 +1,761 @@ +From 175022aa1007ff6c767cb5bbb64df37df2d40044 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pawe=C5=82=20Rubin?= +Date: Fri, 7 Oct 2022 11:33:16 +0200 +Subject: [PATCH 1/2] Update starlette to 0.21.0. + +- Adapt tests suite after breaking changes to the starlette's TestClient +- Fix issues found by mypy caused by more precise type annotations in starlette +--- + fastapi/security/api_key.py | 2 +- + fastapi/security/http.py | 8 ++++---- + fastapi/security/oauth2.py | 6 +++--- + fastapi/security/open_id_connect_url.py | 2 +- + fastapi/security/utils.py | 6 ++++-- + pyproject.toml | 2 +- + tests/test_enforce_once_required_parameter.py | 2 +- + tests/test_extra_routes.py | 2 +- + tests/test_get_request_body.py | 2 +- + tests/test_param_include_in_schema.py | 9 ++++++--- + tests/test_security_api_key_cookie.py | 7 ++++--- + .../test_security_api_key_cookie_description.py | 7 ++++--- + tests/test_security_api_key_cookie_optional.py | 7 ++++--- + tests/test_tuples.py | 6 +++--- + .../test_advanced_middleware/test_tutorial001.py | 2 +- + .../test_tutorial/test_body/test_tutorial001.py | 16 +++++++++------- + .../test_body/test_tutorial001_py310.py | 16 +++++++++------- + .../test_cookie_params/test_tutorial001.py | 5 ++--- + .../test_cookie_params/test_tutorial001_py310.py | 15 +++++---------- + .../test_tutorial001.py | 2 +- + .../test_custom_response/test_tutorial006.py | 2 +- + .../test_custom_response/test_tutorial006b.py | 2 +- + .../test_custom_response/test_tutorial006c.py | 2 +- + .../test_tutorial006.py | 2 +- + .../test_tutorial007.py | 6 +++--- + .../test_websockets/test_tutorial002.py | 12 +++++++----- + 26 files changed, 79 insertions(+), 71 deletions(-) + +diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py +index bca5c721a69..24ddbf48259 100644 +--- a/fastapi/security/api_key.py ++++ b/fastapi/security/api_key.py +@@ -54,7 +54,7 @@ def __init__( + self.auto_error = auto_error + + async def __call__(self, request: Request) -> Optional[str]: +- api_key: str = request.headers.get(self.model.name) ++ api_key = request.headers.get(self.model.name) + if not api_key: + if self.auto_error: + raise HTTPException( +diff --git a/fastapi/security/http.py b/fastapi/security/http.py +index 1b473c69e7c..8b677299dde 100644 +--- a/fastapi/security/http.py ++++ b/fastapi/security/http.py +@@ -38,7 +38,7 @@ def __init__( + async def __call__( + self, request: Request + ) -> Optional[HTTPAuthorizationCredentials]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, credentials = get_authorization_scheme_param(authorization) + if not (authorization and scheme and credentials): + if self.auto_error: +@@ -67,7 +67,7 @@ def __init__( + async def __call__( # type: ignore + self, request: Request + ) -> Optional[HTTPBasicCredentials]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, param = get_authorization_scheme_param(authorization) + if self.realm: + unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'} +@@ -113,7 +113,7 @@ def __init__( + async def __call__( + self, request: Request + ) -> Optional[HTTPAuthorizationCredentials]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, credentials = get_authorization_scheme_param(authorization) + if not (authorization and scheme and credentials): + if self.auto_error: +@@ -148,7 +148,7 @@ def __init__( + async def __call__( + self, request: Request + ) -> Optional[HTTPAuthorizationCredentials]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, credentials = get_authorization_scheme_param(authorization) + if not (authorization and scheme and credentials): + if self.auto_error: +diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py +index 653c3010e58..eb6b4277cf8 100644 +--- a/fastapi/security/oauth2.py ++++ b/fastapi/security/oauth2.py +@@ -126,7 +126,7 @@ def __init__( + self.auto_error = auto_error + + async def __call__(self, request: Request) -> Optional[str]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + if not authorization: + if self.auto_error: + raise HTTPException( +@@ -157,7 +157,7 @@ def __init__( + ) + + async def __call__(self, request: Request) -> Optional[str]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, param = get_authorization_scheme_param(authorization) + if not authorization or scheme.lower() != "bearer": + if self.auto_error: +@@ -200,7 +200,7 @@ def __init__( + ) + + async def __call__(self, request: Request) -> Optional[str]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + scheme, param = get_authorization_scheme_param(authorization) + if not authorization or scheme.lower() != "bearer": + if self.auto_error: +diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py +index dfe9f7b255e..393614f7cbc 100644 +--- a/fastapi/security/open_id_connect_url.py ++++ b/fastapi/security/open_id_connect_url.py +@@ -23,7 +23,7 @@ def __init__( + self.auto_error = auto_error + + async def __call__(self, request: Request) -> Optional[str]: +- authorization: str = request.headers.get("Authorization") ++ authorization = request.headers.get("Authorization") + if not authorization: + if self.auto_error: + raise HTTPException( +diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py +index 2da0dd20f30..fa7a450b74e 100644 +--- a/fastapi/security/utils.py ++++ b/fastapi/security/utils.py +@@ -1,7 +1,9 @@ +-from typing import Tuple ++from typing import Optional, Tuple + + +-def get_authorization_scheme_param(authorization_header_value: str) -> Tuple[str, str]: ++def get_authorization_scheme_param( ++ authorization_header_value: Optional[str], ++) -> Tuple[str, str]: + if not authorization_header_value: + return "", "" + scheme, _, param = authorization_header_value.partition(" ") +diff --git a/pyproject.toml b/pyproject.toml +index a23289fb1ed..fc4602ea8e6 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -39,7 +39,7 @@ classifiers = [ + "Topic :: Internet :: WWW/HTTP", + ] + dependencies = [ +- "starlette==0.20.4", ++ "starlette==0.21.0", + "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", + ] + dynamic = ["version"] +diff --git a/tests/test_enforce_once_required_parameter.py b/tests/test_enforce_once_required_parameter.py +index ba8c7353fa9..bf05aa5852a 100644 +--- a/tests/test_enforce_once_required_parameter.py ++++ b/tests/test_enforce_once_required_parameter.py +@@ -101,7 +101,7 @@ def test_schema(): + + + def test_get_invalid(): +- response = client.get("/foo", params={"client_id": None}) ++ response = client.get("/foo") + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY + + +diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py +index 491ba61c680..e979628a5cc 100644 +--- a/tests/test_extra_routes.py ++++ b/tests/test_extra_routes.py +@@ -333,7 +333,7 @@ def test_get_api_route_not_decorated(): + + + def test_delete(): +- response = client.delete("/items/foo", json={"name": "Foo"}) ++ response = client.request("DELETE", "/items/foo", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} + +diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py +index 88b9d839f5a..52a052faab1 100644 +--- a/tests/test_get_request_body.py ++++ b/tests/test_get_request_body.py +@@ -104,5 +104,5 @@ def test_openapi_schema(): + + def test_get_with_body(): + body = {"name": "Foo", "description": "Some description", "price": 5.5} +- response = client.get("/product", json=body) ++ response = client.request("GET", "/product", json=body) + assert response.json() == body +diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py +index 214f039b67d..cb182a1cd4b 100644 +--- a/tests/test_param_include_in_schema.py ++++ b/tests/test_param_include_in_schema.py +@@ -33,8 +33,6 @@ async def hidden_query( + return {"hidden_query": hidden_query} + + +-client = TestClient(app) +- + openapi_shema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, +@@ -161,6 +159,7 @@ async def hidden_query( + + + def test_openapi_schema(): ++ client = TestClient(app) + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_shema +@@ -184,7 +183,8 @@ def test_openapi_schema(): + ], + ) + def test_hidden_cookie(path, cookies, expected_status, expected_response): +- response = client.get(path, cookies=cookies) ++ client = TestClient(app, cookies=cookies) ++ response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response + +@@ -207,12 +207,14 @@ def test_hidden_cookie(path, cookies, expected_status, expected_response): + ], + ) + def test_hidden_header(path, headers, expected_status, expected_response): ++ client = TestClient(app) + response = client.get(path, headers=headers) + assert response.status_code == expected_status + assert response.json() == expected_response + + + def test_hidden_path(): ++ client = TestClient(app) + response = client.get("/hidden_path/hidden_path") + assert response.status_code == 200 + assert response.json() == {"hidden_path": "hidden_path"} +@@ -234,6 +236,7 @@ def test_hidden_path(): + ], + ) + def test_hidden_query(path, expected_status, expected_response): ++ client = TestClient(app) + response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response +diff --git a/tests/test_security_api_key_cookie.py b/tests/test_security_api_key_cookie.py +index a5b2e44f0ce..0bf4e9bb3ad 100644 +--- a/tests/test_security_api_key_cookie.py ++++ b/tests/test_security_api_key_cookie.py +@@ -22,8 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +-client = TestClient(app) +- + openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, +@@ -51,18 +49,21 @@ def read_current_user(current_user: User = Depends(get_current_user)): + + + def test_openapi_schema(): ++ client = TestClient(app) + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + + def test_security_api_key(): +- response = client.get("/users/me", cookies={"key": "secret"}) ++ client = TestClient(app, cookies={"key": "secret"}) ++ response = client.get("/users/me") + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + + def test_security_api_key_no_key(): ++ client = TestClient(app) + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} +diff --git a/tests/test_security_api_key_cookie_description.py b/tests/test_security_api_key_cookie_description.py +index 2cd3565b43a..ed4e6523944 100644 +--- a/tests/test_security_api_key_cookie_description.py ++++ b/tests/test_security_api_key_cookie_description.py +@@ -22,8 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +-client = TestClient(app) +- + openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, +@@ -56,18 +54,21 @@ def read_current_user(current_user: User = Depends(get_current_user)): + + + def test_openapi_schema(): ++ client = TestClient(app) + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + + def test_security_api_key(): +- response = client.get("/users/me", cookies={"key": "secret"}) ++ client = TestClient(app, cookies={"key": "secret"}) ++ response = client.get("/users/me") + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + + def test_security_api_key_no_key(): ++ client = TestClient(app) + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} +diff --git a/tests/test_security_api_key_cookie_optional.py b/tests/test_security_api_key_cookie_optional.py +index 96a64f09a6e..3e7aa81c07a 100644 +--- a/tests/test_security_api_key_cookie_optional.py ++++ b/tests/test_security_api_key_cookie_optional.py +@@ -29,8 +29,6 @@ def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +-client = TestClient(app) +- + openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, +@@ -58,18 +56,21 @@ def read_current_user(current_user: User = Depends(get_current_user)): + + + def test_openapi_schema(): ++ client = TestClient(app) + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + + def test_security_api_key(): +- response = client.get("/users/me", cookies={"key": "secret"}) ++ client = TestClient(app, cookies={"key": "secret"}) ++ response = client.get("/users/me") + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + + def test_security_api_key_no_key(): ++ client = TestClient(app) + response = client.get("/users/me") + assert response.status_code == 200, response.text + assert response.json() == {"msg": "Create an account first"} +diff --git a/tests/test_tuples.py b/tests/test_tuples.py +index 18ec2d04899..9fa65e1def0 100644 +--- a/tests/test_tuples.py ++++ b/tests/test_tuples.py +@@ -252,16 +252,16 @@ def test_tuple_with_model_invalid(): + + + def test_tuple_form_valid(): +- response = client.post("/tuple-form/", data=[("values", "1"), ("values", "2")]) ++ response = client.post("/tuple-form/", data={"values": ("1", "2")}) + assert response.status_code == 200, response.text + assert response.json() == [1, 2] + + + def test_tuple_form_invalid(): + response = client.post( +- "/tuple-form/", data=[("values", "1"), ("values", "2"), ("values", "3")] ++ "/tuple-form/", content=[("values", "1"), ("values", "2"), ("values", "3")] + ) + assert response.status_code == 422, response.text + +- response = client.post("/tuple-form/", data=[("values", "1")]) ++ response = client.post("/tuple-form/", content=[("values", "1")]) + assert response.status_code == 422, response.text +diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py +index 17165c0fc61..157fa5caf1a 100644 +--- a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py ++++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py +@@ -9,6 +9,6 @@ def test_middleware(): + assert response.status_code == 200, response.text + + client = TestClient(app) +- response = client.get("/", allow_redirects=False) ++ response = client.get("/", follow_redirects=False) + assert response.status_code == 307, response.text + assert response.headers["location"] == "https://testserver/" +diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py +index 8dbaf15dbef..65cdc758adc 100644 +--- a/tests/test_tutorial/test_body/test_tutorial001.py ++++ b/tests/test_tutorial/test_body/test_tutorial001.py +@@ -176,7 +176,7 @@ def test_post_broken_body(): + response = client.post( + "/items/", + headers={"content-type": "application/json"}, +- data="{some broken json}", ++ content="{some broken json}", + ) + assert response.status_code == 422, response.text + assert response.json() == { +@@ -214,7 +214,7 @@ def test_post_form_for_json(): + def test_explicit_content_type(): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/json"}, + ) + assert response.status_code == 200, response.text +@@ -223,7 +223,7 @@ def test_explicit_content_type(): + def test_geo_json(): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/geo+json"}, + ) + assert response.status_code == 200, response.text +@@ -232,7 +232,7 @@ def test_geo_json(): + def test_no_content_type_is_json(): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + ) + assert response.status_code == 200, response.text + assert response.json() == { +@@ -255,17 +255,19 @@ def test_wrong_headers(): + ] + } + +- response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) ++ response = client.post( ++ "/items/", content=data, headers={"Content-Type": "text/plain"} ++ ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + response = client.post( +- "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} ++ "/items/", content=data, headers={"Content-Type": "application/geo+json-seq"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + response = client.post( +- "/items/", data=data, headers={"Content-Type": "application/not-really-json"} ++ "/items/", content=data, headers={"Content-Type": "application/not-really-json"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict +diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py +index dd9d9911e40..83bcb68f30d 100644 +--- a/tests/test_tutorial/test_body/test_tutorial001_py310.py ++++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py +@@ -185,7 +185,7 @@ def test_post_broken_body(client: TestClient): + response = client.post( + "/items/", + headers={"content-type": "application/json"}, +- data="{some broken json}", ++ content="{some broken json}", + ) + assert response.status_code == 422, response.text + assert response.json() == { +@@ -225,7 +225,7 @@ def test_post_form_for_json(client: TestClient): + def test_explicit_content_type(client: TestClient): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/json"}, + ) + assert response.status_code == 200, response.text +@@ -235,7 +235,7 @@ def test_explicit_content_type(client: TestClient): + def test_geo_json(client: TestClient): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/geo+json"}, + ) + assert response.status_code == 200, response.text +@@ -245,7 +245,7 @@ def test_geo_json(client: TestClient): + def test_no_content_type_is_json(client: TestClient): + response = client.post( + "/items/", +- data='{"name": "Foo", "price": 50.5}', ++ content='{"name": "Foo", "price": 50.5}', + ) + assert response.status_code == 200, response.text + assert response.json() == { +@@ -269,17 +269,19 @@ def test_wrong_headers(client: TestClient): + ] + } + +- response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) ++ response = client.post( ++ "/items/", content=data, headers={"Content-Type": "text/plain"} ++ ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + response = client.post( +- "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} ++ "/items/", content=data, headers={"Content-Type": "application/geo+json-seq"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + response = client.post( +- "/items/", data=data, headers={"Content-Type": "application/not-really-json"} ++ "/items/", content=data, headers={"Content-Type": "application/not-really-json"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict +diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py +index edccffec1e8..38ae211db36 100644 +--- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py ++++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py +@@ -3,8 +3,6 @@ + + from docs_src.cookie_params.tutorial001 import app + +-client = TestClient(app) +- + openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, +@@ -88,6 +86,7 @@ + ], + ) + def test(path, cookies, expected_status, expected_response): +- response = client.get(path, cookies=cookies) ++ client = TestClient(app, cookies=cookies) ++ response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response +diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py +index 5caa5c44003..5ad52fb5e12 100644 +--- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py ++++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py +@@ -70,14 +70,6 @@ + } + + +-@pytest.fixture(name="client") +-def get_client(): +- from docs_src.cookie_params.tutorial001_py310 import app +- +- client = TestClient(app) +- return client +- +- + @needs_py310 + @pytest.mark.parametrize( + "path,cookies,expected_status,expected_response", +@@ -94,7 +86,10 @@ def get_client(): + ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}), + ], + ) +-def test(path, cookies, expected_status, expected_response, client: TestClient): +- response = client.get(path, cookies=cookies) ++def test(path, cookies, expected_status, expected_response): ++ from docs_src.cookie_params.tutorial001_py310 import app ++ ++ client = TestClient(app, cookies=cookies) ++ response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response +diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py +index 3eb5822e288..e6da630e881 100644 +--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py ++++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py +@@ -26,7 +26,7 @@ def test_gzip_request(compress): + data = gzip.compress(data) + headers["Content-Encoding"] = "gzip" + headers["Content-Type"] = "application/json" +- response = client.post("/sum", data=data, headers=headers) ++ response = client.post("/sum", content=data, headers=headers) + assert response.json() == {"sum": n} + + +diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py +index 72bbfd27772..9b10916e588 100644 +--- a/tests/test_tutorial/test_custom_response/test_tutorial006.py ++++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py +@@ -32,6 +32,6 @@ def test_openapi_schema(): + + + def test_get(): +- response = client.get("/typer", allow_redirects=False) ++ response = client.get("/typer", follow_redirects=False) + assert response.status_code == 307, response.text + assert response.headers["location"] == "https://typer.tiangolo.com" +diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py +index ac5a76d34d0..b3e60e86a38 100644 +--- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py ++++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py +@@ -27,6 +27,6 @@ def test_openapi_schema(): + + + def test_redirect_response_class(): +- response = client.get("/fastapi", allow_redirects=False) ++ response = client.get("/fastapi", follow_redirects=False) + assert response.status_code == 307 + assert response.headers["location"] == "https://fastapi.tiangolo.com" +diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py +index 009225e8c58..0cb6ddaa330 100644 +--- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py ++++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py +@@ -27,6 +27,6 @@ def test_openapi_schema(): + + + def test_redirect_status_code(): +- response = client.get("/pydantic", allow_redirects=False) ++ response = client.get("/pydantic", follow_redirects=False) + assert response.status_code == 302 + assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/" +diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py +index 5533b295714..330b4e2c791 100644 +--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py ++++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py +@@ -47,7 +47,7 @@ def test_openapi_schema(): + + + def test_post(): +- response = client.post("/items/", data=b"this is actually not validated") ++ response = client.post("/items/", content=b"this is actually not validated") + assert response.status_code == 200, response.text + assert response.json() == { + "size": 30, +diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py +index cb5dbc8eb01..076f60b2f07 100644 +--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py ++++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py +@@ -58,7 +58,7 @@ def test_post(): + - x-men + - x-avengers + """ +- response = client.post("/items/", data=yaml_data) ++ response = client.post("/items/", content=yaml_data) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Deadpoolio", +@@ -74,7 +74,7 @@ def test_post_broken_yaml(): + x - x-men + x - x-avengers + """ +- response = client.post("/items/", data=yaml_data) ++ response = client.post("/items/", content=yaml_data) + assert response.status_code == 422, response.text + assert response.json() == {"detail": "Invalid YAML"} + +@@ -88,7 +88,7 @@ def test_post_invalid(): + - x-avengers + - sneaky: object + """ +- response = client.post("/items/", data=yaml_data) ++ response = client.post("/items/", content=yaml_data) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ +diff --git a/tests/test_tutorial/test_websockets/test_tutorial002.py b/tests/test_tutorial/test_websockets/test_tutorial002.py +index a8523c9c4fc..bb5ccbf8ef6 100644 +--- a/tests/test_tutorial/test_websockets/test_tutorial002.py ++++ b/tests/test_tutorial/test_websockets/test_tutorial002.py +@@ -4,20 +4,18 @@ + + from docs_src.websockets.tutorial002 import app + +-client = TestClient(app) +- + + def test_main(): ++ client = TestClient(app) + response = client.get("/") + assert response.status_code == 200, response.text + assert b"" in response.content + + + def test_websocket_with_cookie(): ++ client = TestClient(app, cookies={"session": "fakesession"}) + with pytest.raises(WebSocketDisconnect): +- with client.websocket_connect( +- "/items/foo/ws", cookies={"session": "fakesession"} +- ) as websocket: ++ with client.websocket_connect("/items/foo/ws") as websocket: + message = "Message one" + websocket.send_text(message) + data = websocket.receive_text() +@@ -33,6 +31,7 @@ def test_websocket_with_cookie(): + + + def test_websocket_with_header(): ++ client = TestClient(app) + with pytest.raises(WebSocketDisconnect): + with client.websocket_connect("/items/bar/ws?token=some-token") as websocket: + message = "Message one" +@@ -50,6 +49,7 @@ def test_websocket_with_header(): + + + def test_websocket_with_header_and_query(): ++ client = TestClient(app) + with pytest.raises(WebSocketDisconnect): + with client.websocket_connect("/items/2/ws?q=3&token=some-token") as websocket: + message = "Message one" +@@ -71,6 +71,7 @@ def test_websocket_with_header_and_query(): + + + def test_websocket_no_credentials(): ++ client = TestClient(app) + with pytest.raises(WebSocketDisconnect): + with client.websocket_connect("/items/foo/ws"): + pytest.fail( +@@ -79,6 +80,7 @@ def test_websocket_no_credentials(): + + + def test_websocket_invalid_data(): ++ client = TestClient(app) + with pytest.raises(WebSocketDisconnect): + with client.websocket_connect("/items/foo/ws?q=bar&token=some-token"): + pytest.fail( + +From ce5b5f7e761c96de329e5641e3f5a52dea4d859c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= +Date: Sun, 13 Nov 2022 15:18:47 +0100 +Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=85=20Fix=20data=20in=20test=20for=20?= + =?UTF-8?q?tuples=20with=20new=20client?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + tests/test_tuples.py | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/tests/test_tuples.py b/tests/test_tuples.py +index 9fa65e1def0..6e2cc0db676 100644 +--- a/tests/test_tuples.py ++++ b/tests/test_tuples.py +@@ -258,10 +258,8 @@ def test_tuple_form_valid(): + + + def test_tuple_form_invalid(): +- response = client.post( +- "/tuple-form/", content=[("values", "1"), ("values", "2"), ("values", "3")] +- ) ++ response = client.post("/tuple-form/", data={"values": ("1", "2", "3")}) + assert response.status_code == 422, response.text + +- response = client.post("/tuple-form/", content=[("values", "1")]) ++ response = client.post("/tuple-form/", data={"values": ("1")}) + assert response.status_code == 422, response.text diff --git a/python-fastapi.spec b/python-fastapi.spec index 4db3680..fdbf1e9 100644 --- a/python-fastapi.spec +++ b/python-fastapi.spec @@ -13,7 +13,7 @@ %global sum_zh FastAPI 框架 Name: python-fastapi -Version: 0.85.2 +Version: 0.86.0 Release: %autorelease Summary: %{sum_en} @@ -29,8 +29,7 @@ Patch: %{url}/pull/4409.patch # Update starlette to 0.21.0. # https://github.com/tiangolo/fastapi/pull/5471 -# Rebased on 0.85.2. -Patch: 0001-Update-starlette-to-0.21.0.patch +Patch: %{url}/pull/5471.patch BuildRequires: python3-devel @@ -337,7 +336,7 @@ sed -r -i 's/("orjson\b.*",)/# \1/' pyproject.toml # and will not be used. Also comment out the “dev” dependency on pre-commit, # which we will not use here. sed -r -i \ - -e 's/("(mypy|black|flake8|isort|autoflake|pytest-cov)\b.*",)/# \1/' \ + -e 's/("(mypy|black|flake8|isort|autoflake|coverage)\b.*",)/# \1/' \ -e 's/("(pre-commit)\b.*",)/# \1/' \ pyproject.toml # We won’t be running a type checker (mypy), so we don’t need any @@ -371,32 +370,6 @@ rm -rvf docs/*/docs/js docs/*/docs/css %check -# These leak a temporary file and fail with a ResourceWarning. Report it -# upstream if it can be reproduced on the latest version in a virtualenv. -# -# FAILED tests/test_tutorial/test_request_files/test_tutorial001.py::test_post_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001.py::test_post_large_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_02.py::test_post_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_02.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py::test_post_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_03.py::test_post_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial001_03.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial002.py::test_post_files -# FAILED tests/test_tutorial/test_request_files/test_tutorial002.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial002_py39.py::test_post_files -# FAILED tests/test_tutorial/test_request_files/test_tutorial002_py39.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial003.py::test_post_files -# FAILED tests/test_tutorial/test_request_files/test_tutorial003.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_files/test_tutorial003_py39.py::test_post_files -# FAILED tests/test_tutorial/test_request_files/test_tutorial003_py39.py::test_post_upload_file -# FAILED tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py::test_post_files_and_token -k="${k-}${k+ and }not test_post_file" -k="${k-}${k+ and }not test_post_large_file" -k="${k-}${k+ and }not test_post_upload_file" -k="${k-}${k+ and }not test_post_files_and_token" - # tests/test_tutorial/test_async_sql_databases/test_tutorial001.py::test_create_read # fails with “ValueError: not enough values to unpack (expected 5, got 4)” # while unpacking context.result_column struct in sqlalchemy.engine.cursor. diff --git a/sources b/sources index 94631ef..9722478 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (fastapi-0.85.2.tar.gz) = 6b8ae2b7cc30b4ebbe6d6bd8c41a8eb68ff5fabb4084c4ea15f8fe56d1fae76e7295fa8ce8eea06c8e96bd73ed14f8dffd4eaadc3b9d0df6646c19510d86cde5 +SHA512 (fastapi-0.86.0.tar.gz) = d2ea8ec0085d90c8dfe2216444eec1478869651b750b7ea660c93b36ea6fe3a9721bd84973587601d94fd433d9e20b19d92a3c86143b74c0740fe063cb746d45