##// END OF EJS Templates
attr: make some docstrings raw strings...
Gregory Szorc -
r41705:a5493a25 default
parent child Browse files
Show More
@@ -1,1059 +1,1059 b''
1 from __future__ import absolute_import, division, print_function
1 from __future__ import absolute_import, division, print_function
2
2
3 import hashlib
3 import hashlib
4 import linecache
4 import linecache
5
5
6 from operator import itemgetter
6 from operator import itemgetter
7
7
8 from . import _config
8 from . import _config
9 from ._compat import PY2, iteritems, isclass, iterkeys, metadata_proxy
9 from ._compat import PY2, iteritems, isclass, iterkeys, metadata_proxy
10 from .exceptions import (
10 from .exceptions import (
11 DefaultAlreadySetError,
11 DefaultAlreadySetError,
12 FrozenInstanceError,
12 FrozenInstanceError,
13 NotAnAttrsClassError,
13 NotAnAttrsClassError,
14 )
14 )
15
15
16
16
17 # This is used at least twice, so cache it here.
17 # This is used at least twice, so cache it here.
18 _obj_setattr = object.__setattr__
18 _obj_setattr = object.__setattr__
19 _init_convert_pat = "__attr_convert_{}"
19 _init_convert_pat = "__attr_convert_{}"
20 _init_factory_pat = "__attr_factory_{}"
20 _init_factory_pat = "__attr_factory_{}"
21 _tuple_property_pat = " {attr_name} = property(itemgetter({index}))"
21 _tuple_property_pat = " {attr_name} = property(itemgetter({index}))"
22 _empty_metadata_singleton = metadata_proxy({})
22 _empty_metadata_singleton = metadata_proxy({})
23
23
24
24
25 class _Nothing(object):
25 class _Nothing(object):
26 """
26 """
27 Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
27 Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
28
28
29 All instances of `_Nothing` are equal.
29 All instances of `_Nothing` are equal.
30 """
30 """
31 def __copy__(self):
31 def __copy__(self):
32 return self
32 return self
33
33
34 def __deepcopy__(self, _):
34 def __deepcopy__(self, _):
35 return self
35 return self
36
36
37 def __eq__(self, other):
37 def __eq__(self, other):
38 return other.__class__ == _Nothing
38 return other.__class__ == _Nothing
39
39
40 def __ne__(self, other):
40 def __ne__(self, other):
41 return not self == other
41 return not self == other
42
42
43 def __repr__(self):
43 def __repr__(self):
44 return "NOTHING"
44 return "NOTHING"
45
45
46 def __hash__(self):
46 def __hash__(self):
47 return 0xdeadbeef
47 return 0xdeadbeef
48
48
49
49
50 NOTHING = _Nothing()
50 NOTHING = _Nothing()
51 """
51 """
52 Sentinel to indicate the lack of a value when ``None`` is ambiguous.
52 Sentinel to indicate the lack of a value when ``None`` is ambiguous.
53 """
53 """
54
54
55
55
56 def attr(default=NOTHING, validator=None,
56 def attr(default=NOTHING, validator=None,
57 repr=True, cmp=True, hash=None, init=True,
57 repr=True, cmp=True, hash=None, init=True,
58 convert=None, metadata={}):
58 convert=None, metadata={}):
59 """
59 r"""
60 Create a new attribute on a class.
60 Create a new attribute on a class.
61
61
62 .. warning::
62 .. warning::
63
63
64 Does *not* do anything unless the class is also decorated with
64 Does *not* do anything unless the class is also decorated with
65 :func:`attr.s`!
65 :func:`attr.s`!
66
66
67 :param default: A value that is used if an ``attrs``-generated ``__init__``
67 :param default: A value that is used if an ``attrs``-generated ``__init__``
68 is used and no value is passed while instantiating or the attribute is
68 is used and no value is passed while instantiating or the attribute is
69 excluded using ``init=False``.
69 excluded using ``init=False``.
70
70
71 If the value is an instance of :class:`Factory`, its callable will be
71 If the value is an instance of :class:`Factory`, its callable will be
72 used to construct a new value (useful for mutable datatypes like lists
72 used to construct a new value (useful for mutable datatypes like lists
73 or dicts).
73 or dicts).
74
74
75 If a default is not set (or set manually to ``attr.NOTHING``), a value
75 If a default is not set (or set manually to ``attr.NOTHING``), a value
76 *must* be supplied when instantiating; otherwise a :exc:`TypeError`
76 *must* be supplied when instantiating; otherwise a :exc:`TypeError`
77 will be raised.
77 will be raised.
78
78
79 The default can also be set using decorator notation as shown below.
79 The default can also be set using decorator notation as shown below.
80
80
81 :type default: Any value.
81 :type default: Any value.
82
82
83 :param validator: :func:`callable` that is called by ``attrs``-generated
83 :param validator: :func:`callable` that is called by ``attrs``-generated
84 ``__init__`` methods after the instance has been initialized. They
84 ``__init__`` methods after the instance has been initialized. They
85 receive the initialized instance, the :class:`Attribute`, and the
85 receive the initialized instance, the :class:`Attribute`, and the
86 passed value.
86 passed value.
87
87
88 The return value is *not* inspected so the validator has to throw an
88 The return value is *not* inspected so the validator has to throw an
89 exception itself.
89 exception itself.
90
90
91 If a ``list`` is passed, its items are treated as validators and must
91 If a ``list`` is passed, its items are treated as validators and must
92 all pass.
92 all pass.
93
93
94 Validators can be globally disabled and re-enabled using
94 Validators can be globally disabled and re-enabled using
95 :func:`get_run_validators`.
95 :func:`get_run_validators`.
96
96
97 The validator can also be set using decorator notation as shown below.
97 The validator can also be set using decorator notation as shown below.
98
98
99 :type validator: ``callable`` or a ``list`` of ``callable``\ s.
99 :type validator: ``callable`` or a ``list`` of ``callable``\ s.
100
100
101 :param bool repr: Include this attribute in the generated ``__repr__``
101 :param bool repr: Include this attribute in the generated ``__repr__``
102 method.
102 method.
103 :param bool cmp: Include this attribute in the generated comparison methods
103 :param bool cmp: Include this attribute in the generated comparison methods
104 (``__eq__`` et al).
104 (``__eq__`` et al).
105 :param hash: Include this attribute in the generated ``__hash__``
105 :param hash: Include this attribute in the generated ``__hash__``
106 method. If ``None`` (default), mirror *cmp*'s value. This is the
106 method. If ``None`` (default), mirror *cmp*'s value. This is the
107 correct behavior according the Python spec. Setting this value to
107 correct behavior according the Python spec. Setting this value to
108 anything else than ``None`` is *discouraged*.
108 anything else than ``None`` is *discouraged*.
109 :type hash: ``bool`` or ``None``
109 :type hash: ``bool`` or ``None``
110 :param bool init: Include this attribute in the generated ``__init__``
110 :param bool init: Include this attribute in the generated ``__init__``
111 method. It is possible to set this to ``False`` and set a default
111 method. It is possible to set this to ``False`` and set a default
112 value. In that case this attributed is unconditionally initialized
112 value. In that case this attributed is unconditionally initialized
113 with the specified default value or factory.
113 with the specified default value or factory.
114 :param callable convert: :func:`callable` that is called by
114 :param callable convert: :func:`callable` that is called by
115 ``attrs``-generated ``__init__`` methods to convert attribute's value
115 ``attrs``-generated ``__init__`` methods to convert attribute's value
116 to the desired format. It is given the passed-in value, and the
116 to the desired format. It is given the passed-in value, and the
117 returned value will be used as the new value of the attribute. The
117 returned value will be used as the new value of the attribute. The
118 value is converted before being passed to the validator, if any.
118 value is converted before being passed to the validator, if any.
119 :param metadata: An arbitrary mapping, to be used by third-party
119 :param metadata: An arbitrary mapping, to be used by third-party
120 components. See :ref:`extending_metadata`.
120 components. See :ref:`extending_metadata`.
121
121
122 .. versionchanged:: 17.1.0 *validator* can be a ``list`` now.
122 .. versionchanged:: 17.1.0 *validator* can be a ``list`` now.
123 .. versionchanged:: 17.1.0
123 .. versionchanged:: 17.1.0
124 *hash* is ``None`` and therefore mirrors *cmp* by default .
124 *hash* is ``None`` and therefore mirrors *cmp* by default .
125 """
125 """
126 if hash is not None and hash is not True and hash is not False:
126 if hash is not None and hash is not True and hash is not False:
127 raise TypeError(
127 raise TypeError(
128 "Invalid value for hash. Must be True, False, or None."
128 "Invalid value for hash. Must be True, False, or None."
129 )
129 )
130 return _CountingAttr(
130 return _CountingAttr(
131 default=default,
131 default=default,
132 validator=validator,
132 validator=validator,
133 repr=repr,
133 repr=repr,
134 cmp=cmp,
134 cmp=cmp,
135 hash=hash,
135 hash=hash,
136 init=init,
136 init=init,
137 convert=convert,
137 convert=convert,
138 metadata=metadata,
138 metadata=metadata,
139 )
139 )
140
140
141
141
142 def _make_attr_tuple_class(cls_name, attr_names):
142 def _make_attr_tuple_class(cls_name, attr_names):
143 """
143 """
144 Create a tuple subclass to hold `Attribute`s for an `attrs` class.
144 Create a tuple subclass to hold `Attribute`s for an `attrs` class.
145
145
146 The subclass is a bare tuple with properties for names.
146 The subclass is a bare tuple with properties for names.
147
147
148 class MyClassAttributes(tuple):
148 class MyClassAttributes(tuple):
149 __slots__ = ()
149 __slots__ = ()
150 x = property(itemgetter(0))
150 x = property(itemgetter(0))
151 """
151 """
152 attr_class_name = "{}Attributes".format(cls_name)
152 attr_class_name = "{}Attributes".format(cls_name)
153 attr_class_template = [
153 attr_class_template = [
154 "class {}(tuple):".format(attr_class_name),
154 "class {}(tuple):".format(attr_class_name),
155 " __slots__ = ()",
155 " __slots__ = ()",
156 ]
156 ]
157 if attr_names:
157 if attr_names:
158 for i, attr_name in enumerate(attr_names):
158 for i, attr_name in enumerate(attr_names):
159 attr_class_template.append(_tuple_property_pat.format(
159 attr_class_template.append(_tuple_property_pat.format(
160 index=i,
160 index=i,
161 attr_name=attr_name,
161 attr_name=attr_name,
162 ))
162 ))
163 else:
163 else:
164 attr_class_template.append(" pass")
164 attr_class_template.append(" pass")
165 globs = {"itemgetter": itemgetter}
165 globs = {"itemgetter": itemgetter}
166 eval(compile("\n".join(attr_class_template), "", "exec"), globs)
166 eval(compile("\n".join(attr_class_template), "", "exec"), globs)
167 return globs[attr_class_name]
167 return globs[attr_class_name]
168
168
169
169
170 def _transform_attrs(cls, these):
170 def _transform_attrs(cls, these):
171 """
171 """
172 Transforms all `_CountingAttr`s on a class into `Attribute`s and saves the
172 Transforms all `_CountingAttr`s on a class into `Attribute`s and saves the
173 list in `__attrs_attrs__`.
173 list in `__attrs_attrs__`.
174
174
175 If *these* is passed, use that and don't look for them on the class.
175 If *these* is passed, use that and don't look for them on the class.
176 """
176 """
177 super_cls = []
177 super_cls = []
178 for c in reversed(cls.__mro__[1:-1]):
178 for c in reversed(cls.__mro__[1:-1]):
179 sub_attrs = getattr(c, "__attrs_attrs__", None)
179 sub_attrs = getattr(c, "__attrs_attrs__", None)
180 if sub_attrs is not None:
180 if sub_attrs is not None:
181 super_cls.extend(a for a in sub_attrs if a not in super_cls)
181 super_cls.extend(a for a in sub_attrs if a not in super_cls)
182 if these is None:
182 if these is None:
183 ca_list = [(name, attr)
183 ca_list = [(name, attr)
184 for name, attr
184 for name, attr
185 in cls.__dict__.items()
185 in cls.__dict__.items()
186 if isinstance(attr, _CountingAttr)]
186 if isinstance(attr, _CountingAttr)]
187 else:
187 else:
188 ca_list = [(name, ca)
188 ca_list = [(name, ca)
189 for name, ca
189 for name, ca
190 in iteritems(these)]
190 in iteritems(these)]
191
191
192 non_super_attrs = [
192 non_super_attrs = [
193 Attribute.from_counting_attr(name=attr_name, ca=ca)
193 Attribute.from_counting_attr(name=attr_name, ca=ca)
194 for attr_name, ca
194 for attr_name, ca
195 in sorted(ca_list, key=lambda e: e[1].counter)
195 in sorted(ca_list, key=lambda e: e[1].counter)
196 ]
196 ]
197 attr_names = [a.name for a in super_cls + non_super_attrs]
197 attr_names = [a.name for a in super_cls + non_super_attrs]
198
198
199 AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
199 AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
200
200
201 cls.__attrs_attrs__ = AttrsClass(super_cls + [
201 cls.__attrs_attrs__ = AttrsClass(super_cls + [
202 Attribute.from_counting_attr(name=attr_name, ca=ca)
202 Attribute.from_counting_attr(name=attr_name, ca=ca)
203 for attr_name, ca
203 for attr_name, ca
204 in sorted(ca_list, key=lambda e: e[1].counter)
204 in sorted(ca_list, key=lambda e: e[1].counter)
205 ])
205 ])
206
206
207 had_default = False
207 had_default = False
208 for a in cls.__attrs_attrs__:
208 for a in cls.__attrs_attrs__:
209 if these is None and a not in super_cls:
209 if these is None and a not in super_cls:
210 setattr(cls, a.name, a)
210 setattr(cls, a.name, a)
211 if had_default is True and a.default is NOTHING and a.init is True:
211 if had_default is True and a.default is NOTHING and a.init is True:
212 raise ValueError(
212 raise ValueError(
213 "No mandatory attributes allowed after an attribute with a "
213 "No mandatory attributes allowed after an attribute with a "
214 "default value or factory. Attribute in question: {a!r}"
214 "default value or factory. Attribute in question: {a!r}"
215 .format(a=a)
215 .format(a=a)
216 )
216 )
217 elif had_default is False and \
217 elif had_default is False and \
218 a.default is not NOTHING and \
218 a.default is not NOTHING and \
219 a.init is not False:
219 a.init is not False:
220 had_default = True
220 had_default = True
221
221
222
222
223 def _frozen_setattrs(self, name, value):
223 def _frozen_setattrs(self, name, value):
224 """
224 """
225 Attached to frozen classes as __setattr__.
225 Attached to frozen classes as __setattr__.
226 """
226 """
227 raise FrozenInstanceError()
227 raise FrozenInstanceError()
228
228
229
229
230 def _frozen_delattrs(self, name):
230 def _frozen_delattrs(self, name):
231 """
231 """
232 Attached to frozen classes as __delattr__.
232 Attached to frozen classes as __delattr__.
233 """
233 """
234 raise FrozenInstanceError()
234 raise FrozenInstanceError()
235
235
236
236
237 def attributes(maybe_cls=None, these=None, repr_ns=None,
237 def attributes(maybe_cls=None, these=None, repr_ns=None,
238 repr=True, cmp=True, hash=None, init=True,
238 repr=True, cmp=True, hash=None, init=True,
239 slots=False, frozen=False, str=False):
239 slots=False, frozen=False, str=False):
240 r"""
240 r"""
241 A class decorator that adds `dunder
241 A class decorator that adds `dunder
242 <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the
242 <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the
243 specified attributes using :func:`attr.ib` or the *these* argument.
243 specified attributes using :func:`attr.ib` or the *these* argument.
244
244
245 :param these: A dictionary of name to :func:`attr.ib` mappings. This is
245 :param these: A dictionary of name to :func:`attr.ib` mappings. This is
246 useful to avoid the definition of your attributes within the class body
246 useful to avoid the definition of your attributes within the class body
247 because you can't (e.g. if you want to add ``__repr__`` methods to
247 because you can't (e.g. if you want to add ``__repr__`` methods to
248 Django models) or don't want to.
248 Django models) or don't want to.
249
249
250 If *these* is not ``None``, ``attrs`` will *not* search the class body
250 If *these* is not ``None``, ``attrs`` will *not* search the class body
251 for attributes.
251 for attributes.
252
252
253 :type these: :class:`dict` of :class:`str` to :func:`attr.ib`
253 :type these: :class:`dict` of :class:`str` to :func:`attr.ib`
254
254
255 :param str repr_ns: When using nested classes, there's no way in Python 2
255 :param str repr_ns: When using nested classes, there's no way in Python 2
256 to automatically detect that. Therefore it's possible to set the
256 to automatically detect that. Therefore it's possible to set the
257 namespace explicitly for a more meaningful ``repr`` output.
257 namespace explicitly for a more meaningful ``repr`` output.
258 :param bool repr: Create a ``__repr__`` method with a human readable
258 :param bool repr: Create a ``__repr__`` method with a human readable
259 represantation of ``attrs`` attributes..
259 represantation of ``attrs`` attributes..
260 :param bool str: Create a ``__str__`` method that is identical to
260 :param bool str: Create a ``__str__`` method that is identical to
261 ``__repr__``. This is usually not necessary except for
261 ``__repr__``. This is usually not necessary except for
262 :class:`Exception`\ s.
262 :class:`Exception`\ s.
263 :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``,
263 :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``,
264 ``__gt__``, and ``__ge__`` methods that compare the class as if it were
264 ``__gt__``, and ``__ge__`` methods that compare the class as if it were
265 a tuple of its ``attrs`` attributes. But the attributes are *only*
265 a tuple of its ``attrs`` attributes. But the attributes are *only*
266 compared, if the type of both classes is *identical*!
266 compared, if the type of both classes is *identical*!
267 :param hash: If ``None`` (default), the ``__hash__`` method is generated
267 :param hash: If ``None`` (default), the ``__hash__`` method is generated
268 according how *cmp* and *frozen* are set.
268 according how *cmp* and *frozen* are set.
269
269
270 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.
270 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.
271 2. If *cmp* is True and *frozen* is False, ``__hash__`` will be set to
271 2. If *cmp* is True and *frozen* is False, ``__hash__`` will be set to
272 None, marking it unhashable (which it is).
272 None, marking it unhashable (which it is).
273 3. If *cmp* is False, ``__hash__`` will be left untouched meaning the
273 3. If *cmp* is False, ``__hash__`` will be left untouched meaning the
274 ``__hash__`` method of the superclass will be used (if superclass is
274 ``__hash__`` method of the superclass will be used (if superclass is
275 ``object``, this means it will fall back to id-based hashing.).
275 ``object``, this means it will fall back to id-based hashing.).
276
276
277 Although not recommended, you can decide for yourself and force
277 Although not recommended, you can decide for yourself and force
278 ``attrs`` to create one (e.g. if the class is immutable even though you
278 ``attrs`` to create one (e.g. if the class is immutable even though you
279 didn't freeze it programmatically) by passing ``True`` or not. Both of
279 didn't freeze it programmatically) by passing ``True`` or not. Both of
280 these cases are rather special and should be used carefully.
280 these cases are rather special and should be used carefully.
281
281
282 See the `Python documentation \
282 See the `Python documentation \
283 <https://docs.python.org/3/reference/datamodel.html#object.__hash__>`_
283 <https://docs.python.org/3/reference/datamodel.html#object.__hash__>`_
284 and the `GitHub issue that led to the default behavior \
284 and the `GitHub issue that led to the default behavior \
285 <https://github.com/python-attrs/attrs/issues/136>`_ for more details.
285 <https://github.com/python-attrs/attrs/issues/136>`_ for more details.
286 :type hash: ``bool`` or ``None``
286 :type hash: ``bool`` or ``None``
287 :param bool init: Create a ``__init__`` method that initialiazes the
287 :param bool init: Create a ``__init__`` method that initialiazes the
288 ``attrs`` attributes. Leading underscores are stripped for the
288 ``attrs`` attributes. Leading underscores are stripped for the
289 argument name. If a ``__attrs_post_init__`` method exists on the
289 argument name. If a ``__attrs_post_init__`` method exists on the
290 class, it will be called after the class is fully initialized.
290 class, it will be called after the class is fully initialized.
291 :param bool slots: Create a slots_-style class that's more
291 :param bool slots: Create a slots_-style class that's more
292 memory-efficient. See :ref:`slots` for further ramifications.
292 memory-efficient. See :ref:`slots` for further ramifications.
293 :param bool frozen: Make instances immutable after initialization. If
293 :param bool frozen: Make instances immutable after initialization. If
294 someone attempts to modify a frozen instance,
294 someone attempts to modify a frozen instance,
295 :exc:`attr.exceptions.FrozenInstanceError` is raised.
295 :exc:`attr.exceptions.FrozenInstanceError` is raised.
296
296
297 Please note:
297 Please note:
298
298
299 1. This is achieved by installing a custom ``__setattr__`` method
299 1. This is achieved by installing a custom ``__setattr__`` method
300 on your class so you can't implement an own one.
300 on your class so you can't implement an own one.
301
301
302 2. True immutability is impossible in Python.
302 2. True immutability is impossible in Python.
303
303
304 3. This *does* have a minor a runtime performance :ref:`impact
304 3. This *does* have a minor a runtime performance :ref:`impact
305 <how-frozen>` when initializing new instances. In other words:
305 <how-frozen>` when initializing new instances. In other words:
306 ``__init__`` is slightly slower with ``frozen=True``.
306 ``__init__`` is slightly slower with ``frozen=True``.
307
307
308 4. If a class is frozen, you cannot modify ``self`` in
308 4. If a class is frozen, you cannot modify ``self`` in
309 ``__attrs_post_init__`` or a self-written ``__init__``. You can
309 ``__attrs_post_init__`` or a self-written ``__init__``. You can
310 circumvent that limitation by using
310 circumvent that limitation by using
311 ``object.__setattr__(self, "attribute_name", value)``.
311 ``object.__setattr__(self, "attribute_name", value)``.
312
312
313 .. _slots: https://docs.python.org/3.5/reference/datamodel.html#slots
313 .. _slots: https://docs.python.org/3.5/reference/datamodel.html#slots
314
314
315 .. versionadded:: 16.0.0 *slots*
315 .. versionadded:: 16.0.0 *slots*
316 .. versionadded:: 16.1.0 *frozen*
316 .. versionadded:: 16.1.0 *frozen*
317 .. versionadded:: 16.3.0 *str*, and support for ``__attrs_post_init__``.
317 .. versionadded:: 16.3.0 *str*, and support for ``__attrs_post_init__``.
318 .. versionchanged::
318 .. versionchanged::
319 17.1.0 *hash* supports ``None`` as value which is also the default
319 17.1.0 *hash* supports ``None`` as value which is also the default
320 now.
320 now.
321 """
321 """
322 def wrap(cls):
322 def wrap(cls):
323 if getattr(cls, "__class__", None) is None:
323 if getattr(cls, "__class__", None) is None:
324 raise TypeError("attrs only works with new-style classes.")
324 raise TypeError("attrs only works with new-style classes.")
325
325
326 if repr is False and str is True:
326 if repr is False and str is True:
327 raise ValueError(
327 raise ValueError(
328 "__str__ can only be generated if a __repr__ exists."
328 "__str__ can only be generated if a __repr__ exists."
329 )
329 )
330
330
331 if slots:
331 if slots:
332 # Only need this later if we're using slots.
332 # Only need this later if we're using slots.
333 if these is None:
333 if these is None:
334 ca_list = [name
334 ca_list = [name
335 for name, attr
335 for name, attr
336 in cls.__dict__.items()
336 in cls.__dict__.items()
337 if isinstance(attr, _CountingAttr)]
337 if isinstance(attr, _CountingAttr)]
338 else:
338 else:
339 ca_list = list(iterkeys(these))
339 ca_list = list(iterkeys(these))
340 _transform_attrs(cls, these)
340 _transform_attrs(cls, these)
341
341
342 # Can't just re-use frozen name because Python's scoping. :(
342 # Can't just re-use frozen name because Python's scoping. :(
343 # Can't compare function objects because Python 2 is terrible. :(
343 # Can't compare function objects because Python 2 is terrible. :(
344 effectively_frozen = _has_frozen_superclass(cls) or frozen
344 effectively_frozen = _has_frozen_superclass(cls) or frozen
345 if repr is True:
345 if repr is True:
346 cls = _add_repr(cls, ns=repr_ns)
346 cls = _add_repr(cls, ns=repr_ns)
347 if str is True:
347 if str is True:
348 cls.__str__ = cls.__repr__
348 cls.__str__ = cls.__repr__
349 if cmp is True:
349 if cmp is True:
350 cls = _add_cmp(cls)
350 cls = _add_cmp(cls)
351
351
352 if hash is not True and hash is not False and hash is not None:
352 if hash is not True and hash is not False and hash is not None:
353 raise TypeError(
353 raise TypeError(
354 "Invalid value for hash. Must be True, False, or None."
354 "Invalid value for hash. Must be True, False, or None."
355 )
355 )
356 elif hash is False or (hash is None and cmp is False):
356 elif hash is False or (hash is None and cmp is False):
357 pass
357 pass
358 elif hash is True or (hash is None and cmp is True and frozen is True):
358 elif hash is True or (hash is None and cmp is True and frozen is True):
359 cls = _add_hash(cls)
359 cls = _add_hash(cls)
360 else:
360 else:
361 cls.__hash__ = None
361 cls.__hash__ = None
362
362
363 if init is True:
363 if init is True:
364 cls = _add_init(cls, effectively_frozen)
364 cls = _add_init(cls, effectively_frozen)
365 if effectively_frozen is True:
365 if effectively_frozen is True:
366 cls.__setattr__ = _frozen_setattrs
366 cls.__setattr__ = _frozen_setattrs
367 cls.__delattr__ = _frozen_delattrs
367 cls.__delattr__ = _frozen_delattrs
368 if slots is True:
368 if slots is True:
369 # slots and frozen require __getstate__/__setstate__ to work
369 # slots and frozen require __getstate__/__setstate__ to work
370 cls = _add_pickle(cls)
370 cls = _add_pickle(cls)
371 if slots is True:
371 if slots is True:
372 cls_dict = dict(cls.__dict__)
372 cls_dict = dict(cls.__dict__)
373 cls_dict["__slots__"] = tuple(ca_list)
373 cls_dict["__slots__"] = tuple(ca_list)
374 for ca_name in ca_list:
374 for ca_name in ca_list:
375 # It might not actually be in there, e.g. if using 'these'.
375 # It might not actually be in there, e.g. if using 'these'.
376 cls_dict.pop(ca_name, None)
376 cls_dict.pop(ca_name, None)
377 cls_dict.pop("__dict__", None)
377 cls_dict.pop("__dict__", None)
378
378
379 qualname = getattr(cls, "__qualname__", None)
379 qualname = getattr(cls, "__qualname__", None)
380 cls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
380 cls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
381 if qualname is not None:
381 if qualname is not None:
382 cls.__qualname__ = qualname
382 cls.__qualname__ = qualname
383
383
384 return cls
384 return cls
385
385
386 # attrs_or class type depends on the usage of the decorator. It's a class
386 # attrs_or class type depends on the usage of the decorator. It's a class
387 # if it's used as `@attributes` but ``None`` if used # as `@attributes()`.
387 # if it's used as `@attributes` but ``None`` if used # as `@attributes()`.
388 if maybe_cls is None:
388 if maybe_cls is None:
389 return wrap
389 return wrap
390 else:
390 else:
391 return wrap(maybe_cls)
391 return wrap(maybe_cls)
392
392
393
393
394 if PY2:
394 if PY2:
395 def _has_frozen_superclass(cls):
395 def _has_frozen_superclass(cls):
396 """
396 """
397 Check whether *cls* has a frozen ancestor by looking at its
397 Check whether *cls* has a frozen ancestor by looking at its
398 __setattr__.
398 __setattr__.
399 """
399 """
400 return (
400 return (
401 getattr(
401 getattr(
402 cls.__setattr__, "__module__", None
402 cls.__setattr__, "__module__", None
403 ) == _frozen_setattrs.__module__ and
403 ) == _frozen_setattrs.__module__ and
404 cls.__setattr__.__name__ == _frozen_setattrs.__name__
404 cls.__setattr__.__name__ == _frozen_setattrs.__name__
405 )
405 )
406 else:
406 else:
407 def _has_frozen_superclass(cls):
407 def _has_frozen_superclass(cls):
408 """
408 """
409 Check whether *cls* has a frozen ancestor by looking at its
409 Check whether *cls* has a frozen ancestor by looking at its
410 __setattr__.
410 __setattr__.
411 """
411 """
412 return cls.__setattr__ == _frozen_setattrs
412 return cls.__setattr__ == _frozen_setattrs
413
413
414
414
415 def _attrs_to_tuple(obj, attrs):
415 def _attrs_to_tuple(obj, attrs):
416 """
416 """
417 Create a tuple of all values of *obj*'s *attrs*.
417 Create a tuple of all values of *obj*'s *attrs*.
418 """
418 """
419 return tuple(getattr(obj, a.name) for a in attrs)
419 return tuple(getattr(obj, a.name) for a in attrs)
420
420
421
421
422 def _add_hash(cls, attrs=None):
422 def _add_hash(cls, attrs=None):
423 """
423 """
424 Add a hash method to *cls*.
424 Add a hash method to *cls*.
425 """
425 """
426 if attrs is None:
426 if attrs is None:
427 attrs = [a
427 attrs = [a
428 for a in cls.__attrs_attrs__
428 for a in cls.__attrs_attrs__
429 if a.hash is True or (a.hash is None and a.cmp is True)]
429 if a.hash is True or (a.hash is None and a.cmp is True)]
430
430
431 def hash_(self):
431 def hash_(self):
432 """
432 """
433 Automatically created by attrs.
433 Automatically created by attrs.
434 """
434 """
435 return hash(_attrs_to_tuple(self, attrs))
435 return hash(_attrs_to_tuple(self, attrs))
436
436
437 cls.__hash__ = hash_
437 cls.__hash__ = hash_
438 return cls
438 return cls
439
439
440
440
441 def _add_cmp(cls, attrs=None):
441 def _add_cmp(cls, attrs=None):
442 """
442 """
443 Add comparison methods to *cls*.
443 Add comparison methods to *cls*.
444 """
444 """
445 if attrs is None:
445 if attrs is None:
446 attrs = [a for a in cls.__attrs_attrs__ if a.cmp]
446 attrs = [a for a in cls.__attrs_attrs__ if a.cmp]
447
447
448 def attrs_to_tuple(obj):
448 def attrs_to_tuple(obj):
449 """
449 """
450 Save us some typing.
450 Save us some typing.
451 """
451 """
452 return _attrs_to_tuple(obj, attrs)
452 return _attrs_to_tuple(obj, attrs)
453
453
454 def eq(self, other):
454 def eq(self, other):
455 """
455 """
456 Automatically created by attrs.
456 Automatically created by attrs.
457 """
457 """
458 if other.__class__ is self.__class__:
458 if other.__class__ is self.__class__:
459 return attrs_to_tuple(self) == attrs_to_tuple(other)
459 return attrs_to_tuple(self) == attrs_to_tuple(other)
460 else:
460 else:
461 return NotImplemented
461 return NotImplemented
462
462
463 def ne(self, other):
463 def ne(self, other):
464 """
464 """
465 Automatically created by attrs.
465 Automatically created by attrs.
466 """
466 """
467 result = eq(self, other)
467 result = eq(self, other)
468 if result is NotImplemented:
468 if result is NotImplemented:
469 return NotImplemented
469 return NotImplemented
470 else:
470 else:
471 return not result
471 return not result
472
472
473 def lt(self, other):
473 def lt(self, other):
474 """
474 """
475 Automatically created by attrs.
475 Automatically created by attrs.
476 """
476 """
477 if isinstance(other, self.__class__):
477 if isinstance(other, self.__class__):
478 return attrs_to_tuple(self) < attrs_to_tuple(other)
478 return attrs_to_tuple(self) < attrs_to_tuple(other)
479 else:
479 else:
480 return NotImplemented
480 return NotImplemented
481
481
482 def le(self, other):
482 def le(self, other):
483 """
483 """
484 Automatically created by attrs.
484 Automatically created by attrs.
485 """
485 """
486 if isinstance(other, self.__class__):
486 if isinstance(other, self.__class__):
487 return attrs_to_tuple(self) <= attrs_to_tuple(other)
487 return attrs_to_tuple(self) <= attrs_to_tuple(other)
488 else:
488 else:
489 return NotImplemented
489 return NotImplemented
490
490
491 def gt(self, other):
491 def gt(self, other):
492 """
492 """
493 Automatically created by attrs.
493 Automatically created by attrs.
494 """
494 """
495 if isinstance(other, self.__class__):
495 if isinstance(other, self.__class__):
496 return attrs_to_tuple(self) > attrs_to_tuple(other)
496 return attrs_to_tuple(self) > attrs_to_tuple(other)
497 else:
497 else:
498 return NotImplemented
498 return NotImplemented
499
499
500 def ge(self, other):
500 def ge(self, other):
501 """
501 """
502 Automatically created by attrs.
502 Automatically created by attrs.
503 """
503 """
504 if isinstance(other, self.__class__):
504 if isinstance(other, self.__class__):
505 return attrs_to_tuple(self) >= attrs_to_tuple(other)
505 return attrs_to_tuple(self) >= attrs_to_tuple(other)
506 else:
506 else:
507 return NotImplemented
507 return NotImplemented
508
508
509 cls.__eq__ = eq
509 cls.__eq__ = eq
510 cls.__ne__ = ne
510 cls.__ne__ = ne
511 cls.__lt__ = lt
511 cls.__lt__ = lt
512 cls.__le__ = le
512 cls.__le__ = le
513 cls.__gt__ = gt
513 cls.__gt__ = gt
514 cls.__ge__ = ge
514 cls.__ge__ = ge
515
515
516 return cls
516 return cls
517
517
518
518
519 def _add_repr(cls, ns=None, attrs=None):
519 def _add_repr(cls, ns=None, attrs=None):
520 """
520 """
521 Add a repr method to *cls*.
521 Add a repr method to *cls*.
522 """
522 """
523 if attrs is None:
523 if attrs is None:
524 attrs = [a for a in cls.__attrs_attrs__ if a.repr]
524 attrs = [a for a in cls.__attrs_attrs__ if a.repr]
525
525
526 def repr_(self):
526 def repr_(self):
527 """
527 """
528 Automatically created by attrs.
528 Automatically created by attrs.
529 """
529 """
530 real_cls = self.__class__
530 real_cls = self.__class__
531 if ns is None:
531 if ns is None:
532 qualname = getattr(real_cls, "__qualname__", None)
532 qualname = getattr(real_cls, "__qualname__", None)
533 if qualname is not None:
533 if qualname is not None:
534 class_name = qualname.rsplit(">.", 1)[-1]
534 class_name = qualname.rsplit(">.", 1)[-1]
535 else:
535 else:
536 class_name = real_cls.__name__
536 class_name = real_cls.__name__
537 else:
537 else:
538 class_name = ns + "." + real_cls.__name__
538 class_name = ns + "." + real_cls.__name__
539
539
540 return "{0}({1})".format(
540 return "{0}({1})".format(
541 class_name,
541 class_name,
542 ", ".join(a.name + "=" + repr(getattr(self, a.name))
542 ", ".join(a.name + "=" + repr(getattr(self, a.name))
543 for a in attrs)
543 for a in attrs)
544 )
544 )
545 cls.__repr__ = repr_
545 cls.__repr__ = repr_
546 return cls
546 return cls
547
547
548
548
549 def _add_init(cls, frozen):
549 def _add_init(cls, frozen):
550 """
550 """
551 Add a __init__ method to *cls*. If *frozen* is True, make it immutable.
551 Add a __init__ method to *cls*. If *frozen* is True, make it immutable.
552 """
552 """
553 attrs = [a for a in cls.__attrs_attrs__
553 attrs = [a for a in cls.__attrs_attrs__
554 if a.init or a.default is not NOTHING]
554 if a.init or a.default is not NOTHING]
555
555
556 # We cache the generated init methods for the same kinds of attributes.
556 # We cache the generated init methods for the same kinds of attributes.
557 sha1 = hashlib.sha1()
557 sha1 = hashlib.sha1()
558 sha1.update(repr(attrs).encode("utf-8"))
558 sha1.update(repr(attrs).encode("utf-8"))
559 unique_filename = "<attrs generated init {0}>".format(
559 unique_filename = "<attrs generated init {0}>".format(
560 sha1.hexdigest()
560 sha1.hexdigest()
561 )
561 )
562
562
563 script, globs = _attrs_to_script(
563 script, globs = _attrs_to_script(
564 attrs,
564 attrs,
565 frozen,
565 frozen,
566 getattr(cls, "__attrs_post_init__", False),
566 getattr(cls, "__attrs_post_init__", False),
567 )
567 )
568 locs = {}
568 locs = {}
569 bytecode = compile(script, unique_filename, "exec")
569 bytecode = compile(script, unique_filename, "exec")
570 attr_dict = dict((a.name, a) for a in attrs)
570 attr_dict = dict((a.name, a) for a in attrs)
571 globs.update({
571 globs.update({
572 "NOTHING": NOTHING,
572 "NOTHING": NOTHING,
573 "attr_dict": attr_dict,
573 "attr_dict": attr_dict,
574 })
574 })
575 if frozen is True:
575 if frozen is True:
576 # Save the lookup overhead in __init__ if we need to circumvent
576 # Save the lookup overhead in __init__ if we need to circumvent
577 # immutability.
577 # immutability.
578 globs["_cached_setattr"] = _obj_setattr
578 globs["_cached_setattr"] = _obj_setattr
579 eval(bytecode, globs, locs)
579 eval(bytecode, globs, locs)
580 init = locs["__init__"]
580 init = locs["__init__"]
581
581
582 # In order of debuggers like PDB being able to step through the code,
582 # In order of debuggers like PDB being able to step through the code,
583 # we add a fake linecache entry.
583 # we add a fake linecache entry.
584 linecache.cache[unique_filename] = (
584 linecache.cache[unique_filename] = (
585 len(script),
585 len(script),
586 None,
586 None,
587 script.splitlines(True),
587 script.splitlines(True),
588 unique_filename
588 unique_filename
589 )
589 )
590 cls.__init__ = init
590 cls.__init__ = init
591 return cls
591 return cls
592
592
593
593
594 def _add_pickle(cls):
594 def _add_pickle(cls):
595 """
595 """
596 Add pickle helpers, needed for frozen and slotted classes
596 Add pickle helpers, needed for frozen and slotted classes
597 """
597 """
598 def _slots_getstate__(obj):
598 def _slots_getstate__(obj):
599 """
599 """
600 Play nice with pickle.
600 Play nice with pickle.
601 """
601 """
602 return tuple(getattr(obj, a.name) for a in fields(obj.__class__))
602 return tuple(getattr(obj, a.name) for a in fields(obj.__class__))
603
603
604 def _slots_setstate__(obj, state):
604 def _slots_setstate__(obj, state):
605 """
605 """
606 Play nice with pickle.
606 Play nice with pickle.
607 """
607 """
608 __bound_setattr = _obj_setattr.__get__(obj, Attribute)
608 __bound_setattr = _obj_setattr.__get__(obj, Attribute)
609 for a, value in zip(fields(obj.__class__), state):
609 for a, value in zip(fields(obj.__class__), state):
610 __bound_setattr(a.name, value)
610 __bound_setattr(a.name, value)
611
611
612 cls.__getstate__ = _slots_getstate__
612 cls.__getstate__ = _slots_getstate__
613 cls.__setstate__ = _slots_setstate__
613 cls.__setstate__ = _slots_setstate__
614 return cls
614 return cls
615
615
616
616
617 def fields(cls):
617 def fields(cls):
618 """
618 """
619 Returns the tuple of ``attrs`` attributes for a class.
619 Returns the tuple of ``attrs`` attributes for a class.
620
620
621 The tuple also allows accessing the fields by their names (see below for
621 The tuple also allows accessing the fields by their names (see below for
622 examples).
622 examples).
623
623
624 :param type cls: Class to introspect.
624 :param type cls: Class to introspect.
625
625
626 :raise TypeError: If *cls* is not a class.
626 :raise TypeError: If *cls* is not a class.
627 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
627 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
628 class.
628 class.
629
629
630 :rtype: tuple (with name accesors) of :class:`attr.Attribute`
630 :rtype: tuple (with name accesors) of :class:`attr.Attribute`
631
631
632 .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
632 .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
633 by name.
633 by name.
634 """
634 """
635 if not isclass(cls):
635 if not isclass(cls):
636 raise TypeError("Passed object must be a class.")
636 raise TypeError("Passed object must be a class.")
637 attrs = getattr(cls, "__attrs_attrs__", None)
637 attrs = getattr(cls, "__attrs_attrs__", None)
638 if attrs is None:
638 if attrs is None:
639 raise NotAnAttrsClassError(
639 raise NotAnAttrsClassError(
640 "{cls!r} is not an attrs-decorated class.".format(cls=cls)
640 "{cls!r} is not an attrs-decorated class.".format(cls=cls)
641 )
641 )
642 return attrs
642 return attrs
643
643
644
644
645 def validate(inst):
645 def validate(inst):
646 """
646 """
647 Validate all attributes on *inst* that have a validator.
647 Validate all attributes on *inst* that have a validator.
648
648
649 Leaves all exceptions through.
649 Leaves all exceptions through.
650
650
651 :param inst: Instance of a class with ``attrs`` attributes.
651 :param inst: Instance of a class with ``attrs`` attributes.
652 """
652 """
653 if _config._run_validators is False:
653 if _config._run_validators is False:
654 return
654 return
655
655
656 for a in fields(inst.__class__):
656 for a in fields(inst.__class__):
657 v = a.validator
657 v = a.validator
658 if v is not None:
658 if v is not None:
659 v(inst, a, getattr(inst, a.name))
659 v(inst, a, getattr(inst, a.name))
660
660
661
661
662 def _attrs_to_script(attrs, frozen, post_init):
662 def _attrs_to_script(attrs, frozen, post_init):
663 """
663 """
664 Return a script of an initializer for *attrs* and a dict of globals.
664 Return a script of an initializer for *attrs* and a dict of globals.
665
665
666 The globals are expected by the generated script.
666 The globals are expected by the generated script.
667
667
668 If *frozen* is True, we cannot set the attributes directly so we use
668 If *frozen* is True, we cannot set the attributes directly so we use
669 a cached ``object.__setattr__``.
669 a cached ``object.__setattr__``.
670 """
670 """
671 lines = []
671 lines = []
672 if frozen is True:
672 if frozen is True:
673 lines.append(
673 lines.append(
674 # Circumvent the __setattr__ descriptor to save one lookup per
674 # Circumvent the __setattr__ descriptor to save one lookup per
675 # assignment.
675 # assignment.
676 "_setattr = _cached_setattr.__get__(self, self.__class__)"
676 "_setattr = _cached_setattr.__get__(self, self.__class__)"
677 )
677 )
678
678
679 def fmt_setter(attr_name, value_var):
679 def fmt_setter(attr_name, value_var):
680 return "_setattr('%(attr_name)s', %(value_var)s)" % {
680 return "_setattr('%(attr_name)s', %(value_var)s)" % {
681 "attr_name": attr_name,
681 "attr_name": attr_name,
682 "value_var": value_var,
682 "value_var": value_var,
683 }
683 }
684
684
685 def fmt_setter_with_converter(attr_name, value_var):
685 def fmt_setter_with_converter(attr_name, value_var):
686 conv_name = _init_convert_pat.format(attr_name)
686 conv_name = _init_convert_pat.format(attr_name)
687 return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % {
687 return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % {
688 "attr_name": attr_name,
688 "attr_name": attr_name,
689 "value_var": value_var,
689 "value_var": value_var,
690 "conv": conv_name,
690 "conv": conv_name,
691 }
691 }
692 else:
692 else:
693 def fmt_setter(attr_name, value):
693 def fmt_setter(attr_name, value):
694 return "self.%(attr_name)s = %(value)s" % {
694 return "self.%(attr_name)s = %(value)s" % {
695 "attr_name": attr_name,
695 "attr_name": attr_name,
696 "value": value,
696 "value": value,
697 }
697 }
698
698
699 def fmt_setter_with_converter(attr_name, value_var):
699 def fmt_setter_with_converter(attr_name, value_var):
700 conv_name = _init_convert_pat.format(attr_name)
700 conv_name = _init_convert_pat.format(attr_name)
701 return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % {
701 return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % {
702 "attr_name": attr_name,
702 "attr_name": attr_name,
703 "value_var": value_var,
703 "value_var": value_var,
704 "conv": conv_name,
704 "conv": conv_name,
705 }
705 }
706
706
707 args = []
707 args = []
708 attrs_to_validate = []
708 attrs_to_validate = []
709
709
710 # This is a dictionary of names to validator and converter callables.
710 # This is a dictionary of names to validator and converter callables.
711 # Injecting this into __init__ globals lets us avoid lookups.
711 # Injecting this into __init__ globals lets us avoid lookups.
712 names_for_globals = {}
712 names_for_globals = {}
713
713
714 for a in attrs:
714 for a in attrs:
715 if a.validator:
715 if a.validator:
716 attrs_to_validate.append(a)
716 attrs_to_validate.append(a)
717 attr_name = a.name
717 attr_name = a.name
718 arg_name = a.name.lstrip("_")
718 arg_name = a.name.lstrip("_")
719 has_factory = isinstance(a.default, Factory)
719 has_factory = isinstance(a.default, Factory)
720 if has_factory and a.default.takes_self:
720 if has_factory and a.default.takes_self:
721 maybe_self = "self"
721 maybe_self = "self"
722 else:
722 else:
723 maybe_self = ""
723 maybe_self = ""
724 if a.init is False:
724 if a.init is False:
725 if has_factory:
725 if has_factory:
726 init_factory_name = _init_factory_pat.format(a.name)
726 init_factory_name = _init_factory_pat.format(a.name)
727 if a.convert is not None:
727 if a.convert is not None:
728 lines.append(fmt_setter_with_converter(
728 lines.append(fmt_setter_with_converter(
729 attr_name,
729 attr_name,
730 init_factory_name + "({0})".format(maybe_self)))
730 init_factory_name + "({0})".format(maybe_self)))
731 conv_name = _init_convert_pat.format(a.name)
731 conv_name = _init_convert_pat.format(a.name)
732 names_for_globals[conv_name] = a.convert
732 names_for_globals[conv_name] = a.convert
733 else:
733 else:
734 lines.append(fmt_setter(
734 lines.append(fmt_setter(
735 attr_name,
735 attr_name,
736 init_factory_name + "({0})".format(maybe_self)
736 init_factory_name + "({0})".format(maybe_self)
737 ))
737 ))
738 names_for_globals[init_factory_name] = a.default.factory
738 names_for_globals[init_factory_name] = a.default.factory
739 else:
739 else:
740 if a.convert is not None:
740 if a.convert is not None:
741 lines.append(fmt_setter_with_converter(
741 lines.append(fmt_setter_with_converter(
742 attr_name,
742 attr_name,
743 "attr_dict['{attr_name}'].default"
743 "attr_dict['{attr_name}'].default"
744 .format(attr_name=attr_name)
744 .format(attr_name=attr_name)
745 ))
745 ))
746 conv_name = _init_convert_pat.format(a.name)
746 conv_name = _init_convert_pat.format(a.name)
747 names_for_globals[conv_name] = a.convert
747 names_for_globals[conv_name] = a.convert
748 else:
748 else:
749 lines.append(fmt_setter(
749 lines.append(fmt_setter(
750 attr_name,
750 attr_name,
751 "attr_dict['{attr_name}'].default"
751 "attr_dict['{attr_name}'].default"
752 .format(attr_name=attr_name)
752 .format(attr_name=attr_name)
753 ))
753 ))
754 elif a.default is not NOTHING and not has_factory:
754 elif a.default is not NOTHING and not has_factory:
755 args.append(
755 args.append(
756 "{arg_name}=attr_dict['{attr_name}'].default".format(
756 "{arg_name}=attr_dict['{attr_name}'].default".format(
757 arg_name=arg_name,
757 arg_name=arg_name,
758 attr_name=attr_name,
758 attr_name=attr_name,
759 )
759 )
760 )
760 )
761 if a.convert is not None:
761 if a.convert is not None:
762 lines.append(fmt_setter_with_converter(attr_name, arg_name))
762 lines.append(fmt_setter_with_converter(attr_name, arg_name))
763 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
763 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
764 else:
764 else:
765 lines.append(fmt_setter(attr_name, arg_name))
765 lines.append(fmt_setter(attr_name, arg_name))
766 elif has_factory:
766 elif has_factory:
767 args.append("{arg_name}=NOTHING".format(arg_name=arg_name))
767 args.append("{arg_name}=NOTHING".format(arg_name=arg_name))
768 lines.append("if {arg_name} is not NOTHING:"
768 lines.append("if {arg_name} is not NOTHING:"
769 .format(arg_name=arg_name))
769 .format(arg_name=arg_name))
770 init_factory_name = _init_factory_pat.format(a.name)
770 init_factory_name = _init_factory_pat.format(a.name)
771 if a.convert is not None:
771 if a.convert is not None:
772 lines.append(" " + fmt_setter_with_converter(attr_name,
772 lines.append(" " + fmt_setter_with_converter(attr_name,
773 arg_name))
773 arg_name))
774 lines.append("else:")
774 lines.append("else:")
775 lines.append(" " + fmt_setter_with_converter(
775 lines.append(" " + fmt_setter_with_converter(
776 attr_name,
776 attr_name,
777 init_factory_name + "({0})".format(maybe_self)
777 init_factory_name + "({0})".format(maybe_self)
778 ))
778 ))
779 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
779 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
780 else:
780 else:
781 lines.append(" " + fmt_setter(attr_name, arg_name))
781 lines.append(" " + fmt_setter(attr_name, arg_name))
782 lines.append("else:")
782 lines.append("else:")
783 lines.append(" " + fmt_setter(
783 lines.append(" " + fmt_setter(
784 attr_name,
784 attr_name,
785 init_factory_name + "({0})".format(maybe_self)
785 init_factory_name + "({0})".format(maybe_self)
786 ))
786 ))
787 names_for_globals[init_factory_name] = a.default.factory
787 names_for_globals[init_factory_name] = a.default.factory
788 else:
788 else:
789 args.append(arg_name)
789 args.append(arg_name)
790 if a.convert is not None:
790 if a.convert is not None:
791 lines.append(fmt_setter_with_converter(attr_name, arg_name))
791 lines.append(fmt_setter_with_converter(attr_name, arg_name))
792 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
792 names_for_globals[_init_convert_pat.format(a.name)] = a.convert
793 else:
793 else:
794 lines.append(fmt_setter(attr_name, arg_name))
794 lines.append(fmt_setter(attr_name, arg_name))
795
795
796 if attrs_to_validate: # we can skip this if there are no validators.
796 if attrs_to_validate: # we can skip this if there are no validators.
797 names_for_globals["_config"] = _config
797 names_for_globals["_config"] = _config
798 lines.append("if _config._run_validators is True:")
798 lines.append("if _config._run_validators is True:")
799 for a in attrs_to_validate:
799 for a in attrs_to_validate:
800 val_name = "__attr_validator_{}".format(a.name)
800 val_name = "__attr_validator_{}".format(a.name)
801 attr_name = "__attr_{}".format(a.name)
801 attr_name = "__attr_{}".format(a.name)
802 lines.append(" {}(self, {}, self.{})".format(
802 lines.append(" {}(self, {}, self.{})".format(
803 val_name, attr_name, a.name))
803 val_name, attr_name, a.name))
804 names_for_globals[val_name] = a.validator
804 names_for_globals[val_name] = a.validator
805 names_for_globals[attr_name] = a
805 names_for_globals[attr_name] = a
806 if post_init:
806 if post_init:
807 lines.append("self.__attrs_post_init__()")
807 lines.append("self.__attrs_post_init__()")
808
808
809 return """\
809 return """\
810 def __init__(self, {args}):
810 def __init__(self, {args}):
811 {lines}
811 {lines}
812 """.format(
812 """.format(
813 args=", ".join(args),
813 args=", ".join(args),
814 lines="\n ".join(lines) if lines else "pass",
814 lines="\n ".join(lines) if lines else "pass",
815 ), names_for_globals
815 ), names_for_globals
816
816
817
817
818 class Attribute(object):
818 class Attribute(object):
819 """
819 """
820 *Read-only* representation of an attribute.
820 *Read-only* representation of an attribute.
821
821
822 :attribute name: The name of the attribute.
822 :attribute name: The name of the attribute.
823
823
824 Plus *all* arguments of :func:`attr.ib`.
824 Plus *all* arguments of :func:`attr.ib`.
825 """
825 """
826 __slots__ = (
826 __slots__ = (
827 "name", "default", "validator", "repr", "cmp", "hash", "init",
827 "name", "default", "validator", "repr", "cmp", "hash", "init",
828 "convert", "metadata",
828 "convert", "metadata",
829 )
829 )
830
830
831 def __init__(self, name, default, validator, repr, cmp, hash, init,
831 def __init__(self, name, default, validator, repr, cmp, hash, init,
832 convert=None, metadata=None):
832 convert=None, metadata=None):
833 # Cache this descriptor here to speed things up later.
833 # Cache this descriptor here to speed things up later.
834 bound_setattr = _obj_setattr.__get__(self, Attribute)
834 bound_setattr = _obj_setattr.__get__(self, Attribute)
835
835
836 bound_setattr("name", name)
836 bound_setattr("name", name)
837 bound_setattr("default", default)
837 bound_setattr("default", default)
838 bound_setattr("validator", validator)
838 bound_setattr("validator", validator)
839 bound_setattr("repr", repr)
839 bound_setattr("repr", repr)
840 bound_setattr("cmp", cmp)
840 bound_setattr("cmp", cmp)
841 bound_setattr("hash", hash)
841 bound_setattr("hash", hash)
842 bound_setattr("init", init)
842 bound_setattr("init", init)
843 bound_setattr("convert", convert)
843 bound_setattr("convert", convert)
844 bound_setattr("metadata", (metadata_proxy(metadata) if metadata
844 bound_setattr("metadata", (metadata_proxy(metadata) if metadata
845 else _empty_metadata_singleton))
845 else _empty_metadata_singleton))
846
846
847 def __setattr__(self, name, value):
847 def __setattr__(self, name, value):
848 raise FrozenInstanceError()
848 raise FrozenInstanceError()
849
849
850 @classmethod
850 @classmethod
851 def from_counting_attr(cls, name, ca):
851 def from_counting_attr(cls, name, ca):
852 inst_dict = {
852 inst_dict = {
853 k: getattr(ca, k)
853 k: getattr(ca, k)
854 for k
854 for k
855 in Attribute.__slots__
855 in Attribute.__slots__
856 if k not in (
856 if k not in (
857 "name", "validator", "default",
857 "name", "validator", "default",
858 ) # exclude methods
858 ) # exclude methods
859 }
859 }
860 return cls(name=name, validator=ca._validator, default=ca._default,
860 return cls(name=name, validator=ca._validator, default=ca._default,
861 **inst_dict)
861 **inst_dict)
862
862
863 # Don't use _add_pickle since fields(Attribute) doesn't work
863 # Don't use _add_pickle since fields(Attribute) doesn't work
864 def __getstate__(self):
864 def __getstate__(self):
865 """
865 """
866 Play nice with pickle.
866 Play nice with pickle.
867 """
867 """
868 return tuple(getattr(self, name) if name != "metadata"
868 return tuple(getattr(self, name) if name != "metadata"
869 else dict(self.metadata)
869 else dict(self.metadata)
870 for name in self.__slots__)
870 for name in self.__slots__)
871
871
872 def __setstate__(self, state):
872 def __setstate__(self, state):
873 """
873 """
874 Play nice with pickle.
874 Play nice with pickle.
875 """
875 """
876 bound_setattr = _obj_setattr.__get__(self, Attribute)
876 bound_setattr = _obj_setattr.__get__(self, Attribute)
877 for name, value in zip(self.__slots__, state):
877 for name, value in zip(self.__slots__, state):
878 if name != "metadata":
878 if name != "metadata":
879 bound_setattr(name, value)
879 bound_setattr(name, value)
880 else:
880 else:
881 bound_setattr(name, metadata_proxy(value) if value else
881 bound_setattr(name, metadata_proxy(value) if value else
882 _empty_metadata_singleton)
882 _empty_metadata_singleton)
883
883
884
884
885 _a = [Attribute(name=name, default=NOTHING, validator=None,
885 _a = [Attribute(name=name, default=NOTHING, validator=None,
886 repr=True, cmp=True, hash=(name != "metadata"), init=True)
886 repr=True, cmp=True, hash=(name != "metadata"), init=True)
887 for name in Attribute.__slots__]
887 for name in Attribute.__slots__]
888
888
889 Attribute = _add_hash(
889 Attribute = _add_hash(
890 _add_cmp(_add_repr(Attribute, attrs=_a), attrs=_a),
890 _add_cmp(_add_repr(Attribute, attrs=_a), attrs=_a),
891 attrs=[a for a in _a if a.hash]
891 attrs=[a for a in _a if a.hash]
892 )
892 )
893
893
894
894
895 class _CountingAttr(object):
895 class _CountingAttr(object):
896 """
896 """
897 Intermediate representation of attributes that uses a counter to preserve
897 Intermediate representation of attributes that uses a counter to preserve
898 the order in which the attributes have been defined.
898 the order in which the attributes have been defined.
899
899
900 *Internal* data structure of the attrs library. Running into is most
900 *Internal* data structure of the attrs library. Running into is most
901 likely the result of a bug like a forgotten `@attr.s` decorator.
901 likely the result of a bug like a forgotten `@attr.s` decorator.
902 """
902 """
903 __slots__ = ("counter", "_default", "repr", "cmp", "hash", "init",
903 __slots__ = ("counter", "_default", "repr", "cmp", "hash", "init",
904 "metadata", "_validator", "convert")
904 "metadata", "_validator", "convert")
905 __attrs_attrs__ = tuple(
905 __attrs_attrs__ = tuple(
906 Attribute(name=name, default=NOTHING, validator=None,
906 Attribute(name=name, default=NOTHING, validator=None,
907 repr=True, cmp=True, hash=True, init=True)
907 repr=True, cmp=True, hash=True, init=True)
908 for name
908 for name
909 in ("counter", "_default", "repr", "cmp", "hash", "init",)
909 in ("counter", "_default", "repr", "cmp", "hash", "init",)
910 ) + (
910 ) + (
911 Attribute(name="metadata", default=None, validator=None,
911 Attribute(name="metadata", default=None, validator=None,
912 repr=True, cmp=True, hash=False, init=True),
912 repr=True, cmp=True, hash=False, init=True),
913 )
913 )
914 cls_counter = 0
914 cls_counter = 0
915
915
916 def __init__(self, default, validator, repr, cmp, hash, init, convert,
916 def __init__(self, default, validator, repr, cmp, hash, init, convert,
917 metadata):
917 metadata):
918 _CountingAttr.cls_counter += 1
918 _CountingAttr.cls_counter += 1
919 self.counter = _CountingAttr.cls_counter
919 self.counter = _CountingAttr.cls_counter
920 self._default = default
920 self._default = default
921 # If validator is a list/tuple, wrap it using helper validator.
921 # If validator is a list/tuple, wrap it using helper validator.
922 if validator and isinstance(validator, (list, tuple)):
922 if validator and isinstance(validator, (list, tuple)):
923 self._validator = and_(*validator)
923 self._validator = and_(*validator)
924 else:
924 else:
925 self._validator = validator
925 self._validator = validator
926 self.repr = repr
926 self.repr = repr
927 self.cmp = cmp
927 self.cmp = cmp
928 self.hash = hash
928 self.hash = hash
929 self.init = init
929 self.init = init
930 self.convert = convert
930 self.convert = convert
931 self.metadata = metadata
931 self.metadata = metadata
932
932
933 def validator(self, meth):
933 def validator(self, meth):
934 """
934 """
935 Decorator that adds *meth* to the list of validators.
935 Decorator that adds *meth* to the list of validators.
936
936
937 Returns *meth* unchanged.
937 Returns *meth* unchanged.
938
938
939 .. versionadded:: 17.1.0
939 .. versionadded:: 17.1.0
940 """
940 """
941 if self._validator is None:
941 if self._validator is None:
942 self._validator = meth
942 self._validator = meth
943 else:
943 else:
944 self._validator = and_(self._validator, meth)
944 self._validator = and_(self._validator, meth)
945 return meth
945 return meth
946
946
947 def default(self, meth):
947 def default(self, meth):
948 """
948 """
949 Decorator that allows to set the default for an attribute.
949 Decorator that allows to set the default for an attribute.
950
950
951 Returns *meth* unchanged.
951 Returns *meth* unchanged.
952
952
953 :raises DefaultAlreadySetError: If default has been set before.
953 :raises DefaultAlreadySetError: If default has been set before.
954
954
955 .. versionadded:: 17.1.0
955 .. versionadded:: 17.1.0
956 """
956 """
957 if self._default is not NOTHING:
957 if self._default is not NOTHING:
958 raise DefaultAlreadySetError()
958 raise DefaultAlreadySetError()
959
959
960 self._default = Factory(meth, takes_self=True)
960 self._default = Factory(meth, takes_self=True)
961
961
962 return meth
962 return meth
963
963
964
964
965 _CountingAttr = _add_cmp(_add_repr(_CountingAttr))
965 _CountingAttr = _add_cmp(_add_repr(_CountingAttr))
966
966
967
967
968 @attributes(slots=True, init=False)
968 @attributes(slots=True, init=False)
969 class Factory(object):
969 class Factory(object):
970 """
970 """
971 Stores a factory callable.
971 Stores a factory callable.
972
972
973 If passed as the default value to :func:`attr.ib`, the factory is used to
973 If passed as the default value to :func:`attr.ib`, the factory is used to
974 generate a new value.
974 generate a new value.
975
975
976 :param callable factory: A callable that takes either none or exactly one
976 :param callable factory: A callable that takes either none or exactly one
977 mandatory positional argument depending on *takes_self*.
977 mandatory positional argument depending on *takes_self*.
978 :param bool takes_self: Pass the partially initialized instance that is
978 :param bool takes_self: Pass the partially initialized instance that is
979 being initialized as a positional argument.
979 being initialized as a positional argument.
980
980
981 .. versionadded:: 17.1.0 *takes_self*
981 .. versionadded:: 17.1.0 *takes_self*
982 """
982 """
983 factory = attr()
983 factory = attr()
984 takes_self = attr()
984 takes_self = attr()
985
985
986 def __init__(self, factory, takes_self=False):
986 def __init__(self, factory, takes_self=False):
987 """
987 """
988 `Factory` is part of the default machinery so if we want a default
988 `Factory` is part of the default machinery so if we want a default
989 value here, we have to implement it ourselves.
989 value here, we have to implement it ourselves.
990 """
990 """
991 self.factory = factory
991 self.factory = factory
992 self.takes_self = takes_self
992 self.takes_self = takes_self
993
993
994
994
995 def make_class(name, attrs, bases=(object,), **attributes_arguments):
995 def make_class(name, attrs, bases=(object,), **attributes_arguments):
996 """
996 """
997 A quick way to create a new class called *name* with *attrs*.
997 A quick way to create a new class called *name* with *attrs*.
998
998
999 :param name: The name for the new class.
999 :param name: The name for the new class.
1000 :type name: str
1000 :type name: str
1001
1001
1002 :param attrs: A list of names or a dictionary of mappings of names to
1002 :param attrs: A list of names or a dictionary of mappings of names to
1003 attributes.
1003 attributes.
1004 :type attrs: :class:`list` or :class:`dict`
1004 :type attrs: :class:`list` or :class:`dict`
1005
1005
1006 :param tuple bases: Classes that the new class will subclass.
1006 :param tuple bases: Classes that the new class will subclass.
1007
1007
1008 :param attributes_arguments: Passed unmodified to :func:`attr.s`.
1008 :param attributes_arguments: Passed unmodified to :func:`attr.s`.
1009
1009
1010 :return: A new class with *attrs*.
1010 :return: A new class with *attrs*.
1011 :rtype: type
1011 :rtype: type
1012
1012
1013 .. versionadded:: 17.1.0 *bases*
1013 .. versionadded:: 17.1.0 *bases*
1014 """
1014 """
1015 if isinstance(attrs, dict):
1015 if isinstance(attrs, dict):
1016 cls_dict = attrs
1016 cls_dict = attrs
1017 elif isinstance(attrs, (list, tuple)):
1017 elif isinstance(attrs, (list, tuple)):
1018 cls_dict = dict((a, attr()) for a in attrs)
1018 cls_dict = dict((a, attr()) for a in attrs)
1019 else:
1019 else:
1020 raise TypeError("attrs argument must be a dict or a list.")
1020 raise TypeError("attrs argument must be a dict or a list.")
1021
1021
1022 return attributes(**attributes_arguments)(type(name, bases, cls_dict))
1022 return attributes(**attributes_arguments)(type(name, bases, cls_dict))
1023
1023
1024
1024
1025 # These are required by whithin this module so we define them here and merely
1025 # These are required by whithin this module so we define them here and merely
1026 # import into .validators.
1026 # import into .validators.
1027
1027
1028
1028
1029 @attributes(slots=True, hash=True)
1029 @attributes(slots=True, hash=True)
1030 class _AndValidator(object):
1030 class _AndValidator(object):
1031 """
1031 """
1032 Compose many validators to a single one.
1032 Compose many validators to a single one.
1033 """
1033 """
1034 _validators = attr()
1034 _validators = attr()
1035
1035
1036 def __call__(self, inst, attr, value):
1036 def __call__(self, inst, attr, value):
1037 for v in self._validators:
1037 for v in self._validators:
1038 v(inst, attr, value)
1038 v(inst, attr, value)
1039
1039
1040
1040
1041 def and_(*validators):
1041 def and_(*validators):
1042 """
1042 """
1043 A validator that composes multiple validators into one.
1043 A validator that composes multiple validators into one.
1044
1044
1045 When called on a value, it runs all wrapped validators.
1045 When called on a value, it runs all wrapped validators.
1046
1046
1047 :param validators: Arbitrary number of validators.
1047 :param validators: Arbitrary number of validators.
1048 :type validators: callables
1048 :type validators: callables
1049
1049
1050 .. versionadded:: 17.1.0
1050 .. versionadded:: 17.1.0
1051 """
1051 """
1052 vals = []
1052 vals = []
1053 for validator in validators:
1053 for validator in validators:
1054 vals.extend(
1054 vals.extend(
1055 validator._validators if isinstance(validator, _AndValidator)
1055 validator._validators if isinstance(validator, _AndValidator)
1056 else [validator]
1056 else [validator]
1057 )
1057 )
1058
1058
1059 return _AndValidator(tuple(vals))
1059 return _AndValidator(tuple(vals))
@@ -1,52 +1,52 b''
1 """
1 """
2 Commonly useful filters for :func:`attr.asdict`.
2 Commonly useful filters for :func:`attr.asdict`.
3 """
3 """
4
4
5 from __future__ import absolute_import, division, print_function
5 from __future__ import absolute_import, division, print_function
6
6
7 from ._compat import isclass
7 from ._compat import isclass
8 from ._make import Attribute
8 from ._make import Attribute
9
9
10
10
11 def _split_what(what):
11 def _split_what(what):
12 """
12 """
13 Returns a tuple of `frozenset`s of classes and attributes.
13 Returns a tuple of `frozenset`s of classes and attributes.
14 """
14 """
15 return (
15 return (
16 frozenset(cls for cls in what if isclass(cls)),
16 frozenset(cls for cls in what if isclass(cls)),
17 frozenset(cls for cls in what if isinstance(cls, Attribute)),
17 frozenset(cls for cls in what if isinstance(cls, Attribute)),
18 )
18 )
19
19
20
20
21 def include(*what):
21 def include(*what):
22 """
22 r"""
23 Whitelist *what*.
23 Whitelist *what*.
24
24
25 :param what: What to whitelist.
25 :param what: What to whitelist.
26 :type what: :class:`list` of :class:`type` or :class:`attr.Attribute`\ s
26 :type what: :class:`list` of :class:`type` or :class:`attr.Attribute`\ s
27
27
28 :rtype: :class:`callable`
28 :rtype: :class:`callable`
29 """
29 """
30 cls, attrs = _split_what(what)
30 cls, attrs = _split_what(what)
31
31
32 def include_(attribute, value):
32 def include_(attribute, value):
33 return value.__class__ in cls or attribute in attrs
33 return value.__class__ in cls or attribute in attrs
34
34
35 return include_
35 return include_
36
36
37
37
38 def exclude(*what):
38 def exclude(*what):
39 """
39 r"""
40 Blacklist *what*.
40 Blacklist *what*.
41
41
42 :param what: What to blacklist.
42 :param what: What to blacklist.
43 :type what: :class:`list` of classes or :class:`attr.Attribute`\ s.
43 :type what: :class:`list` of classes or :class:`attr.Attribute`\ s.
44
44
45 :rtype: :class:`callable`
45 :rtype: :class:`callable`
46 """
46 """
47 cls, attrs = _split_what(what)
47 cls, attrs = _split_what(what)
48
48
49 def exclude_(attribute, value):
49 def exclude_(attribute, value):
50 return value.__class__ not in cls and attribute not in attrs
50 return value.__class__ not in cls and attribute not in attrs
51
51
52 return exclude_
52 return exclude_
General Comments 0
You need to be logged in to leave comments. Login now