|
1 """ |
|
2 Commonly useful validators. |
|
3 """ |
|
4 |
|
5 from __future__ import absolute_import, division, print_function |
|
6 |
|
7 from ._make import attr, attributes, and_, _AndValidator |
|
8 |
|
9 |
|
10 __all__ = [ |
|
11 "and_", |
|
12 "in_", |
|
13 "instance_of", |
|
14 "optional", |
|
15 "provides", |
|
16 ] |
|
17 |
|
18 |
|
19 @attributes(repr=False, slots=True, hash=True) |
|
20 class _InstanceOfValidator(object): |
|
21 type = attr() |
|
22 |
|
23 def __call__(self, inst, attr, value): |
|
24 """ |
|
25 We use a callable class to be able to change the ``__repr__``. |
|
26 """ |
|
27 if not isinstance(value, self.type): |
|
28 raise TypeError( |
|
29 "'{name}' must be {type!r} (got {value!r} that is a " |
|
30 "{actual!r})." |
|
31 .format(name=attr.name, type=self.type, |
|
32 actual=value.__class__, value=value), |
|
33 attr, self.type, value, |
|
34 ) |
|
35 |
|
36 def __repr__(self): |
|
37 return ( |
|
38 "<instance_of validator for type {type!r}>" |
|
39 .format(type=self.type) |
|
40 ) |
|
41 |
|
42 |
|
43 def instance_of(type): |
|
44 """ |
|
45 A validator that raises a :exc:`TypeError` if the initializer is called |
|
46 with a wrong type for this particular attribute (checks are perfomed using |
|
47 :func:`isinstance` therefore it's also valid to pass a tuple of types). |
|
48 |
|
49 :param type: The type to check for. |
|
50 :type type: type or tuple of types |
|
51 |
|
52 :raises TypeError: With a human readable error message, the attribute |
|
53 (of type :class:`attr.Attribute`), the expected type, and the value it |
|
54 got. |
|
55 """ |
|
56 return _InstanceOfValidator(type) |
|
57 |
|
58 |
|
59 @attributes(repr=False, slots=True, hash=True) |
|
60 class _ProvidesValidator(object): |
|
61 interface = attr() |
|
62 |
|
63 def __call__(self, inst, attr, value): |
|
64 """ |
|
65 We use a callable class to be able to change the ``__repr__``. |
|
66 """ |
|
67 if not self.interface.providedBy(value): |
|
68 raise TypeError( |
|
69 "'{name}' must provide {interface!r} which {value!r} " |
|
70 "doesn't." |
|
71 .format(name=attr.name, interface=self.interface, value=value), |
|
72 attr, self.interface, value, |
|
73 ) |
|
74 |
|
75 def __repr__(self): |
|
76 return ( |
|
77 "<provides validator for interface {interface!r}>" |
|
78 .format(interface=self.interface) |
|
79 ) |
|
80 |
|
81 |
|
82 def provides(interface): |
|
83 """ |
|
84 A validator that raises a :exc:`TypeError` if the initializer is called |
|
85 with an object that does not provide the requested *interface* (checks are |
|
86 performed using ``interface.providedBy(value)`` (see `zope.interface |
|
87 <https://zopeinterface.readthedocs.io/en/latest/>`_). |
|
88 |
|
89 :param zope.interface.Interface interface: The interface to check for. |
|
90 |
|
91 :raises TypeError: With a human readable error message, the attribute |
|
92 (of type :class:`attr.Attribute`), the expected interface, and the |
|
93 value it got. |
|
94 """ |
|
95 return _ProvidesValidator(interface) |
|
96 |
|
97 |
|
98 @attributes(repr=False, slots=True, hash=True) |
|
99 class _OptionalValidator(object): |
|
100 validator = attr() |
|
101 |
|
102 def __call__(self, inst, attr, value): |
|
103 if value is None: |
|
104 return |
|
105 |
|
106 self.validator(inst, attr, value) |
|
107 |
|
108 def __repr__(self): |
|
109 return ( |
|
110 "<optional validator for {what} or None>" |
|
111 .format(what=repr(self.validator)) |
|
112 ) |
|
113 |
|
114 |
|
115 def optional(validator): |
|
116 """ |
|
117 A validator that makes an attribute optional. An optional attribute is one |
|
118 which can be set to ``None`` in addition to satisfying the requirements of |
|
119 the sub-validator. |
|
120 |
|
121 :param validator: A validator (or a list of validators) that is used for |
|
122 non-``None`` values. |
|
123 :type validator: callable or :class:`list` of callables. |
|
124 |
|
125 .. versionadded:: 15.1.0 |
|
126 .. versionchanged:: 17.1.0 *validator* can be a list of validators. |
|
127 """ |
|
128 if isinstance(validator, list): |
|
129 return _OptionalValidator(_AndValidator(validator)) |
|
130 return _OptionalValidator(validator) |
|
131 |
|
132 |
|
133 @attributes(repr=False, slots=True, hash=True) |
|
134 class _InValidator(object): |
|
135 options = attr() |
|
136 |
|
137 def __call__(self, inst, attr, value): |
|
138 if value not in self.options: |
|
139 raise ValueError( |
|
140 "'{name}' must be in {options!r} (got {value!r})" |
|
141 .format(name=attr.name, options=self.options, value=value) |
|
142 ) |
|
143 |
|
144 def __repr__(self): |
|
145 return ( |
|
146 "<in_ validator with options {options!r}>" |
|
147 .format(options=self.options) |
|
148 ) |
|
149 |
|
150 |
|
151 def in_(options): |
|
152 """ |
|
153 A validator that raises a :exc:`ValueError` if the initializer is called |
|
154 with a value that does not belong in the options provided. The check is |
|
155 performed using ``value in options``. |
|
156 |
|
157 :param options: Allowed options. |
|
158 :type options: list, tuple, :class:`enum.Enum`, ... |
|
159 |
|
160 :raises ValueError: With a human readable error message, the attribute (of |
|
161 type :class:`attr.Attribute`), the expected options, and the value it |
|
162 got. |
|
163 |
|
164 .. versionadded:: 17.1.0 |
|
165 """ |
|
166 return _InValidator(options) |