Skip to content
This repository was archived by the owner on Mar 8, 2018. It is now read-only.

Commit a87acbf

Browse files
committed
BACKWARDS INCOMPATIBLE: Hash instances by object id rather than value
This patch updates our usage of `attr.s` to set `hash=False`, so that we use id-based hashing instead of value-based hashing. attrs 17.1.0 changed the default for `hash` to `None`, which makes objects unhashable. We set `hash=False` so that we can continue to use objects as keys in dictionaries, but without attempting to hash by value. http://www.attrs.org/en/stable/changelog.html
1 parent 8a1b880 commit a87acbf

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

README.rst

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ attrs_sqlalchemy
1010
:alt: CI status
1111

1212
Use the amazing `attrs <https://attrs.readthedocs.io>`_ library to add
13-
``__repr__``, ``__eq__``, ``__cmp__``, and ``__hash__`` methods according to
14-
the fields on a SQLAlchemy model class.
13+
``__repr__``, ``__eq__``, and ``__cmp__`` methods according to the fields on a
14+
SQLAlchemy model class.
15+
16+
``__hash__`` will always fall back to id-based hashing from ``object``.
1517

1618

1719
Example
@@ -47,6 +49,26 @@ Installation
4749
4850
$ pip install attrs_sqlalchemy
4951
52+
Changelog
53+
=========
54+
55+
0.2.0 (UNRELEASED)
56+
------------------
57+
58+
- **Backward-incompatible**: Apply ``attr.s`` with ``hash=False``, using
59+
id-based hashing instead of value-based hashing.
60+
61+
attrs 17.0.0 changed the default for ``hash`` to ``None``, which makes
62+
objects unhashable. We set ``hash=False`` so that we can continue to use
63+
objects as keys in dictionaries, but without attempting to hash by value.
64+
65+
http://www.attrs.org/en/stable/changelog.html
66+
67+
0.1.0 (2016-09-24)
68+
------------------
69+
70+
- Initial release
71+
5072
Project Information
5173
===================
5274

attrs_sqlalchemy.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,24 @@
2626

2727
def attrs_sqlalchemy(maybe_cls=None):
2828
"""
29-
A class decorator that adds ``__repr__``, ``__eq__``, ``__cmp__``, and
30-
``__hash__`` methods according to the fields defined on the SQLAlchemy
31-
model class.
29+
A class decorator that adds ``__repr__``, ``__eq__``, and ``__cmp__``,
30+
methods according to the fields defined on the SQLAlchemy model class.
31+
32+
``__hash__`` will always fall back to id-based hashing from
33+
:class:`object`.
34+
35+
.. versionchanged:: 0.2.0
36+
37+
:func:`attr.s` is applied with ``hash=False``, using id-based hashing
38+
instead of value-based hashing.
39+
40+
attrs 17.1.0 changed the default for ``hash`` to ``None``, which makes
41+
objects unhashable.
42+
43+
We set ``hash=False`` so that we can continue to use objects as keys in
44+
dictionaries, but without attempting to hash by value.
45+
46+
http://www.attrs.org/en/stable/changelog.html
3247
"""
3348
def wrap(cls):
3449
these = {
@@ -53,7 +68,7 @@ def wrap(cls):
5368
# which won't be ready yet.
5469
for name in inspect(cls).columns.keys()
5570
}
56-
return attr.s(cls, these=these, init=False)
71+
return attr.s(cls, these=these, init=False, hash=False)
5772

5873
# `maybe_cls` depends on the usage of the decorator. It's a class if it's
5974
# used as `@attrs_sqlalchemy` but `None` if it's used as

test_attrs_sqlalchemy.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ class MyModel(TestBase):
3737
# Instances should have a repr containing their keys and type
3838
assert repr(instance) == "MyModel(id=1, text='hello')"
3939

40-
# Instances should be hashable by their fields and used in a dict
40+
# Instances should be hashable by ID, not fields
4141
d = {instance: True}
42-
assert d.get(same_data) == d[instance]
42+
assert instance in d
43+
assert d.get(same_data) is None
4344
assert d.get(same_pk) is None
4445

4546
def test_field_name_not_column_name(self):

0 commit comments

Comments
 (0)