Coverage for pydantic/_internal/_validators.py: 99.45%

274 statements  

« prev     ^ index     » next       coverage.py v7.10.0, created at 2025-07-26 11:49 +0000

1"""Validator functions for standard library types. 

2 

3Import of this module is deferred since it contains imports of many standard library modules. 

4""" 

5 

6from __future__ import annotations as _annotations 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

7 

8import collections.abc 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

9import math 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

10import re 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

11import typing 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

12from decimal import Decimal 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

13from fractions import Fraction 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

14from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

15from typing import Any, Callable, Union, cast, get_origin 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

16from zoneinfo import ZoneInfo, ZoneInfoNotFoundError 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

17 

18import typing_extensions 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

19from pydantic_core import PydanticCustomError, core_schema 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

20from pydantic_core._pydantic_core import PydanticKnownError 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

21from typing_inspection import typing_objects 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

22 

23from pydantic._internal._import_utils import import_cached_field_info 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

24from pydantic.errors import PydanticSchemaGenerationError 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

25 

26 

27def sequence_validator( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

28 input_value: typing.Sequence[Any], 

29 /, 

30 validator: core_schema.ValidatorFunctionWrapHandler, 

31) -> typing.Sequence[Any]: 

32 """Validator for `Sequence` types, isinstance(v, Sequence) has already been called.""" 

33 value_type = type(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

34 

35 # We don't accept any plain string as a sequence 

36 # Relevant issue: https://github.com/pydantic/pydantic/issues/5595 

37 if issubclass(value_type, (str, bytes)): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

38 raise PydanticCustomError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

39 'sequence_str', 

40 "'{type_name}' instances are not allowed as a Sequence value", 

41 {'type_name': value_type.__name__}, 

42 ) 

43 

44 # TODO: refactor sequence validation to validate with either a list or a tuple 

45 # schema, depending on the type of the value. 

46 # Additionally, we should be able to remove one of either this validator or the 

47 # SequenceValidator in _std_types_schema.py (preferably this one, while porting over some logic). 

48 # Effectively, a refactor for sequence validation is needed. 

49 if value_type is tuple: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

50 input_value = list(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

51 

52 v_list = validator(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

53 

54 # the rest of the logic is just re-creating the original type from `v_list` 

55 if value_type is list: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

56 return v_list 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

57 elif issubclass(value_type, range): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

58 # return the list as we probably can't re-create the range 

59 return v_list 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

60 elif value_type is tuple: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

61 return tuple(v_list) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

62 else: 

63 # best guess at how to re-create the original type, more custom construction logic might be required 

64 return value_type(v_list) # type: ignore[call-arg] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

65 

66 

67def import_string(value: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

68 if isinstance(value, str): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

69 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

70 return _import_string_logic(value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

71 except ImportError as e: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

72 raise PydanticCustomError('import_error', 'Invalid python path: {error}', {'error': str(e)}) from e 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

73 else: 

74 # otherwise we just return the value and let the next validator do the rest of the work 

75 return value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

76 

77 

78def _import_string_logic(dotted_path: str) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

79 """Inspired by uvicorn — dotted paths should include a colon before the final item if that item is not a module. 

80 (This is necessary to distinguish between a submodule and an attribute when there is a conflict.). 

81 

82 If the dotted path does not include a colon and the final item is not a valid module, importing as an attribute 

83 rather than a submodule will be attempted automatically. 

84 

85 So, for example, the following values of `dotted_path` result in the following returned values: 

86 * 'collections': <module 'collections'> 

87 * 'collections.abc': <module 'collections.abc'> 

88 * 'collections.abc:Mapping': <class 'collections.abc.Mapping'> 

89 * `collections.abc.Mapping`: <class 'collections.abc.Mapping'> (though this is a bit slower than the previous line) 

90 

91 An error will be raised under any of the following scenarios: 

92 * `dotted_path` contains more than one colon (e.g., 'collections:abc:Mapping') 

93 * the substring of `dotted_path` before the colon is not a valid module in the environment (e.g., '123:Mapping') 

94 * the substring of `dotted_path` after the colon is not an attribute of the module (e.g., 'collections:abc123') 

95 """ 

96 from importlib import import_module 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

97 

98 components = dotted_path.strip().split(':') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

99 if len(components) > 2: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

100 raise ImportError(f"Import strings should have at most one ':'; received {dotted_path!r}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

101 

102 module_path = components[0] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

103 if not module_path: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

104 raise ImportError(f'Import strings should have a nonempty module name; received {dotted_path!r}') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

105 

106 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

107 module = import_module(module_path) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

108 except ModuleNotFoundError as e: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

109 if '.' in module_path: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

110 # Check if it would be valid if the final item was separated from its module with a `:` 

111 maybe_module_path, maybe_attribute = dotted_path.strip().rsplit('.', 1) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

112 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

113 return _import_string_logic(f'{maybe_module_path}:{maybe_attribute}') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

114 except ImportError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

115 pass 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

116 raise ImportError(f'No module named {module_path!r}') from e 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

117 raise e 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

118 

119 if len(components) > 1: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

120 attribute = components[1] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

121 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

122 return getattr(module, attribute) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

123 except AttributeError as e: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

124 raise ImportError(f'cannot import name {attribute!r} from {module_path!r}') from e 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

125 else: 

126 return module 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

127 

128 

129def pattern_either_validator(input_value: Any, /) -> typing.Pattern[Any]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

130 if isinstance(input_value, typing.Pattern): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

131 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

132 elif isinstance(input_value, (str, bytes)): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

133 # todo strict mode 

134 return compile_pattern(input_value) # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

135 else: 

136 raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

137 

138 

139def pattern_str_validator(input_value: Any, /) -> typing.Pattern[str]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

140 if isinstance(input_value, typing.Pattern): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

141 if isinstance(input_value.pattern, str): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

142 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

143 else: 

144 raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

145 elif isinstance(input_value, str): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

146 return compile_pattern(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

147 elif isinstance(input_value, bytes): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

148 raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

149 else: 

150 raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

151 

152 

153def pattern_bytes_validator(input_value: Any, /) -> typing.Pattern[bytes]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

154 if isinstance(input_value, typing.Pattern): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

155 if isinstance(input_value.pattern, bytes): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

156 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

157 else: 

158 raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

159 elif isinstance(input_value, bytes): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

160 return compile_pattern(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

161 elif isinstance(input_value, str): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

162 raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

163 else: 

164 raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

165 

166 

167PatternType = typing.TypeVar('PatternType', str, bytes) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

168 

169 

170def compile_pattern(pattern: PatternType) -> typing.Pattern[PatternType]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

171 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

172 return re.compile(pattern) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

173 except re.error: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

174 raise PydanticCustomError('pattern_regex', 'Input should be a valid regular expression') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

175 

176 

177def ip_v4_address_validator(input_value: Any, /) -> IPv4Address: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

178 if isinstance(input_value, IPv4Address): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

179 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

180 

181 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

182 return IPv4Address(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

183 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

184 raise PydanticCustomError('ip_v4_address', 'Input is not a valid IPv4 address') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

185 

186 

187def ip_v6_address_validator(input_value: Any, /) -> IPv6Address: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

188 if isinstance(input_value, IPv6Address): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

189 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

190 

191 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

192 return IPv6Address(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

193 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

194 raise PydanticCustomError('ip_v6_address', 'Input is not a valid IPv6 address') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

195 

196 

197def ip_v4_network_validator(input_value: Any, /) -> IPv4Network: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

198 """Assume IPv4Network initialised with a default `strict` argument. 

199 

200 See more: 

201 https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network 

202 """ 

203 if isinstance(input_value, IPv4Network): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

204 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

205 

206 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

207 return IPv4Network(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

208 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

209 raise PydanticCustomError('ip_v4_network', 'Input is not a valid IPv4 network') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

210 

211 

212def ip_v6_network_validator(input_value: Any, /) -> IPv6Network: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

213 """Assume IPv6Network initialised with a default `strict` argument. 

214 

215 See more: 

216 https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network 

217 """ 

218 if isinstance(input_value, IPv6Network): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

219 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

220 

221 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

222 return IPv6Network(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

223 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

224 raise PydanticCustomError('ip_v6_network', 'Input is not a valid IPv6 network') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

225 

226 

227def ip_v4_interface_validator(input_value: Any, /) -> IPv4Interface: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

228 if isinstance(input_value, IPv4Interface): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

229 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

230 

231 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

232 return IPv4Interface(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

233 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

234 raise PydanticCustomError('ip_v4_interface', 'Input is not a valid IPv4 interface') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

235 

236 

237def ip_v6_interface_validator(input_value: Any, /) -> IPv6Interface: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

238 if isinstance(input_value, IPv6Interface): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

239 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

240 

241 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

242 return IPv6Interface(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

243 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

244 raise PydanticCustomError('ip_v6_interface', 'Input is not a valid IPv6 interface') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

245 

246 

247def fraction_validator(input_value: Any, /) -> Fraction: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

248 if isinstance(input_value, Fraction): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

249 return input_value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

250 

251 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

252 return Fraction(input_value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

253 except ValueError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

254 raise PydanticCustomError('fraction_parsing', 'Input is not a valid fraction') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

255 

256 

257def forbid_inf_nan_check(x: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

258 if not math.isfinite(x): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

259 raise PydanticKnownError('finite_number') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

260 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

261 

262 

263def _safe_repr(v: Any) -> int | float | str: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

264 """The context argument for `PydanticKnownError` requires a number or str type, so we do a simple repr() coercion for types like timedelta. 

265 

266 See tests/test_types.py::test_annotated_metadata_any_order for some context. 

267 """ 

268 if isinstance(v, (int, float, str)): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

269 return v 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

270 return repr(v) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

271 

272 

273def greater_than_validator(x: Any, gt: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

274 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

275 if not (x > gt): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

276 raise PydanticKnownError('greater_than', {'gt': _safe_repr(gt)}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

277 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

278 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

279 raise TypeError(f"Unable to apply constraint 'gt' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

280 

281 

282def greater_than_or_equal_validator(x: Any, ge: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

283 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

284 if not (x >= ge): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

285 raise PydanticKnownError('greater_than_equal', {'ge': _safe_repr(ge)}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

286 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

287 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

288 raise TypeError(f"Unable to apply constraint 'ge' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

289 

290 

291def less_than_validator(x: Any, lt: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

292 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

293 if not (x < lt): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

294 raise PydanticKnownError('less_than', {'lt': _safe_repr(lt)}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

295 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

296 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

297 raise TypeError(f"Unable to apply constraint 'lt' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

298 

299 

300def less_than_or_equal_validator(x: Any, le: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

301 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

302 if not (x <= le): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

303 raise PydanticKnownError('less_than_equal', {'le': _safe_repr(le)}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

304 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

305 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

306 raise TypeError(f"Unable to apply constraint 'le' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

307 

308 

309def multiple_of_validator(x: Any, multiple_of: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

310 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

311 if x % multiple_of: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

312 raise PydanticKnownError('multiple_of', {'multiple_of': _safe_repr(multiple_of)}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

313 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

314 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

315 raise TypeError(f"Unable to apply constraint 'multiple_of' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

316 

317 

318def min_length_validator(x: Any, min_length: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

319 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

320 if not (len(x) >= min_length): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

321 raise PydanticKnownError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

322 'too_short', {'field_type': 'Value', 'min_length': min_length, 'actual_length': len(x)} 

323 ) 

324 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

325 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

326 raise TypeError(f"Unable to apply constraint 'min_length' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

327 

328 

329def max_length_validator(x: Any, max_length: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

330 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

331 if len(x) > max_length: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

332 raise PydanticKnownError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

333 'too_long', 

334 {'field_type': 'Value', 'max_length': max_length, 'actual_length': len(x)}, 

335 ) 

336 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

337 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

338 raise TypeError(f"Unable to apply constraint 'max_length' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

339 

340 

341def _extract_decimal_digits_info(decimal: Decimal) -> tuple[int, int]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

342 """Compute the total number of digits and decimal places for a given [`Decimal`][decimal.Decimal] instance. 

343 

344 This function handles both normalized and non-normalized Decimal instances. 

345 Example: Decimal('1.230') -> 4 digits, 3 decimal places 

346 

347 Args: 

348 decimal (Decimal): The decimal number to analyze. 

349 

350 Returns: 

351 tuple[int, int]: A tuple containing the number of decimal places and total digits. 

352 

353 Though this could be divided into two separate functions, the logic is easier to follow if we couple the computation 

354 of the number of decimals and digits together. 

355 """ 

356 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

357 decimal_tuple = decimal.as_tuple() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

358 

359 assert isinstance(decimal_tuple.exponent, int) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

360 

361 exponent = decimal_tuple.exponent 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

362 num_digits = len(decimal_tuple.digits) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

363 

364 if exponent >= 0: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

365 # A positive exponent adds that many trailing zeros 

366 # Ex: digit_tuple=(1, 2, 3), exponent=2 -> 12300 -> 0 decimal places, 5 digits 

367 num_digits += exponent 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

368 decimal_places = 0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

369 else: 

370 # If the absolute value of the negative exponent is larger than the 

371 # number of digits, then it's the same as the number of digits, 

372 # because it'll consume all the digits in digit_tuple and then 

373 # add abs(exponent) - len(digit_tuple) leading zeros after the decimal point. 

374 # Ex: digit_tuple=(1, 2, 3), exponent=-2 -> 1.23 -> 2 decimal places, 3 digits 

375 # Ex: digit_tuple=(1, 2, 3), exponent=-4 -> 0.0123 -> 4 decimal places, 4 digits 

376 decimal_places = abs(exponent) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

377 num_digits = max(num_digits, decimal_places) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

378 

379 return decimal_places, num_digits 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

380 except (AssertionError, AttributeError): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

381 raise TypeError(f'Unable to extract decimal digits info from supplied value {decimal}') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

382 

383 

384def max_digits_validator(x: Any, max_digits: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

385 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

386 _, num_digits = _extract_decimal_digits_info(x) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

387 _, normalized_num_digits = _extract_decimal_digits_info(x.normalize()) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

388 if (num_digits > max_digits) and (normalized_num_digits > max_digits): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

389 raise PydanticKnownError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

390 'decimal_max_digits', 

391 {'max_digits': max_digits}, 

392 ) 

393 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

394 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

395 raise TypeError(f"Unable to apply constraint 'max_digits' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

396 

397 

398def decimal_places_validator(x: Any, decimal_places: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

399 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

400 decimal_places_, _ = _extract_decimal_digits_info(x) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

401 if decimal_places_ > decimal_places: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

402 normalized_decimal_places, _ = _extract_decimal_digits_info(x.normalize()) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

403 if normalized_decimal_places > decimal_places: 403 ↛ 408line 403 didn't jump to line 408 because the condition on line 403 was always true1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

404 raise PydanticKnownError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

405 'decimal_max_places', 

406 {'decimal_places': decimal_places}, 

407 ) 

408 return x 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

409 except TypeError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

410 raise TypeError(f"Unable to apply constraint 'decimal_places' to supplied value {x}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

411 

412 

413def deque_validator(input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> collections.deque[Any]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

414 return collections.deque(handler(input_value), maxlen=getattr(input_value, 'maxlen', None)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

415 

416 

417def defaultdict_validator( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

418 input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler, default_default_factory: Callable[[], Any] 

419) -> collections.defaultdict[Any, Any]: 

420 if isinstance(input_value, collections.defaultdict): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

421 default_factory = input_value.default_factory 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

422 return collections.defaultdict(default_factory, handler(input_value)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

423 else: 

424 return collections.defaultdict(default_default_factory, handler(input_value)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

425 

426 

427def get_defaultdict_default_default_factory(values_source_type: Any) -> Callable[[], Any]: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

428 FieldInfo = import_cached_field_info() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

429 

430 values_type_origin = get_origin(values_source_type) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

431 

432 def infer_default() -> Callable[[], Any]: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

433 allowed_default_types: dict[Any, Any] = { 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

434 tuple: tuple, 

435 collections.abc.Sequence: tuple, 

436 collections.abc.MutableSequence: list, 

437 list: list, 

438 typing.Sequence: list, 

439 set: set, 

440 typing.MutableSet: set, 

441 collections.abc.MutableSet: set, 

442 collections.abc.Set: frozenset, 

443 typing.MutableMapping: dict, 

444 typing.Mapping: dict, 

445 collections.abc.Mapping: dict, 

446 collections.abc.MutableMapping: dict, 

447 float: float, 

448 int: int, 

449 str: str, 

450 bool: bool, 

451 } 

452 values_type = values_type_origin or values_source_type 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

453 instructions = 'set using `DefaultDict[..., Annotated[..., Field(default_factory=...)]]`' 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

454 if typing_objects.is_typevar(values_type): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

455 

456 def type_var_default_factory() -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

457 raise RuntimeError( 

458 'Generic defaultdict cannot be used without a concrete value type or an' 

459 ' explicit default factory, ' + instructions 

460 ) 

461 

462 return type_var_default_factory 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

463 elif values_type not in allowed_default_types: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

464 # a somewhat subjective set of types that have reasonable default values 

465 allowed_msg = ', '.join([t.__name__ for t in set(allowed_default_types.values())]) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

466 raise PydanticSchemaGenerationError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

467 f'Unable to infer a default factory for keys of type {values_source_type}.' 

468 f' Only {allowed_msg} are supported, other types require an explicit default factory' 

469 ' ' + instructions 

470 ) 

471 return allowed_default_types[values_type] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

472 

473 # Assume Annotated[..., Field(...)] 

474 if typing_objects.is_annotated(values_type_origin): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

475 field_info = next((v for v in typing_extensions.get_args(values_source_type) if isinstance(v, FieldInfo)), None) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

476 else: 

477 field_info = None 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

478 if field_info and field_info.default_factory: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

479 # Assume the default factory does not take any argument: 

480 default_default_factory = cast(Callable[[], Any], field_info.default_factory) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

481 else: 

482 default_default_factory = infer_default() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

483 return default_default_factory 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

484 

485 

486def validate_str_is_valid_iana_tz(value: Any, /) -> ZoneInfo: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

487 if isinstance(value, ZoneInfo): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

488 return value 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

489 try: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

490 return ZoneInfo(value) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

491 except (ZoneInfoNotFoundError, ValueError, TypeError): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

492 raise PydanticCustomError('zoneinfo_str', 'invalid timezone: {value}', {'value': value}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

493 

494 

495NUMERIC_VALIDATOR_LOOKUP: dict[str, Callable] = { 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

496 'gt': greater_than_validator, 

497 'ge': greater_than_or_equal_validator, 

498 'lt': less_than_validator, 

499 'le': less_than_or_equal_validator, 

500 'multiple_of': multiple_of_validator, 

501 'min_length': min_length_validator, 

502 'max_length': max_length_validator, 

503 'max_digits': max_digits_validator, 

504 'decimal_places': decimal_places_validator, 

505} 

506 

507IpType = Union[IPv4Address, IPv6Address, IPv4Network, IPv6Network, IPv4Interface, IPv6Interface] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

508 

509IP_VALIDATOR_LOOKUP: dict[type[IpType], Callable] = { 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

510 IPv4Address: ip_v4_address_validator, 

511 IPv6Address: ip_v6_address_validator, 

512 IPv4Network: ip_v4_network_validator, 

513 IPv6Network: ip_v6_network_validator, 

514 IPv4Interface: ip_v4_interface_validator, 

515 IPv6Interface: ip_v6_interface_validator, 

516} 

517 

518MAPPING_ORIGIN_MAP: dict[Any, Any] = { 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

519 typing.DefaultDict: collections.defaultdict, # noqa: UP006 

520 collections.defaultdict: collections.defaultdict, 

521 typing.OrderedDict: collections.OrderedDict, # noqa: UP006 

522 collections.OrderedDict: collections.OrderedDict, 

523 typing_extensions.OrderedDict: collections.OrderedDict, 

524 typing.Counter: collections.Counter, 

525 collections.Counter: collections.Counter, 

526 # this doesn't handle subclasses of these 

527 typing.Mapping: dict, 

528 typing.MutableMapping: dict, 

529 # parametrized typing.{Mutable}Mapping creates one of these 

530 collections.abc.Mapping: dict, 

531 collections.abc.MutableMapping: dict, 

532}