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