This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: get_type_hints fails to resolve forward references in nested function
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.10, Python 3.9, Python 3.8, Python 3.7
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: cjw296, gvanrossum, levkivskyi
Priority: normal Keywords: 3.6regression

Created on 2020-09-27 13:58 by cjw296, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg377569 - (view) Author: Chris Withers (cjw296) * (Python committer) Date: 2020-09-27 13:58

    def test_forward_type_references(self):
        def foo(a: 'Foo') -> 'Bar': pass

        class Foo: pass
        class Bar: pass


The above gives the following exception, rather than resolving the type:

/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ in get_type_hints
    value = _eval_type(value, globalns, localns)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ in _eval_type
    return t._evaluate(globalns, localns)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ in _evaluate
    eval(self.__forward_code__, globalns, localns),
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   NameError: name 'Foo' is not defined
msg377578 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2020-09-27 19:59
This cannot be helped (unless we were to add an ugly sys._getframe() call to get_type_hints(), which I don't want to do). The solution is to pass `localns=locals()`, e.g.

get_type_hints(foo, None, locals())


get_type_hints(foo, localns=locals())
msg377579 - (view) Author: Chris Withers (cjw296) * (Python committer) Date: 2020-09-27 21:23
The tough one is that no-one wants an ugly sys._getframe() call, but by avoiding it in the standard library, we force each library that needs this to have the ugly sys._getframe() call rather than it being an unpleasant implementation detail of get_type_hints that users of the function don't have to know about.

That said, I've only hit this so far when writing a unit test, but will update this issue if I see real-world cases of this.
msg377581 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2020-09-27 22:00
I've only seen it in test cases too -- that's one of the very few
situations where it makes sense to define a class inside a function.
(Creating a class is an expensive operation, so any function that expects
to be called more than once is better off moving the class out of the
Date User Action Args
2022-04-11 14:59:36adminsetgithub: 86038
2020-09-27 22:00:19gvanrossumsetmessages: + msg377581
2020-09-27 21:23:14cjw296setmessages: + msg377579
2020-09-27 19:59:08gvanrossumsetstatus: open -> closed
messages: + msg377578

keywords: + 3.6regression
resolution: not a bug
stage: resolved
2020-09-27 15:29:02xtreaksetnosy: + gvanrossum, levkivskyi
2020-09-27 13:58:04cjw296create