Coverage for pydantic/experimental/pipeline.py: 92.34%

355 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-20 16:49 +0000

1"""Experimental pipeline API functionality. Be careful with this API, it's subject to change.""" 

2 

3from __future__ import annotations 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

4 

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

16 

17import annotated_types 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

18 

19if TYPE_CHECKING: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

20 from pydantic_core import core_schema as cs 

21 

22 from pydantic import GetCoreSchemaHandler 

23 

24from pydantic._internal._internal_dataclass import slots_true as _slots_true 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

25 

26if sys.version_info < (3, 10): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

27 EllipsisType = type(Ellipsis) 1owexypz

28else: 

29 from types import EllipsisType 1qArBagbhsCNfDEFGijklHIJtKuLcmdnvMO

30 

31__all__ = ['validate_as', 'validate_as_deferred', 'transform'] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

32 

33_slots_frozen = {**_slots_true, 'frozen': True} 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

34 

35 

36@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

37class _ValidateAs: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

38 tp: type[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

39 strict: bool = False 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

40 

41 

42@dataclass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

43class _ValidateAsDefer: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

44 func: Callable[[], type[Any]] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

45 

46 @cached_property 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

47 def tp(self) -> type[Any]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

48 return self.func() 

49 

50 

51@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

52class _Transform: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

53 func: Callable[[Any], Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

54 

55 

56@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

57class _PipelineOr: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

58 left: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

59 right: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

60 

61 

62@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

63class _PipelineAnd: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

64 left: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

65 right: _Pipeline[Any, Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

66 

67 

68@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

69class _Eq: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

70 value: Any 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

71 

72 

73@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

74class _NotEq: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

75 value: Any 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

76 

77 

78@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

79class _In: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

80 values: Container[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

81 

82 

83@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

84class _NotIn: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

85 values: Container[Any] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

86 

87 

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] 

106 

107 

108@dataclass(**_slots_frozen) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

109class _Constraint: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

110 constraint: _ConstraintAnnotation 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

111 

112 

113_Step = Union[_ValidateAs, _ValidateAsDefer, _Transform, _PipelineOr, _PipelineAnd, _Constraint] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

114 

115_InT = TypeVar('_InT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

116_OutT = TypeVar('_OutT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

117_NewOutT = TypeVar('_NewOutT') 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

118 

119 

120class _FieldTypeMarker: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

121 pass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

122 

123 

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.""" 

131 

132 _steps: tuple[_Step, ...] 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

133 

134 def transform( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

135 self, 

136 func: Callable[[_OutT], _NewOutT], 

137 ) -> _Pipeline[_InT, _NewOutT]: 

138 """Transform the output of the previous step. 

139 

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

144 

145 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

146 def validate_as(self, tp: type[_NewOutT], *, strict: bool = ...) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

147 

148 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

149 def validate_as(self, tp: EllipsisType, *, strict: bool = ...) -> _Pipeline[_InT, Any]: # type: ignore 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

150 ... 

151 

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. 

154 

155 If no type is provided, the type of the field is used. 

156 

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

163 

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. 

167 

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),)) 

171 

172 # constraints 

173 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

174 def constrain(self: _Pipeline[_InT, _NewOutGe], constraint: annotated_types.Ge) -> _Pipeline[_InT, _NewOutGe]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

175 

176 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

177 def constrain(self: _Pipeline[_InT, _NewOutGt], constraint: annotated_types.Gt) -> _Pipeline[_InT, _NewOutGt]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

178 

179 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

180 def constrain(self: _Pipeline[_InT, _NewOutLe], constraint: annotated_types.Le) -> _Pipeline[_InT, _NewOutLe]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

181 

182 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

183 def constrain(self: _Pipeline[_InT, _NewOutLt], constraint: annotated_types.Lt) -> _Pipeline[_InT, _NewOutLt]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

184 

185 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

186 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

187 self: _Pipeline[_InT, _NewOutLen], constraint: annotated_types.Len 1agbhefijklcmdn

188 ) -> _Pipeline[_InT, _NewOutLen]: ... 1agbhefijklcmdn

189 

190 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

191 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

192 self: _Pipeline[_InT, _NewOutT], constraint: annotated_types.MultipleOf 1agbhefijklcmdn

193 ) -> _Pipeline[_InT, _NewOutT]: ... 1agbhefijklcmdn

194 

195 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

196 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

197 self: _Pipeline[_InT, _NewOutDatetime], constraint: annotated_types.Timezone 1agbhefijklcmdn

198 ) -> _Pipeline[_InT, _NewOutDatetime]: ... 1agbhefijklcmdn

199 

200 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

201 def constrain(self: _Pipeline[_InT, _OutT], constraint: annotated_types.Predicate) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

202 

203 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

204 def constrain( 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

205 self: _Pipeline[_InT, _NewOutInterval], constraint: annotated_types.Interval 1agbhefijklcmdn

206 ) -> _Pipeline[_InT, _NewOutInterval]: ... 1agbhefijklcmdn

207 

208 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

209 def constrain(self: _Pipeline[_InT, _OutT], constraint: _Eq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

210 

211 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

212 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotEq) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

213 

214 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

215 def constrain(self: _Pipeline[_InT, _OutT], constraint: _In) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

216 

217 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

218 def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotIn) -> _Pipeline[_InT, _OutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

219 

220 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

221 def constrain(self: _Pipeline[_InT, _NewOutT], constraint: Pattern[str]) -> _Pipeline[_InT, _NewOutT]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

222 

223 def constrain(self, constraint: _ConstraintAnnotation) -> Any: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

224 """Constrain a value to meet a certain condition. 

225 

226 We support most conditions from `annotated_types`, as well as regular expressions. 

227 

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

232 

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

236 

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

240 

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

244 

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

248 

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

252 

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

256 

257 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

258 def multiple_of(self: _Pipeline[_InT, _NewOutDiv], multiple_of: _NewOutDiv) -> _Pipeline[_InT, _NewOutDiv]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

259 

260 @overload 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

261 def multiple_of(self: _Pipeline[_InT, _NewOutMod], multiple_of: _NewOutMod) -> _Pipeline[_InT, _NewOutMod]: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

262 

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

266 

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

270 

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

274 

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

278 

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

282 

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

286 

287 def datetime_tz_aware(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

288 return self.constrain(annotated_types.Timezone(...)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

289 

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 

294 

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)) 

299 

300 # string methods 

301 def str_lower(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

302 return self.transform(str.lower) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

303 

304 def str_upper(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

305 return self.transform(str.upper) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

306 

307 def str_title(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

308 return self.transform(str.title) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

309 

310 def str_strip(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

311 return self.transform(str.strip) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

312 

313 def str_pattern(self: _Pipeline[_InT, str], pattern: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

314 return self.constrain(re.compile(pattern)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

315 

316 def str_contains(self: _Pipeline[_InT, str], substring: str) -> _Pipeline[_InT, str]: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

317 return self.predicate(lambda v: substring in v) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

318 

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

321 

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

324 

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

329 

330 __or__ = otherwise 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

331 

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

335 

336 __and__ = then 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

337 

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

340 

341 queue = deque(self._steps) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

342 

343 s = None 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

344 

345 while queue: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

346 step = queue.popleft() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

347 s = _apply_step(step, s, handler, source_type) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

348 

349 s = s or cs.any_schema() 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

350 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

351 

352 def __supports_type__(self, _: _OutT) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

353 raise NotImplementedError 

354 

355 

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

359 

360 

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

365 

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

370 

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

375 

376 

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

379 

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

394 

395 

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

404 

405 from pydantic import Strict 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

406 

407 if tp is _FieldTypeMarker: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

408 return cs.chain_schema([s, handler(source_type)]) if s else handler(source_type) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

409 

410 if strict: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

411 tp = Annotated[tp, Strict()] # type: ignore 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

412 

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

417 

418 

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

423 

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) 

426 

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

440 

441 return cs.no_info_after_validator_function(func, s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

442 

443 

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: 

459 

460 def check_gt(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

461 return v > gt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

462 

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

474 

475 def check_ge(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

476 return v >= ge 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

477 

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

489 

490 def check_lt(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

491 return v < lt 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

492 

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

504 

505 def check_le(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

506 return v <= le 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

507 

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

512 

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

527 

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

532 

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

544 

545 def check_multiple_of(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

546 return v % multiple_of == 0 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

547 

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

551 

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: 

557 

558 def check_tz_aware(v: object) -> bool: 

559 assert isinstance(v, datetime.datetime) 

560 return v.tzinfo is not None 

561 

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: 

568 

569 def check_tz_naive(v: object) -> bool: 

570 assert isinstance(v, datetime.datetime) 

571 return v.tzinfo is None 

572 

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

588 

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

594 

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

602 

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

608 

609 def check_not_eq(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

610 return operator.__ne__(v, value) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

611 

612 s = _check_func(check_not_eq, f'!= {value}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

613 elif isinstance(constraint, _Eq): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

614 value = constraint.value 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

615 

616 def check_eq(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

617 return operator.__eq__(v, value) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

618 

619 s = _check_func(check_eq, f'== {value}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

620 elif isinstance(constraint, _In): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

621 values = constraint.values 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

622 

623 def check_in(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

624 return operator.__contains__(values, v) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

625 

626 s = _check_func(check_in, f'in {values}', s) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

627 elif isinstance(constraint, _NotIn): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

628 values = constraint.values 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

629 

630 def check_not_in(v: Any) -> bool: 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

631 return operator.__not__(operator.__contains__(values, v)) 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

632 

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: 

640 

641 def check_pattern(v: object) -> bool: 

642 assert isinstance(v, str) 

643 return constraint.match(v) is not None 

644 

645 s = _check_func(check_pattern, f'~ {constraint.pattern}', s) 

646 return s 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

647 

648 

649class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

650 pass 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

651 

652 

653class _SupportsLen(Protocol): 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

654 def __len__(self) -> int: ... 1owqArBagbhsCNefxyDEFGijklHIJpztKuLcmdnvMO

655 

656 

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