From 044a1048ca93d466965afc027b91a5a9eb9ce23c Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 6 Oct 2020 23:03:02 +0300 Subject: bpo-38605: Make 'from __future__ import annotations' the default (GH-20434) The hard part was making all the tests pass; there are some subtle issues here, because apparently the future import wasn't tested very thoroughly in previous Python versions. For example, `inspect.signature()` returned type objects normally (except for forward references), but strings with the future import. We changed it to try and return type objects by calling `typing.get_type_hints()`, but fall back on returning strings if that function fails (which it may do if there are future references in the annotations that require passing in a specific namespace to resolve). --- Lib/inspect.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'Lib/inspect.py') diff --git a/Lib/inspect.py b/Lib/inspect.py index 887a342405..ac127cbd72 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -45,6 +45,7 @@ import sys import tokenize import token import types +import typing import warnings import functools import builtins @@ -1877,7 +1878,10 @@ def _signature_is_functionlike(obj): code = getattr(obj, '__code__', None) defaults = getattr(obj, '__defaults__', _void) # Important to use _void ... kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here - annotations = getattr(obj, '__annotations__', None) + try: + annotations = _get_type_hints(obj) + except AttributeError: + annotations = None return (isinstance(code, types.CodeType) and isinstance(name, str) and @@ -2118,6 +2122,16 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True): return cls(parameters, return_annotation=cls.empty) +def _get_type_hints(func): + try: + return typing.get_type_hints(func) + except Exception: + # First, try to use the get_type_hints to resolve + # annotations. But for keeping the behavior intact + # if there was a problem with that (like the namespace + # can't resolve some annotation) continue to use + # string annotations + return func.__annotations__ def _signature_from_builtin(cls, func, skip_bound_arg=True): """Private helper function to get signature for @@ -2161,7 +2175,8 @@ def _signature_from_function(cls, func, skip_bound_arg=True): positional = arg_names[:pos_count] keyword_only_count = func_code.co_kwonlyargcount keyword_only = arg_names[pos_count:pos_count + keyword_only_count] - annotations = func.__annotations__ + annotations = _get_type_hints(func) + defaults = func.__defaults__ kwdefaults = func.__kwdefaults__ -- cgit v1.2.1