Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/attr/validators.py
7763 views
1
# SPDX-License-Identifier: MIT
2
3
"""
4
Commonly useful validators.
5
"""
6
7
from __future__ import absolute_import, division, print_function
8
9
import operator
10
import re
11
12
from contextlib import contextmanager
13
14
from ._config import get_run_validators, set_run_validators
15
from ._make import _AndValidator, and_, attrib, attrs
16
from .exceptions import NotCallableError
17
18
19
try:
20
Pattern = re.Pattern
21
except AttributeError: # Python <3.7 lacks a Pattern type.
22
Pattern = type(re.compile(""))
23
24
25
__all__ = [
26
"and_",
27
"deep_iterable",
28
"deep_mapping",
29
"disabled",
30
"ge",
31
"get_disabled",
32
"gt",
33
"in_",
34
"instance_of",
35
"is_callable",
36
"le",
37
"lt",
38
"matches_re",
39
"max_len",
40
"optional",
41
"provides",
42
"set_disabled",
43
]
44
45
46
def set_disabled(disabled):
47
"""
48
Globally disable or enable running validators.
49
50
By default, they are run.
51
52
:param disabled: If ``True``, disable running all validators.
53
:type disabled: bool
54
55
.. warning::
56
57
This function is not thread-safe!
58
59
.. versionadded:: 21.3.0
60
"""
61
set_run_validators(not disabled)
62
63
64
def get_disabled():
65
"""
66
Return a bool indicating whether validators are currently disabled or not.
67
68
:return: ``True`` if validators are currently disabled.
69
:rtype: bool
70
71
.. versionadded:: 21.3.0
72
"""
73
return not get_run_validators()
74
75
76
@contextmanager
77
def disabled():
78
"""
79
Context manager that disables running validators within its context.
80
81
.. warning::
82
83
This context manager is not thread-safe!
84
85
.. versionadded:: 21.3.0
86
"""
87
set_run_validators(False)
88
try:
89
yield
90
finally:
91
set_run_validators(True)
92
93
94
@attrs(repr=False, slots=True, hash=True)
95
class _InstanceOfValidator(object):
96
type = attrib()
97
98
def __call__(self, inst, attr, value):
99
"""
100
We use a callable class to be able to change the ``__repr__``.
101
"""
102
if not isinstance(value, self.type):
103
raise TypeError(
104
"'{name}' must be {type!r} (got {value!r} that is a "
105
"{actual!r}).".format(
106
name=attr.name,
107
type=self.type,
108
actual=value.__class__,
109
value=value,
110
),
111
attr,
112
self.type,
113
value,
114
)
115
116
def __repr__(self):
117
return "<instance_of validator for type {type!r}>".format(
118
type=self.type
119
)
120
121
122
def instance_of(type):
123
"""
124
A validator that raises a `TypeError` if the initializer is called
125
with a wrong type for this particular attribute (checks are performed using
126
`isinstance` therefore it's also valid to pass a tuple of types).
127
128
:param type: The type to check for.
129
:type type: type or tuple of types
130
131
:raises TypeError: With a human readable error message, the attribute
132
(of type `attrs.Attribute`), the expected type, and the value it
133
got.
134
"""
135
return _InstanceOfValidator(type)
136
137
138
@attrs(repr=False, frozen=True, slots=True)
139
class _MatchesReValidator(object):
140
pattern = attrib()
141
match_func = attrib()
142
143
def __call__(self, inst, attr, value):
144
"""
145
We use a callable class to be able to change the ``__repr__``.
146
"""
147
if not self.match_func(value):
148
raise ValueError(
149
"'{name}' must match regex {pattern!r}"
150
" ({value!r} doesn't)".format(
151
name=attr.name, pattern=self.pattern.pattern, value=value
152
),
153
attr,
154
self.pattern,
155
value,
156
)
157
158
def __repr__(self):
159
return "<matches_re validator for pattern {pattern!r}>".format(
160
pattern=self.pattern
161
)
162
163
164
def matches_re(regex, flags=0, func=None):
165
r"""
166
A validator that raises `ValueError` if the initializer is called
167
with a string that doesn't match *regex*.
168
169
:param regex: a regex string or precompiled pattern to match against
170
:param int flags: flags that will be passed to the underlying re function
171
(default 0)
172
:param callable func: which underlying `re` function to call (options
173
are `re.fullmatch`, `re.search`, `re.match`, default
174
is ``None`` which means either `re.fullmatch` or an emulation of
175
it on Python 2). For performance reasons, they won't be used directly
176
but on a pre-`re.compile`\ ed pattern.
177
178
.. versionadded:: 19.2.0
179
.. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern.
180
"""
181
fullmatch = getattr(re, "fullmatch", None)
182
valid_funcs = (fullmatch, None, re.search, re.match)
183
if func not in valid_funcs:
184
raise ValueError(
185
"'func' must be one of {}.".format(
186
", ".join(
187
sorted(
188
e and e.__name__ or "None" for e in set(valid_funcs)
189
)
190
)
191
)
192
)
193
194
if isinstance(regex, Pattern):
195
if flags:
196
raise TypeError(
197
"'flags' can only be used with a string pattern; "
198
"pass flags to re.compile() instead"
199
)
200
pattern = regex
201
else:
202
pattern = re.compile(regex, flags)
203
204
if func is re.match:
205
match_func = pattern.match
206
elif func is re.search:
207
match_func = pattern.search
208
elif fullmatch:
209
match_func = pattern.fullmatch
210
else: # Python 2 fullmatch emulation (https://bugs.python.org/issue16203)
211
pattern = re.compile(
212
r"(?:{})\Z".format(pattern.pattern), pattern.flags
213
)
214
match_func = pattern.match
215
216
return _MatchesReValidator(pattern, match_func)
217
218
219
@attrs(repr=False, slots=True, hash=True)
220
class _ProvidesValidator(object):
221
interface = attrib()
222
223
def __call__(self, inst, attr, value):
224
"""
225
We use a callable class to be able to change the ``__repr__``.
226
"""
227
if not self.interface.providedBy(value):
228
raise TypeError(
229
"'{name}' must provide {interface!r} which {value!r} "
230
"doesn't.".format(
231
name=attr.name, interface=self.interface, value=value
232
),
233
attr,
234
self.interface,
235
value,
236
)
237
238
def __repr__(self):
239
return "<provides validator for interface {interface!r}>".format(
240
interface=self.interface
241
)
242
243
244
def provides(interface):
245
"""
246
A validator that raises a `TypeError` if the initializer is called
247
with an object that does not provide the requested *interface* (checks are
248
performed using ``interface.providedBy(value)`` (see `zope.interface
249
<https://zopeinterface.readthedocs.io/en/latest/>`_).
250
251
:param interface: The interface to check for.
252
:type interface: ``zope.interface.Interface``
253
254
:raises TypeError: With a human readable error message, the attribute
255
(of type `attrs.Attribute`), the expected interface, and the
256
value it got.
257
"""
258
return _ProvidesValidator(interface)
259
260
261
@attrs(repr=False, slots=True, hash=True)
262
class _OptionalValidator(object):
263
validator = attrib()
264
265
def __call__(self, inst, attr, value):
266
if value is None:
267
return
268
269
self.validator(inst, attr, value)
270
271
def __repr__(self):
272
return "<optional validator for {what} or None>".format(
273
what=repr(self.validator)
274
)
275
276
277
def optional(validator):
278
"""
279
A validator that makes an attribute optional. An optional attribute is one
280
which can be set to ``None`` in addition to satisfying the requirements of
281
the sub-validator.
282
283
:param validator: A validator (or a list of validators) that is used for
284
non-``None`` values.
285
:type validator: callable or `list` of callables.
286
287
.. versionadded:: 15.1.0
288
.. versionchanged:: 17.1.0 *validator* can be a list of validators.
289
"""
290
if isinstance(validator, list):
291
return _OptionalValidator(_AndValidator(validator))
292
return _OptionalValidator(validator)
293
294
295
@attrs(repr=False, slots=True, hash=True)
296
class _InValidator(object):
297
options = attrib()
298
299
def __call__(self, inst, attr, value):
300
try:
301
in_options = value in self.options
302
except TypeError: # e.g. `1 in "abc"`
303
in_options = False
304
305
if not in_options:
306
raise ValueError(
307
"'{name}' must be in {options!r} (got {value!r})".format(
308
name=attr.name, options=self.options, value=value
309
)
310
)
311
312
def __repr__(self):
313
return "<in_ validator with options {options!r}>".format(
314
options=self.options
315
)
316
317
318
def in_(options):
319
"""
320
A validator that raises a `ValueError` if the initializer is called
321
with a value that does not belong in the options provided. The check is
322
performed using ``value in options``.
323
324
:param options: Allowed options.
325
:type options: list, tuple, `enum.Enum`, ...
326
327
:raises ValueError: With a human readable error message, the attribute (of
328
type `attrs.Attribute`), the expected options, and the value it
329
got.
330
331
.. versionadded:: 17.1.0
332
"""
333
return _InValidator(options)
334
335
336
@attrs(repr=False, slots=False, hash=True)
337
class _IsCallableValidator(object):
338
def __call__(self, inst, attr, value):
339
"""
340
We use a callable class to be able to change the ``__repr__``.
341
"""
342
if not callable(value):
343
message = (
344
"'{name}' must be callable "
345
"(got {value!r} that is a {actual!r})."
346
)
347
raise NotCallableError(
348
msg=message.format(
349
name=attr.name, value=value, actual=value.__class__
350
),
351
value=value,
352
)
353
354
def __repr__(self):
355
return "<is_callable validator>"
356
357
358
def is_callable():
359
"""
360
A validator that raises a `attr.exceptions.NotCallableError` if the
361
initializer is called with a value for this particular attribute
362
that is not callable.
363
364
.. versionadded:: 19.1.0
365
366
:raises `attr.exceptions.NotCallableError`: With a human readable error
367
message containing the attribute (`attrs.Attribute`) name,
368
and the value it got.
369
"""
370
return _IsCallableValidator()
371
372
373
@attrs(repr=False, slots=True, hash=True)
374
class _DeepIterable(object):
375
member_validator = attrib(validator=is_callable())
376
iterable_validator = attrib(
377
default=None, validator=optional(is_callable())
378
)
379
380
def __call__(self, inst, attr, value):
381
"""
382
We use a callable class to be able to change the ``__repr__``.
383
"""
384
if self.iterable_validator is not None:
385
self.iterable_validator(inst, attr, value)
386
387
for member in value:
388
self.member_validator(inst, attr, member)
389
390
def __repr__(self):
391
iterable_identifier = (
392
""
393
if self.iterable_validator is None
394
else " {iterable!r}".format(iterable=self.iterable_validator)
395
)
396
return (
397
"<deep_iterable validator for{iterable_identifier}"
398
" iterables of {member!r}>"
399
).format(
400
iterable_identifier=iterable_identifier,
401
member=self.member_validator,
402
)
403
404
405
def deep_iterable(member_validator, iterable_validator=None):
406
"""
407
A validator that performs deep validation of an iterable.
408
409
:param member_validator: Validator to apply to iterable members
410
:param iterable_validator: Validator to apply to iterable itself
411
(optional)
412
413
.. versionadded:: 19.1.0
414
415
:raises TypeError: if any sub-validators fail
416
"""
417
return _DeepIterable(member_validator, iterable_validator)
418
419
420
@attrs(repr=False, slots=True, hash=True)
421
class _DeepMapping(object):
422
key_validator = attrib(validator=is_callable())
423
value_validator = attrib(validator=is_callable())
424
mapping_validator = attrib(default=None, validator=optional(is_callable()))
425
426
def __call__(self, inst, attr, value):
427
"""
428
We use a callable class to be able to change the ``__repr__``.
429
"""
430
if self.mapping_validator is not None:
431
self.mapping_validator(inst, attr, value)
432
433
for key in value:
434
self.key_validator(inst, attr, key)
435
self.value_validator(inst, attr, value[key])
436
437
def __repr__(self):
438
return (
439
"<deep_mapping validator for objects mapping {key!r} to {value!r}>"
440
).format(key=self.key_validator, value=self.value_validator)
441
442
443
def deep_mapping(key_validator, value_validator, mapping_validator=None):
444
"""
445
A validator that performs deep validation of a dictionary.
446
447
:param key_validator: Validator to apply to dictionary keys
448
:param value_validator: Validator to apply to dictionary values
449
:param mapping_validator: Validator to apply to top-level mapping
450
attribute (optional)
451
452
.. versionadded:: 19.1.0
453
454
:raises TypeError: if any sub-validators fail
455
"""
456
return _DeepMapping(key_validator, value_validator, mapping_validator)
457
458
459
@attrs(repr=False, frozen=True, slots=True)
460
class _NumberValidator(object):
461
bound = attrib()
462
compare_op = attrib()
463
compare_func = attrib()
464
465
def __call__(self, inst, attr, value):
466
"""
467
We use a callable class to be able to change the ``__repr__``.
468
"""
469
if not self.compare_func(value, self.bound):
470
raise ValueError(
471
"'{name}' must be {op} {bound}: {value}".format(
472
name=attr.name,
473
op=self.compare_op,
474
bound=self.bound,
475
value=value,
476
)
477
)
478
479
def __repr__(self):
480
return "<Validator for x {op} {bound}>".format(
481
op=self.compare_op, bound=self.bound
482
)
483
484
485
def lt(val):
486
"""
487
A validator that raises `ValueError` if the initializer is called
488
with a number larger or equal to *val*.
489
490
:param val: Exclusive upper bound for values
491
492
.. versionadded:: 21.3.0
493
"""
494
return _NumberValidator(val, "<", operator.lt)
495
496
497
def le(val):
498
"""
499
A validator that raises `ValueError` if the initializer is called
500
with a number greater than *val*.
501
502
:param val: Inclusive upper bound for values
503
504
.. versionadded:: 21.3.0
505
"""
506
return _NumberValidator(val, "<=", operator.le)
507
508
509
def ge(val):
510
"""
511
A validator that raises `ValueError` if the initializer is called
512
with a number smaller than *val*.
513
514
:param val: Inclusive lower bound for values
515
516
.. versionadded:: 21.3.0
517
"""
518
return _NumberValidator(val, ">=", operator.ge)
519
520
521
def gt(val):
522
"""
523
A validator that raises `ValueError` if the initializer is called
524
with a number smaller or equal to *val*.
525
526
:param val: Exclusive lower bound for values
527
528
.. versionadded:: 21.3.0
529
"""
530
return _NumberValidator(val, ">", operator.gt)
531
532
533
@attrs(repr=False, frozen=True, slots=True)
534
class _MaxLengthValidator(object):
535
max_length = attrib()
536
537
def __call__(self, inst, attr, value):
538
"""
539
We use a callable class to be able to change the ``__repr__``.
540
"""
541
if len(value) > self.max_length:
542
raise ValueError(
543
"Length of '{name}' must be <= {max}: {len}".format(
544
name=attr.name, max=self.max_length, len=len(value)
545
)
546
)
547
548
def __repr__(self):
549
return "<max_len validator for {max}>".format(max=self.max_length)
550
551
552
def max_len(length):
553
"""
554
A validator that raises `ValueError` if the initializer is called
555
with a string or iterable that is longer than *length*.
556
557
:param int length: Maximum length of the string or iterable
558
559
.. versionadded:: 21.3.0
560
"""
561
return _MaxLengthValidator(length)
562
563