-
-
Notifications
You must be signed in to change notification settings - Fork 534
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
Fix default cache dataloader raise key error on non-existing key #3569
base: main
Are you sure you want to change the base?
Conversation
Reviewer's Guide by SourceryThis pull request addresses a bug where calling the File-Level Changes
Tips
|
for more information, see https://pre-commit.ci
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.
Hey @dartt0n - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟢 General issues: all looks good
- 🟢 Security: all looks good
- 🟡 Testing: 1 issue found
- 🟢 Complexity: all looks good
- 🟡 Documentation: 3 issues found
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.
RELEASE.md
Outdated
@@ -0,0 +1,12 @@ | |||
Release type: patch | |||
|
|||
Calling `.clean(key)` on default dataloader with non-existing `key` will not throw `KeyError` error anymore. Example: |
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.
issue (documentation): Redundant phrase 'KeyError error'
Consider changing 'KeyError error' to just 'KeyError' to avoid redundancy.
async def load_data(keys): | ||
return [str(key) for key in keys] | ||
|
||
dataloader = DataLoader(load_fn=load_data) |
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.
suggestion (documentation): Mention import statement for DataLoader
Consider adding a comment or a line to indicate that DataLoader
should be imported from the relevant module to avoid confusion.
dataloader = DataLoader(load_fn=load_data) | |
```suggestion | |
```python | |
from some_module import DataLoader | |
dataloader = DataLoader(load_fn=load_data) |
RELEASE.md
Outdated
dataloader.clean(42) # does not throw KeyError anymore | ||
``` | ||
|
||
This is a patch release, so no breaking changes. |
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.
suggestion (documentation): Improve sentence flow
Consider rephrasing to 'This is a patch release with no breaking changes.'
This is a patch release, so no breaking changes. | |
This is a patch release with no breaking changes. |
Thanks for adding the Here's a preview of the changelog: Calling from strawberry.dataloader import DataLoader
async def load_data(keys):
return [str(key) for key in keys]
dataloader = DataLoader(load_fn=load_data)
dataloader.clear(42) # does not throw KeyError anymore This is a patch release with no breaking changes. Here's the tweet text:
|
Thanks for adding the Here's a preview of the changelog: Calling async def load_data(keys):
return [str(key) for key in keys]
dataloader = DataLoader(load_fn=load_data)
dataloader.clean(42) # does not throw KeyError anymore This is a patch release, so no breaking changes. Here's the tweet text:
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3569 +/- ##
==========================================
+ Coverage 96.58% 97.02% +0.43%
==========================================
Files 524 503 -21
Lines 33632 33464 -168
Branches 5577 5619 +42
==========================================
- Hits 32485 32468 -17
+ Misses 912 790 -122
+ Partials 235 206 -29 |
CodSpeed Performance ReportMerging #3569 will not alter performanceComparing Summary
|
Hmm, seems like type linting fails to resolve:
However, a overload exist:
The type is Will change code to if key in self.cache_map:
del self.cache_map[key] to satisfy linter |
Seems thats all check passed, waiting for the review |
@dartt0n in what cases would this be useful? 😊 wouldn't an error be a useful indication that something was wrong somewhere else? |
For example, some services modify an object, and this service needs to invalidate the cache for the modified object. However, the service does not know whether the object has already been loaded into the cache. This is a common problem for larger applications. I think most developers who face this issue either use try-catch blocks or create their own wrapper (like original issue suggest). Therefore, I believe that making this behavior non-exceptional would be beneficial for the developer's user experience. Additionally, as an example, the Redis DEL command does not throw an error when invalidating a non-existent cache entry. If you think that this explicit behavior would be more appropriate for the project, I suggest including a clear statement about it in the documentation in the "Cache Invalidation" section. |
Hey @patrick91 , I would find this useful too (I came here to do a similar PR but found this instead), for similar reasons to those described by @dartt0n . My reasoning is that cache invalidation is usually about ensuring an object doesn't exist in the cache. Strict remove-or-error semantics don't make sense because the nature of a data-loader is that the cache entries could be added from anywhere, and with arbitrary concurrency. For example, my current use-case is that an internal helper ( |
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.
Thanks for doing this.
I believe you made a typo, the function is called .clear()
rather than .clean()
tests/test_dataloaders.py
Outdated
try: | ||
loader.clean(1) # no effect on non-cached values | ||
except Exception as e: | ||
raise AssertionError("clean non-cached values does not raise KeyError") |
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.
I'm not sure what your intention is here. Normally a test will implement desired behaviour, and if it works without errors then (that part of) the test passes. So we could simplify to this ...
try: | |
loader.clean(1) # no effect on non-cached values | |
except Exception as e: | |
raise AssertionError("clean non-cached values does not raise KeyError") | |
loader.clear(1) # no effect on non-cached values |
...which is similar to the other calls below to loader.clear()
/ loader.clear_many()
/ etc
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.
You should also add this to the test_clear()
test function above, so that we can exercise the .clear()
functionality with an underlying cache
Co-authored-by: Gary Donovan <[email protected]>
Co-authored-by: Gary Donovan <[email protected]>
…chemap deletion behaviour These tests call `.clear()` on a non-existent cache key. Previously, this would have resulted in an exception being thrown. The new behaviour should be to throw no exceptions.
Hi @garyd203! Thank you for bringing this up! The pull request remained incomplete because I eventually implemented my class, which inherits from AbstractCacheMap and used it for the project (failed to implement Redis cache due to other issues related to strawberry dataloaders, so ended up storing everything in app memory :( ). I have updated the code based on your comments, if you have free time, please 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.
LGTM, thanks @dartt0n
@patrick91 Are you happy with this change?
Description
Right now, calling the
.clean(key)
method on a non-cached key will raise aKeyError
exception. There are several ways to solve this problem:CustomDefaultCache
class and override thedelete
method to first check if the key exists..clean
method is called..clean
.Among these options, the fourth solution seems to be the best, so these changes are proposed.
Types of Changes
Issues Fixed or Closed by This PR
Checklist
Summary by Sourcery
This pull request fixes a bug where calling
.clean(key)
on a non-cached key in the default dataloader would raise aKeyError
. The fix ensures that the method no longer throws an exception in such cases. Documentation and tests have been updated accordingly..clean(key)
on a non-cached key in the default dataloader would raise aKeyError
.RELEASE.md
to document the change in behavior for the.clean(key)
method in the default dataloader..clean(key)
on a non-cached key does not raise an error.