Skip to content

Instantly share code, notes, and snippets.

@laurent-laporte-pro
Last active October 13, 2023 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laurent-laporte-pro/af348ae1eb8414935373a659e236a013 to your computer and use it in GitHub Desktop.
Save laurent-laporte-pro/af348ae1eb8414935373a659e236a013 to your computer and use it in GitHub Desktop.
Metaclass that makes all fields of a Pydantic model optional.
from typing import Any, Dict, Optional, Tuple, Type
import pydantic.main
class AllOptionalMetaclass(pydantic.main.ModelMetaclass):
"""
Metaclass that makes all fields of a Pydantic model optional.
This metaclass modifies the class's annotations to make all fields
optional by wrapping them with the `Optional` type.
Usage:
class MyModel(BaseModel, metaclass=AllOptionalMetaclass):
field1: str
field2: int
...
The fields defined in the model will be automatically converted to optional
fields, allowing instances of the model to be created even if not all fields
are provided during initialization.
"""
def __new__(
cls: Type["AllOptionalMetaclass"],
name: str,
bases: Tuple[Type[Any], ...],
namespaces: Dict[str, Any],
**kwargs: Dict[str, Any],
) -> Any:
annotations = namespaces.get("__annotations__", {})
for base in bases:
for ancestor in base.__mro__:
annotations.update(getattr(ancestor, "__annotations__", {}))
for field, field_type in annotations.items():
if not field.startswith("__"):
# Optional fields are correctly handled
annotations[field] = Optional[annotations[field]]
namespaces["__annotations__"] = annotations
return super().__new__(cls, name, bases, namespaces)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment