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.

classification
Title: typing.get_type_hints doesn't know about typeshed
Type: enhancement Stage:
Components: Versions: Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: levkivskyi Nosy List: Ben.Darnell, gvanrossum, jstasiak, levkivskyi
Priority: normal Keywords:

Created on 2018-09-15 20:10 by Ben.Darnell, last changed 2022-04-11 14:59 by admin.

Messages (4)
msg325455 - (view) Author: Ben Darnell (Ben.Darnell) * Date: 2018-09-15 20:10
Currently, most type annotations for the standard library are provided in typeshed rather than in the library itself. Not all consumers of type annotations are aware of typeshed, and this can cause problems. Specifically, Sphinx 1.8 accesses type hints via `typing.get_type_hints()`, which fails for some hints which are (implicitly) relying on typeshed. This currently manifests as failures to build Tornado's docs with Sphinx 1.8 (Tornado is using inline type annotations).

Concretely, the issue involves the `concurrent.futures.Future` class. In typeshed, this class is a `Generic[T]`, but in the standard library it's just a normal class. Consider a function that returns a parameterized Future type:

    from concurrent.futures import Future

    def do_something_background() -> 'Future[int]':
        return executor.submit(do_something)

Note that the type annotation is already a string. We can't use `Future[int]` directly because at runtime, the real Future type is not subscriptable. The string defers resolution of the subscript until something tries to access the annotation *as a type hint*. When mypy does this, it uses the typeshed definition of Future, so everything passes. But when Sphinx calls `typing.get_type_hints()` on this function, it fails:

```
>>> typing.get_type_hints(do_something_background)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/typing.py", line 1543, in get_type_hints
    value = _eval_type(value, globalns, localns)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/typing.py", line 350, in _eval_type
    return t._eval_type(globalns, localns)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/typing.py", line 245, in _eval_type
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
TypeError: 'type' object is not subscriptable
```


What can be done about this? I see a few approaches:

1. Require that any use of type hints consults typeshed. This would entail either making typing.get_type_hints aware of typeshed or deprecating and removing it.

2. Disallow references to typeshed from inline type annotations; types that require typeshed must only appear in `.pyi` stubs, which will only be interpreted by tools like mypy that know about typeshed. (is this true, or are there tools that know about pyi files but not typeshed?)

3. Annotate types in the standard library as generic. So far, this problem has always taken the form of "type is not subscriptable", and it could be resolved by making all generic types in the stdlib subclasses of `typing.Generic[T]`. This would bring enough typing detail into the stdlib to allow the annotations to be parsed without typeshed. This would also avoid the need for the awkward quotes in the example above.
msg326040 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-09-21 20:51
I think there is also a fourth option: add a flag to `get_type_hints()` that will guard evaluation of forward references, as proposed in https://github.com/python/typing/issues/508. If the evaluation of a "forward reference" raises an error, then we keep it unevaluated (i.e. a string).
msg326313 - (view) Author: Ben Darnell (Ben.Darnell) * Date: 2018-09-25 03:08
Yeah, I think that would work at least for the sphinx use case. It seems like a strange partially-degraded mode and anything that needs structured access to the annotation would still need typeshed, but just getting the string would probably be enough for a lot of applications. In fact, sphinx *only* wants the string (AFAICT), so a separate method like get_type_hints_as_string() which stringifies everything even if it can be resolved might be a better route than an option to get_type_hints().
msg342922 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-05-20 15:40
Yeah, the Sphinx use case is somewhat different from the originally envisioned use case for get_type_hints().  Possibly Sphinx could just directly inspect __annotations__ rather than calling get_type_hints()?  I'm not sure if there's any situation where it would need the things that get_type_hints() is supposed to take care of.
History
Date User Action Args
2022-04-11 14:59:06adminsetgithub: 78881
2019-05-20 15:40:49gvanrossumsetmessages: + msg342922
2019-05-17 22:15:17jstasiaksetnosy: + jstasiak
2018-09-27 16:02:52levkivskyisetassignee: levkivskyi
2018-09-25 03:08:24Ben.Darnellsetmessages: + msg326313
2018-09-21 20:51:15levkivskyisetnosy: + gvanrossum, levkivskyi
messages: + msg326040
2018-09-15 20:10:00Ben.Darnellcreate