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

"""
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