Coverage for pydantic/experimental/pipeline.py: 92.34%
355 statements
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-26 11:49 +0000
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-26 11:49 +0000
1"""Experimental pipeline API functionality. Be careful with this API, it's subject to change."""
3from __future__ import annotations 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
5import datetime 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
6import operator 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
7import re 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
8import sys 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
9from collections import deque 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
10from collections.abc import Container 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
11from dataclasses import dataclass 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
12from decimal import Decimal 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
13from functools import cached_property, partial 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
14from re import Pattern 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
15from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Protocol, TypeVar, Union, overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
17import annotated_types 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
19if TYPE_CHECKING: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
20 from pydantic_core import core_schema as cs
22 from pydantic import GetCoreSchemaHandler
24from pydantic._internal._internal_dataclass import slots_true as _slots_true 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
26if sys.version_info < (3, 10): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
27 EllipsisType = type(Ellipsis) 1owexypz
28else:
29 from types import EllipsisType 1qArBagbhsCDfEFGHijklIJKtLuMcmdnvNO
31__all__ = ['validate_as', 'validate_as_deferred', 'transform'] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
33_slots_frozen = {**_slots_true, 'frozen': True} 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
36@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
37class _ValidateAs: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
38 tp: type[Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
39 strict: bool = False 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
42@dataclass 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
43class _ValidateAsDefer: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
44 func: Callable[[], type[Any]] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
46 @cached_property 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
47 def tp(self) -> type[Any]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
48 return self.func()
51@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
52class _Transform: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
53 func: Callable[[Any], Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
56@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
57class _PipelineOr: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
58 left: _Pipeline[Any, Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
59 right: _Pipeline[Any, Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
62@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
63class _PipelineAnd: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
64 left: _Pipeline[Any, Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
65 right: _Pipeline[Any, Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
68@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
69class _Eq: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
70 value: Any 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
73@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
74class _NotEq: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
75 value: Any 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
78@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
79class _In: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
80 values: Container[Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
83@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
84class _NotIn: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
85 values: Container[Any] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
88_ConstraintAnnotation = Union[ 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
89 annotated_types.Le,
90 annotated_types.Ge,
91 annotated_types.Lt,
92 annotated_types.Gt,
93 annotated_types.Len,
94 annotated_types.MultipleOf,
95 annotated_types.Timezone,
96 annotated_types.Interval,
97 annotated_types.Predicate,
98 # common predicates not included in annotated_types
99 _Eq,
100 _NotEq,
101 _In,
102 _NotIn,
103 # regular expressions
104 Pattern[str],
105]
108@dataclass(**_slots_frozen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
109class _Constraint: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
110 constraint: _ConstraintAnnotation 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
113_Step = Union[_ValidateAs, _ValidateAsDefer, _Transform, _PipelineOr, _PipelineAnd, _Constraint] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
115_InT = TypeVar('_InT') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
116_OutT = TypeVar('_OutT') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
117_NewOutT = TypeVar('_NewOutT') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
120class _FieldTypeMarker: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
121 pass 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
124# TODO: ultimately, make this public, see https://github.com/pydantic/pydantic/pull/9459#discussion_r1628197626
125# Also, make this frozen eventually, but that doesn't work right now because of the generic base
126# Which attempts to modify __orig_base__ and such.
127# We could go with a manual freeze, but that seems overkill for now.
128@dataclass(**_slots_true) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
129class _Pipeline(Generic[_InT, _OutT]): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
130 """Abstract representation of a chain of validation, transformation, and parsing steps."""
132 _steps: tuple[_Step, ...] 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
134 def transform( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
135 self,
136 func: Callable[[_OutT], _NewOutT],
137 ) -> _Pipeline[_InT, _NewOutT]:
138 """Transform the output of the previous step.
140 If used as the first step in a pipeline, the type of the field is used.
141 That is, the transformation is applied to after the value is parsed to the field's type.
142 """
143 return _Pipeline[_InT, _NewOutT](self._steps + (_Transform(func),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
145 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
146 def validate_as(self, tp: type[_NewOutT], *, strict: bool = ...) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
148 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
149 def validate_as(self, tp: EllipsisType, *, strict: bool = ...) -> _Pipeline[_InT, Any]: # type: ignore 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
150 ...
152 def validate_as(self, tp: type[_NewOutT] | EllipsisType, *, strict: bool = False) -> _Pipeline[_InT, Any]: # type: ignore 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
153 """Validate / parse the input into a new type.
155 If no type is provided, the type of the field is used.
157 Types are parsed in Pydantic's `lax` mode by default,
158 but you can enable `strict` mode by passing `strict=True`.
159 """
160 if isinstance(tp, EllipsisType): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
161 return _Pipeline[_InT, Any](self._steps + (_ValidateAs(_FieldTypeMarker, strict=strict),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
162 return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAs(tp, strict=strict),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
164 def validate_as_deferred(self, func: Callable[[], type[_NewOutT]]) -> _Pipeline[_InT, _NewOutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
165 """Parse the input into a new type, deferring resolution of the type until the current class
166 is fully defined.
168 This is useful when you need to reference the class in it's own type annotations.
169 """
170 return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAsDefer(func),))
172 # constraints
173 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
174 def constrain(self: _Pipeline[_InT, _NewOutGe], constraint: annotated_types.Ge) -> _Pipeline[_InT, _NewOutGe]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
176 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
177 def constrain(self: _Pipeline[_InT, _NewOutGt], constraint: annotated_types.Gt) -> _Pipeline[_InT, _NewOutGt]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
179 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
180 def constrain(self: _Pipeline[_InT, _NewOutLe], constraint: annotated_types.Le) -> _Pipeline[_InT, _NewOutLe]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
182 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
183 def constrain(self: _Pipeline[_InT, _NewOutLt], constraint: annotated_types.Lt) -> _Pipeline[_InT, _NewOutLt]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
185 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
186 def constrain( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
187 self: _Pipeline[_InT, _NewOutLen], constraint: annotated_types.Len 1agbhefijklcmdn
188 ) -> _Pipeline[_InT, _NewOutLen]: ... 1agbhefijklcmdn
190 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
191 def constrain( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
192 self: _Pipeline[_InT, _NewOutT], constraint: annotated_types.MultipleOf 1agbhefijklcmdn
193 ) -> _Pipeline[_InT, _NewOutT]: ... 1agbhefijklcmdn
195 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
196 def constrain( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
197 self: _Pipeline[_InT, _NewOutDatetime], constraint: annotated_types.Timezone 1agbhefijklcmdn
198 ) -> _Pipeline[_InT, _NewOutDatetime]: ... 1agbhefijklcmdn
200 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
201 def constrain(self: _Pipeline[_InT, _OutT], constraint: annotated_types.Predicate) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
203 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
204 def constrain( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
205 self: _Pipeline[_InT, _NewOutInterval], constraint: annotated_types.Interval 1agbhefijklcmdn
206 ) -> _Pipeline[_InT, _NewOutInterval]: ... 1agbhefijklcmdn
208 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
209 def constrain(self: _Pipeline[_InT, _OutT], constraint: _Eq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
211 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
212 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotEq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
214 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
215 def constrain(self: _Pipeline[_InT, _OutT], constraint: _In) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
217 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
218 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotIn) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
220 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
221 def constrain(self: _Pipeline[_InT, _NewOutT], constraint: Pattern[str]) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
223 def constrain(self, constraint: _ConstraintAnnotation) -> Any: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
224 """Constrain a value to meet a certain condition.
226 We support most conditions from `annotated_types`, as well as regular expressions.
228 Most of the time you'll be calling a shortcut method like `gt`, `lt`, `len`, etc
229 so you don't need to call this directly.
230 """
231 return _Pipeline[_InT, _OutT](self._steps + (_Constraint(constraint),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
233 def predicate(self: _Pipeline[_InT, _NewOutT], func: Callable[[_NewOutT], bool]) -> _Pipeline[_InT, _NewOutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
234 """Constrain a value to meet a certain predicate."""
235 return self.constrain(annotated_types.Predicate(func)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
237 def gt(self: _Pipeline[_InT, _NewOutGt], gt: _NewOutGt) -> _Pipeline[_InT, _NewOutGt]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
238 """Constrain a value to be greater than a certain value."""
239 return self.constrain(annotated_types.Gt(gt)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
241 def lt(self: _Pipeline[_InT, _NewOutLt], lt: _NewOutLt) -> _Pipeline[_InT, _NewOutLt]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
242 """Constrain a value to be less than a certain value."""
243 return self.constrain(annotated_types.Lt(lt)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
245 def ge(self: _Pipeline[_InT, _NewOutGe], ge: _NewOutGe) -> _Pipeline[_InT, _NewOutGe]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
246 """Constrain a value to be greater than or equal to a certain value."""
247 return self.constrain(annotated_types.Ge(ge)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
249 def le(self: _Pipeline[_InT, _NewOutLe], le: _NewOutLe) -> _Pipeline[_InT, _NewOutLe]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
250 """Constrain a value to be less than or equal to a certain value."""
251 return self.constrain(annotated_types.Le(le)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
253 def len(self: _Pipeline[_InT, _NewOutLen], min_len: int, max_len: int | None = None) -> _Pipeline[_InT, _NewOutLen]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
254 """Constrain a value to have a certain length."""
255 return self.constrain(annotated_types.Len(min_len, max_len)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
257 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
258 def multiple_of(self: _Pipeline[_InT, _NewOutDiv], multiple_of: _NewOutDiv) -> _Pipeline[_InT, _NewOutDiv]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
260 @overload 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
261 def multiple_of(self: _Pipeline[_InT, _NewOutMod], multiple_of: _NewOutMod) -> _Pipeline[_InT, _NewOutMod]: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
263 def multiple_of(self: _Pipeline[_InT, Any], multiple_of: Any) -> _Pipeline[_InT, Any]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
264 """Constrain a value to be a multiple of a certain number."""
265 return self.constrain(annotated_types.MultipleOf(multiple_of)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
267 def eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
268 """Constrain a value to be equal to a certain value."""
269 return self.constrain(_Eq(value)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
271 def not_eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
272 """Constrain a value to not be equal to a certain value."""
273 return self.constrain(_NotEq(value)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
275 def in_(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
276 """Constrain a value to be in a certain set."""
277 return self.constrain(_In(values)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
279 def not_in(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
280 """Constrain a value to not be in a certain set."""
281 return self.constrain(_NotIn(values)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
283 # timezone methods
284 def datetime_tz_naive(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
285 return self.constrain(annotated_types.Timezone(None)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
287 def datetime_tz_aware(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
288 return self.constrain(annotated_types.Timezone(...)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
290 def datetime_tz( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
291 self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo
292 ) -> _Pipeline[_InT, datetime.datetime]:
293 return self.constrain(annotated_types.Timezone(tz)) # type: ignore
295 def datetime_with_tz( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
296 self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo | None
297 ) -> _Pipeline[_InT, datetime.datetime]:
298 return self.transform(partial(datetime.datetime.replace, tzinfo=tz))
300 # string methods
301 def str_lower(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
302 return self.transform(str.lower) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
304 def str_upper(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
305 return self.transform(str.upper) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
307 def str_title(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
308 return self.transform(str.title) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
310 def str_strip(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
311 return self.transform(str.strip) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
313 def str_pattern(self: _Pipeline[_InT, str], pattern: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
314 return self.constrain(re.compile(pattern)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
316 def str_contains(self: _Pipeline[_InT, str], substring: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
317 return self.predicate(lambda v: substring in v) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
319 def str_starts_with(self: _Pipeline[_InT, str], prefix: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
320 return self.predicate(lambda v: v.startswith(prefix)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
322 def str_ends_with(self: _Pipeline[_InT, str], suffix: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
323 return self.predicate(lambda v: v.endswith(suffix)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
325 # operators
326 def otherwise(self, other: _Pipeline[_OtherIn, _OtherOut]) -> _Pipeline[_InT | _OtherIn, _OutT | _OtherOut]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
327 """Combine two validation chains, returning the result of the first chain if it succeeds, and the second chain if it fails."""
328 return _Pipeline((_PipelineOr(self, other),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
330 __or__ = otherwise 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
332 def then(self, other: _Pipeline[_OutT, _OtherOut]) -> _Pipeline[_InT, _OtherOut]: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
333 """Pipe the result of one validation chain into another."""
334 return _Pipeline((_PipelineAnd(self, other),)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
336 __and__ = then 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
338 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> cs.CoreSchema: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
339 from pydantic_core import core_schema as cs 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
341 queue = deque(self._steps) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
343 s = None 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
345 while queue: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
346 step = queue.popleft() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
347 s = _apply_step(step, s, handler, source_type) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
349 s = s or cs.any_schema() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
350 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
352 def __supports_type__(self, _: _OutT) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
353 raise NotImplementedError
356validate_as = _Pipeline[Any, Any](()).validate_as 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
357validate_as_deferred = _Pipeline[Any, Any](()).validate_as_deferred 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
358transform = _Pipeline[Any, Any]((_ValidateAs(_FieldTypeMarker),)).transform 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
361def _check_func( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
362 func: Callable[[Any], bool], predicate_err: str | Callable[[], str], s: cs.CoreSchema | None
363) -> cs.CoreSchema:
364 from pydantic_core import core_schema as cs 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
366 def handler(v: Any) -> Any: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
367 if func(v): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
368 return v 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
369 raise ValueError(f'Expected {predicate_err if isinstance(predicate_err, str) else predicate_err()}') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
371 if s is None: 371 ↛ 372line 371 didn't jump to line 372 because the condition on line 371 was never true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
372 return cs.no_info_plain_validator_function(handler)
373 else:
374 return cs.no_info_after_validator_function(handler, s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
377def _apply_step(step: _Step, s: cs.CoreSchema | None, handler: GetCoreSchemaHandler, source_type: Any) -> cs.CoreSchema: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
378 from pydantic_core import core_schema as cs 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
380 if isinstance(step, _ValidateAs): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
381 s = _apply_parse(s, step.tp, step.strict, handler, source_type) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
382 elif isinstance(step, _ValidateAsDefer): 382 ↛ 383line 382 didn't jump to line 383 because the condition on line 382 was never true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
383 s = _apply_parse(s, step.tp, False, handler, source_type)
384 elif isinstance(step, _Transform): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
385 s = _apply_transform(s, step.func, handler) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
386 elif isinstance(step, _Constraint): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
387 s = _apply_constraint(s, step.constraint) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
388 elif isinstance(step, _PipelineOr): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
389 s = cs.union_schema([handler(step.left), handler(step.right)]) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
390 else:
391 assert isinstance(step, _PipelineAnd) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
392 s = cs.chain_schema([handler(step.left), handler(step.right)]) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
393 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
396def _apply_parse( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
397 s: cs.CoreSchema | None,
398 tp: type[Any],
399 strict: bool,
400 handler: GetCoreSchemaHandler,
401 source_type: Any,
402) -> cs.CoreSchema:
403 from pydantic_core import core_schema as cs 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
405 from pydantic import Strict 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
407 if tp is _FieldTypeMarker: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
408 return cs.chain_schema([s, handler(source_type)]) if s else handler(source_type) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
410 if strict: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
411 tp = Annotated[tp, Strict()] # type: ignore 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
413 if s and s['type'] == 'any': 413 ↛ 414line 413 didn't jump to line 414 because the condition on line 413 was never true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
414 return handler(tp)
415 else:
416 return cs.chain_schema([s, handler(tp)]) if s else handler(tp) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
419def _apply_transform( 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
420 s: cs.CoreSchema | None, func: Callable[[Any], Any], handler: GetCoreSchemaHandler
421) -> cs.CoreSchema:
422 from pydantic_core import core_schema as cs 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
424 if s is None: 424 ↛ 425line 424 didn't jump to line 425 because the condition on line 424 was never true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
425 return cs.no_info_plain_validator_function(func)
427 if s['type'] == 'str': 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
428 if func is str.strip: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
429 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
430 s['strip_whitespace'] = True 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
431 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
432 elif func is str.lower: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
433 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
434 s['to_lower'] = True 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
435 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
436 elif func is str.upper: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
437 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
438 s['to_upper'] = True 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
439 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
441 return cs.no_info_after_validator_function(func, s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
444def _apply_constraint( # noqa: C901 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
445 s: cs.CoreSchema | None, constraint: _ConstraintAnnotation
446) -> cs.CoreSchema:
447 """Apply a single constraint to a schema."""
448 if isinstance(constraint, annotated_types.Gt): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
449 gt = constraint.gt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
450 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
451 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
452 if s['type'] == 'int' and isinstance(gt, int): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
453 s['gt'] = gt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
454 elif s['type'] == 'float' and isinstance(gt, float): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
455 s['gt'] = gt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
456 elif s['type'] == 'decimal' and isinstance(gt, Decimal): 456 ↛ 646line 456 didn't jump to line 646 because the condition on line 456 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
457 s['gt'] = gt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
458 else:
460 def check_gt(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
461 return v > gt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
463 s = _check_func(check_gt, f'> {gt}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
464 elif isinstance(constraint, annotated_types.Ge): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
465 ge = constraint.ge 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
466 if s and s['type'] in {'int', 'float', 'decimal'}: 466 ↛ 475line 466 didn't jump to line 475 because the condition on line 466 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
467 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
468 if s['type'] == 'int' and isinstance(ge, int): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
469 s['ge'] = ge 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
470 elif s['type'] == 'float' and isinstance(ge, float): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
471 s['ge'] = ge 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
472 elif s['type'] == 'decimal' and isinstance(ge, Decimal): 472 ↛ 475line 472 didn't jump to line 475 because the condition on line 472 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
473 s['ge'] = ge 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
475 def check_ge(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
476 return v >= ge 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
478 s = _check_func(check_ge, f'>= {ge}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
479 elif isinstance(constraint, annotated_types.Lt): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
480 lt = constraint.lt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
481 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
482 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
483 if s['type'] == 'int' and isinstance(lt, int): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
484 s['lt'] = lt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
485 elif s['type'] == 'float' and isinstance(lt, float): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
486 s['lt'] = lt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
487 elif s['type'] == 'decimal' and isinstance(lt, Decimal): 487 ↛ 490line 487 didn't jump to line 490 because the condition on line 487 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
488 s['lt'] = lt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
490 def check_lt(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
491 return v < lt 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
493 s = _check_func(check_lt, f'< {lt}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
494 elif isinstance(constraint, annotated_types.Le): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
495 le = constraint.le 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
496 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
497 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
498 if s['type'] == 'int' and isinstance(le, int): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
499 s['le'] = le 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
500 elif s['type'] == 'float' and isinstance(le, float): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
501 s['le'] = le 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
502 elif s['type'] == 'decimal' and isinstance(le, Decimal): 502 ↛ 505line 502 didn't jump to line 505 because the condition on line 502 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
503 s['le'] = le 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
505 def check_le(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
506 return v <= le 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
508 s = _check_func(check_le, f'<= {le}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
509 elif isinstance(constraint, annotated_types.Len): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
510 min_len = constraint.min_length 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
511 max_len = constraint.max_length 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
513 if s and s['type'] in {'str', 'list', 'tuple', 'set', 'frozenset', 'dict'}: 513 ↛ 528line 513 didn't jump to line 528 because the condition on line 513 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
514 assert ( 1owefxypz
515 s['type'] == 'str'
516 or s['type'] == 'list'
517 or s['type'] == 'tuple'
518 or s['type'] == 'set'
519 or s['type'] == 'dict'
520 or s['type'] == 'frozenset'
521 )
522 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
523 if min_len != 0: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
524 s['min_length'] = min_len 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
525 if max_len is not None: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
526 s['max_length'] = max_len 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
528 def check_len(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
529 if max_len is not None: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
530 return (min_len <= len(v)) and (len(v) <= max_len) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
531 return min_len <= len(v) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
533 s = _check_func(check_len, f'length >= {min_len} and length <= {max_len}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
534 elif isinstance(constraint, annotated_types.MultipleOf): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
535 multiple_of = constraint.multiple_of 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
536 if s and s['type'] in {'int', 'float', 'decimal'}: 536 ↛ 545line 536 didn't jump to line 545 because the condition on line 536 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
537 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
538 if s['type'] == 'int' and isinstance(multiple_of, int): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
539 s['multiple_of'] = multiple_of 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
540 elif s['type'] == 'float' and isinstance(multiple_of, float): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
541 s['multiple_of'] = multiple_of 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
542 elif s['type'] == 'decimal' and isinstance(multiple_of, Decimal): 542 ↛ 545line 542 didn't jump to line 545 because the condition on line 542 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
543 s['multiple_of'] = multiple_of 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
545 def check_multiple_of(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
546 return v % multiple_of == 0 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
548 s = _check_func(check_multiple_of, f'% {multiple_of} == 0', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
549 elif isinstance(constraint, annotated_types.Timezone): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
550 tz = constraint.tz 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
552 if tz is ...: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
553 if s and s['type'] == 'datetime': 553 ↛ 558line 553 didn't jump to line 558 because the condition on line 553 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
554 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
555 s['tz_constraint'] = 'aware' 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
556 else:
558 def check_tz_aware(v: object) -> bool:
559 assert isinstance(v, datetime.datetime)
560 return v.tzinfo is not None
562 s = _check_func(check_tz_aware, 'timezone aware', s)
563 elif tz is None: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
564 if s and s['type'] == 'datetime': 564 ↛ 569line 564 didn't jump to line 569 because the condition on line 564 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
565 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
566 s['tz_constraint'] = 'naive' 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
567 else:
569 def check_tz_naive(v: object) -> bool:
570 assert isinstance(v, datetime.datetime)
571 return v.tzinfo is None
573 s = _check_func(check_tz_naive, 'timezone naive', s)
574 else:
575 raise NotImplementedError('Constraining to a specific timezone is not yet supported')
576 elif isinstance(constraint, annotated_types.Interval): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
577 if constraint.ge: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
578 s = _apply_constraint(s, annotated_types.Ge(constraint.ge)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
579 if constraint.gt: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
580 s = _apply_constraint(s, annotated_types.Gt(constraint.gt)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
581 if constraint.le: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
582 s = _apply_constraint(s, annotated_types.Le(constraint.le)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
583 if constraint.lt: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
584 s = _apply_constraint(s, annotated_types.Lt(constraint.lt)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
585 assert s is not None 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
586 elif isinstance(constraint, annotated_types.Predicate): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
587 func = constraint.func 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
589 if func.__name__ == '<lambda>': 589 ↛ 605line 589 didn't jump to line 605 because the condition on line 589 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
590 # attempt to extract the source code for a lambda function
591 # to use as the function name in error messages
592 # TODO: is there a better way? should we just not do this?
593 import inspect 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
595 try: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
596 source = inspect.getsource(func).strip() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
597 source = source.removesuffix(')') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
598 lambda_source_code = '`' + ''.join(''.join(source.split('lambda ')[1:]).split(':')[1:]).strip() + '`' 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
599 except OSError: 1oqrabsptucdv
600 # stringified annotations
601 lambda_source_code = 'lambda' 1oqrabsptucdv
603 s = _check_func(func, lambda_source_code, s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
604 else:
605 s = _check_func(func, func.__name__, s)
606 elif isinstance(constraint, _NotEq): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
607 value = constraint.value 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
609 def check_not_eq(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
610 return operator.__ne__(v, value) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
612 s = _check_func(check_not_eq, f'!= {value}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
613 elif isinstance(constraint, _Eq): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
614 value = constraint.value 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
616 def check_eq(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
617 return operator.__eq__(v, value) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
619 s = _check_func(check_eq, f'== {value}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
620 elif isinstance(constraint, _In): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
621 values = constraint.values 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
623 def check_in(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
624 return operator.__contains__(values, v) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
626 s = _check_func(check_in, f'in {values}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
627 elif isinstance(constraint, _NotIn): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
628 values = constraint.values 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
630 def check_not_in(v: Any) -> bool: 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
631 return operator.__not__(operator.__contains__(values, v)) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
633 s = _check_func(check_not_in, f'not in {values}', s) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
634 else:
635 assert isinstance(constraint, Pattern) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
636 if s and s['type'] == 'str': 636 ↛ 641line 636 didn't jump to line 641 because the condition on line 636 was always true1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
637 s = s.copy() 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
638 s['pattern'] = constraint.pattern 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
639 else:
641 def check_pattern(v: object) -> bool:
642 assert isinstance(v, str)
643 return constraint.match(v) is not None
645 s = _check_func(check_pattern, f'~ {constraint.pattern}', s)
646 return s 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
649class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
650 pass 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
653class _SupportsLen(Protocol): 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
654 def __len__(self) -> int: ... 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
657_NewOutGt = TypeVar('_NewOutGt', bound=annotated_types.SupportsGt) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
658_NewOutGe = TypeVar('_NewOutGe', bound=annotated_types.SupportsGe) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
659_NewOutLt = TypeVar('_NewOutLt', bound=annotated_types.SupportsLt) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
660_NewOutLe = TypeVar('_NewOutLe', bound=annotated_types.SupportsLe) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
661_NewOutLen = TypeVar('_NewOutLen', bound=_SupportsLen) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
662_NewOutDiv = TypeVar('_NewOutDiv', bound=annotated_types.SupportsDiv) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
663_NewOutMod = TypeVar('_NewOutMod', bound=annotated_types.SupportsMod) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
664_NewOutDatetime = TypeVar('_NewOutDatetime', bound=datetime.datetime) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
665_NewOutInterval = TypeVar('_NewOutInterval', bound=_SupportsRange) 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
666_OtherIn = TypeVar('_OtherIn') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO
667_OtherOut = TypeVar('_OtherOut') 1owqArBagbhsCDefxyEFGHijklIJKpztLuMcmdnvNO