-
-
Notifications
You must be signed in to change notification settings - Fork 374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache hash codes #426
Cache hash codes #426
Conversation
Currently all existing tests pass but no cache_hash tests have yet been added.
@hynek : I believe this is now ready for review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a PR of this size this looks quite excellent! I’ve added a bunch of nits, but this should be mergeable very soon!
src/attr/_make.py
Outdated
raise TypeError( | ||
"Invalid value for cache_hash. To use hash caching," | ||
" hashing must be either explicitly or implicitly " | ||
"enabled" |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/attr/_make.py
Outdated
raise TypeError( | ||
"Invalid value for cache_hash. To use hash caching," | ||
" hashing must be either explicitly or implicitly " | ||
"enabled" |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/attr/_make.py
Outdated
if cache_hash: | ||
raise TypeError( | ||
"Invalid value for cache_hash. To use hash caching," | ||
" init must be True" |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@@ -283,8 +293,34 @@ def test_enforces_type(self): | |||
|
|||
assert exc_args == e.value.args | |||
|
|||
@given(booleans()) | |||
def test_hash_attribute(self, slots): | |||
def test_enforce_no_cache_hash_without_hash(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
changelog.d/425.change.rst
Outdated
@@ -0,0 +1 @@ | |||
Added ``cache_hash`` option which causes the hash code to be computed once and stored on the object. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
docs/hashing.rst
Outdated
|
||
Some objects have hash codes which are expensive to compute. | ||
If such objects are to be stored in hash-based collections, it can be useful to compute the hash codes only once and then store the result on the object to make future hash code requests fast. | ||
To enable caching of hash codes, specify ``cache_hash=True``. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
docs/hashing.rst
Outdated
To enable caching of hash codes, specify ``cache_hash=True``. | ||
This may only be done if ``attrs`` is already generating a hash function for the object. | ||
If the hash code is cached, no field involved in hash code computation may be mutated after construction. | ||
It is strongly recommended that classes with cached hashcodes be ``frozen`` |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
docs/init.rst
Outdated
@@ -348,6 +348,7 @@ If you need to set attributes on a frozen class, you'll have to resort to the :r | |||
>>> Frozen(1) | |||
Frozen(x=1, y=2) | |||
|
|||
Note that you may not access the hash code of the object in ``__attrs_post__init__`` if ``cache_hash=True`` |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/attr/_make.py
Outdated
|
||
if cache_hash: | ||
method_lines.append(tab + "if self.%s is None:" % _hash_cache_field) | ||
# we use __setattr__ all the time so we don't need to special-case for |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
) | ||
assert exc_args == e.value.args | ||
|
||
def test_enforce_no_cached_hash_without_init(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@hynek : Ready for re-review. For all the trivial changes (periods, adding phrases to docs, docstrings, etc.) I made the suggested changes. In the two more complex cases, I commented on your comments to highlight my changes. |
Great work, thank you! |
@hynek : no problem, thanks for reviewing and merging! Do you happen to know when the next release is likely to be? My team would really like to use this feature and the new kw-only args support. |
@hynek : Great, thank you! |
Pull Request Check List
This is just a reminder about the most common mistakes. Please make sure that you tick all appropriate boxes. But please read our contribution guide at least once, it will save you unnecessary review cycles!
.pyi
)..rst
files is written using semantic newlines.versionadded
,versionchanged
, ordeprecated
directives.changelog.d
.Description
This adds a
cache_hash
flag to@attrs
which causes the hash code to be computed once and stored on the object. Setting this flag totrue
is allowed only ifattrs
is set to generate both the__hash__
and__init__
methods for a class.This closes issues #423.