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:
Tin Tvrtković 2017-05-19 20:31:00 +02:00 committed by Hynek Schlawack
parent 616f24491d
commit 82ea73cb47
6 changed files with 40 additions and 22 deletions

View File

@ -24,7 +24,9 @@ Deprecations:
Changes: 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>`_
---- ----

View File

@ -818,14 +818,14 @@ class Attribute(object):
"convert", "metadata", "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): convert=None, metadata=None):
# Cache this descriptor here to speed things up later. # Cache this descriptor here to speed things up later.
bound_setattr = _obj_setattr.__get__(self, Attribute) bound_setattr = _obj_setattr.__get__(self, Attribute)
bound_setattr("name", name) bound_setattr("name", name)
bound_setattr("default", _default) bound_setattr("default", default)
bound_setattr("validator", _validator) bound_setattr("validator", validator)
bound_setattr("repr", repr) bound_setattr("repr", repr)
bound_setattr("cmp", cmp) bound_setattr("cmp", cmp)
bound_setattr("hash", hash) bound_setattr("hash", hash)
@ -842,12 +842,13 @@ class Attribute(object):
inst_dict = { inst_dict = {
k: getattr(ca, k) k: getattr(ca, k)
for k for k
in Attribute.__slots__ + ("_validator", "_default") in Attribute.__slots__
if k != "name" and k not in ( if k not in (
"validator", "default", "name", "validator", "default",
) # exclude methods ) # 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 # Don't use _add_pickle since fields(Attribute) doesn't work
def __getstate__(self): def __getstate__(self):
@ -871,7 +872,7 @@ class Attribute(object):
_empty_metadata_singleton) _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) repr=True, cmp=True, hash=(name != "metadata"), init=True)
for name in Attribute.__slots__] for name in Attribute.__slots__]
@ -892,12 +893,12 @@ class _CountingAttr(object):
__slots__ = ("counter", "_default", "repr", "cmp", "hash", "init", __slots__ = ("counter", "_default", "repr", "cmp", "hash", "init",
"metadata", "_validator", "convert") "metadata", "_validator", "convert")
__attrs_attrs__ = tuple( __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) repr=True, cmp=True, hash=True, init=True)
for name for name
in ("counter", "_default", "repr", "cmp", "hash", "init",) 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), repr=True, cmp=True, hash=False, init=True),
) )
cls_counter = 0 cls_counter = 0
@ -1015,7 +1016,7 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
# import into .validators. # import into .validators.
@attributes(slots=True) @attributes(slots=True, hash=True)
class _AndValidator(object): class _AndValidator(object):
""" """
Compose many validators to a single one. Compose many validators to a single one.

View File

@ -9,13 +9,14 @@ from ._make import attr, attributes, and_, _AndValidator
__all__ = [ __all__ = [
"and_", "and_",
"in_",
"instance_of", "instance_of",
"optional", "optional",
"provides", "provides",
] ]
@attributes(repr=False, slots=True) @attributes(repr=False, slots=True, hash=True)
class _InstanceOfValidator(object): class _InstanceOfValidator(object):
type = attr() type = attr()
@ -55,7 +56,7 @@ def instance_of(type):
return _InstanceOfValidator(type) return _InstanceOfValidator(type)
@attributes(repr=False, slots=True) @attributes(repr=False, slots=True, hash=True)
class _ProvidesValidator(object): class _ProvidesValidator(object):
interface = attr() interface = attr()
@ -94,7 +95,7 @@ def provides(interface):
return _ProvidesValidator(interface) return _ProvidesValidator(interface)
@attributes(repr=False, slots=True) @attributes(repr=False, slots=True, hash=True)
class _OptionalValidator(object): class _OptionalValidator(object):
validator = attr() validator = attr()
@ -129,7 +130,7 @@ def optional(validator):
return _OptionalValidator(validator) return _OptionalValidator(validator)
@attributes(repr=False, slots=True) @attributes(repr=False, slots=True, hash=True)
class _InValidator(object): class _InValidator(object):
options = attr() options = attr()

View File

@ -109,9 +109,9 @@ class TestDarkMagic(object):
`attr.fields` works. `attr.fields` works.
""" """
assert ( assert (
Attribute(name="x", _default=foo, _validator=None, Attribute(name="x", default=foo, validator=None,
repr=True, cmp=True, hash=None, init=True), 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), repr=True, cmp=True, hash=None, init=True),
) == attr.fields(cls) ) == attr.fields(cls)
@ -158,9 +158,9 @@ class TestDarkMagic(object):
""" """
PC = attr.make_class("PC", ["a", "b"], slots=slots, frozen=frozen) PC = attr.make_class("PC", ["a", "b"], slots=slots, frozen=frozen)
assert ( assert (
Attribute(name="a", _default=NOTHING, _validator=None, Attribute(name="a", default=NOTHING, validator=None,
repr=True, cmp=True, hash=None, init=True), 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), repr=True, cmp=True, hash=None, init=True),
) == attr.fields(PC) ) == attr.fields(PC)

View File

@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function
import pytest import pytest
import zope.interface import zope.interface
from attr import validators as validator_module, has
from attr.validators import and_, instance_of, provides, optional, in_ from attr.validators import and_, instance_of, provides, optional, in_
from attr._compat import TYPE from attr._compat import TYPE
from attr._make import attributes, attr from attr._make import attributes, attr
@ -248,3 +249,16 @@ class TestIn_(object):
assert( assert(
("<in_ validator with options [3, 4, 5]>") ("<in_ validator with options [3, 4, 5]>")
) == repr(v) ) == 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__

View File

@ -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 an attribute with a name and no other bells and whistles.
""" """
return Attribute( return Attribute(
name=name, _default=default, _validator=validator, repr=repr, name=name, default=default, validator=validator, repr=repr,
cmp=cmp, hash=hash, init=init 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() vals = st.booleans() | st.binary() | st.integers() | st.text()
metadata = draw(st.dictionaries(keys=keys, values=vals)) 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, c_attr.cmp, c_attr.hash, c_attr.init, c_attr.convert,
metadata) metadata)