pythonasyncioapiasyncfastapiframeworkjsonjson-schemaopenapiopenapi3pydanticpython-typespython3redocreststarletteswaggerswagger-uiuvicornweb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.5 KiB
112 lines
3.5 KiB
"""
|
|
FastAPI schema utilities including PropertyNames constraint support.
|
|
"""
|
|
|
|
from typing import Any, Dict, Optional, Union
|
|
from pydantic import BaseModel
|
|
from pydantic.fields import FieldInfo
|
|
|
|
|
|
class PropertyNames:
|
|
"""
|
|
A constraint class for specifying propertyNames validation in JSON Schema.
|
|
|
|
This allows developers to specify patterns or schemas that all property names
|
|
in a dictionary/object must match.
|
|
|
|
Examples:
|
|
# Pattern-based constraint
|
|
PropertyNames(pattern="^prefix_")
|
|
|
|
# Schema-based constraint
|
|
PropertyNames(min_length=3, max_length=50)
|
|
|
|
# Complex schema constraint
|
|
PropertyNames(schema={"type": "string", "enum": ["key1", "key2", "key3"]})
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
pattern: Optional[str] = None,
|
|
min_length: Optional[int] = None,
|
|
max_length: Optional[int] = None,
|
|
schema: Optional[Dict[str, Any]] = None,
|
|
**kwargs: Any
|
|
):
|
|
"""
|
|
Initialize PropertyNames constraint.
|
|
|
|
Args:
|
|
pattern: Regular expression pattern that property names must match
|
|
min_length: Minimum length for property names
|
|
max_length: Maximum length for property names
|
|
schema: Custom JSON schema for property names validation
|
|
**kwargs: Additional JSON schema properties
|
|
"""
|
|
self.constraint_schema: Dict[str, Any] = {}
|
|
|
|
if pattern is not None:
|
|
self.constraint_schema["pattern"] = pattern
|
|
|
|
if min_length is not None:
|
|
self.constraint_schema["minLength"] = min_length
|
|
|
|
if max_length is not None:
|
|
self.constraint_schema["maxLength"] = max_length
|
|
|
|
if schema is not None:
|
|
self.constraint_schema.update(schema)
|
|
|
|
# Add any additional properties
|
|
for key, value in kwargs.items():
|
|
if value is not None:
|
|
self.constraint_schema[key] = value
|
|
|
|
if not self.constraint_schema:
|
|
raise ValueError("PropertyNames constraint must specify at least one validation rule")
|
|
|
|
def get_constraint_schema(self) -> Dict[str, Any]:
|
|
"""Get the JSON schema representation of this constraint."""
|
|
return self.constraint_schema.copy()
|
|
|
|
def __repr__(self) -> str:
|
|
return f"PropertyNames({self.constraint_schema})"
|
|
|
|
|
|
def get_property_names_constraint(field_info: FieldInfo) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Extract PropertyNames constraint from field metadata.
|
|
|
|
Args:
|
|
field_info: Pydantic FieldInfo object
|
|
|
|
Returns:
|
|
PropertyNames constraint schema or None if not found
|
|
"""
|
|
if not hasattr(field_info, 'metadata') or not field_info.metadata:
|
|
return None
|
|
|
|
for metadata_item in field_info.metadata:
|
|
if isinstance(metadata_item, PropertyNames):
|
|
return metadata_item.get_constraint_schema()
|
|
|
|
return None
|
|
|
|
|
|
def apply_property_names_to_schema(
|
|
schema: Dict[str, Any],
|
|
property_names_constraint: Dict[str, Any]
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Apply PropertyNames constraint to a JSON schema.
|
|
|
|
Args:
|
|
schema: The JSON schema to modify
|
|
property_names_constraint: The propertyNames constraint to apply
|
|
|
|
Returns:
|
|
Modified schema with propertyNames constraint
|
|
"""
|
|
if schema.get("type") == "object":
|
|
schema["propertyNames"] = property_names_constraint
|
|
return schema
|
|
|