Skip to content

fix: lazyproperty re-evaluates getter when cached value is None - #1602

Open
afonsojanu wants to merge 1 commit into
python-openxml:masterfrom
afonsojanu:fix/lazyproperty-caches-none-1600
Open

fix: lazyproperty re-evaluates getter when cached value is None#1602
afonsojanu wants to merge 1 commit into
python-openxml:masterfrom
afonsojanu:fix/lazyproperty-caches-none-1600

Conversation

@afonsojanu

Copy link
Copy Markdown

Fixes #1600.

lazyproperty.__get__ decided whether the getter had already run by checking if value is None, using the instance __dict__ lookup's own None default as the "not computed yet" signal. That works fine as long as the getter never legitimately returns None, but if it does, the cached None looks identical to an unset value and the getter runs again on every single access, silently breaking the "evaluated only on first access" guarantee this class documents and exists to provide.

The fix checks for key presence in obj.__dict__ instead of comparing the value to None, so a getter that returns None is cached correctly after its first call, same as any other value.

Added two tests in tests/test_shared.py::DescribeLazyproperty covering both a getter that returns None and one that doesn't, asserting the getter's call count stays at 1 after multiple accesses in each case. Confirmed the new None-returning test fails against the old implementation (3 calls instead of 1) and passes against the fix.

Ran the full local suite (uv run pytest -x, 1611 passed), ruff check / ruff format --check on the changed files, and pyright (clean on the changed files; the one pyright error surfaced is inside a bundled typeshed stub, unrelated to this change and pre-existing on master).

lazyproperty.__get__ checked whether the cached value was None to
decide if the getter had run yet, so any getter that legitimately
returns None got re-evaluated on every access instead of being cached
after the first call. Check for key presence in the instance __dict__
instead, which distinguishes "not yet computed" from "computed None"
correctly.
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.

lazyproperty re-evaluates its getter on every access when the cached value is None

1 participant