Last active
May 25, 2019 23:48
-
-
Save dmontagu/0a8b823c2c5dec3954405a921028f7dd to your computer and use it in GitHub Desktop.
Pydantic benchmark line-profiled
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Full output on cython branch: | |
----------------------------- | |
pydantic time=6.347s, success=50.60% | |
pydantic time=7.167s, success=50.60% | |
pydantic time=8.733s, success=50.60% | |
pydantic time=6.832s, success=50.60% | |
pydantic time=7.747s, success=50.60% | |
pydantic best=6.347s, avg=7.365s, stdev=0.919s | |
pydantic best=211.579μs/iter avg=245.504μs/iter stdev=30.618μs/iter | |
Timer unit: 1e-06 s | |
Total time: 36.6847 s | |
File: pydantic/benchmarks/run.py | |
Function: run_tests at line 149 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
149 def run_tests(tests: List[Type]): | |
150 1 43.0 43.0 0.0 json_path = THIS_DIR / 'cases.json' | |
151 1 31.0 31.0 0.0 if not json_path.exists(): | |
152 print('generating test cases...') | |
153 cases = [generate_case() for _ in range(2000)] | |
154 with json_path.open('w') as f: | |
155 json.dump(cases, f, indent=2, sort_keys=True) | |
156 else: | |
157 1 91.0 91.0 0.0 with json_path.open() as f: | |
158 1 64371.0 64371.0 0.2 cases = json.load(f) | |
159 1 28.0 28.0 0.0 repeats = int(os.getenv('BENCHMARK_REPEATS', '5')) | |
160 1 1.0 1.0 0.0 results = [] | |
161 1 2.0 2.0 0.0 csv_results = [] | |
162 2 3.0 1.5 0.0 for test_class in tests: | |
163 1 1.0 1.0 0.0 times = [] | |
164 1 2.0 2.0 0.0 p = test_class.package | |
165 6 12.0 2.0 0.0 for i in range(repeats): | |
166 5 9.0 1.8 0.0 count, pass_count = 0, 0 | |
167 5 30.0 6.0 0.0 start = datetime.now() | |
168 5 26.0 5.2 0.0 test = test_class(True) | |
169 20 37.0 1.9 0.0 for i in range(3): | |
170 30015 45920.0 1.5 0.1 for case in cases: | |
171 30000 36470104.0 1215.7 99.4 passed, result = test.validate(case) | |
172 30000 55220.0 1.8 0.2 count += 1 | |
173 30000 47280.0 1.6 0.1 pass_count += passed | |
174 5 63.0 12.6 0.0 time = (datetime.now() - start).total_seconds() | |
175 5 10.0 2.0 0.0 success = pass_count / count * 100 | |
176 5 202.0 40.4 0.0 print(f'{p:>40} time={time:0.3f}s, success={success:0.2f}%') | |
177 5 14.0 2.8 0.0 times.append(time) | |
178 1 657.0 657.0 0.0 print(f'{p:>40} best={min(times):0.3f}s, avg={mean(times):0.3f}s, stdev={stdev(times):0.3f}s') | |
179 1 2.0 2.0 0.0 model_count = repeats * 3 * len(cases) | |
180 1 114.0 114.0 0.0 avg = mean(times) / model_count * 1e6 | |
181 1 379.0 379.0 0.0 sd = stdev(times) / model_count * 1e6 | |
182 1 8.0 8.0 0.0 results.append(f'{p:>40} best={min(times) / model_count * 1e6:0.3f}μs/iter ' | |
183 f'avg={avg:0.3f}μs/iter stdev={sd:0.3f}μs/iter') | |
184 1 2.0 2.0 0.0 csv_results.append([p, avg, sd]) | |
185 1 10.0 10.0 0.0 print() | |
186 2 2.0 1.0 0.0 for r in results: | |
187 1 6.0 6.0 0.0 print(r) | |
188 1 15.0 15.0 0.0 if 'SAVE' in os.environ: | |
189 csv_file = StringIO() | |
190 csv_writer = csv.writer(csv_file) | |
191 first_avg = None | |
192 for p, avg, sd in sorted(csv_results, key=itemgetter(1)): | |
193 if first_avg: | |
194 relative = f'{avg / first_avg:0.1f}x slower' | |
195 else: | |
196 relative = '' | |
197 first_avg = avg | |
198 csv_writer.writerow([p, relative, f'{avg:0.1f}μs', f'{sd:0.3f}μs']) | |
199 p = Path(THIS_DIR / '../docs/benchmarks.csv') | |
200 print(f'saving results to {p}') | |
201 p.write_text(csv_file.getvalue()) | |
Total time: 36.2438 s | |
File: pydantic/benchmarks/test_pydantic.py | |
Function: validate at line 53 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
53 def validate(self, data): | |
54 30000 13931.0 0.5 0.0 try: | |
55 30000 35611362.0 1187.0 98.3 return True, self.model(**data) | |
56 14820 15806.0 1.1 0.0 except ValidationError as e: | |
57 14820 602737.0 40.7 1.7 return False, str(e) | |
Total time: 8.9698 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 202 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
202 1178985 8969804.0 7.6 100.0 return lambda cls, v, values, field, config: validator(v) | |
Total time: 0.32665 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 206 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
206 58710 326650.0 5.6 100.0 return lambda cls, v, values, field, config: validator(v, field=field) | |
Total time: 1.05909 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 214 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
214 159330 1059089.0 6.6 100.0 return lambda cls, v, values, field, config: validator(v, field=field, config=config) | |
Total time: 1.80439 s | |
File: pydantic/pydantic/datetime_parse.py | |
Function: parse_datetime at line 139 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
139 def parse_datetime(value: Union[datetime, StrIntFloat]) -> datetime: | |
140 """ | |
141 Parse a datetime/int/float/string and return a datetime.datetime. | |
142 | |
143 This function supports time zone offsets. When the input contains one, | |
144 the output uses a timezone with a fixed offset from UTC. | |
145 | |
146 Raise ValueError if the input is well formatted but not a valid datetime. | |
147 Raise ValueError if the input isn't well formatted. | |
148 """ | |
149 30000 43897.0 1.5 2.4 if isinstance(value, datetime): | |
150 return value | |
151 | |
152 30000 382451.0 12.7 21.2 number = get_numeric(value) | |
153 30000 29223.0 1.0 1.6 if number is not None: | |
154 return from_unix_seconds(number) | |
155 | |
156 30000 235176.0 7.8 13.0 match = datetime_re.match(cast(str, value)) | |
157 30000 29546.0 1.0 1.6 if not match: | |
158 raise errors.DateTimeError() | |
159 | |
160 30000 99635.0 3.3 5.5 kw = match.groupdict() | |
161 30000 35429.0 1.2 2.0 if kw['microsecond']: | |
162 kw['microsecond'] = kw['microsecond'].ljust(6, '0') | |
163 | |
164 30000 38811.0 1.3 2.2 tzinfo_str = kw.pop('tzinfo') | |
165 30000 29548.0 1.0 1.6 if tzinfo_str == 'Z': | |
166 tzinfo = timezone.utc | |
167 30000 26438.0 0.9 1.5 elif tzinfo_str is not None: | |
168 offset_mins = int(tzinfo_str[-2:]) if len(tzinfo_str) > 3 else 0 | |
169 offset = 60 * int(tzinfo_str[1:3]) + offset_mins | |
170 if tzinfo_str[0] == '-': | |
171 offset = -offset | |
172 tzinfo = timezone(timedelta(minutes=offset)) | |
173 else: | |
174 30000 24569.0 0.8 1.4 tzinfo = None | |
175 | |
176 30000 228746.0 7.6 12.7 kw_: Dict[str, Union[int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} | |
177 30000 32779.0 1.1 1.8 kw_['tzinfo'] = tzinfo | |
178 | |
179 30000 273113.0 9.1 15.1 with change_exception(errors.DateTimeError, ValueError): | |
180 30000 295030.0 9.8 16.4 return datetime(**kw_) # type: ignore | |
Total time: 26.0323 s | |
File: pydantic/pydantic/main.py | |
Function: __init__ at line 221 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
221 def __init__(self, **data: Any) -> None: | |
222 133245 73015.0 0.5 0.3 if TYPE_CHECKING: # pragma: no cover | |
223 self.__values__: Dict[str, Any] = {} | |
224 self.__fields_set__: 'SetStr' = set() | |
225 133245 25706724.0 192.9 98.7 values, fields_set, _ = parse_model(self, data) | |
226 117150 158198.0 1.4 0.6 object.__setattr__(self, '__values__', values) | |
227 117150 94338.0 0.8 0.4 object.__setattr__(self, '__fields_set__', fields_set) | |
Total time: 18.4985 s | |
File: pydantic/pydantic/main.py | |
Function: validate at line 413 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
413 @classmethod | |
414 def validate(cls: Type['Model'], value: Union['DictStrAny', 'Model']) -> 'Model': | |
415 103245 86499.0 0.8 0.5 if isinstance(value, dict): | |
416 103245 18411991.0 178.3 99.5 return cls(**value) | |
417 elif isinstance(value, cls): | |
418 return value.copy() | |
419 else: | |
420 with change_exception(DictError, TypeError, ValueError): | |
421 return cls(**dict(value)) # type: ignore | |
Total time: 0.130548 s | |
File: pydantic/pydantic/types.py | |
Function: validate at line 144 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
144 @classmethod | |
145 def validate(cls, value: str) -> str: | |
146 75795 51430.0 0.7 39.4 if cls.curtail_length and len(value) > cls.curtail_length: | |
147 value = value[: cls.curtail_length] | |
148 | |
149 75795 48743.0 0.6 37.3 if cls.regex: | |
150 if not cls.regex.match(value): | |
151 raise errors.StrRegexError(pattern=cls.regex.pattern) | |
152 | |
153 75795 30375.0 0.4 23.3 return value | |
Total time: 0.351456 s | |
File: pydantic/pydantic/types.py | |
Function: constr_length_validator at line 629 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
629 def constr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
630 79665 69432.0 0.9 19.8 v_len = len(v) | |
631 | |
632 79665 60986.0 0.8 17.4 min_length = field.type_.min_length or config.min_anystr_length # type: ignore | |
633 79665 49105.0 0.6 14.0 if min_length is not None and v_len < min_length: | |
634 240 2215.0 9.2 0.6 raise errors.AnyStrMinLengthError(limit_value=min_length) | |
635 | |
636 79425 51255.0 0.6 14.6 max_length = field.type_.max_length or config.max_anystr_length # type: ignore | |
637 79425 51205.0 0.6 14.6 if max_length is not None and v_len > max_length: | |
638 3630 32920.0 9.1 9.4 raise errors.AnyStrMaxLengthError(limit_value=max_length) | |
639 | |
640 75795 34338.0 0.5 9.8 return v | |
Total time: 0.133752 s | |
File: pydantic/pydantic/types.py | |
Function: constr_strip_whitespace at line 643 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
643 def constr_strip_whitespace(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
644 79665 62219.0 0.8 46.5 strip_whitespace = field.type_.strip_whitespace or config.anystr_strip_whitespace # type: ignore | |
645 79665 39084.0 0.5 29.2 if strip_whitespace: | |
646 v = v.strip() | |
647 | |
648 79665 32449.0 0.4 24.3 return v | |
Total time: 20.9474 s | |
File: pydantic/fields.py | |
Function: validate at line 267 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
267 def validate( | |
268 self, v: Any, values: Dict[str, Any], *, loc: 'LocType', cls: Optional['ModelOrDc'] = None | |
269 ) -> 'ValidateReturn': | |
270 774270 416122.0 0.5 2.0 if self.allow_none and not self.validate_always and v is None: | |
271 12450 5395.0 0.4 0.0 return None, None | |
272 | |
273 761820 289390.0 0.4 1.4 loc = loc if isinstance(loc, tuple) else (loc,) | |
274 | |
275 761820 322689.0 0.4 1.5 if v is not None and self.parse_json: | |
276 v, error = self._validate_json(v, loc) | |
277 if error: | |
278 return v, error | |
279 | |
280 761820 267501.0 0.4 1.3 errors: Optional['ErrorList'] = None | |
281 761820 311815.0 0.4 1.5 if self.whole_pre_validators: | |
282 v, errors = self._apply_validators(v, values, loc, cls, self.whole_pre_validators) | |
283 if errors: | |
284 return v, errors | |
285 | |
286 761820 510978.0 0.7 2.4 if self.shape is Shape.SINGLETON: | |
287 731820 17140549.0 23.4 81.8 v, errors = self._validate_singleton(v, values, loc, cls) | |
288 30000 21263.0 0.7 0.1 elif self.shape is Shape.MAPPING: | |
289 v, errors = self._validate_mapping(v, values, loc, cls) | |
290 30000 19867.0 0.7 0.1 elif self.shape is Shape.TUPLE: | |
291 v, errors = self._validate_tuple(v, values, loc, cls) | |
292 else: | |
293 # sequence, list, tuple, set, generator | |
294 30000 1003391.0 33.4 4.8 v, errors = self._validate_sequence_like(v, values, loc, cls) | |
295 | |
296 761820 335088.0 0.4 1.6 if not errors and self.whole_post_validators: | |
297 v, errors = self._apply_validators(v, values, loc, cls, self.whole_post_validators) | |
298 761820 303304.0 0.4 1.4 return v, errors | |
Total time: 18.278 s | |
File: pydantic/fields.py | |
Function: _validate_singleton at line 407 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
407 def _validate_singleton( | |
408 self, v: Any, values: Dict[str, Any], loc: 'LocType', cls: Optional['ModelOrDc'] | |
409 ) -> 'ValidateReturn': | |
410 805065 384619.0 0.5 2.1 if self.sub_fields: | |
411 errors = [] | |
412 for field in self.sub_fields: | |
413 value, error = field.validate(v, values, loc=loc, cls=cls) | |
414 if error: | |
415 errors.append(error) | |
416 else: | |
417 return value, None | |
418 return v, errors | |
419 else: | |
420 805065 17893342.0 22.2 97.9 return self._apply_validators(v, values, loc, cls, self.validators) | |
Total time: 14.7918 s | |
File: pydantic/fields.py | |
Function: _apply_validators at line 422 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
422 def _apply_validators( | |
423 self, v: Any, values: Dict[str, Any], loc: 'LocType', cls: Optional['ModelOrDc'], validators: 'ValidatorsList' | |
424 ) -> 'ValidateReturn': | |
425 2187810 920126.0 0.4 6.2 for validator in validators: | |
426 1397025 1028795.0 0.7 7.0 get_line_profiler().add_function(validator) # just adds lambdas | |
427 # The added lambdas are from class_validators.py lines 202, 206, 214 (see that file's line 198) | |
428 1397025 545188.0 0.4 3.7 try: | |
429 1397025 11902918.0 8.5 80.5 v = validator(cls, v, values, self, self.model_config) | |
430 14280 20968.0 1.5 0.1 except (ValueError, TypeError) as exc: | |
431 14280 72789.0 5.1 0.5 return v, ErrorWrapper(exc, loc=loc, config=self.model_config) | |
432 790785 301055.0 0.4 2.0 return v, None | |
Total time: 29.2752 s | |
File: pydantic/parse.py | |
Function: parse_model at line 37 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
37 def parse_model( # noqa: C901 (ignore complexity) | |
38 model: Union['BaseModel', Type['BaseModel']], | |
39 input_data: 'DictStrAny', | |
40 raise_exc: bool = True, | |
41 cls: 'ModelOrDc' = None, | |
42 ) -> Tuple['DictStrAny', 'SetStr', Optional[ValidationError]]: | |
43 """ | |
44 validate data against a model. | |
45 """ | |
46 133245 107999.0 0.8 0.4 values = {} | |
47 133245 66082.0 0.5 0.2 errors = [] | |
48 # input_data names, possibly alias | |
49 133245 73858.0 0.6 0.3 names_used = set() | |
50 # field names, never aliases | |
51 133245 77625.0 0.6 0.3 fields_set = set() | |
52 133245 77971.0 0.6 0.3 config = model.__config__ | |
53 133245 123935.0 0.9 0.4 check_extra = config.extra is not Extra.ignore | |
54 | |
55 133245 82103.0 0.6 0.3 for name, field in model.__fields__.items(): | |
56 799470 460635.0 0.6 1.6 if type(field.type_) == ForwardRef: | |
57 raise ConfigError( | |
58 f'field "{field.name}" not yet prepared so type is still a ForwardRef, ' | |
59 f'you might need to call {model.__class__.__name__}.update_forward_refs().' | |
60 ) | |
61 | |
62 799470 551927.0 0.7 1.9 value = input_data.get(field.alias, _missing) | |
63 799470 327377.0 0.4 1.1 using_name = False | |
64 799470 336394.0 0.4 1.1 if value is _missing and config.allow_population_by_alias and field.alt_alias: | |
65 value = input_data.get(field.name, _missing) | |
66 using_name = True | |
67 | |
68 799470 343603.0 0.4 1.2 if value is _missing: | |
69 25200 16435.0 0.7 0.1 if field.required: | |
70 5820 57500.0 9.9 0.2 errors.append(ErrorWrapper(MissingError(), loc=field.alias, config=model.__config__)) | |
71 5820 3612.0 0.6 0.0 continue | |
72 19380 153271.0 7.9 0.5 value = deepcopy(field.default) | |
73 19380 17232.0 0.9 0.1 if not model.__config__.validate_all and not field.validate_always: | |
74 19380 9527.0 0.5 0.0 values[name] = value | |
75 19380 8953.0 0.5 0.0 continue | |
76 else: | |
77 774270 477415.0 0.6 1.6 fields_set.add(name) | |
78 774270 329243.0 0.4 1.1 if check_extra: | |
79 275460 148200.0 0.5 0.5 names_used.add(field.name if using_name else field.alias) | |
80 | |
81 774270 23755947.0 30.7 81.1 v_, errors_ = field.validate(value, values, loc=field.alias, cls=cls or model.__class__) # type: ignore | |
82 774270 418027.0 0.5 1.4 if isinstance(errors_, ErrorWrapper): | |
83 13005 8909.0 0.7 0.0 errors.append(errors_) | |
84 761265 317434.0 0.4 1.1 elif isinstance(errors_, list): | |
85 1245 891.0 0.7 0.0 errors.extend(errors_) | |
86 else: | |
87 760020 455734.0 0.6 1.6 values[name] = v_ | |
88 | |
89 133245 62109.0 0.5 0.2 if check_extra: | |
90 30000 118488.0 3.9 0.4 extra = input_data.keys() - names_used | |
91 30000 18360.0 0.6 0.1 if extra: | |
92 fields_set |= extra | |
93 if config.extra is Extra.allow: | |
94 for f in extra: | |
95 values[f] = input_data[f] | |
96 else: | |
97 for f in sorted(extra): | |
98 errors.append(ErrorWrapper(ExtraError(), loc=f, config=config)) | |
99 | |
100 133245 56371.0 0.4 0.2 if not raise_exc: | |
101 return values, fields_set, ValidationError(errors) if errors else None | |
102 | |
103 133245 63516.0 0.5 0.2 if errors: | |
104 16095 68167.0 4.2 0.2 raise ValidationError(errors) | |
105 117150 80334.0 0.7 0.3 return values, fields_set, None | |
Total time: 0.286555 s | |
File: pydantic/validators.py | |
Function: not_none_validator at line 42 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
42 def not_none_validator(v: Any) -> Any: | |
43 302085 144334.0 0.5 50.4 if v is None: | |
44 3960 23423.0 5.9 8.2 raise errors.NoneIsNotAllowedError() | |
45 298125 118798.0 0.4 41.5 return v | |
Total time: 0.27822 s | |
File: pydantic/validators.py | |
Function: str_validator at line 53 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
53 def str_validator(v: Any) -> Optional[str]: | |
54 298125 180131.0 0.6 64.7 if type(v) == str or v is None: | |
55 298125 98089.0 0.3 35.3 return v | |
56 elif isinstance(v, str): | |
57 if isinstance(v, Enum): | |
58 return v.value | |
59 else: | |
60 return v | |
61 elif isinstance(v, (bytes, bytearray)): | |
62 return v.decode() | |
63 elif isinstance(v, (float, int, Decimal)): | |
64 # is there anything else we want to add here? If you think so, create an issue. | |
65 return str(v) | |
66 else: | |
67 raise errors.StrError() | |
Total time: 0.641086 s | |
File: pydantic/validators.py | |
Function: int_validator at line 96 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
96 def int_validator(v: Any) -> int: | |
97 206490 113053.0 0.5 17.6 if isinstance(v, int) and not isinstance(v, bool): | |
98 176490 59966.0 0.3 9.4 return v | |
99 | |
100 30000 296106.0 9.9 46.2 with change_exception(errors.IntegerError, TypeError, ValueError): | |
101 30000 171961.0 5.7 26.8 return int(v) | |
Total time: 0.122023 s | |
File: pydantic/validators.py | |
Function: float_validator at line 104 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
104 def float_validator(v: Any) -> float: | |
105 163245 69505.0 0.4 57.0 if isinstance(v, float): | |
106 163245 52518.0 0.3 43.0 return v | |
107 | |
108 with change_exception(errors.FloatError, TypeError, ValueError): | |
109 return float(v) | |
Total time: 0.033397 s | |
File: pydantic/validators.py | |
Function: number_multiple_validator at line 112 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
112 def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number': | |
113 28710 12600.0 0.4 37.7 field_type: ConstrainedNumber = field.type_ # type: ignore | |
114 28710 11818.0 0.4 35.4 if field_type.multiple_of is not None and v % field_type.multiple_of != 0: # type: ignore | |
115 raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) | |
116 | |
117 28710 8979.0 0.3 26.9 return v | |
Total time: 0.089658 s | |
File: pydantic/validators.py | |
Function: number_size_validator at line 120 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
120 def number_size_validator(v: 'Number', field: 'Field') -> 'Number': | |
121 30000 14069.0 0.5 15.7 field_type: ConstrainedNumber = field.type_ # type: ignore | |
122 30000 18160.0 0.6 20.3 if field_type.gt is not None and not v > field_type.gt: | |
123 1290 10871.0 8.4 12.1 raise errors.NumberNotGtError(limit_value=field_type.gt) | |
124 28710 13198.0 0.5 14.7 elif field_type.ge is not None and not v >= field_type.ge: | |
125 raise errors.NumberNotGeError(limit_value=field_type.ge) | |
126 | |
127 28710 12220.0 0.4 13.6 if field_type.lt is not None and not v < field_type.lt: | |
128 raise errors.NumberNotLtError(limit_value=field_type.lt) | |
129 28710 11285.0 0.4 12.6 if field_type.le is not None and not v <= field_type.le: | |
130 raise errors.NumberNotLeError(limit_value=field_type.le) | |
131 | |
132 28710 9855.0 0.3 11.0 return v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Only last "layer" of functions output on cython branch (rebuilt): | |
----------------------------------------------------------------- | |
pydantic time=2.390s, success=50.60% | |
pydantic time=2.360s, success=50.60% | |
pydantic time=2.356s, success=50.60% | |
pydantic time=2.362s, success=50.60% | |
pydantic time=2.382s, success=50.60% | |
pydantic best=2.356s, avg=2.370s, stdev=0.015s | |
pydantic best=78.526μs/iter avg=78.998μs/iter stdev=0.501μs/iter | |
Timer unit: 1e-06 s | |
Total time: 1.35921 s | |
File: pydantic/pydantic/datetime_parse.py | |
Function: parse_datetime at line 139 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
139 def parse_datetime(value: Union[datetime, StrIntFloat]) -> datetime: | |
140 """ | |
141 Parse a datetime/int/float/string and return a datetime.datetime. | |
142 | |
143 This function supports time zone offsets. When the input contains one, | |
144 the output uses a timezone with a fixed offset from UTC. | |
145 | |
146 Raise ValueError if the input is well formatted but not a valid datetime. | |
147 Raise ValueError if the input isn't well formatted. | |
148 """ | |
149 30000 35065.0 1.2 2.6 if isinstance(value, datetime): | |
150 return value | |
151 | |
152 30000 267460.0 8.9 19.7 number = get_numeric(value) | |
153 30000 24521.0 0.8 1.8 if number is not None: | |
154 return from_unix_seconds(number) | |
155 | |
156 30000 161104.0 5.4 11.9 match = datetime_re.match(cast(str, value)) | |
157 30000 24395.0 0.8 1.8 if not match: | |
158 raise errors.DateTimeError() | |
159 | |
160 30000 66960.0 2.2 4.9 kw = match.groupdict() | |
161 30000 28583.0 1.0 2.1 if kw['microsecond']: | |
162 kw['microsecond'] = kw['microsecond'].ljust(6, '0') | |
163 | |
164 30000 33135.0 1.1 2.4 tzinfo_str = kw.pop('tzinfo') | |
165 30000 25899.0 0.9 1.9 if tzinfo_str == 'Z': | |
166 tzinfo = timezone.utc | |
167 30000 21819.0 0.7 1.6 elif tzinfo_str is not None: | |
168 offset_mins = int(tzinfo_str[-2:]) if len(tzinfo_str) > 3 else 0 | |
169 offset = 60 * int(tzinfo_str[1:3]) + offset_mins | |
170 if tzinfo_str[0] == '-': | |
171 offset = -offset | |
172 tzinfo = timezone(timedelta(minutes=offset)) | |
173 else: | |
174 30000 21797.0 0.7 1.6 tzinfo = None | |
175 | |
176 30000 184802.0 6.2 13.6 kw_: Dict[str, Union[int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} | |
177 30000 27140.0 0.9 2.0 kw_['tzinfo'] = tzinfo | |
178 | |
179 30000 211138.0 7.0 15.5 with change_exception(errors.DateTimeError, ValueError): | |
180 30000 225396.0 7.5 16.6 return datetime(**kw_) # type: ignore | |
Total time: 4.57487 s | |
File: pydantic/pydantic/main.py | |
Function: validate at line 413 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
413 @classmethod | |
414 def validate(cls: Type['Model'], value: Union['DictStrAny', 'Model']) -> 'Model': | |
415 103245 75794.0 0.7 1.7 if isinstance(value, dict): | |
416 103245 4499081.0 43.6 98.3 return cls(**value) | |
417 elif isinstance(value, cls): | |
418 return value.copy() | |
419 else: | |
420 with change_exception(DictError, TypeError, ValueError): | |
421 return cls(**dict(value)) # type: ignore | |
Total time: 0.102269 s | |
File: pydantic/pydantic/types.py | |
Function: validate at line 144 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
144 @classmethod | |
145 def validate(cls, value: str) -> str: | |
146 75795 38268.0 0.5 37.4 if cls.curtail_length and len(value) > cls.curtail_length: | |
147 value = value[: cls.curtail_length] | |
148 | |
149 75795 35379.0 0.5 34.6 if cls.regex: | |
150 if not cls.regex.match(value): | |
151 raise errors.StrRegexError(pattern=cls.regex.pattern) | |
152 | |
153 75795 28622.0 0.4 28.0 return value | |
Total time: 0.30178 s | |
File: pydantic/pydantic/types.py | |
Function: constr_length_validator at line 629 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
629 def constr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
630 79665 57998.0 0.7 19.2 v_len = len(v) | |
631 | |
632 79665 52897.0 0.7 17.5 min_length = field.type_.min_length or config.min_anystr_length # type: ignore | |
633 79665 43675.0 0.5 14.5 if min_length is not None and v_len < min_length: | |
634 240 1488.0 6.2 0.5 raise errors.AnyStrMinLengthError(limit_value=min_length) | |
635 | |
636 79425 46118.0 0.6 15.3 max_length = field.type_.max_length or config.max_anystr_length # type: ignore | |
637 79425 46699.0 0.6 15.5 if max_length is not None and v_len > max_length: | |
638 3630 20717.0 5.7 6.9 raise errors.AnyStrMaxLengthError(limit_value=max_length) | |
639 | |
640 75795 32188.0 0.4 10.7 return v | |
Total time: 0.118638 s | |
File: pydantic/pydantic/types.py | |
Function: constr_strip_whitespace at line 643 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
643 def constr_strip_whitespace(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
644 79665 52725.0 0.7 44.4 strip_whitespace = field.type_.strip_whitespace or config.anystr_strip_whitespace # type: ignore | |
645 79665 35205.0 0.4 29.7 if strip_whitespace: | |
646 v = v.strip() | |
647 | |
648 79665 30708.0 0.4 25.9 return v | |
Total time: 0.192056 s | |
File: pydantic/validators.py | |
Function: not_none_validator at line 42 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
42 def not_none_validator(v: Any) -> Any: | |
43 302085 97435.0 0.3 50.7 if v is None: | |
44 3960 14558.0 3.7 7.6 raise errors.NoneIsNotAllowedError() | |
45 298125 80063.0 0.3 41.7 return v | |
Total time: 0.175338 s | |
File: pydantic/validators.py | |
Function: str_validator at line 53 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
53 def str_validator(v: Any) -> Optional[str]: | |
54 298125 96370.0 0.3 55.0 if type(v) == str or v is None: | |
55 298125 78968.0 0.3 45.0 return v | |
56 elif isinstance(v, str): | |
57 if isinstance(v, Enum): | |
58 return v.value | |
59 else: | |
60 return v | |
61 elif isinstance(v, (bytes, bytearray)): | |
62 return v.decode() | |
63 elif isinstance(v, (float, int, Decimal)): | |
64 # is there anything else we want to add here? If you think so, create an issue. | |
65 return str(v) | |
66 else: | |
67 raise errors.StrError() | |
Total time: 0.463655 s | |
File: pydantic/validators.py | |
Function: int_validator at line 96 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
96 def int_validator(v: Any) -> int: | |
97 206490 87733.0 0.4 18.9 if isinstance(v, int) and not isinstance(v, bool): | |
98 176490 49375.0 0.3 10.6 return v | |
99 | |
100 30000 210534.0 7.0 45.4 with change_exception(errors.IntegerError, TypeError, ValueError): | |
101 30000 116013.0 3.9 25.0 return int(v) | |
Total time: 0.101566 s | |
File: pydantic/validators.py | |
Function: float_validator at line 104 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
104 def float_validator(v: Any) -> float: | |
105 163245 56418.0 0.3 55.5 if isinstance(v, float): | |
106 163245 45148.0 0.3 44.5 return v | |
107 | |
108 with change_exception(errors.FloatError, TypeError, ValueError): | |
109 return float(v) | |
Total time: 0.029538 s | |
File: pydantic/validators.py | |
Function: number_multiple_validator at line 112 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
112 def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number': | |
113 28710 11334.0 0.4 38.4 field_type: ConstrainedNumber = field.type_ # type: ignore | |
114 28710 9891.0 0.3 33.5 if field_type.multiple_of is not None and v % field_type.multiple_of != 0: # type: ignore | |
115 raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) | |
116 | |
117 28710 8313.0 0.3 28.1 return v | |
Total time: 0.08339 s | |
File: pydantic/validators.py | |
Function: number_size_validator at line 120 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
120 def number_size_validator(v: 'Number', field: 'Field') -> 'Number': | |
121 30000 13196.0 0.4 15.8 field_type: ConstrainedNumber = field.type_ # type: ignore | |
122 30000 16044.0 0.5 19.2 if field_type.gt is not None and not v > field_type.gt: | |
123 1290 7594.0 5.9 9.1 raise errors.NumberNotGtError(limit_value=field_type.gt) | |
124 28710 10729.0 0.4 12.9 elif field_type.ge is not None and not v >= field_type.ge: | |
125 raise errors.NumberNotGeError(limit_value=field_type.ge) | |
126 | |
127 28710 10116.0 0.4 12.1 if field_type.lt is not None and not v < field_type.lt: | |
128 raise errors.NumberNotLtError(limit_value=field_type.lt) | |
129 28710 17292.0 0.6 20.7 if field_type.le is not None and not v <= field_type.le: | |
130 raise errors.NumberNotLeError(limit_value=field_type.le) | |
131 | |
132 28710 8419.0 0.3 10.1 return v | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Full output on master branch: | |
----------------------------- | |
pydantic time=12.307s, success=50.60% | |
pydantic time=12.382s, success=50.60% | |
pydantic time=11.954s, success=50.60% | |
pydantic time=11.702s, success=50.60% | |
pydantic time=12.395s, success=50.60% | |
pydantic best=11.702s, avg=12.148s, stdev=0.307s | |
pydantic best=390.063μs/iter avg=404.935μs/iter stdev=10.241μs/iter | |
Timer unit: 1e-06 s | |
Total time: 60.6283 s | |
File: pydantic/benchmarks/run.py | |
Function: run_tests at line 149 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
149 def run_tests(tests: List[Type]): | |
150 1 49.0 49.0 0.0 json_path = THIS_DIR / 'cases.json' | |
151 1 34.0 34.0 0.0 if not json_path.exists(): | |
152 print('generating test cases...') | |
153 cases = [generate_case() for _ in range(2000)] | |
154 with json_path.open('w') as f: | |
155 json.dump(cases, f, indent=2, sort_keys=True) | |
156 else: | |
157 1 95.0 95.0 0.0 with json_path.open() as f: | |
158 1 62785.0 62785.0 0.1 cases = json.load(f) | |
159 1 25.0 25.0 0.0 repeats = int(os.getenv('BENCHMARK_REPEATS', '5')) | |
160 1 1.0 1.0 0.0 results = [] | |
161 1 1.0 1.0 0.0 csv_results = [] | |
162 2 4.0 2.0 0.0 for test_class in tests: | |
163 1 1.0 1.0 0.0 times = [] | |
164 1 2.0 2.0 0.0 p = test_class.package | |
165 6 11.0 1.8 0.0 for i in range(repeats): | |
166 5 6.0 1.2 0.0 count, pass_count = 0, 0 | |
167 5 27.0 5.4 0.0 start = datetime.now() | |
168 5 29.0 5.8 0.0 test = test_class(True) | |
169 20 36.0 1.8 0.0 for i in range(3): | |
170 30015 39068.0 1.3 0.1 for case in cases: | |
171 30000 60434256.0 2014.5 99.7 passed, result = test.validate(case) | |
172 30000 48534.0 1.6 0.1 count += 1 | |
173 30000 42018.0 1.4 0.1 pass_count += passed | |
174 5 75.0 15.0 0.0 time = (datetime.now() - start).total_seconds() | |
175 5 12.0 2.4 0.0 success = pass_count / count * 100 | |
176 5 168.0 33.6 0.0 print(f'{p:>40} time={time:0.3f}s, success={success:0.2f}%') | |
177 5 9.0 1.8 0.0 times.append(time) | |
178 1 582.0 582.0 0.0 print(f'{p:>40} best={min(times):0.3f}s, avg={mean(times):0.3f}s, stdev={stdev(times):0.3f}s') | |
179 1 2.0 2.0 0.0 model_count = repeats * 3 * len(cases) | |
180 1 100.0 100.0 0.0 avg = mean(times) / model_count * 1e6 | |
181 1 331.0 331.0 0.0 sd = stdev(times) / model_count * 1e6 | |
182 1 7.0 7.0 0.0 results.append(f'{p:>40} best={min(times) / model_count * 1e6:0.3f}μs/iter ' | |
183 f'avg={avg:0.3f}μs/iter stdev={sd:0.3f}μs/iter') | |
184 1 2.0 2.0 0.0 csv_results.append([p, avg, sd]) | |
185 1 6.0 6.0 0.0 print() | |
186 2 3.0 1.5 0.0 for r in results: | |
187 1 5.0 5.0 0.0 print(r) | |
188 1 16.0 16.0 0.0 if 'SAVE' in os.environ: | |
189 csv_file = StringIO() | |
190 csv_writer = csv.writer(csv_file) | |
191 first_avg = None | |
192 for p, avg, sd in sorted(csv_results, key=itemgetter(1)): | |
193 if first_avg: | |
194 relative = f'{avg / first_avg:0.1f}x slower' | |
195 else: | |
196 relative = '' | |
197 first_avg = avg | |
198 csv_writer.writerow([p, relative, f'{avg:0.1f}μs', f'{sd:0.3f}μs']) | |
199 p = Path(THIS_DIR / '../docs/benchmarks.csv') | |
200 print(f'saving results to {p}') | |
201 p.write_text(csv_file.getvalue()) | |
Total time: 60.2448 s | |
File: pydantic/benchmarks/test_pydantic.py | |
Function: validate at line 53 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
53 def validate(self, data): | |
54 30000 14928.0 0.5 0.0 try: | |
55 30000 59591597.0 1986.4 98.9 return True, self.model(**data) | |
56 14820 15881.0 1.1 0.0 except ValidationError as e: | |
57 14820 622425.0 42.0 1.0 return False, str(e) | |
Total time: 11.6536 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 202 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
202 1178985 11653613.0 9.9 100.0 return lambda cls, v, values, field, config: validator(v) | |
Total time: 0.390685 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 206 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
206 58710 390685.0 6.7 100.0 return lambda cls, v, values, field, config: validator(v, field=field) | |
Total time: 3.56107 s | |
File: pydantic/pydantic/class_validators.py | |
Function: <lambda> at line 214 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
214 596250 3561067.0 6.0 100.0 return lambda cls, v, values, field, config: validator(v, field=field, config=config) | |
Total time: 1.65067 s | |
File: pydantic/pydantic/datetime_parse.py | |
Function: parse_datetime at line 139 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
139 def parse_datetime(value: Union[datetime, StrIntFloat]) -> datetime: | |
140 """ | |
141 Parse a datetime/int/float/string and return a datetime.datetime. | |
142 | |
143 This function supports time zone offsets. When the input contains one, | |
144 the output uses a timezone with a fixed offset from UTC. | |
145 | |
146 Raise ValueError if the input is well formatted but not a valid datetime. | |
147 Raise ValueError if the input isn't well formatted. | |
148 """ | |
149 30000 60334.0 2.0 3.7 if isinstance(value, datetime): | |
150 return value | |
151 | |
152 30000 316207.0 10.5 19.2 number = get_numeric(value) | |
153 30000 26116.0 0.9 1.6 if number is not None: | |
154 return from_unix_seconds(number) | |
155 | |
156 30000 180445.0 6.0 10.9 match = datetime_re.match(cast(str, value)) | |
157 30000 26376.0 0.9 1.6 if not match: | |
158 raise errors.DateTimeError() | |
159 | |
160 30000 82864.0 2.8 5.0 kw = match.groupdict() | |
161 30000 29587.0 1.0 1.8 if kw['microsecond']: | |
162 kw['microsecond'] = kw['microsecond'].ljust(6, '0') | |
163 | |
164 30000 35600.0 1.2 2.2 tzinfo_str = kw.pop('tzinfo') | |
165 30000 27440.0 0.9 1.7 if tzinfo_str == 'Z': | |
166 tzinfo = timezone.utc | |
167 30000 22895.0 0.8 1.4 elif tzinfo_str is not None: | |
168 offset_mins = int(tzinfo_str[-2:]) if len(tzinfo_str) > 3 else 0 | |
169 offset = 60 * int(tzinfo_str[1:3]) + offset_mins | |
170 if tzinfo_str[0] == '-': | |
171 offset = -offset | |
172 tzinfo = timezone(timedelta(minutes=offset)) | |
173 else: | |
174 30000 22300.0 0.7 1.4 tzinfo = None | |
175 | |
176 30000 198638.0 6.6 12.0 kw_: Dict[str, Union[int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} | |
177 30000 26687.0 0.9 1.6 kw_['tzinfo'] = tzinfo | |
178 | |
179 30000 238436.0 7.9 14.4 with change_exception(errors.DateTimeError, ValueError): | |
180 30000 356750.0 11.9 21.6 return datetime(**kw_) # type: ignore | |
Total time: 30.968 s | |
File: pydantic/pydantic/fields.py | |
Function: validate at line 271 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
271 def validate( | |
272 self, v: Any, values: Dict[str, Any], *, loc: 'LocType', cls: Optional['ModelOrDc'] = None | |
273 ) -> 'ValidateReturn': | |
274 774270 534705.0 0.7 1.7 if self.allow_none and not self.validate_always and v is None: | |
275 12450 6744.0 0.5 0.0 return None, None | |
276 | |
277 761820 641225.0 0.8 2.1 loc = loc if isinstance(loc, tuple) else (loc,) | |
278 | |
279 761820 514757.0 0.7 1.7 if v is not None and self.parse_json: | |
280 v, error = self._validate_json(v, loc) | |
281 if error: | |
282 return v, error | |
283 | |
284 761820 393910.0 0.5 1.3 errors: Optional['ErrorList'] = None | |
285 761820 455050.0 0.6 1.5 if self.whole_pre_validators: | |
286 v, errors = self._apply_validators(v, values, loc, cls, self.whole_pre_validators) | |
287 if errors: | |
288 return v, errors | |
289 | |
290 761820 704593.0 0.9 2.3 if self.shape is Shape.SINGLETON: | |
291 731820 25010557.0 34.2 80.8 v, errors = self._validate_singleton(v, values, loc, cls) | |
292 30000 25431.0 0.8 0.1 elif self.shape is Shape.MAPPING: | |
293 v, errors = self._validate_mapping(v, values, loc, cls) | |
294 30000 24942.0 0.8 0.1 elif self.shape is Shape.TUPLE: | |
295 v, errors = self._validate_tuple(v, values, loc, cls) | |
296 else: | |
297 # sequence, list, tuple, set, generator | |
298 30000 1691135.0 56.4 5.5 v, errors = self._validate_sequence_like(v, values, loc, cls) | |
299 | |
300 761820 529107.0 0.7 1.7 if not errors and self.whole_post_validators: | |
301 v, errors = self._apply_validators(v, values, loc, cls, self.whole_post_validators) | |
302 761820 435795.0 0.6 1.4 return v, errors | |
Total time: 27.5416 s | |
File: pydantic/pydantic/fields.py | |
Function: _validate_singleton at line 411 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
411 def _validate_singleton( | |
412 self, v: Any, values: Dict[str, Any], loc: 'LocType', cls: Optional['ModelOrDc'] | |
413 ) -> 'ValidateReturn': | |
414 805065 441474.0 0.5 1.6 if self.sub_fields: | |
415 errors = [] | |
416 for field in self.sub_fields: | |
417 value, error = field.validate(v, values, loc=loc, cls=cls) | |
418 if error: | |
419 errors.append(error) | |
420 else: | |
421 return value, None | |
422 return v, errors | |
423 else: | |
424 805065 27100161.0 33.7 98.4 return self._apply_validators(v, values, loc, cls, self.validators) | |
Total time: 22.3984 s | |
File: pydantic/pydantic/fields.py | |
Function: _apply_validators at line 426 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
426 def _apply_validators( | |
427 self, v: Any, values: Dict[str, Any], loc: 'LocType', cls: Optional['ModelOrDc'], validators: 'ValidatorsList' | |
428 ) -> 'ValidateReturn': | |
429 2624730 1480360.0 0.6 6.6 for validator in validators: | |
430 1833945 1543719.0 0.8 6.9 get_line_profiler().add_function(validator) # just adds lambdas | |
431 # The added lambdas are from class_validators.py lines 202, 206, 214 (see that file's line 198) | |
432 1833945 812147.0 0.4 3.6 try: | |
433 1833945 17856009.0 9.7 79.7 v = validator(cls, v, values, self, self.model_config) | |
434 14280 16763.0 1.2 0.1 except (ValueError, TypeError) as exc: | |
435 14280 273711.0 19.2 1.2 return v, ErrorWrapper(exc, loc=loc, config=self.model_config) | |
436 790785 415709.0 0.5 1.9 return v, None | |
Total time: 46.9821 s | |
File: pydantic/pydantic/main.py | |
Function: __init__ at line 231 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
231 def __init__(self, **data: Any) -> None: | |
232 133245 71478.0 0.5 0.2 if TYPE_CHECKING: # pragma: no cover | |
233 self.__values__: Dict[str, Any] = {} | |
234 self.__fields_set__: 'SetStr' = set() | |
235 133245 46680707.0 350.3 99.4 values, fields_set, _ = validate_model(self, data) | |
236 117150 139681.0 1.2 0.3 object.__setattr__(self, '__values__', values) | |
237 117150 90223.0 0.8 0.2 object.__setattr__(self, '__fields_set__', fields_set) | |
Total time: 35.7694 s | |
File: pydantic/pydantic/main.py | |
Function: validate at line 423 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
423 @classmethod | |
424 def validate(cls: Type['Model'], value: Union['DictStrAny', 'Model']) -> 'Model': | |
425 103245 76633.0 0.7 0.2 if isinstance(value, dict): | |
426 103245 35692744.0 345.7 99.8 return cls(**value) | |
427 elif isinstance(value, cls): | |
428 return value.copy() | |
429 else: | |
430 with change_exception(DictError, TypeError, ValueError): | |
431 return cls(**dict(value)) # type: ignore | |
Total time: 45.8329 s | |
File: pydantic/pydantic/main.py | |
Function: validate_model at line 570 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
570 def validate_model( # noqa: C901 (ignore complexity) | |
571 model: Union[BaseModel, Type[BaseModel]], input_data: 'DictStrAny', raise_exc: bool = True, cls: 'ModelOrDc' = None | |
572 ) -> Tuple['DictStrAny', 'SetStr', Optional[ValidationError]]: | |
573 """ | |
574 validate data against a model. | |
575 """ | |
576 133245 132484.0 1.0 0.3 values = {} | |
577 133245 120764.0 0.9 0.3 errors = [] | |
578 # input_data names, possibly alias | |
579 133245 242812.0 1.8 0.5 names_used = set() | |
580 # field names, never aliases | |
581 133245 224687.0 1.7 0.5 fields_set = set() | |
582 133245 134154.0 1.0 0.3 config = model.__config__ | |
583 133245 417987.0 3.1 0.9 check_extra = config.extra is not Extra.ignore | |
584 | |
585 932715 991986.0 1.1 2.2 for name, field in model.__fields__.items(): | |
586 799470 912165.0 1.1 2.0 if type(field.type_) == ForwardRef: | |
587 raise ConfigError( | |
588 f'field "{field.name}" not yet prepared so type is still a ForwardRef, ' | |
589 f'you might need to call {model.__class__.__name__}.update_forward_refs().' | |
590 ) | |
591 | |
592 799470 947139.0 1.2 2.1 value = input_data.get(field.alias, _missing) | |
593 799470 658311.0 0.8 1.4 using_name = False | |
594 799470 725421.0 0.9 1.6 if value is _missing and config.allow_population_by_alias and field.alt_alias: | |
595 value = input_data.get(field.name, _missing) | |
596 using_name = True | |
597 | |
598 799470 697492.0 0.9 1.5 if value is _missing: | |
599 25200 24714.0 1.0 0.1 if field.required: | |
600 5820 150386.0 25.8 0.3 errors.append(ErrorWrapper(MissingError(), loc=field.alias, config=model.__config__)) | |
601 5820 5704.0 1.0 0.0 continue | |
602 19380 135717.0 7.0 0.3 value = deepcopy(field.default) | |
603 19380 24035.0 1.2 0.1 if not model.__config__.validate_all and not field.validate_always: | |
604 19380 19348.0 1.0 0.0 values[name] = value | |
605 19380 16344.0 0.8 0.0 continue | |
606 else: | |
607 774270 817193.0 1.1 1.8 fields_set.add(name) | |
608 774270 676364.0 0.9 1.5 if check_extra: | |
609 275460 330176.0 1.2 0.7 names_used.add(field.name if using_name else field.alias) | |
610 | |
611 774270 34265013.0 44.3 74.8 v_, errors_ = field.validate(value, values, loc=field.alias, cls=cls or model.__class__) # type: ignore | |
612 774270 894026.0 1.2 2.0 if isinstance(errors_, ErrorWrapper): | |
613 13005 15919.0 1.2 0.0 errors.append(errors_) | |
614 761265 813576.0 1.1 1.8 elif isinstance(errors_, list): | |
615 1245 1628.0 1.3 0.0 errors.extend(errors_) | |
616 else: | |
617 760020 764923.0 1.0 1.7 values[name] = v_ | |
618 | |
619 133245 122193.0 0.9 0.3 if check_extra: | |
620 30000 117963.0 3.9 0.3 extra = input_data.keys() - names_used | |
621 30000 30160.0 1.0 0.1 if extra: | |
622 fields_set |= extra | |
623 if config.extra is Extra.allow: | |
624 for f in extra: | |
625 values[f] = input_data[f] | |
626 else: | |
627 for f in sorted(extra): | |
628 errors.append(ErrorWrapper(ExtraError(), loc=f, config=config)) | |
629 | |
630 133245 120810.0 0.9 0.3 if not raise_exc: | |
631 return values, fields_set, ValidationError(errors) if errors else None | |
632 | |
633 133245 126492.0 0.9 0.3 if errors: | |
634 16095 46711.0 2.9 0.1 raise ValidationError(errors) | |
635 117150 108092.0 0.9 0.2 return values, fields_set, None | |
Total time: 0.114953 s | |
File: pydantic/pydantic/types.py | |
Function: validate at line 146 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
146 @classmethod | |
147 def validate(cls, value: str) -> str: | |
148 75795 48233.0 0.6 42.0 if cls.curtail_length and len(value) > cls.curtail_length: | |
149 value = value[: cls.curtail_length] | |
150 | |
151 75795 37275.0 0.5 32.4 if cls.regex: | |
152 if not cls.regex.match(value): | |
153 raise errors.StrRegexError(pattern=cls.regex.pattern) | |
154 | |
155 75795 29445.0 0.4 25.6 return value | |
Total time: 0.27713 s | |
File: pydantic/pydantic/validators.py | |
Function: not_none_validator at line 28 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
28 def not_none_validator(v: Any) -> Any: | |
29 302085 153932.0 0.5 55.5 if v is None: | |
30 3960 20052.0 5.1 7.2 raise errors.NoneIsNotAllowedError() | |
31 298125 103146.0 0.3 37.2 return v | |
Total time: 0.377421 s | |
File: pydantic/pydantic/validators.py | |
Function: str_validator at line 39 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
39 def str_validator(v: Any) -> str: | |
40 298125 250271.0 0.8 66.3 if isinstance(v, (str, NoneType)): # type: ignore | |
41 298125 127150.0 0.4 33.7 return v | |
42 elif isinstance(v, (bytes, bytearray)): | |
43 return v.decode() | |
44 elif isinstance(v, (float, int, Decimal)): | |
45 # is there anything else we want to add here? If you think so, create an issue. | |
46 return str(v) | |
47 else: | |
48 raise errors.StrError() | |
Total time: 0.746154 s | |
File: pydantic/pydantic/validators.py | |
Function: int_validator at line 77 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
77 def int_validator(v: Any) -> int: | |
78 206490 198595.0 1.0 26.6 if not isinstance(v, bool) and isinstance(v, int): | |
79 176490 79141.0 0.4 10.6 return v | |
80 | |
81 30000 281582.0 9.4 37.7 with change_exception(errors.IntegerError, TypeError, ValueError): | |
82 30000 186836.0 6.2 25.0 return int(v) | |
Total time: 0.174489 s | |
File: pydantic/pydantic/validators.py | |
Function: float_validator at line 85 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
85 def float_validator(v: Any) -> float: | |
86 163245 108581.0 0.7 62.2 if isinstance(v, float): | |
87 163245 65908.0 0.4 37.8 return v | |
88 | |
89 with change_exception(errors.FloatError, TypeError, ValueError): | |
90 return float(v) | |
Total time: 0.061112 s | |
File: pydantic/pydantic/validators.py | |
Function: number_multiple_validator at line 93 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
93 def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number': | |
94 28710 34935.0 1.2 57.2 field_type = cast('ConstrainedNumber', field.type_) | |
95 28710 15157.0 0.5 24.8 if field_type.multiple_of is not None and v % field_type.multiple_of != 0: # type: ignore | |
96 raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) | |
97 | |
98 28710 11020.0 0.4 18.0 return v | |
Total time: 0.134011 s | |
File: pydantic/pydantic/validators.py | |
Function: number_size_validator at line 101 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
101 def number_size_validator(v: 'Number', field: 'Field') -> 'Number': | |
102 30000 41308.0 1.4 30.8 field_type = cast('ConstrainedNumber', field.type_) | |
103 30000 27218.0 0.9 20.3 if field_type.gt is not None and not v > field_type.gt: | |
104 1290 9497.0 7.4 7.1 raise errors.NumberNotGtError(limit_value=field_type.gt) | |
105 28710 15688.0 0.5 11.7 elif field_type.ge is not None and not v >= field_type.ge: | |
106 raise errors.NumberNotGeError(limit_value=field_type.ge) | |
107 | |
108 28710 14612.0 0.5 10.9 if field_type.lt is not None and not v < field_type.lt: | |
109 raise errors.NumberNotLtError(limit_value=field_type.lt) | |
110 28710 13973.0 0.5 10.4 if field_type.le is not None and not v <= field_type.le: | |
111 raise errors.NumberNotLeError(limit_value=field_type.le) | |
112 | |
113 28710 11715.0 0.4 8.7 return v | |
Total time: 1.23868 s | |
File: pydantic/pydantic/validators.py | |
Function: anystr_length_validator at line 129 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
129 def anystr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
130 298125 176380.0 0.6 14.2 v_len = len(v) | |
131 | |
132 298125 311834.0 1.0 25.2 min_length = getattr(field.type_, 'min_length', config.min_anystr_length) | |
133 298125 161325.0 0.5 13.0 if min_length is not None and v_len < min_length: | |
134 240 2619.0 10.9 0.2 raise errors.AnyStrMinLengthError(limit_value=min_length) | |
135 | |
136 297885 279888.0 0.9 22.6 max_length = getattr(field.type_, 'max_length', config.max_anystr_length) | |
137 297885 151702.0 0.5 12.2 if max_length is not None and v_len > max_length: | |
138 3630 31430.0 8.7 2.5 raise errors.AnyStrMaxLengthError(limit_value=max_length) | |
139 | |
140 294255 123498.0 0.4 10.0 return v | |
Total time: 0.606503 s | |
File: pydantic/pydantic/validators.py | |
Function: anystr_strip_whitespace at line 143 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
143 def anystr_strip_whitespace(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
144 298125 373010.0 1.3 61.5 strip_whitespace = getattr(field.type_, 'strip_whitespace', config.anystr_strip_whitespace) | |
145 298125 126165.0 0.4 20.8 if strip_whitespace: | |
146 v = v.strip() | |
147 | |
148 298125 107328.0 0.4 17.7 return v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Only last "layer" of functions output on master branch: | |
------------------------------------------------------- | |
pydantic time=4.412s, success=50.60% | |
pydantic time=4.516s, success=50.60% | |
pydantic time=4.501s, success=50.60% | |
pydantic time=4.476s, success=50.60% | |
pydantic time=4.477s, success=50.60% | |
pydantic best=4.412s, avg=4.476s, stdev=0.040s | |
pydantic best=147.058μs/iter avg=149.212μs/iter stdev=1.333μs/iter | |
Timer unit: 1e-06 s | |
Total time: 1.41706 s | |
File: pydantic/pydantic/datetime_parse.py | |
Function: parse_datetime at line 139 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
139 def parse_datetime(value: Union[datetime, StrIntFloat]) -> datetime: | |
140 """ | |
141 Parse a datetime/int/float/string and return a datetime.datetime. | |
142 | |
143 This function supports time zone offsets. When the input contains one, | |
144 the output uses a timezone with a fixed offset from UTC. | |
145 | |
146 Raise ValueError if the input is well formatted but not a valid datetime. | |
147 Raise ValueError if the input isn't well formatted. | |
148 """ | |
149 30000 33653.0 1.1 2.4 if isinstance(value, datetime): | |
150 return value | |
151 | |
152 30000 282550.0 9.4 19.9 number = get_numeric(value) | |
153 30000 24813.0 0.8 1.8 if number is not None: | |
154 return from_unix_seconds(number) | |
155 | |
156 30000 158066.0 5.3 11.2 match = datetime_re.match(cast(str, value)) | |
157 30000 25795.0 0.9 1.8 if not match: | |
158 raise errors.DateTimeError() | |
159 | |
160 30000 72533.0 2.4 5.1 kw = match.groupdict() | |
161 30000 30746.0 1.0 2.2 if kw['microsecond']: | |
162 kw['microsecond'] = kw['microsecond'].ljust(6, '0') | |
163 | |
164 30000 36102.0 1.2 2.5 tzinfo_str = kw.pop('tzinfo') | |
165 30000 27285.0 0.9 1.9 if tzinfo_str == 'Z': | |
166 tzinfo = timezone.utc | |
167 30000 22741.0 0.8 1.6 elif tzinfo_str is not None: | |
168 offset_mins = int(tzinfo_str[-2:]) if len(tzinfo_str) > 3 else 0 | |
169 offset = 60 * int(tzinfo_str[1:3]) + offset_mins | |
170 if tzinfo_str[0] == '-': | |
171 offset = -offset | |
172 tzinfo = timezone(timedelta(minutes=offset)) | |
173 else: | |
174 30000 22922.0 0.8 1.6 tzinfo = None | |
175 | |
176 30000 175511.0 5.9 12.4 kw_: Dict[str, Union[int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} | |
177 30000 26931.0 0.9 1.9 kw_['tzinfo'] = tzinfo | |
178 | |
179 30000 215625.0 7.2 15.2 with change_exception(errors.DateTimeError, ValueError): | |
180 30000 261783.0 8.7 18.5 return datetime(**kw_) # type: ignore | |
Total time: 11.7748 s | |
File: pydantic/pydantic/main.py | |
Function: validate at line 423 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
423 @classmethod | |
424 def validate(cls: Type['Model'], value: Union['DictStrAny', 'Model']) -> 'Model': | |
425 103245 68490.0 0.7 0.6 if isinstance(value, dict): | |
426 103245 11706284.0 113.4 99.4 return cls(**value) | |
427 elif isinstance(value, cls): | |
428 return value.copy() | |
429 else: | |
430 with change_exception(DictError, TypeError, ValueError): | |
431 return cls(**dict(value)) # type: ignore | |
Total time: 0.105743 s | |
File: pydantic/pydantic/types.py | |
Function: validate at line 146 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
146 @classmethod | |
147 def validate(cls, value: str) -> str: | |
148 75795 40696.0 0.5 38.5 if cls.curtail_length and len(value) > cls.curtail_length: | |
149 value = value[: cls.curtail_length] | |
150 | |
151 75795 36606.0 0.5 34.6 if cls.regex: | |
152 if not cls.regex.match(value): | |
153 raise errors.StrRegexError(pattern=cls.regex.pattern) | |
154 | |
155 75795 28441.0 0.4 26.9 return value | |
Total time: 0.303975 s | |
File: pydantic/pydantic/validators.py | |
Function: not_none_validator at line 28 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
28 def not_none_validator(v: Any) -> Any: | |
29 302085 125627.0 0.4 41.3 if v is None: | |
30 3960 83772.0 21.2 27.6 raise errors.NoneIsNotAllowedError() | |
31 298125 94576.0 0.3 31.1 return v | |
Total time: 0.316406 s | |
File: pydantic/pydantic/validators.py | |
Function: str_validator at line 39 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
39 def str_validator(v: Any) -> str: | |
40 298125 206865.0 0.7 65.4 if isinstance(v, (str, NoneType)): # type: ignore | |
41 298125 109541.0 0.4 34.6 return v | |
42 elif isinstance(v, (bytes, bytearray)): | |
43 return v.decode() | |
44 elif isinstance(v, (float, int, Decimal)): | |
45 # is there anything else we want to add here? If you think so, create an issue. | |
46 return str(v) | |
47 else: | |
48 raise errors.StrError() | |
Total time: 0.633337 s | |
File: pydantic/pydantic/validators.py | |
Function: int_validator at line 77 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
77 def int_validator(v: Any) -> int: | |
78 206490 170508.0 0.8 26.9 if not isinstance(v, bool) and isinstance(v, int): | |
79 176490 67546.0 0.4 10.7 return v | |
80 | |
81 30000 242029.0 8.1 38.2 with change_exception(errors.IntegerError, TypeError, ValueError): | |
82 30000 153254.0 5.1 24.2 return int(v) | |
Total time: 0.156316 s | |
File: pydantic/pydantic/validators.py | |
Function: float_validator at line 85 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
85 def float_validator(v: Any) -> float: | |
86 163245 98141.0 0.6 62.8 if isinstance(v, float): | |
87 163245 58175.0 0.4 37.2 return v | |
88 | |
89 with change_exception(errors.FloatError, TypeError, ValueError): | |
90 return float(v) | |
Total time: 0.049485 s | |
File: pydantic/pydantic/validators.py | |
Function: number_multiple_validator at line 93 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
93 def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number': | |
94 28710 25596.0 0.9 51.7 field_type = cast('ConstrainedNumber', field.type_) | |
95 28710 13260.0 0.5 26.8 if field_type.multiple_of is not None and v % field_type.multiple_of != 0: # type: ignore | |
96 raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) | |
97 | |
98 28710 10629.0 0.4 21.5 return v | |
Total time: 0.123027 s | |
File: pydantic/pydantic/validators.py | |
Function: number_size_validator at line 101 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
101 def number_size_validator(v: 'Number', field: 'Field') -> 'Number': | |
102 30000 36365.0 1.2 29.6 field_type = cast('ConstrainedNumber', field.type_) | |
103 30000 25133.0 0.8 20.4 if field_type.gt is not None and not v > field_type.gt: | |
104 1290 7575.0 5.9 6.2 raise errors.NumberNotGtError(limit_value=field_type.gt) | |
105 28710 14729.0 0.5 12.0 elif field_type.ge is not None and not v >= field_type.ge: | |
106 raise errors.NumberNotGeError(limit_value=field_type.ge) | |
107 | |
108 28710 14053.0 0.5 11.4 if field_type.lt is not None and not v < field_type.lt: | |
109 raise errors.NumberNotLtError(limit_value=field_type.lt) | |
110 28710 13675.0 0.5 11.1 if field_type.le is not None and not v <= field_type.le: | |
111 raise errors.NumberNotLeError(limit_value=field_type.le) | |
112 | |
113 28710 11497.0 0.4 9.3 return v | |
Total time: 1.14471 s | |
File: pydantic/pydantic/validators.py | |
Function: anystr_length_validator at line 129 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
129 def anystr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
130 298125 161344.0 0.5 14.1 v_len = len(v) | |
131 | |
132 298125 290901.0 1.0 25.4 min_length = getattr(field.type_, 'min_length', config.min_anystr_length) | |
133 298125 141083.0 0.5 12.3 if min_length is not None and v_len < min_length: | |
134 240 1642.0 6.8 0.1 raise errors.AnyStrMinLengthError(limit_value=min_length) | |
135 | |
136 297885 268956.0 0.9 23.5 max_length = getattr(field.type_, 'max_length', config.max_anystr_length) | |
137 297885 143572.0 0.5 12.5 if max_length is not None and v_len > max_length: | |
138 3630 22062.0 6.1 1.9 raise errors.AnyStrMaxLengthError(limit_value=max_length) | |
139 | |
140 294255 115148.0 0.4 10.1 return v | |
Total time: 0.547554 s | |
File: pydantic/pydantic/validators.py | |
Function: anystr_strip_whitespace at line 143 | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
143 def anystr_strip_whitespace(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes': | |
144 298125 331283.0 1.1 60.5 strip_whitespace = getattr(field.type_, 'strip_whitespace', config.anystr_strip_whitespace) | |
145 298125 116094.0 0.4 21.2 if strip_whitespace: | |
146 v = v.strip() | |
147 | |
148 298125 100177.0 0.3 18.3 return v |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment