Compatibility fixes. (#193)
* Restore hash to validators. * Restore Attribute.default and Attribute.validator. * _AndValidator is hashable now. Test validator hashability. * Add in_ to validators.__all__.
This commit is contained in:
parent
616f24491d
commit
82ea73cb47
|
@ -24,7 +24,9 @@ Deprecations:
|
|||
Changes:
|
||||
^^^^^^^^
|
||||
|
||||
*none*
|
||||
- Validators are hashable again.
|
||||
Note that validators may become frozen in the future, pending availability of no-overhead frozen classes.
|
||||
`#192 <https://github.com/python-attrs/attrs/issues/192>`_
|
||||
|
||||
|
||||
----
|
||||
|
|
|
@ -818,14 +818,14 @@ class Attribute(object):
|
|||
"convert", "metadata",
|
||||
)
|
||||
|
||||
def __init__(self, name, _default, _validator, repr, cmp, hash, init,
|
||||
def __init__(self, name, default, validator, repr, cmp, hash, init,
|
||||
convert=None, metadata=None):
|
||||
# Cache this descriptor here to speed things up later.
|
||||
bound_setattr = _obj_setattr.__get__(self, Attribute)
|
||||
|
||||
bound_setattr("name", name)
|
||||
bound_setattr("default", _default)
|
||||
bound_setattr("validator", _validator)
|
||||
bound_setattr("default", default)
|
||||
bound_setattr("validator", validator)
|
||||
bound_setattr("repr", repr)
|
||||
bound_setattr("cmp", cmp)
|
||||
bound_setattr("hash", hash)
|
||||
|
@ -842,12 +842,13 @@ class Attribute(object):
|
|||
inst_dict = {
|
||||
k: getattr(ca, k)
|
||||
for k
|
||||
in Attribute.__slots__ + ("_validator", "_default")
|
||||
if k != "name" and k not in (
|
||||
"validator", "default",
|
||||
in Attribute.__slots__
|
||||
if k not in (
|
||||
"name", "validator", "default",
|
||||
) # exclude methods
|
||||
}
|
||||
return cls(name=name, **inst_dict)
|
||||
return cls(name=name, validator=ca._validator, default=ca._default,
|
||||
**inst_dict)
|
||||
|
||||
# Don't use _add_pickle since fields(Attribute) doesn't work
|
||||
def __getstate__(self):
|
||||
|
@ -871,7 +872,7 @@ class Attribute(object):
|
|||
_empty_metadata_singleton)
|
||||
|
||||
|
||||
_a = [Attribute(name=name, _default=NOTHING, _validator=None,
|
||||
_a = [Attribute(name=name, default=NOTHING, validator=None,
|
||||
repr=True, cmp=True, hash=(name != "metadata"), init=True)
|
||||
for name in Attribute.__slots__]
|
||||
|
||||
|
@ -892,12 +893,12 @@ class _CountingAttr(object):
|
|||
__slots__ = ("counter", "_default", "repr", "cmp", "hash", "init",
|
||||
"metadata", "_validator", "convert")
|
||||
__attrs_attrs__ = tuple(
|
||||
Attribute(name=name, _default=NOTHING, _validator=None,
|
||||
Attribute(name=name, default=NOTHING, validator=None,
|
||||
repr=True, cmp=True, hash=True, init=True)
|
||||
for name
|
||||
in ("counter", "_default", "repr", "cmp", "hash", "init",)
|
||||
) + (
|
||||
Attribute(name="metadata", _default=None, _validator=None,
|
||||
Attribute(name="metadata", default=None, validator=None,
|
||||
repr=True, cmp=True, hash=False, init=True),
|
||||
)
|
||||
cls_counter = 0
|
||||
|
@ -1015,7 +1016,7 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
|||
# import into .validators.
|
||||
|
||||
|
||||
@attributes(slots=True)
|
||||
@attributes(slots=True, hash=True)
|
||||
class _AndValidator(object):
|
||||
"""
|
||||
Compose many validators to a single one.
|
||||
|
|
|
@ -9,13 +9,14 @@ from ._make import attr, attributes, and_, _AndValidator
|
|||
|
||||
__all__ = [
|
||||
"and_",
|
||||
"in_",
|
||||
"instance_of",
|
||||
"optional",
|
||||
"provides",
|
||||
]
|
||||
|
||||
|
||||
@attributes(repr=False, slots=True)
|
||||
@attributes(repr=False, slots=True, hash=True)
|
||||
class _InstanceOfValidator(object):
|
||||
type = attr()
|
||||
|
||||
|
@ -55,7 +56,7 @@ def instance_of(type):
|
|||
return _InstanceOfValidator(type)
|
||||
|
||||
|
||||
@attributes(repr=False, slots=True)
|
||||
@attributes(repr=False, slots=True, hash=True)
|
||||
class _ProvidesValidator(object):
|
||||
interface = attr()
|
||||
|
||||
|
@ -94,7 +95,7 @@ def provides(interface):
|
|||
return _ProvidesValidator(interface)
|
||||
|
||||
|
||||
@attributes(repr=False, slots=True)
|
||||
@attributes(repr=False, slots=True, hash=True)
|
||||
class _OptionalValidator(object):
|
||||
validator = attr()
|
||||
|
||||
|
@ -129,7 +130,7 @@ def optional(validator):
|
|||
return _OptionalValidator(validator)
|
||||
|
||||
|
||||
@attributes(repr=False, slots=True)
|
||||
@attributes(repr=False, slots=True, hash=True)
|
||||
class _InValidator(object):
|
||||
options = attr()
|
||||
|
||||
|
|
|
@ -109,9 +109,9 @@ class TestDarkMagic(object):
|
|||
`attr.fields` works.
|
||||
"""
|
||||
assert (
|
||||
Attribute(name="x", _default=foo, _validator=None,
|
||||
Attribute(name="x", default=foo, validator=None,
|
||||
repr=True, cmp=True, hash=None, init=True),
|
||||
Attribute(name="y", _default=attr.Factory(list), _validator=None,
|
||||
Attribute(name="y", default=attr.Factory(list), validator=None,
|
||||
repr=True, cmp=True, hash=None, init=True),
|
||||
) == attr.fields(cls)
|
||||
|
||||
|
@ -158,9 +158,9 @@ class TestDarkMagic(object):
|
|||
"""
|
||||
PC = attr.make_class("PC", ["a", "b"], slots=slots, frozen=frozen)
|
||||
assert (
|
||||
Attribute(name="a", _default=NOTHING, _validator=None,
|
||||
Attribute(name="a", default=NOTHING, validator=None,
|
||||
repr=True, cmp=True, hash=None, init=True),
|
||||
Attribute(name="b", _default=NOTHING, _validator=None,
|
||||
Attribute(name="b", default=NOTHING, validator=None,
|
||||
repr=True, cmp=True, hash=None, init=True),
|
||||
) == attr.fields(PC)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function
|
|||
import pytest
|
||||
import zope.interface
|
||||
|
||||
from attr import validators as validator_module, has
|
||||
from attr.validators import and_, instance_of, provides, optional, in_
|
||||
from attr._compat import TYPE
|
||||
from attr._make import attributes, attr
|
||||
|
@ -248,3 +249,16 @@ class TestIn_(object):
|
|||
assert(
|
||||
("<in_ validator with options [3, 4, 5]>")
|
||||
) == repr(v)
|
||||
|
||||
|
||||
def test_hashability():
|
||||
"""
|
||||
Validator classes are hashable.
|
||||
"""
|
||||
for obj_name in dir(validator_module):
|
||||
obj = getattr(validator_module, obj_name)
|
||||
if not has(obj):
|
||||
continue
|
||||
hash_func = getattr(obj, '__hash__', None)
|
||||
assert hash_func is not None
|
||||
assert hash_func is not object.__hash__
|
||||
|
|
|
@ -35,7 +35,7 @@ def simple_attr(name, default=NOTHING, validator=None, repr=True,
|
|||
Return an attribute with a name and no other bells and whistles.
|
||||
"""
|
||||
return Attribute(
|
||||
name=name, _default=default, _validator=validator, repr=repr,
|
||||
name=name, default=default, validator=validator, repr=repr,
|
||||
cmp=cmp, hash=hash, init=init
|
||||
)
|
||||
|
||||
|
@ -166,7 +166,7 @@ def simple_attrs_with_metadata(draw):
|
|||
vals = st.booleans() | st.binary() | st.integers() | st.text()
|
||||
metadata = draw(st.dictionaries(keys=keys, values=vals))
|
||||
|
||||
return attr.ib(c_attr.default, c_attr._validator, c_attr.repr,
|
||||
return attr.ib(c_attr._default, c_attr._validator, c_attr.repr,
|
||||
c_attr.cmp, c_attr.hash, c_attr.init, c_attr.convert,
|
||||
metadata)
|
||||
|
||||
|
|
Loading…
Reference in New Issue