Browse Source
v0.128.0 introduced non-deterministic openapi spec schema naming in the case of multiple pydantic models with the same name. Commit [pull/14797/heade300630](e300630551 (diff-1086603fdd56511aafd1d279396b142b803e48164327148e6de26cef4cdaed81L504))removed the check for conflicting names. The component names two classes named `User` would randomly be either ``` User tests__test_duplicate_model_names_openapi__b__model__User ``` ``` tests__test_duplicate_model_names_openapi__a__model__User User ``` With this change, we reintroduce the conflict check to always use a hash of the fully qualified names in case of conflict.
10 changed files with 155 additions and 1 deletions
@ -0,0 +1,5 @@ |
|||||
|
from pydantic import BaseModel |
||||
|
|
||||
|
|
||||
|
class User(BaseModel): |
||||
|
a: int |
||||
@ -0,0 +1,19 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
|
||||
|
from tests.test_duplicate_model_names_openapi.a.model import User as UserA |
||||
|
from tests.test_duplicate_model_names_openapi.b.model import User as UserB |
||||
|
from tests.test_duplicate_model_names_openapi.c.model import User as UserC |
||||
|
|
||||
|
app = FastAPI() |
||||
|
|
||||
|
|
||||
|
@app.get("/a", response_model=UserA) |
||||
|
def user_a(): ... |
||||
|
|
||||
|
|
||||
|
@app.get("/b", response_model=UserB) |
||||
|
def user_b(): ... |
||||
|
|
||||
|
|
||||
|
@app.get("/c", response_model=UserC) |
||||
|
def user_c(): ... |
||||
@ -0,0 +1,5 @@ |
|||||
|
from pydantic import BaseModel |
||||
|
|
||||
|
|
||||
|
class User(BaseModel): |
||||
|
b: int |
||||
@ -0,0 +1,5 @@ |
|||||
|
from pydantic import BaseModel |
||||
|
|
||||
|
|
||||
|
class User(BaseModel): |
||||
|
c: int |
||||
@ -0,0 +1,105 @@ |
|||||
|
import json |
||||
|
|
||||
|
from fastapi.testclient import TestClient |
||||
|
|
||||
|
from .app import app |
||||
|
|
||||
|
client = TestClient(app) |
||||
|
|
||||
|
|
||||
|
def test_openapi_schema(): |
||||
|
response = client.get("/openapi.json") |
||||
|
assert response.status_code == 200, response.text |
||||
|
|
||||
|
schema = response.json() |
||||
|
component_names = schema["components"]["schemas"].keys() |
||||
|
|
||||
|
# Hashed fully qualified names due to conflict |
||||
|
assert set(component_names) == { |
||||
|
"User_46cbb9d5ba5400ba253a3caa105ccc482d1388ff", |
||||
|
"User_42908c96f764fbf5360c1ae9d3a2a96d90d97bef", |
||||
|
"User_3c4b81c0ed34bf97eb9b4ac8ced9dc17e0dccbb7", |
||||
|
} |
||||
|
|
||||
|
assert schema == { |
||||
|
"openapi": "3.1.0", |
||||
|
"info": {"title": "FastAPI", "version": "0.1.0"}, |
||||
|
"paths": { |
||||
|
"/a": { |
||||
|
"get": { |
||||
|
"summary": "User A", |
||||
|
"operationId": "user_a_a_get", |
||||
|
"responses": { |
||||
|
"200": { |
||||
|
"description": "Successful Response", |
||||
|
"content": { |
||||
|
"application/json": { |
||||
|
"schema": { |
||||
|
"$ref": "#/components/schemas/User_42908c96f764fbf5360c1ae9d3a2a96d90d97bef" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
"/b": { |
||||
|
"get": { |
||||
|
"summary": "User B", |
||||
|
"operationId": "user_b_b_get", |
||||
|
"responses": { |
||||
|
"200": { |
||||
|
"description": "Successful Response", |
||||
|
"content": { |
||||
|
"application/json": { |
||||
|
"schema": { |
||||
|
"$ref": "#/components/schemas/User_3c4b81c0ed34bf97eb9b4ac8ced9dc17e0dccbb7" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
"/c": { |
||||
|
"get": { |
||||
|
"summary": "User C", |
||||
|
"operationId": "user_c_c_get", |
||||
|
"responses": { |
||||
|
"200": { |
||||
|
"description": "Successful Response", |
||||
|
"content": { |
||||
|
"application/json": { |
||||
|
"schema": { |
||||
|
"$ref": "#/components/schemas/User_46cbb9d5ba5400ba253a3caa105ccc482d1388ff" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
"components": { |
||||
|
"schemas": { |
||||
|
"User_3c4b81c0ed34bf97eb9b4ac8ced9dc17e0dccbb7": { |
||||
|
"properties": {"b": {"type": "integer", "title": "B"}}, |
||||
|
"type": "object", |
||||
|
"required": ["b"], |
||||
|
"title": "User", |
||||
|
}, |
||||
|
"User_42908c96f764fbf5360c1ae9d3a2a96d90d97bef": { |
||||
|
"properties": {"a": {"type": "integer", "title": "A"}}, |
||||
|
"type": "object", |
||||
|
"required": ["a"], |
||||
|
"title": "User", |
||||
|
}, |
||||
|
"User_46cbb9d5ba5400ba253a3caa105ccc482d1388ff": { |
||||
|
"properties": {"c": {"type": "integer", "title": "C"}}, |
||||
|
"type": "object", |
||||
|
"required": ["c"], |
||||
|
"title": "User", |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
Loading…
Reference in new issue