Skip to content

annotationlib: ref.evaluate() not working for generics as local variables #138151

Closed

Description

@dr-carlos

Bug report

Bug description:

Usually, when a local variable is introduced after getting a ForwardRef, evaluate() picks this up and correctly evaluates it using the self.__cell__ short-circuit. However, this does not work when that local variable is a generic. It does still work for globals.

from annotationlib import Format, get_annotations

def works_global():
    class Demo:
        x: sequence_a[int]

    fwdref = get_annotations(Demo, format=Format.FORWARDREF)['x']
    print(f"Global {fwdref!r}")

    global sequence_a
    sequence_a = list
    evaluated = fwdref.evaluate()
    print(f"Evaluated {evaluated!r}")

def works_nongeneric():
    class Demo:
        nonlocal alias # Optional
        x: alias

    fwdref = get_annotations(Demo, format=Format.FORWARDREF)['x']
    print(f"Global {fwdref!r}")

    alias = int
    evaluated = fwdref.evaluate()
    print(f"Evaluated {evaluated!r}")


def fails():
    class Demo:
        nonlocal sequence_b
        x: sequence_b[int]

    fwdref = get_annotations(Demo, format=Format.FORWARDREF)['x']
    print(f"Local {fwdref!r}")

    sequence_b = list
    evaluated = fwdref.evaluate() # NameError
    print(f"Evaluated {evaluated!r}")


works_global()
works_nongeneric()
fails()

CPython versions tested on:

CPython main branch, 3.14

Operating systems tested on:

Linux

Linked PRs

Activity

  1. JelleZijlstra commented on Aug 26, 2025

    @JelleZijlstra
    Member

    I wouldn't expect your fails() to work: you set sequence_b only in that function's local scope, and that's not the scope the annotation was defined in.

  2. added
    pendingThe issue will be closed if no feedback is provided
    on Aug 26, 2025
  3. dr-carlos commented on Aug 26, 2025

    @dr-carlos
    ContributorAuthor

    I wouldn't expect your fails() to work: you set sequence_b only in that function's local scope, and that's not the scope the annotation was defined in.

    Thanks, this is a good point, I forgot to consider that when writing up the example.
    I've edited the OP with more complete examples, and put the classes inside the function definitions so the scoping should be correct.

  4. JelleZijlstra commented on Aug 26, 2025

    @JelleZijlstra
    Member

    The problem here is that we don't properly preserve a reference to the cell object that was used to create the ForwardRef. This should be done when we create the ForwardRef (i.e., in get_annotations or code called from it), not in ForwardRef.evaluate. We can probably fix this by putting more information in the __cell__ attribute of the ForwardRef.

  5. removed
    pendingThe issue will be closed if no feedback is provided
    on Aug 26, 2025
  6. added a commit that references this issue on Aug 26, 2025
  7. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Aug 26, 2025
  8. dr-carlos commented on Aug 27, 2025

    @dr-carlos
    ContributorAuthor

    @JelleZijlstra Is #138161 still necessary given the broader fix in #138164 , or should I close it?

  9. JelleZijlstra commented on Aug 27, 2025

    @JelleZijlstra
    Member

    I don't think #138161 is necessary, but someone will need to review #138164.

  10. added a commit that references this issue on Nov 3, 2025
  11. added a commit that references this issue on Nov 3, 2025
  12. added a commit that references this issue on Nov 3, 2025
  13. efimov-mikhail commented on Nov 3, 2025

    @efimov-mikhail
    Member

    I've checked that merged PRs fix this issue on main and 3.14. So I'll close this.

  14. added a commit that references this issue on Dec 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions