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

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

2 

3from __future__ import annotations 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

4 

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

15 

16import annotated_types 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

17from typing_extensions import Annotated 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

18 

19if TYPE_CHECKING: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

25 

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

27 EllipsisType = type(Ellipsis) 1oqircstuvpwjx

28else: 

29 from types import EllipsisType 1kylzaedABCDfgmEnFbh

30 

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

32 

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

34 

35 

36@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

37class _ValidateAs: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

38 tp: type[Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

39 strict: bool = False 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

40 

41 

42@dataclass 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

43class _ValidateAsDefer: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

45 

46 @cached_property 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

48 return self.func() 1iklajmnb

49 

50 

51@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

52class _Transform: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

54 

55 

56@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

57class _PipelineOr: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

58 left: _Pipeline[Any, Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

59 right: _Pipeline[Any, Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

60 

61 

62@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

63class _PipelineAnd: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

64 left: _Pipeline[Any, Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

65 right: _Pipeline[Any, Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

66 

67 

68@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

69class _Eq: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

70 value: Any 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

71 

72 

73@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

74class _NotEq: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

75 value: Any 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

76 

77 

78@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

79class _In: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

80 values: Container[Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

81 

82 

83@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

84class _NotIn: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

85 values: Container[Any] 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

86 

87 

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] 

106 

107 

108@dataclass(**_slots_frozen) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

109class _Constraint: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

110 constraint: _ConstraintAnnotation 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

111 

112 

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

114 

115_InT = TypeVar('_InT') 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

116_OutT = TypeVar('_OutT') 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

117_NewOutT = TypeVar('_NewOutT') 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

118 

119 

120class _FieldTypeMarker: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

121 pass 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

129class _Pipeline(Generic[_InT, _OutT]): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

130 """Abstract representation of a chain of validation, transformation, and parsing steps.""" 

131 

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

133 

134 def transform( 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

144 

145 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

147 

148 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

150 ... 

151 

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. 

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

163 

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. 

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

171 

172 # constraints 

173 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

175 

176 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

178 

179 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

181 

182 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

184 

185 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

186 def constrain( 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

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

189 

190 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

191 def constrain( 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

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

194 

195 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

196 def constrain( 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

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

199 

200 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

202 

203 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

204 def constrain( 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

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

207 

208 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

210 

211 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

213 

214 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

216 

217 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

219 

220 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

222 

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

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

232 

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

236 

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

240 

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

244 

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

248 

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

252 

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

256 

257 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

259 

260 @overload 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

262 

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

266 

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

270 

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

274 

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

278 

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

282 

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

286 

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

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

289 

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 

294 

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

299 

300 # string methods 

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

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

303 

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

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

306 

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

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

309 

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

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

312 

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

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

315 

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

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

318 

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

321 

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

324 

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

329 

330 __or__ = otherwise 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

331 

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

335 

336 __and__ = then 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

337 

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

340 

341 queue = deque(self._steps) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

342 

343 s = None 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

344 

345 while queue: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

346 step = queue.popleft() 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

348 

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

350 return s 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

351 

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

353 raise NotImplementedError 

354 

355 

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

359 

360 

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

365 

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

370 

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

375 

376 

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

379 

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

394 

395 

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

404 

405 from pydantic import Strict 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

406 

407 if tp is _FieldTypeMarker: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

408 return handler(source_type) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

409 

410 if strict: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

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

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 true1oqirkylzaecdstuvABCDfgpwjxmEnFbh

414 return handler(tp) 

415 else: 

416 return cs.chain_schema([s, handler(tp)]) if s else handler(tp) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

417 

418 

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

423 

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) 

426 

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

440 

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

442 

443 

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: 

459 

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

461 return v > gt 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

462 

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

474 

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

476 return v >= ge 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

477 

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

489 

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

491 return v < lt 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

492 

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

504 

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

506 return v <= le 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

507 

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

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

527 

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

532 

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

544 

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

546 return v % multiple_of == 0 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

547 

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

551 

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: 

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

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

588 

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

594 

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

604 

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

610 

611 def check_not_eq(v: Any) -> bool: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

612 return operator.__ne__(v, value) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

613 

614 s = _check_func(check_not_eq, f'!= {value}', s) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

615 elif isinstance(constraint, _Eq): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

616 value = constraint.value 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

617 

618 def check_eq(v: Any) -> bool: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

619 return operator.__eq__(v, value) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

620 

621 s = _check_func(check_eq, f'== {value}', s) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

622 elif isinstance(constraint, _In): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

623 values = constraint.values 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

624 

625 def check_in(v: Any) -> bool: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

626 return operator.__contains__(values, v) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

627 

628 s = _check_func(check_in, f'in {values}', s) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

629 elif isinstance(constraint, _NotIn): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

630 values = constraint.values 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

631 

632 def check_not_in(v: Any) -> bool: 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

633 return operator.__not__(operator.__contains__(values, v)) 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

634 

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: 

642 

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

644 assert isinstance(v, str) 

645 return constraint.match(v) is not None 

646 

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

648 return s 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

649 

650 

651class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

652 pass 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

653 

654 

655class _SupportsLen(Protocol): 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

656 def __len__(self) -> int: ... 1oqirkylzaecdstuvABCDfgpwjxmEnFbh

657 

658 

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