Coverage for pydantic/experimental/pipeline.py: 92.34%
355 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-10 09:28 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-10 09:28 +0000
1"""Experimental pipeline API functionality. Be careful with this API, it's subject to change."""
3from __future__ import annotations 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
5import datetime 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
6import operator 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
7import re 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
8import sys 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
9from collections import deque 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
10from collections.abc import Container 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
11from dataclasses import dataclass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
12from decimal import Decimal 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
13from functools import cached_property, partial 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
14from re import Pattern 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
15from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Protocol, TypeVar, Union, overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
17import annotated_types 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
19if TYPE_CHECKING: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
26if sys.version_info < (3, 10): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
27 EllipsisType = type(Ellipsis) 1owexypz
28else:
29 from types import EllipsisType 1qArBagbhsCNfDEFGijklHIJtKuLcmdnvMO
31__all__ = ['validate_as', 'validate_as_deferred', 'transform'] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
33_slots_frozen = {**_slots_true, 'frozen': True} 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
36@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
37class _ValidateAs: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
38 tp: type[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
39 strict: bool = False 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
42@dataclass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
43class _ValidateAsDefer: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
44 func: Callable[[], type[Any]] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
46 @cached_property 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
47 def tp(self) -> type[Any]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
48 return self.func()
51@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
52class _Transform: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
53 func: Callable[[Any], Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
56@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
57class _PipelineOr: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
58 left: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
59 right: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
62@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
63class _PipelineAnd: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
64 left: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
65 right: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
68@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
69class _Eq: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
70 value: Any 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
73@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
74class _NotEq: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
75 value: Any 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
78@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
79class _In: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
80 values: Container[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
83@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
84class _NotIn: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
85 values: Container[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
88_ConstraintAnnotation = Union[ 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
109class _Constraint: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
110 constraint: _ConstraintAnnotation 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
113_Step = Union[_ValidateAs, _ValidateAsDefer, _Transform, _PipelineOr, _PipelineAnd, _Constraint] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
115_InT = TypeVar('_InT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
116_OutT = TypeVar('_OutT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
117_NewOutT = TypeVar('_NewOutT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
120class _FieldTypeMarker: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
121 pass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
129class _Pipeline(Generic[_InT, _OutT]): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
130 """Abstract representation of a chain of validation, transformation, and parsing steps."""
132 _steps: tuple[_Step, ...] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
134 def transform( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
145 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
146 def validate_as(self, tp: type[_NewOutT], *, strict: bool = ...) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
148 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
149 def validate_as(self, tp: EllipsisType, *, strict: bool = ...) -> _Pipeline[_InT, Any]: # type: ignore 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
150 ...
152 def validate_as(self, tp: type[_NewOutT] | EllipsisType, *, strict: bool = False) -> _Pipeline[_InT, Any]: # type: ignore 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
161 return _Pipeline[_InT, Any](self._steps + (_ValidateAs(_FieldTypeMarker, strict=strict),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
162 return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAs(tp, strict=strict),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
164 def validate_as_deferred(self, func: Callable[[], type[_NewOutT]]) -> _Pipeline[_InT, _NewOutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
174 def constrain(self: _Pipeline[_InT, _NewOutGe], constraint: annotated_types.Ge) -> _Pipeline[_InT, _NewOutGe]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
176 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
177 def constrain(self: _Pipeline[_InT, _NewOutGt], constraint: annotated_types.Gt) -> _Pipeline[_InT, _NewOutGt]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
179 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
180 def constrain(self: _Pipeline[_InT, _NewOutLe], constraint: annotated_types.Le) -> _Pipeline[_InT, _NewOutLe]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
182 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
183 def constrain(self: _Pipeline[_InT, _NewOutLt], constraint: annotated_types.Lt) -> _Pipeline[_InT, _NewOutLt]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
185 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
186 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
187 self: _Pipeline[_InT, _NewOutLen], constraint: annotated_types.Len 1agbhefijklcmdn
188 ) -> _Pipeline[_InT, _NewOutLen]: ... 1agbhefijklcmdn
190 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
191 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
192 self: _Pipeline[_InT, _NewOutT], constraint: annotated_types.MultipleOf 1agbhefijklcmdn
193 ) -> _Pipeline[_InT, _NewOutT]: ... 1agbhefijklcmdn
195 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
196 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
197 self: _Pipeline[_InT, _NewOutDatetime], constraint: annotated_types.Timezone 1agbhefijklcmdn
198 ) -> _Pipeline[_InT, _NewOutDatetime]: ... 1agbhefijklcmdn
200 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
201 def constrain(self: _Pipeline[_InT, _OutT], constraint: annotated_types.Predicate) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
203 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
204 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
205 self: _Pipeline[_InT, _NewOutInterval], constraint: annotated_types.Interval 1agbhefijklcmdn
206 ) -> _Pipeline[_InT, _NewOutInterval]: ... 1agbhefijklcmdn
208 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
209 def constrain(self: _Pipeline[_InT, _OutT], constraint: _Eq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
211 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
212 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotEq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
214 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
215 def constrain(self: _Pipeline[_InT, _OutT], constraint: _In) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
217 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
218 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotIn) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
220 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
221 def constrain(self: _Pipeline[_InT, _NewOutT], constraint: Pattern[str]) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
223 def constrain(self, constraint: _ConstraintAnnotation) -> Any: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
233 def predicate(self: _Pipeline[_InT, _NewOutT], func: Callable[[_NewOutT], bool]) -> _Pipeline[_InT, _NewOutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
234 """Constrain a value to meet a certain predicate."""
235 return self.constrain(annotated_types.Predicate(func)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
237 def gt(self: _Pipeline[_InT, _NewOutGt], gt: _NewOutGt) -> _Pipeline[_InT, _NewOutGt]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
238 """Constrain a value to be greater than a certain value."""
239 return self.constrain(annotated_types.Gt(gt)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
241 def lt(self: _Pipeline[_InT, _NewOutLt], lt: _NewOutLt) -> _Pipeline[_InT, _NewOutLt]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
242 """Constrain a value to be less than a certain value."""
243 return self.constrain(annotated_types.Lt(lt)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
245 def ge(self: _Pipeline[_InT, _NewOutGe], ge: _NewOutGe) -> _Pipeline[_InT, _NewOutGe]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
246 """Constrain a value to be greater than or equal to a certain value."""
247 return self.constrain(annotated_types.Ge(ge)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
249 def le(self: _Pipeline[_InT, _NewOutLe], le: _NewOutLe) -> _Pipeline[_InT, _NewOutLe]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
250 """Constrain a value to be less than or equal to a certain value."""
251 return self.constrain(annotated_types.Le(le)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
253 def len(self: _Pipeline[_InT, _NewOutLen], min_len: int, max_len: int | None = None) -> _Pipeline[_InT, _NewOutLen]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
254 """Constrain a value to have a certain length."""
255 return self.constrain(annotated_types.Len(min_len, max_len)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
257 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
258 def multiple_of(self: _Pipeline[_InT, _NewOutDiv], multiple_of: _NewOutDiv) -> _Pipeline[_InT, _NewOutDiv]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
260 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
261 def multiple_of(self: _Pipeline[_InT, _NewOutMod], multiple_of: _NewOutMod) -> _Pipeline[_InT, _NewOutMod]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
263 def multiple_of(self: _Pipeline[_InT, Any], multiple_of: Any) -> _Pipeline[_InT, Any]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
264 """Constrain a value to be a multiple of a certain number."""
265 return self.constrain(annotated_types.MultipleOf(multiple_of)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
267 def eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
268 """Constrain a value to be equal to a certain value."""
269 return self.constrain(_Eq(value)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
271 def not_eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
272 """Constrain a value to not be equal to a certain value."""
273 return self.constrain(_NotEq(value)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
275 def in_(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
276 """Constrain a value to be in a certain set."""
277 return self.constrain(_In(values)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
279 def not_in(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
280 """Constrain a value to not be in a certain set."""
281 return self.constrain(_NotIn(values)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
283 # timezone methods
284 def datetime_tz_naive(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
285 return self.constrain(annotated_types.Timezone(None)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
287 def datetime_tz_aware(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
288 return self.constrain(annotated_types.Timezone(...)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
290 def datetime_tz( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
302 return self.transform(str.lower) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
304 def str_upper(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
305 return self.transform(str.upper) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
307 def str_title(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
308 return self.transform(str.title) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
310 def str_strip(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
311 return self.transform(str.strip) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
313 def str_pattern(self: _Pipeline[_InT, str], pattern: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
314 return self.constrain(re.compile(pattern)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
316 def str_contains(self: _Pipeline[_InT, str], substring: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
317 return self.predicate(lambda v: substring in v) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
319 def str_starts_with(self: _Pipeline[_InT, str], prefix: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
320 return self.predicate(lambda v: v.startswith(prefix)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
322 def str_ends_with(self: _Pipeline[_InT, str], suffix: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
323 return self.predicate(lambda v: v.endswith(suffix)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
325 # operators
326 def otherwise(self, other: _Pipeline[_OtherIn, _OtherOut]) -> _Pipeline[_InT | _OtherIn, _OutT | _OtherOut]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
330 __or__ = otherwise 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
332 def then(self, other: _Pipeline[_OutT, _OtherOut]) -> _Pipeline[_InT, _OtherOut]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
333 """Pipe the result of one validation chain into another."""
334 return _Pipeline((_PipelineAnd(self, other),)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
336 __and__ = then 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
338 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> cs.CoreSchema: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
339 from pydantic_core import core_schema as cs 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
341 queue = deque(self._steps) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
343 s = None 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
345 while queue: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
346 step = queue.popleft() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
347 s = _apply_step(step, s, handler, source_type) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
349 s = s or cs.any_schema() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
350 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
352 def __supports_type__(self, _: _OutT) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
353 raise NotImplementedError
356validate_as = _Pipeline[Any, Any](()).validate_as 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
357validate_as_deferred = _Pipeline[Any, Any](()).validate_as_deferred 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
358transform = _Pipeline[Any, Any]((_ValidateAs(_FieldTypeMarker),)).transform 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
361def _check_func( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
366 def handler(v: Any) -> Any: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
367 if func(v): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
368 return v 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
369 raise ValueError(f'Expected {predicate_err if isinstance(predicate_err, str) else predicate_err()}') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
371 if s is None: 371 ↛ 372line 371 didn't jump to line 372 because the condition on line 371 was never true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
372 return cs.no_info_plain_validator_function(handler)
373 else:
374 return cs.no_info_after_validator_function(handler, s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
377def _apply_step(step: _Step, s: cs.CoreSchema | None, handler: GetCoreSchemaHandler, source_type: Any) -> cs.CoreSchema: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
378 from pydantic_core import core_schema as cs 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
380 if isinstance(step, _ValidateAs): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
381 s = _apply_parse(s, step.tp, step.strict, handler, source_type) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
382 elif isinstance(step, _ValidateAsDefer): 382 ↛ 383line 382 didn't jump to line 383 because the condition on line 382 was never true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
383 s = _apply_parse(s, step.tp, False, handler, source_type)
384 elif isinstance(step, _Transform): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
385 s = _apply_transform(s, step.func, handler) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
386 elif isinstance(step, _Constraint): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
387 s = _apply_constraint(s, step.constraint) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
388 elif isinstance(step, _PipelineOr): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
389 s = cs.union_schema([handler(step.left), handler(step.right)]) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
390 else:
391 assert isinstance(step, _PipelineAnd) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
392 s = cs.chain_schema([handler(step.left), handler(step.right)]) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
393 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
396def _apply_parse( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
405 from pydantic import Strict 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
407 if tp is _FieldTypeMarker: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
408 return cs.chain_schema([s, handler(source_type)]) if s else handler(source_type) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
410 if strict: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
411 tp = Annotated[tp, Strict()] # type: ignore 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
413 if s and s['type'] == 'any': 413 ↛ 414line 413 didn't jump to line 414 because the condition on line 413 was never true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
414 return handler(tp)
415 else:
416 return cs.chain_schema([s, handler(tp)]) if s else handler(tp) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
419def _apply_transform( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
420 s: cs.CoreSchema | None, func: Callable[[Any], Any], handler: GetCoreSchemaHandler
421) -> cs.CoreSchema:
422 from pydantic_core import core_schema as cs 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
424 if s is None: 424 ↛ 425line 424 didn't jump to line 425 because the condition on line 424 was never true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
425 return cs.no_info_plain_validator_function(func)
427 if s['type'] == 'str': 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
428 if func is str.strip: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
429 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
430 s['strip_whitespace'] = True 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
431 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
432 elif func is str.lower: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
433 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
434 s['to_lower'] = True 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
435 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
436 elif func is str.upper: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
437 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
438 s['to_upper'] = True 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
439 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
441 return cs.no_info_after_validator_function(func, s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
444def _apply_constraint( # noqa: C901 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
449 gt = constraint.gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
450 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
451 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
452 if s['type'] == 'int' and isinstance(gt, int): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
453 s['gt'] = gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
454 elif s['type'] == 'float' and isinstance(gt, float): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
455 s['gt'] = gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
457 s['gt'] = gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
458 else:
460 def check_gt(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
461 return v > gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
463 s = _check_func(check_gt, f'> {gt}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
464 elif isinstance(constraint, annotated_types.Ge): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
465 ge = constraint.ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
467 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
468 if s['type'] == 'int' and isinstance(ge, int): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
469 s['ge'] = ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
470 elif s['type'] == 'float' and isinstance(ge, float): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
471 s['ge'] = ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
473 s['ge'] = ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
475 def check_ge(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
476 return v >= ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
478 s = _check_func(check_ge, f'>= {ge}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
479 elif isinstance(constraint, annotated_types.Lt): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
480 lt = constraint.lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
481 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
482 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
483 if s['type'] == 'int' and isinstance(lt, int): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
484 s['lt'] = lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
485 elif s['type'] == 'float' and isinstance(lt, float): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
486 s['lt'] = lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
488 s['lt'] = lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
490 def check_lt(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
491 return v < lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
493 s = _check_func(check_lt, f'< {lt}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
494 elif isinstance(constraint, annotated_types.Le): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
495 le = constraint.le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
496 if s and s['type'] in {'int', 'float', 'decimal'}: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
497 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
498 if s['type'] == 'int' and isinstance(le, int): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
499 s['le'] = le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
500 elif s['type'] == 'float' and isinstance(le, float): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
501 s['le'] = le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
503 s['le'] = le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
505 def check_le(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
506 return v <= le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
508 s = _check_func(check_le, f'<= {le}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
509 elif isinstance(constraint, annotated_types.Len): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
510 min_len = constraint.min_length 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
511 max_len = constraint.max_length 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
523 if min_len != 0: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
524 s['min_length'] = min_len 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
525 if max_len is not None: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
526 s['max_length'] = max_len 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
528 def check_len(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
529 if max_len is not None: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
530 return (min_len <= len(v)) and (len(v) <= max_len) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
531 return min_len <= len(v) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
533 s = _check_func(check_len, f'length >= {min_len} and length <= {max_len}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
534 elif isinstance(constraint, annotated_types.MultipleOf): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
535 multiple_of = constraint.multiple_of 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
537 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
538 if s['type'] == 'int' and isinstance(multiple_of, int): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
539 s['multiple_of'] = multiple_of 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
540 elif s['type'] == 'float' and isinstance(multiple_of, float): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
541 s['multiple_of'] = multiple_of 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
543 s['multiple_of'] = multiple_of 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
545 def check_multiple_of(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
546 return v % multiple_of == 0 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
548 s = _check_func(check_multiple_of, f'% {multiple_of} == 0', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
549 elif isinstance(constraint, annotated_types.Timezone): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
550 tz = constraint.tz 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
552 if tz is ...: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
553 if s and s['type'] == 'datetime': 553 ↛ 558line 553 didn't jump to line 558 because the condition on line 553 was always true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
554 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
555 s['tz_constraint'] = 'aware' 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
564 if s and s['type'] == 'datetime': 564 ↛ 569line 564 didn't jump to line 569 because the condition on line 564 was always true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
565 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
566 s['tz_constraint'] = 'naive' 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
577 if constraint.ge: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
578 s = _apply_constraint(s, annotated_types.Ge(constraint.ge)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
579 if constraint.gt: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
580 s = _apply_constraint(s, annotated_types.Gt(constraint.gt)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
581 if constraint.le: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
582 s = _apply_constraint(s, annotated_types.Le(constraint.le)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
583 if constraint.lt: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
584 s = _apply_constraint(s, annotated_types.Lt(constraint.lt)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
585 assert s is not None 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
586 elif isinstance(constraint, annotated_types.Predicate): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
587 func = constraint.func 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
589 if func.__name__ == '<lambda>': 589 ↛ 605line 589 didn't jump to line 605 because the condition on line 589 was always true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
595 try: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
596 source = inspect.getsource(func).strip() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
597 source = source.removesuffix(')') 1owqArBagbhsCefxyDEFGijklHIJpztKuLcmdnvM
598 lambda_source_code = '`' + ''.join(''.join(source.split('lambda ')[1:]).split(':')[1:]).strip() + '`' 1owqArBagbhsCefxyDEFGijklHIJpztKuLcmdnvM
599 except OSError: 1oqrabsptucdv
600 # stringified annotations
601 lambda_source_code = 'lambda' 1oqrabsptucdv
603 s = _check_func(func, lambda_source_code, s) 1owqArBagbhsCefxyDEFGijklHIJpztKuLcmdnvM
604 else:
605 s = _check_func(func, func.__name__, s)
606 elif isinstance(constraint, _NotEq): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
607 value = constraint.value 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
609 def check_not_eq(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
610 return operator.__ne__(v, value) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
612 s = _check_func(check_not_eq, f'!= {value}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
613 elif isinstance(constraint, _Eq): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
614 value = constraint.value 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
616 def check_eq(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
617 return operator.__eq__(v, value) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
619 s = _check_func(check_eq, f'== {value}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
620 elif isinstance(constraint, _In): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
621 values = constraint.values 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
623 def check_in(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
624 return operator.__contains__(values, v) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
626 s = _check_func(check_in, f'in {values}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
627 elif isinstance(constraint, _NotIn): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
628 values = constraint.values 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
630 def check_not_in(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
631 return operator.__not__(operator.__contains__(values, v)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
633 s = _check_func(check_not_in, f'not in {values}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
634 else:
635 assert isinstance(constraint, Pattern) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
636 if s and s['type'] == 'str': 636 ↛ 641line 636 didn't jump to line 641 because the condition on line 636 was always true1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
637 s = s.copy() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
638 s['pattern'] = constraint.pattern 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
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 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
649class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
650 pass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
653class _SupportsLen(Protocol): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
654 def __len__(self) -> int: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
657_NewOutGt = TypeVar('_NewOutGt', bound=annotated_types.SupportsGt) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
658_NewOutGe = TypeVar('_NewOutGe', bound=annotated_types.SupportsGe) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
659_NewOutLt = TypeVar('_NewOutLt', bound=annotated_types.SupportsLt) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
660_NewOutLe = TypeVar('_NewOutLe', bound=annotated_types.SupportsLe) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
661_NewOutLen = TypeVar('_NewOutLen', bound=_SupportsLen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
662_NewOutDiv = TypeVar('_NewOutDiv', bound=annotated_types.SupportsDiv) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
663_NewOutMod = TypeVar('_NewOutMod', bound=annotated_types.SupportsMod) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
664_NewOutDatetime = TypeVar('_NewOutDatetime', bound=datetime.datetime) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
665_NewOutInterval = TypeVar('_NewOutInterval', bound=_SupportsRange) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
666_OtherIn = TypeVar('_OtherIn') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO
667_OtherOut = TypeVar('_OtherOut') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO