Skip to content

Keep subfield memoization keys alive during execution - #285

Open
jadenfix wants to merge 1 commit into
graphql-python:mainfrom
jadenfix:fix/subfield-cache-key-lifetime
Open

jadenfix wants to merge 1 commit into
graphql-python:mainfrom
jadenfix:fix/subfield-cache-key-lifetime

Conversation

@jadenfix

Copy link
Copy Markdown

The subfield cache keys on id(FieldDetails) but does not retain those objects. After a field detail is freed, CPython can reuse its identity for another field, returning the earlier field's selection set.

Keep an immutable tuple of the key objects alongside each collected result. The existing identity keys and cache hits remain intact, including calls with a different list containing the same objects. Keeping a snapshot also handles callers clearing their input list; references are released with the shared execution cache.

The regression checks key lifetime, cache identity, distinct selection results, and eventual release. The reported reproducer produced 497 incorrect selections in 500 runs on main and none with this change. A separately installed wheel also passed 400 complete GraphQL schema/query/result journeys covering distinct fields, merged selections, and aliases.

Validation: Python 3.14 full suite 3,528 passed / 18 skipped with the required 100% source and test coverage; Python 3.10 floor 3,529 passed / 17 skipped. Ruff check/format, mypy (353 files), and the strict sphinx -b html -nEW build pass. An independent AI reviewer inspected the cache's ownership across sub-executors and reran all 43 executor tests. Prepared with AI assistance.

Fixes #284.

@jadenfix
jadenfix requested a review from Cito as a code owner October 18, 2026 13:07
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.

collect_subfields memoization keyed on id() of FieldDetails that are not kept alive returns another field's subfields

1 participant