Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pydantic/root_model.py: 52%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

64 statements  

1"""RootModel class and type definitions.""" 

2 

3from __future__ import annotations as _annotations 

4 

5from copy import copy, deepcopy 

6from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar 

7 

8from pydantic_core import PydanticUndefined 

9from typing_extensions import Self, dataclass_transform 

10 

11from . import PydanticUserError 

12from ._internal import _model_construction, _repr 

13from .main import BaseModel, _object_setattr 

14 

15if TYPE_CHECKING: 

16 from .fields import Field as PydanticModelField 

17 from .fields import PrivateAttr as PydanticModelPrivateAttr 

18 

19 # dataclass_transform could be applied to RootModel directly, but `ModelMetaclass`'s dataclass_transform 

20 # takes priority (at least with pyright). We trick type checkers into thinking we apply dataclass_transform 

21 # on a new metaclass. 

22 @dataclass_transform(kw_only_default=False, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr)) 

23 class _RootModelMetaclass(_model_construction.ModelMetaclass): ... 

24else: 

25 _RootModelMetaclass = _model_construction.ModelMetaclass 

26 

27__all__ = ('RootModel',) 

28 

29RootModelRootType = TypeVar('RootModelRootType') 

30 

31 

32class RootModel(BaseModel, Generic[RootModelRootType], metaclass=_RootModelMetaclass): 

33 """!!! abstract "Usage Documentation" 

34 [`RootModel` and Custom Root Types](../concepts/models.md#rootmodel-and-custom-root-types) 

35 

36 A Pydantic `BaseModel` for the root object of the model. 

37 

38 Attributes: 

39 root: The root object of the model. 

40 __pydantic_root_model__: Whether the model is a RootModel. 

41 __pydantic_private__: Private fields in the model. 

42 __pydantic_extra__: Extra fields in the model. 

43 

44 """ 

45 

46 __pydantic_root_model__ = True 

47 __pydantic_private__ = None 

48 __pydantic_extra__ = None 

49 

50 root: RootModelRootType 

51 

52 def __init_subclass__(cls, **kwargs): 

53 extra = cls.model_config.get('extra') 

54 if extra is not None: 

55 raise PydanticUserError( 

56 "`RootModel` does not support setting `model_config['extra']`", code='root-model-extra' 

57 ) 

58 super().__init_subclass__(**kwargs) 

59 

60 def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None: # type: ignore 

61 __tracebackhide__ = True 

62 if data: 

63 if root is not PydanticUndefined: 

64 raise ValueError( 

65 '"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments' 

66 ) 

67 root = data # type: ignore 

68 self.__pydantic_validator__.validate_python(root, self_instance=self) 

69 

70 __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] 

71 

72 @classmethod 

73 def model_construct(cls, root: RootModelRootType, _fields_set: set[str] | None = None) -> Self: # type: ignore 

74 """Create a new model using the provided root object and update fields set. 

75 

76 Args: 

77 root: The root object of the model. 

78 _fields_set: The set of fields to be updated. 

79 

80 Returns: 

81 The new model. 

82 

83 Raises: 

84 NotImplemented: If the model is not a subclass of `RootModel`. 

85 """ 

86 return super().model_construct(root=root, _fields_set=_fields_set) 

87 

88 def __getstate__(self) -> dict[Any, Any]: 

89 return { 

90 '__dict__': self.__dict__, 

91 '__pydantic_fields_set__': self.__pydantic_fields_set__, 

92 } 

93 

94 def __setstate__(self, state: dict[Any, Any]) -> None: 

95 _object_setattr(self, '__pydantic_fields_set__', state['__pydantic_fields_set__']) 

96 _object_setattr(self, '__dict__', state['__dict__']) 

97 

98 def __copy__(self) -> Self: 

99 """Returns a shallow copy of the model.""" 

100 cls = type(self) 

101 m = cls.__new__(cls) 

102 _object_setattr(m, '__dict__', copy(self.__dict__)) 

103 _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) 

104 return m 

105 

106 def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: 

107 """Returns a deep copy of the model.""" 

108 cls = type(self) 

109 m = cls.__new__(cls) 

110 _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) 

111 # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str], 

112 # and attempting a deepcopy would be marginally slower. 

113 _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) 

114 return m 

115 

116 if TYPE_CHECKING: 

117 

118 def model_dump( # type: ignore 

119 self, 

120 *, 

121 mode: Literal['json', 'python'] | str = 'python', 

122 include: Any = None, 

123 exclude: Any = None, 

124 context: dict[str, Any] | None = None, 

125 by_alias: bool | None = None, 

126 exclude_unset: bool = False, 

127 exclude_defaults: bool = False, 

128 exclude_none: bool = False, 

129 exclude_computed_fields: bool = False, 

130 round_trip: bool = False, 

131 warnings: bool | Literal['none', 'warn', 'error'] = True, 

132 serialize_as_any: bool = False, 

133 ) -> Any: 

134 """This method is included just to get a more accurate return type for type checkers. 

135 It is included in this `if TYPE_CHECKING:` block since no override is actually necessary. 

136 

137 See the documentation of `BaseModel.model_dump` for more details about the arguments. 

138 

139 Generally, this method will have a return type of `RootModelRootType`, assuming that `RootModelRootType` is 

140 not a `BaseModel` subclass. If `RootModelRootType` is a `BaseModel` subclass, then the return 

141 type will likely be `dict[str, Any]`, as `model_dump` calls are recursive. The return type could 

142 even be something different, in the case of a custom serializer. 

143 Thus, `Any` is used here to catch all of these cases. 

144 """ 

145 ... 

146 

147 def __eq__(self, other: Any) -> bool: 

148 if not isinstance(other, RootModel): 

149 return NotImplemented 

150 return self.__pydantic_fields__['root'].annotation == other.__pydantic_fields__[ 

151 'root' 

152 ].annotation and super().__eq__(other) 

153 

154 def __repr_args__(self) -> _repr.ReprArgs: 

155 yield 'root', self.root