url: AnyUrl
+# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type
+SchemaType = Literal[
+ "array", "boolean", "integer", "null", "number", "object", "string"
+]
+
+
class Schema(BaseModelWithConfig):
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
# Core Vocabulary
dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None
prefixItems: Optional[List["SchemaOrBool"]] = None
# TODO: uncomment and remove below when deprecating Pydantic v1
- # It generales a list of schemas for tuples, before prefixItems was available
+ # It generates a list of schemas for tuples, before prefixItems was available
# items: Optional["SchemaOrBool"] = None
items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None
contains: Optional["SchemaOrBool"] = None
unevaluatedProperties: Optional["SchemaOrBool"] = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
# A Vocabulary for Structural Validation
- type: Optional[str] = None
+ type: Optional[Union[SchemaType, List[SchemaType]]] = None
enum: Optional[List[Any]] = None
const: Optional[Any] = None
multipleOf: Optional[float] = Field(default=None, gt=0)
+from typing import Optional
+
from fastapi import FastAPI
from fastapi._compat import PYDANTIC_V2
from fastapi.testclient import TestClient
from pydantic import BaseModel
+from typing_extensions import Annotated
+
+if PYDANTIC_V2:
+ from pydantic import WithJsonSchema
app = FastAPI()
name: str
if PYDANTIC_V2:
+ description: Annotated[
+ Optional[str], WithJsonSchema({"type": ["string", "null"]})
+ ] = None
+
model_config = {
"json_schema_extra": {
"x-something-internal": {"level": 4},
}
}
else:
+ description: Optional[str] = None # type: ignore[no-redef]
class Config:
schema_extra = {
"name": {
"title": "Name",
"type": "string",
- }
+ },
+ "description": {
+ "title": "Description",
+ "type": ["string", "null"] if PYDANTIC_V2 else "string",
+ },
},
}
# For coverage
response = client.get("/foo")
assert response.status_code == 200, response.text
- assert response.json() == {"name": "Foo item"}
+ assert response.json() == {"name": "Foo item", "description": None}
--- /dev/null
+from typing import List, Optional, Union
+
+import pytest
+from fastapi.openapi.models import Schema, SchemaType
+
+
+@pytest.mark.parametrize(
+ "type_value",
+ [
+ "array",
+ ["string", "null"],
+ None,
+ ],
+)
+def test_allowed_schema_type(
+ type_value: Optional[Union[SchemaType, List[SchemaType]]],
+) -> None:
+ """Test that Schema accepts SchemaType, List[SchemaType] and None for type field."""
+ schema = Schema(type=type_value)
+ assert schema.type == type_value
+
+
+def test_invalid_type_value() -> None:
+ """Test that Schema raises ValueError for invalid type values."""
+ with pytest.raises(ValueError, match="2 validation errors for Schema"):
+ Schema(type=True) # type: ignore[arg-type]