Issues recovering a lambda from "stringized" type annotations

I recently ran into a weird bug at work, and after some work managed to reduce it to the following code (note the PEP 563 “stringized” annotations):

from __future__ import annotations
from typing import get_type_hints
import sys

FIND_ME = 42


def function():
    return FIND_ME


class Example:
    my_function: function
    my_lambda: lambda: FIND_ME


hints = get_type_hints(
    Example,
    # globalns=sys.modules[Example.__module__].__dict__,
    # localns=dict(vars(Example)),
)
hints['my_function']()  # Succeeds
hints['my_lambda']()  # Fails

When I run it, calling the regular function from the annotations works as expected, but calling the lambda fails with NameError: name ‘FIND_ME’ is not defined.

However, if I pass in globalns or localns as shown in the commented out lines, both calls work as expected. This has me confused because the typing.get_type_hints() documentation states:

If globalns or localns is not given, appropriate namespace dictionaries are inferred from obj.

And as far as I can tell, those commented out lines are the exact logic typing.get_type_hints() uses to infer the namespace dictionaries.

Can you help me understand what I’m missing here?

Thanks!

2 Likes