Skip to content

gh-160948: Fix annotationlib.ForwardRef.evaluate() ignoring explicit globals/locals for closure-cell references - #160952

Open
arpittkhandelwal wants to merge 1 commit into
python:mainfrom
arpittkhandelwal:fix/annotationlib-forwardref-evaluate
Open

arpittkhandelwal wants to merge 1 commit into
python:mainfrom
arpittkhandelwal:fix/annotationlib-forwardref-evaluate

Conversation

@arpittkhandelwal

Copy link
Copy Markdown

Summary

ForwardRef.evaluate() had an early return for references holding a
single closure cell (__cell__ is a CellType) that ran before any
namespace handling. As a result, explicitly passed globals/locals
were silently ignored for such references, while every other path in
the same method (plain references, dict-of-cells references) gives
explicit namespaces precedence over the captured scope.

Fix

In Lib/annotationlib.py (ForwardRef.evaluate):

  • The single-cell shortcut now only applies when neither globals
    nor locals was passed, preserving the existing fast path and
    behaviour for the common no-argument call.
  • In the plain-identifier resolution branch, the cell value is
    consulted after locals and globals (and before builtins,
    matching normal scope order), so it acts as a fallback when an
    explicitly passed namespace does not provide the name. An empty
    cell (ValueError) falls through exactly as before.

No other paths are changed: the dict-of-cells and __extra_names__
handling, type-parameter injection, and the non-identifier eval
path are untouched.

Tests

Two regression tests in Lib/test/test_annotationlib.py
(TestForwardRefClass):

  • test_evaluate_cell_with_explicit_namespaces — explicit locals
    and globals win over the cell (locals over globals when both are
    given, in both VALUE and FORWARDREF formats); the cell remains the
    fallback when the name is absent from the explicit namespaces.
  • test_evaluate_empty_cell_with_explicit_namespaces — an emptied
    cell still raises NameError with no arguments, explicit namespaces
    are consulted, and a refilled cell resumes its fallback role without
    overriding explicit namespaces.

Both tests fail on the unmodified code and pass with this change.

Results (local build of main @ 83fe630):

  • test_annotationlib: 123 tests run — SUCCESS (121 pre-existing +
    2 new).
  • test_typing: SUCCESS.
  • test_inspect: 1 failure in
    test_details_option_with_package, which also fails on the
    unmodified tree in this environment (it compares inspect CLI
    output containing stdlib file paths); unrelated to this change.

Fixes gh-160948.

Disclosure: this change was drafted with AI assistance and reviewed by the author, who takes responsibility for it.

…licit globals/locals for closure-cell references
@picnixz

picnixz commented Oct 31, 2026

Copy link
Copy Markdown
Member

Considering the issue is still under discussion, I'm closing this.

@picnixz picnixz closed this Oct 31, 2026
@picnixz picnixz reopened this Oct 31, 2026
@picnixz

picnixz commented Oct 31, 2026

Copy link
Copy Markdown
Member

We may keep it open and only change the locals handling. Because the globals one may not be wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

annotationlib.ForwardRef.evaluate() ignores explicit globals/locals when the reference holds a closure cell

2 participants