Coverage for pydantic/root_model.py: 100.00%
54 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-15 15:02 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-15 15:02 +0000
1"""RootModel class and type definitions."""
3from __future__ import annotations as _annotations 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
5import typing 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
6from copy import copy, deepcopy 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
8from pydantic_core import PydanticUndefined 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
10from . import PydanticUserError 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
11from ._internal import _model_construction, _repr 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
12from .main import BaseModel, _object_setattr 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
14if typing.TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
15 from typing import Any, Literal
17 from typing_extensions import Self, dataclass_transform
19 from .fields import Field as PydanticModelField
20 from .fields import PrivateAttr as PydanticModelPrivateAttr
22 # dataclass_transform could be applied to RootModel directly, but `ModelMetaclass`'s dataclass_transform
23 # takes priority (at least with pyright). We trick type checkers into thinking we apply dataclass_transform
24 # on a new metaclass.
25 @dataclass_transform(kw_only_default=False, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr))
26 class _RootModelMetaclass(_model_construction.ModelMetaclass): ...
27else:
28 _RootModelMetaclass = _model_construction.ModelMetaclass 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
30__all__ = ('RootModel',) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
32RootModelRootType = typing.TypeVar('RootModelRootType') 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
35class RootModel(BaseModel, typing.Generic[RootModelRootType], metaclass=_RootModelMetaclass): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
36 """!!! abstract "Usage Documentation"
37 [`RootModel` and Custom Root Types](../concepts/models.md#rootmodel-and-custom-root-types)
39 A Pydantic `BaseModel` for the root object of the model.
41 Attributes:
42 root: The root object of the model.
43 __pydantic_root_model__: Whether the model is a RootModel.
44 __pydantic_private__: Private fields in the model.
45 __pydantic_extra__: Extra fields in the model.
47 """
49 __pydantic_root_model__ = True 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
50 __pydantic_private__ = None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
51 __pydantic_extra__ = None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
53 root: RootModelRootType 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
55 def __init_subclass__(cls, **kwargs): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
56 extra = cls.model_config.get('extra') 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
57 if extra is not None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
58 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
59 "`RootModel` does not support setting `model_config['extra']`", code='root-model-extra'
60 )
61 super().__init_subclass__(**kwargs) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
63 def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None: # type: ignore 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
64 __tracebackhide__ = True 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
65 if data: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
66 if root is not PydanticUndefined: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
67 raise ValueError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
68 '"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments'
69 )
70 root = data # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
71 self.__pydantic_validator__.validate_python(root, self_instance=self) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
73 __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
75 @classmethod 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
76 def model_construct(cls, root: RootModelRootType, _fields_set: set[str] | None = None) -> Self: # type: ignore 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
77 """Create a new model using the provided root object and update fields set.
79 Args:
80 root: The root object of the model.
81 _fields_set: The set of fields to be updated.
83 Returns:
84 The new model.
86 Raises:
87 NotImplemented: If the model is not a subclass of `RootModel`.
88 """
89 return super().model_construct(root=root, _fields_set=_fields_set) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
91 def __getstate__(self) -> dict[Any, Any]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
92 return { 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
93 '__dict__': self.__dict__,
94 '__pydantic_fields_set__': self.__pydantic_fields_set__,
95 }
97 def __setstate__(self, state: dict[Any, Any]) -> None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
98 _object_setattr(self, '__pydantic_fields_set__', state['__pydantic_fields_set__']) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
99 _object_setattr(self, '__dict__', state['__dict__']) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
101 def __copy__(self) -> Self: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
102 """Returns a shallow copy of the model."""
103 cls = type(self) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
104 m = cls.__new__(cls) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
105 _object_setattr(m, '__dict__', copy(self.__dict__)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
106 _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
107 return m 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
109 def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
110 """Returns a deep copy of the model."""
111 cls = type(self) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
112 m = cls.__new__(cls) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
113 _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
114 # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str],
115 # and attempting a deepcopy would be marginally slower.
116 _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
117 return m 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
119 if typing.TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
121 def model_dump( # type: ignore
122 self,
123 *,
124 mode: Literal['json', 'python'] | str = 'python',
125 include: Any = None,
126 exclude: Any = None,
127 context: dict[str, Any] | None = None,
128 by_alias: bool | None = None,
129 exclude_unset: bool = False,
130 exclude_defaults: bool = False,
131 exclude_none: bool = False,
132 round_trip: bool = False,
133 warnings: bool | Literal['none', 'warn', 'error'] = True,
134 serialize_as_any: bool = False,
135 ) -> Any:
136 """This method is included just to get a more accurate return type for type checkers.
137 It is included in this `if TYPE_CHECKING:` block since no override is actually necessary.
139 See the documentation of `BaseModel.model_dump` for more details about the arguments.
141 Generally, this method will have a return type of `RootModelRootType`, assuming that `RootModelRootType` is
142 not a `BaseModel` subclass. If `RootModelRootType` is a `BaseModel` subclass, then the return
143 type will likely be `dict[str, Any]`, as `model_dump` calls are recursive. The return type could
144 even be something different, in the case of a custom serializer.
145 Thus, `Any` is used here to catch all of these cases.
146 """
147 ...
149 def __eq__(self, other: Any) -> bool: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
150 if not isinstance(other, RootModel): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
151 return NotImplemented 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
152 return self.__pydantic_fields__['root'].annotation == other.__pydantic_fields__[ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
153 'root'
154 ].annotation and super().__eq__(other)
156 def __repr_args__(self) -> _repr.ReprArgs: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO
157 yield 'root', self.root 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO