* 🚚 Refactor deprecated import general_plain_validator_function to with_info_plain_validator_function
* 🚚 Rename deprecated FieldValidationInfo to ValidationInfo
* ✅ Update tests with new defaults for JSON Schema for default values
* ♻️ Add Pydantic v1 version of with_info_plain_validator_function
* 👷 Invalidate cache
* ✅ Fix tests for Pydantic v1
* ✅ Tweak tests coverage for older Pydantic v2 versions
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v05
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v06
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v05
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v06
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
from pydantic_core import CoreSchema as CoreSchema
from pydantic_core import PydanticUndefined, PydanticUndefinedType
from pydantic_core import Url as Url
- from pydantic_core.core_schema import (
- general_plain_validator_function as general_plain_validator_function,
- )
+
+ try:
+ from pydantic_core.core_schema import (
+ with_info_plain_validator_function as with_info_plain_validator_function,
+ )
+ except ImportError: # pragma: no cover
+ from pydantic_core.core_schema import (
+ general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
+ )
Required = PydanticUndefined
Undefined = PydanticUndefined
class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef]
pass
- def general_plain_validator_function( # type: ignore[misc]
+ def with_info_plain_validator_function( # type: ignore[misc]
function: Callable[..., Any],
*,
ref: Union[str, None] = None,
CoreSchema,
GetJsonSchemaHandler,
JsonSchemaValue,
- general_plain_validator_function,
+ with_info_plain_validator_function,
)
from starlette.datastructures import URL as URL # noqa: F401
from starlette.datastructures import Address as Address # noqa: F401
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
) -> CoreSchema:
- return general_plain_validator_function(cls._validate)
+ return with_info_plain_validator_function(cls._validate)
class DefaultPlaceholder:
GetJsonSchemaHandler,
JsonSchemaValue,
_model_rebuild,
- general_plain_validator_function,
+ with_info_plain_validator_function,
)
from fastapi.logger import logger
from pydantic import AnyUrl, BaseModel, Field
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
) -> CoreSchema:
- return general_plain_validator_function(cls._validate)
+ return with_info_plain_validator_function(cls._validate)
class Contact(BaseModel):
@needs_pydanticv1
-def test_upload_file_dummy_general_plain_validator_function():
+def test_upload_file_dummy_with_info_plain_validator_function():
# For coverage
assert UploadFile.__get_pydantic_core_schema__(str, lambda x: None) == {}
@pytest.fixture(name="client")
def get_client():
- from pydantic import BaseModel, FieldValidationInfo, field_validator
+ from pydantic import BaseModel, ValidationInfo, field_validator
app = FastAPI()
foo: ModelB
@field_validator("name")
- def lower_username(cls, name: str, info: FieldValidationInfo):
+ def lower_username(cls, name: str, info: ValidationInfo):
if not name.endswith("A"):
raise ValueError("name must end in A")
return name
from fastapi.testclient import TestClient
from pydantic import BaseModel
-from .utils import needs_pydanticv2
+from .utils import PYDANTIC_V2, needs_pydanticv2
class SubItem(BaseModel):
subname: str
sub_description: Optional[str] = None
tags: List[str] = []
+ if PYDANTIC_V2:
+ model_config = {"json_schema_serialization_defaults_required": True}
class Item(BaseModel):
name: str
description: Optional[str] = None
sub: Optional[SubItem] = None
+ if PYDANTIC_V2:
+ model_config = {"json_schema_serialization_defaults_required": True}
def get_app_client(separate_input_output_schemas: bool = True) -> TestClient:
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
- "title": "Item",
+ "Item": {
"type": "object",
- "properties": {
- "name": {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "description": {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "price": {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "Item-Output": {
"title": "Item",
- "type": "object",
- "required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
- "title": "Item",
+ "Item": {
"type": "object",
- "properties": {
- "name": {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "description": {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "price": {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "Item-Output": {
"title": "Item",
- "type": "object",
- "required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
- "title": "Item",
+ "Item": {
"type": "object",
- "properties": {
- "name": {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "description": {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "price": {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "Item-Output": {
"title": "Item",
- "type": "object",
- "required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"schema": {
"title": "Items",
"type": "array",
- "items": {
- "$ref": "#/components/schemas/Item-Input"
- },
+ "items": {"$ref": "#/components/schemas/Item"},
}
}
},
"schemas": {
"Author": {
"title": "Author",
- "required": ["name", "items"],
+ "required": ["name"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"items": {
"title": "Items",
"type": "array",
- "items": {"$ref": "#/components/schemas/Item-Output"},
+ "items": {"$ref": "#/components/schemas/Item"},
},
},
},
}
},
},
- "Item-Input": {
+ "Item": {
"title": "Item",
"required": ["name"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
- "title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
- },
- },
- },
- "Item-Output": {
- "title": "Item",
- "required": ["name", "description"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
"title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"description": "Successful Response",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
+ "Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
},
},
},
- "Item-Output": {
- "title": "Item",
- "required": ["name", "description", "price", "tax", "tags"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- },
- "price": {"title": "Price", "type": "number"},
- "tax": {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"description": "The created item",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
+ "Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
},
},
},
- "Item-Output": {
- "title": "Item",
- "required": ["name", "description", "price", "tax", "tags"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- "price": {"title": "Price", "type": "number"},
- "tax": {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"description": "The created item",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
+ "Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
},
},
},
- "Item-Output": {
- "title": "Item",
- "required": ["name", "description", "price", "tax", "tags"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- "price": {"title": "Price", "type": "number"},
- "tax": {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"description": "The created item",
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/Item-Output"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"components": {
"schemas": {
- "Item-Input": {
+ "Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
},
},
},
- "Item-Output": {
- "title": "Item",
- "required": ["name", "description", "price", "tax", "tags"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- "price": {"title": "Price", "type": "number"},
- "tax": {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- },
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
{
"type": "enum",
"loc": ["path", "model_name"],
- "msg": "Input should be 'alexnet','resnet' or 'lenet'",
+ "msg": "Input should be 'alexnet', 'resnet' or 'lenet'",
"input": "foo",
- "ctx": {"expected": "'alexnet','resnet' or 'lenet'"},
+ "ctx": {"expected": "'alexnet', 'resnet' or 'lenet'"},
}
]
}
"content": {
"application/json": {
"schema": {
- "items": {
- "$ref": "#/components/schemas/Item-Output"
- },
+ "items": {"$ref": "#/components/schemas/Item"},
"type": "array",
"title": "Response Read Items Items Get",
}
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
"type": "object",
"title": "HTTPValidationError",
},
- "Item-Input": {
+ "Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {
"required": ["name"],
"title": "Item",
},
- "Item-Output": {
- "properties": {
- "name": {"type": "string", "title": "Name"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- },
- "type": "object",
- "required": ["name", "description"],
- "title": "Item",
- },
"ValidationError": {
"properties": {
"loc": {
"content": {
"application/json": {
"schema": {
- "items": {
- "$ref": "#/components/schemas/Item-Output"
- },
+ "items": {"$ref": "#/components/schemas/Item"},
"type": "array",
"title": "Response Read Items Items Get",
}
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
"type": "object",
"title": "HTTPValidationError",
},
- "Item-Input": {
+ "Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {
"required": ["name"],
"title": "Item",
},
- "Item-Output": {
- "properties": {
- "name": {"type": "string", "title": "Name"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- },
- "type": "object",
- "required": ["name", "description"],
- "title": "Item",
- },
"ValidationError": {
"properties": {
"loc": {
"content": {
"application/json": {
"schema": {
- "items": {
- "$ref": "#/components/schemas/Item-Output"
- },
+ "items": {"$ref": "#/components/schemas/Item"},
"type": "array",
"title": "Response Read Items Items Get",
}
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item-Input"}
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
"type": "object",
"title": "HTTPValidationError",
},
- "Item-Input": {
+ "Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {
"required": ["name"],
"title": "Item",
},
- "Item-Output": {
- "properties": {
- "name": {"type": "string", "title": "Name"},
- "description": {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Description",
- },
- },
- "type": "object",
- "required": ["name", "description"],
- "title": "Item",
- },
"ValidationError": {
"properties": {
"loc": {