Skip to content
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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
16 changes: 16 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Release type: patch

Calling `.clean(key)` on default dataloader with non-existing `key` will not throw `KeyError` anymore. Example:
dartt0n marked this conversation as resolved.
Show resolved Hide resolved
```python
from strawberry.dataloader import DataLoader


async def load_data(keys):
return [str(key) for key in keys]


dataloader = DataLoader(load_fn=load_data)
Copy link
Contributor

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.

Suggested change
dataloader = DataLoader(load_fn=load_data)
```suggestion
```python
from some_module import DataLoader
dataloader = DataLoader(load_fn=load_data)

dataloader.clean(42) # does not throw KeyError anymore
dartt0n marked this conversation as resolved.
Show resolved Hide resolved
```

This is a patch release with no breaking changes.
4 changes: 3 additions & 1 deletion strawberry/dataloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ def set(self, key: K, value: Future[T]) -> None:
self.cache_map[self.cache_key_fn(key)] = value

def delete(self, key: K) -> None:
del self.cache_map[self.cache_key_fn(key)]
cache_key = self.cache_key_fn(key)
if cache_key in self.cache_map:
del self.cache_map[cache_key]

def clear(self) -> None:
self.cache_map.clear()
Expand Down
5 changes: 5 additions & 0 deletions tests/test_dataloaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ async def idx(keys: List[int]) -> List[Tuple[int, int]]:

loader = DataLoader(load_fn=idx, cache=False)

try:
loader.clean(1) # no effect on non-cached values
except Exception as e:
raise AssertionError("clean non-cached values does not raise KeyError")
Copy link
Contributor

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 ...

Suggested change
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

Copy link
Contributor

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

See https://github.com/strawberry-graphql/strawberry/pull/3569/files#diff-9e2920b06c9fb1a3a76b9f675328e820421756fa44783ebdd45ca2c7a047c8a7R266-R279


assert await loader.load_many([1, 2, 3]) == [(1, 1), (2, 1), (3, 1)]

loader.clear(1)
Expand Down
Loading