From 687065509b047a642acd1d281d6d68c6698509b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 28 Jun 2019 19:35:16 +0200 Subject: [PATCH] :building_construction: Fix same function names in different modules with composite bodies (#347) * :building_construction: Implement unique IDs for dynamic models like those used for composite bodies and responses. IDs based on path (not only on function name, as it can be duplicated in a different module). * :white_check_mark: Add tests for same function name and composite body * :white_check_mark: Update OpenAPI in tests with new dynamic model ID generation --- fastapi/openapi/utils.py | 11 +- fastapi/routing.py | 19 ++- fastapi/utils.py | 7 + tests/test_modules_same_name_body/__init__.py | 0 .../app/__init__.py | 0 tests/test_modules_same_name_body/app/a.py | 8 + tests/test_modules_same_name_body/app/b.py | 8 + tests/test_modules_same_name_body/app/main.py | 8 + .../test_modules_same_name_body/test_main.py | 155 ++++++++++++++++++ tests/test_security_oauth2.py | 6 +- tests/test_security_oauth2_optional.py | 6 +- .../test_tutorial001.py | 2 +- .../test_tutorial003.py | 8 +- .../test_body_schema/test_tutorial001.py | 8 +- .../test_extra_data_types/test_tutorial001.py | 8 +- .../test_extra_models/test_tutorial003.py | 2 +- .../test_extra_models/test_tutorial004.py | 2 +- .../test_extra_models/test_tutorial005.py | 2 +- .../test_request_files/test_tutorial001.py | 14 +- .../test_request_files/test_tutorial002.py | 14 +- .../test_request_forms/test_tutorial001.py | 8 +- .../test_tutorial001.py | 8 +- .../test_security/test_tutorial003.py | 8 +- .../test_security/test_tutorial005.py | 18 +- .../test_sql_databases/test_sql_databases.py | 4 +- 25 files changed, 270 insertions(+), 64 deletions(-) create mode 100644 tests/test_modules_same_name_body/__init__.py create mode 100644 tests/test_modules_same_name_body/app/__init__.py create mode 100644 tests/test_modules_same_name_body/app/a.py create mode 100644 tests/test_modules_same_name_body/app/b.py create mode 100644 tests/test_modules_same_name_body/app/main.py create mode 100644 tests/test_modules_same_name_body/test_main.py diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 8d02a4751..7786e2527 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -8,7 +8,11 @@ from fastapi.encoders import jsonable_encoder from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX from fastapi.openapi.models import OpenAPI from fastapi.params import Body, Param -from fastapi.utils import get_flat_models_from_routes, get_model_definitions +from fastapi.utils import ( + generate_operation_id_for_path, + get_flat_models_from_routes, + get_model_definitions, +) from pydantic.fields import Field from pydantic.schema import field_schema, get_model_name_map from pydantic.utils import lenient_issubclass @@ -113,10 +117,7 @@ def generate_operation_id(*, route: routing.APIRoute, method: str) -> str: if route.operation_id: return route.operation_id path: str = route.path_format - operation_id = route.name + path - operation_id = operation_id.replace("{", "_").replace("}", "_").replace("/", "_") - operation_id = operation_id + "_" + method.lower() - return operation_id + return generate_operation_id_for_path(name=route.name, path=path, method=method) def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str: diff --git a/fastapi/routing.py b/fastapi/routing.py index e349787d7..8eb6f47fa 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -13,7 +13,7 @@ from fastapi.dependencies.utils import ( ) from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.utils import create_cloned_field +from fastapi.utils import create_cloned_field, generate_operation_id_for_path from pydantic import BaseConfig, BaseModel, Schema from pydantic.error_wrappers import ErrorWrapper, ValidationError from pydantic.fields import Field @@ -205,12 +205,19 @@ class APIRoute(routing.Route): self.path = path self.endpoint = endpoint self.name = get_name(endpoint) if name is None else name + self.path_regex, self.path_format, self.param_convertors = compile_path(path) + if methods is None: + methods = ["GET"] + self.methods = set([method.upper() for method in methods]) + self.unique_id = generate_operation_id_for_path( + name=self.name, path=self.path_format, method=list(methods)[0] + ) self.response_model = response_model if self.response_model: assert lenient_issubclass( response_class, JSONResponse ), "To declare a type the response must be a JSON response" - response_name = "Response_" + self.name + response_name = "Response_" + self.unique_id self.response_field: Optional[Field] = Field( name=response_name, type_=self.response_model, @@ -251,7 +258,7 @@ class APIRoute(routing.Route): assert lenient_issubclass( model, BaseModel ), "A response model must be a Pydantic model" - response_name = f"Response_{additional_status_code}_{self.name}" + response_name = f"Response_{additional_status_code}_{self.unique_id}" response_field = Field( name=response_name, type_=model, @@ -267,9 +274,6 @@ class APIRoute(routing.Route): else: self.response_fields = {} self.deprecated = deprecated - if methods is None: - methods = ["GET"] - self.methods = set([method.upper() for method in methods]) self.operation_id = operation_id self.response_model_include = response_model_include self.response_model_exclude = response_model_exclude @@ -278,7 +282,6 @@ class APIRoute(routing.Route): self.include_in_schema = include_in_schema self.response_class = response_class - self.path_regex, self.path_format, self.param_convertors = compile_path(path) assert inspect.isfunction(endpoint) or inspect.ismethod( endpoint ), f"An endpoint must be a function or method" @@ -288,7 +291,7 @@ class APIRoute(routing.Route): 0, get_parameterless_sub_dependant(depends=depends, path=self.path_format), ) - self.body_field = get_body_field(dependant=self.dependant, name=self.name) + self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id) self.dependency_overrides_provider = dependency_overrides_provider self.app = request_response( get_app( diff --git a/fastapi/utils.py b/fastapi/utils.py index 21bca1d3f..fc3bc7289 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -93,3 +93,10 @@ def create_cloned_field(field: Field) -> Field: new_field.shape = field.shape new_field._populate_validators() return new_field + + +def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str: + operation_id = name + path + operation_id = operation_id.replace("{", "_").replace("}", "_").replace("/", "_") + operation_id = operation_id + "_" + method.lower() + return operation_id diff --git a/tests/test_modules_same_name_body/__init__.py b/tests/test_modules_same_name_body/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_modules_same_name_body/app/__init__.py b/tests/test_modules_same_name_body/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_modules_same_name_body/app/a.py b/tests/test_modules_same_name_body/app/a.py new file mode 100644 index 000000000..3c86c1865 --- /dev/null +++ b/tests/test_modules_same_name_body/app/a.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter, Body + +router = APIRouter() + + +@router.post("/compute") +def compute(a: int = Body(...), b: str = Body(...)): + return {"a": a, "b": b} diff --git a/tests/test_modules_same_name_body/app/b.py b/tests/test_modules_same_name_body/app/b.py new file mode 100644 index 000000000..f7c7fdfc6 --- /dev/null +++ b/tests/test_modules_same_name_body/app/b.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter, Body + +router = APIRouter() + + +@router.post("/compute/") +def compute(a: int = Body(...), b: str = Body(...)): + return {"a": a, "b": b} diff --git a/tests/test_modules_same_name_body/app/main.py b/tests/test_modules_same_name_body/app/main.py new file mode 100644 index 000000000..392360899 --- /dev/null +++ b/tests/test_modules_same_name_body/app/main.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +from . import a, b + +app = FastAPI() + +app.include_router(a.router, prefix="/a") +app.include_router(b.router, prefix="/b") diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py new file mode 100644 index 000000000..bf50b7566 --- /dev/null +++ b/tests/test_modules_same_name_body/test_main.py @@ -0,0 +1,155 @@ +from starlette.testclient import TestClient + +from .app.main import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "Fast API", "version": "0.1.0"}, + "paths": { + "/a/compute": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Compute", + "operationId": "compute_a_compute_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_compute_a_compute_post" + } + } + }, + "required": True, + }, + } + }, + "/b/compute/": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Compute", + "operationId": "compute_b_compute__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_compute_b_compute__post" + } + } + }, + "required": True, + }, + } + }, + }, + "components": { + "schemas": { + "Body_compute_b_compute__post": { + "title": "Body_compute_b_compute__post", + "required": ["a", "b"], + "type": "object", + "properties": { + "a": {"title": "A", "type": "integer"}, + "b": {"title": "B", "type": "string"}, + }, + }, + "Body_compute_a_compute_post": { + "title": "Body_compute_a_compute_post", + "required": ["a", "b"], + "type": "object", + "properties": { + "a": {"title": "A", "type": "integer"}, + "b": {"title": "B", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_post_a(): + data = {"a": 2, "b": "foo"} + response = client.post("/a/compute", json=data) + assert response.status_code == 200 + data = response.json() + + +def test_post_a_invalid(): + data = {"a": "bar", "b": "foo"} + response = client.post("/a/compute", json=data) + assert response.status_code == 422 + + +def test_post_b(): + data = {"a": 2, "b": "foo"} + response = client.post("/b/compute/", json=data) + assert response.status_code == 200 + data = response.json() + + +def test_post_b_invalid(): + data = {"a": "bar", "b": "foo"} + response = client.post("/b/compute/", json=data) + assert response.status_code == 422 diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py index 08f610f93..890613b29 100644 --- a/tests/test_security_oauth2.py +++ b/tests/test_security_oauth2.py @@ -66,7 +66,7 @@ openapi_schema = { "content": { "application/x-www-form-urlencoded": { "schema": { - "$ref": "#/components/schemas/Body_read_current_user" + "$ref": "#/components/schemas/Body_read_current_user_login_post" } } }, @@ -90,8 +90,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_read_current_user": { - "title": "Body_read_current_user", + "Body_read_current_user_login_post": { + "title": "Body_read_current_user_login_post", "required": ["grant_type", "username", "password"], "type": "object", "properties": { diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py index e585e2927..f85db00d3 100644 --- a/tests/test_security_oauth2_optional.py +++ b/tests/test_security_oauth2_optional.py @@ -73,7 +73,7 @@ openapi_schema = { "content": { "application/x-www-form-urlencoded": { "schema": { - "$ref": "#/components/schemas/Body_read_current_user" + "$ref": "#/components/schemas/Body_read_current_user_login_post" } } }, @@ -97,8 +97,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_read_current_user": { - "title": "Body_read_current_user", + "Body_read_current_user_login_post": { + "title": "Body_read_current_user_login_post", "required": ["grant_type", "username", "password"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py index d7ceb6642..be5f56dbd 100644 --- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py @@ -14,7 +14,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Notes", + "title": "Response_Read_Notes_Notes__Get", "type": "array", "items": {"$ref": "#/components/schemas/Note"}, } diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py index 9a1c56bc2..dc7e518e2 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py @@ -40,7 +40,9 @@ openapi_schema = { "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Body_update_item"} + "schema": { + "$ref": "#/components/schemas/Body_update_item_items__item_id__put" + } } }, "required": True, @@ -70,8 +72,8 @@ openapi_schema = { "full_name": {"title": "Full_Name", "type": "string"}, }, }, - "Body_update_item": { - "title": "Body_update_item", + "Body_update_item_items__item_id__put": { + "title": "Body_update_item_items__item_id__put", "required": ["item", "user", "importance"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_body_schema/test_tutorial001.py b/tests/test_tutorial/test_body_schema/test_tutorial001.py index c213fab1c..eb9388396 100644 --- a/tests/test_tutorial/test_body_schema/test_tutorial001.py +++ b/tests/test_tutorial/test_body_schema/test_tutorial001.py @@ -41,7 +41,9 @@ openapi_schema = { "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Body_update_item"} + "schema": { + "$ref": "#/components/schemas/Body_update_item_items__item_id__put" + } } }, "required": True, @@ -71,8 +73,8 @@ openapi_schema = { "tax": {"title": "Tax", "type": "number"}, }, }, - "Body_update_item": { - "title": "Body_update_item", + "Body_update_item_items__item_id__put": { + "title": "Body_update_item_items__item_id__put", "required": ["item"], "type": "object", "properties": {"item": {"$ref": "#/components/schemas/Item"}}, diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py index 921b24aad..6c53b7adc 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py @@ -44,7 +44,9 @@ openapi_schema = { "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Body_read_items"} + "schema": { + "$ref": "#/components/schemas/Body_read_items_items__item_id__put" + } } } }, @@ -53,8 +55,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_read_items": { - "title": "Body_read_items", + "Body_read_items_items__item_id__put": { + "title": "Body_read_items_items__item_id__put", "type": "object", "properties": { "start_datetime": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py index 9a1c8a146..95aef55cb 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py @@ -16,7 +16,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Item", + "title": "Response_Read_Item_Items__Item_Id__Get", "anyOf": [ {"$ref": "#/components/schemas/PlaneItem"}, {"$ref": "#/components/schemas/CarItem"}, diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py index 82a609e01..17ea0e1be 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial004.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py @@ -16,7 +16,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Items", + "title": "Response_Read_Items_Items__Get", "type": "array", "items": {"$ref": "#/components/schemas/Item"}, } diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py index efb319bd2..d8259f1cd 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py @@ -16,7 +16,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Keyword_Weights", + "title": "Response_Read_Keyword_Weights_Keyword-Weights__Get", "type": "object", "additionalProperties": {"type": "number"}, } diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index 726691662..b5f64af95 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -33,7 +33,9 @@ openapi_schema = { "requestBody": { "content": { "multipart/form-data": { - "schema": {"$ref": "#/components/schemas/Body_create_file"} + "schema": { + "$ref": "#/components/schemas/Body_create_file_files__post" + } } }, "required": True, @@ -64,7 +66,7 @@ openapi_schema = { "content": { "multipart/form-data": { "schema": { - "$ref": "#/components/schemas/Body_create_upload_file" + "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post" } } }, @@ -75,16 +77,16 @@ openapi_schema = { }, "components": { "schemas": { - "Body_create_file": { - "title": "Body_create_file", + "Body_create_upload_file_uploadfile__post": { + "title": "Body_create_upload_file_uploadfile__post", "required": ["file"], "type": "object", "properties": { "file": {"title": "File", "type": "string", "format": "binary"} }, }, - "Body_create_upload_file": { - "title": "Body_create_upload_file", + "Body_create_file_files__post": { + "title": "Body_create_file_files__post", "required": ["file"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 15ea952ba..092b9901c 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -33,7 +33,9 @@ openapi_schema = { "requestBody": { "content": { "multipart/form-data": { - "schema": {"$ref": "#/components/schemas/Body_create_files"} + "schema": { + "$ref": "#/components/schemas/Body_create_files_files__post" + } } }, "required": True, @@ -64,7 +66,7 @@ openapi_schema = { "content": { "multipart/form-data": { "schema": { - "$ref": "#/components/schemas/Body_create_upload_files" + "$ref": "#/components/schemas/Body_create_upload_files_uploadfiles__post" } } }, @@ -87,8 +89,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_create_files": { - "title": "Body_create_files", + "Body_create_upload_files_uploadfiles__post": { + "title": "Body_create_upload_files_uploadfiles__post", "required": ["files"], "type": "object", "properties": { @@ -99,8 +101,8 @@ openapi_schema = { } }, }, - "Body_create_upload_files": { - "title": "Body_create_upload_files", + "Body_create_files_files__post": { + "title": "Body_create_files_files__post", "required": ["files"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py index fe85628ac..46c926767 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py @@ -32,7 +32,9 @@ openapi_schema = { "requestBody": { "content": { "application/x-www-form-urlencoded": { - "schema": {"$ref": "#/components/schemas/Body_login"} + "schema": { + "$ref": "#/components/schemas/Body_login_login__post" + } } }, "required": True, @@ -42,8 +44,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_login": { - "title": "Body_login", + "Body_login_login__post": { + "title": "Body_login_login__post", "required": ["username", "password"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index eea945937..a30fbf60f 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -34,7 +34,9 @@ openapi_schema = { "requestBody": { "content": { "multipart/form-data": { - "schema": {"$ref": "#/components/schemas/Body_create_file"} + "schema": { + "$ref": "#/components/schemas/Body_create_file_files__post" + } } }, "required": True, @@ -44,8 +46,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_create_file": { - "title": "Body_create_file", + "Body_create_file_files__post": { + "title": "Body_create_file_files__post", "required": ["file", "fileb", "token"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index c55e7b7a6..ebd8731ab 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -31,7 +31,9 @@ openapi_schema = { "requestBody": { "content": { "application/x-www-form-urlencoded": { - "schema": {"$ref": "#/components/schemas/Body_login"} + "schema": { + "$ref": "#/components/schemas/Body_login_token_post" + } } }, "required": True, @@ -54,8 +56,8 @@ openapi_schema = { }, "components": { "schemas": { - "Body_login": { - "title": "Body_login", + "Body_login_token_post": { + "title": "Body_login_token_post", "required": ["username", "password"], "type": "object", "properties": { diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index 403130e49..786fbc3ac 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -42,7 +42,7 @@ openapi_schema = { "content": { "application/x-www-form-urlencoded": { "schema": { - "$ref": "#/components/schemas/Body_login_for_access_token" + "$ref": "#/components/schemas/Body_login_for_access_token_token_post" } } }, @@ -116,8 +116,8 @@ openapi_schema = { "token_type": {"title": "Token_Type", "type": "string"}, }, }, - "Body_login_for_access_token": { - "title": "Body_login_for_access_token", + "Body_login_for_access_token_token_post": { + "title": "Body_login_for_access_token_token_post", "required": ["username", "password"], "type": "object", "properties": { @@ -177,6 +177,12 @@ openapi_schema = { } +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + def get_access_token(username="johndoe", password="secret", scope=None): data = {"username": username, "password": password} if scope: @@ -187,12 +193,6 @@ def get_access_token(username="johndoe", password="secret", scope=None): return access_token -def test_openapi_schema(): - response = client.get("/openapi.json") - assert response.status_code == 200 - assert response.json() == openapi_schema - - def test_login(): response = client.post("/token", data={"username": "johndoe", "password": "secret"}) assert response.status_code == 200 diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py index 9e1dcc2bb..8f46a9437 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py @@ -16,7 +16,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Users", + "title": "Response_Read_Users_Users__Get", "type": "array", "items": {"$ref": "#/components/schemas/User"}, } @@ -168,7 +168,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response_Read_Items", + "title": "Response_Read_Items_Items__Get", "type": "array", "items": {"$ref": "#/components/schemas/Item"}, }