Skip to content

Add key parameter for custom cache key computation#782

Open
rodrigobnogueira wants to merge 7 commits into
masterfrom
feat/cache-key-support
Open

Add key parameter for custom cache key computation#782
rodrigobnogueira wants to merge 7 commits into
masterfrom
feat/cache-key-support

Conversation

@rodrigobnogueira

@rodrigobnogueira rodrigobnogueira commented Jul 5, 2026

Copy link
Copy Markdown
Member

What do these changes do?

Add an optional key parameter to alru_cache for custom cache key computation, so arguments that do not affect the result can be excluded from the key (the motivating case in #619: a DB connection passed alongside a query). The callable receives the same arguments as the wrapped function and its hashable result replaces the default functools._make_key tuple. cache_invalidate() and cache_contains() compute keys the same way, so a custom key invalidates exactly what it cached. typed=True combined with key raises ValueError, since typed only affects the default computation. With key unset (the default), behavior is unchanged, keeping the stdlib-mirroring interface intact; the README documents the parameter as an async-lru extension beyond the lru_cache interface.

On the stdlib-compatibility question from the issue discussion: there was an upstream proposal, python/cpython#90780 (bpo-46622, 2022), which was closed in favor of a separate implementation rather than extending lru_cache to coroutines; the functools docs were later amended (python/cpython#107619) to note that caching async functions with lru_cache "doesn't make sense". Whatever shape a future stdlib solution might take, reconciling stays easy because key=None keeps the mirror exact.

Are there changes in behavior for the user?

Only when the new parameter is used. Without key, everything is unchanged.

Is it a substantial burden for the maintainers to support this?

No. The feature is a single code path shared by the three key computation sites and is fully covered by tests.

Related issue number

Fixes #619

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • Add a new news fragment into the CHANGES folder (N/A; CHANGES.rst is updated in release PRs in this repo)

The optional key callable receives the call arguments and returns the
cache key, letting callers exclude arguments that do not affect the
result, such as a DB connection passed alongside a query (#619). The
same computation backs the call, cache_invalidate and cache_contains
paths. typed=True with key raises ValueError since typed only affects
the default key computation. With key unset the behavior is
unchanged.
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.96%. Comparing base (b5717c7) to head (41f6151).
⚠️ Report is 7 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #782      +/-   ##
==========================================
+ Coverage   97.78%   97.96%   +0.17%     
==========================================
  Files          16       17       +1     
  Lines        1176     1279     +103     
  Branches       61       66       +5     
==========================================
+ Hits         1150     1253     +103     
  Misses         23       23              
  Partials        3        3              
Flag Coverage Δ
unit 97.10% <100.00%> (+0.25%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq

codspeed-hq Bot commented Jul 5, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 63 untouched benchmarks
⏩ 4 skipped benchmarks1


Comparing feat/cache-key-support (41f6151) with master (b5717c7)2

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on master (37b3033) during the generation of this report, so b5717c7 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

An extra method call is measurable on cache_invalidate, which
CodSpeed put at about 21 percent; branching inline on the stored key
keeps the default path at parity with master.
@rodrigobnogueira
rodrigobnogueira marked this pull request as ready for review July 5, 2026 20:01

@Vizonex Vizonex left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall great job, I'll see if we can get this approved or merged.

Comment thread async_lru/__init__.py
@rodrigobnogueira

Copy link
Copy Markdown
Member Author

Thanks @Vizonex

@Dreamsorcerer

Copy link
Copy Markdown
Member

upstreaming an async lru_cache was formally attempted, not merely hypothetical, and it was rejected

Not really. It just suggested a different implementation.

Comment thread async_lru/__init__.py Outdated
@rodrigobnogueira

Copy link
Copy Markdown
Member Author

upstreaming an async lru_cache was formally attempted, not merely hypothetical, and it was rejected

Not really. It just suggested a different implementation.

Fair 🙏
Reworded the body

When no custom key is given, __init__ wraps functools._make_key in a
packing lambda so __key is always callable, and the None branches in
__call__, cache_invalidate and cache_contains collapse to a single
call, as suggested in review. The default path gains one call layer;
CodSpeed will show whether it is measurable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request] Hash key support

3 participants