diff options
author | Guido van Rossum <guido@python.org> | 2016-11-09 21:12:51 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2016-11-09 21:12:51 (GMT) |
commit | 991d14fee1805e17647940a2a8cbf4f62f0f09ea (patch) | |
tree | f4fe29631fd94f9e309ee7a9c454ed64487f40d8 /Lib/typing.py | |
parent | a1a8b7d3d7f628aec31be364c77cbb3e21cdbc0b (diff) | |
download | cpython-991d14fee1805e17647940a2a8cbf4f62f0f09ea.zip cpython-991d14fee1805e17647940a2a8cbf4f62f0f09ea.tar.gz cpython-991d14fee1805e17647940a2a8cbf4f62f0f09ea.tar.bz2 |
Issue #28556: More typing.py updates from upstream.
Diffstat (limited to 'Lib/typing.py')
-rw-r--r-- | Lib/typing.py | 206 |
1 files changed, 72 insertions, 134 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index 2a1ea08..e748fd9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -10,8 +10,6 @@ try: import collections.abc as collections_abc except ImportError: import collections as collections_abc # Fallback for PY3.2. -if sys.version_info[:2] >= (3, 3): - from collections import ChainMap # Please keep __all__ alphabetized within each category. @@ -1194,14 +1192,12 @@ class CallableMeta(GenericMeta): # super()._tree_repr() for nice formatting. arg_list = [] for arg in tree[1:]: - if arg == (): - arg_list.append('[]') - elif not isinstance(arg, tuple): + if not isinstance(arg, tuple): arg_list.append(_type_repr(arg)) else: arg_list.append(arg[0]._tree_repr(arg)) - if len(arg_list) == 2: - return repr(tree[0]) + '[%s]' % ', '.join(arg_list) + if arg_list[0] == '...': + return repr(tree[0]) + '[..., %s]' % arg_list[1] return (repr(tree[0]) + '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) @@ -1216,26 +1212,22 @@ class CallableMeta(GenericMeta): raise TypeError("Callable must be used as " "Callable[[arg, ...], result].") args, result = parameters - if args is ...: - parameters = (..., result) - elif args == []: - parameters = ((), result) + if args is Ellipsis: + parameters = (Ellipsis, result) else: if not isinstance(args, list): raise TypeError("Callable[args, result]: args must be a list." " Got %.100r." % (args,)) - parameters = tuple(args) + (result,) + parameters = (tuple(args), result) return self.__getitem_inner__(parameters) @_tp_cache def __getitem_inner__(self, parameters): - *args, result = parameters + args, result = parameters msg = "Callable[args, result]: result must be a type." result = _type_check(result, msg) - if args == [...,]: + if args is Ellipsis: return super().__getitem__((_TypingEllipsis, result)) - if args == [(),]: - return super().__getitem__((_TypingEmpty, result)) msg = "Callable[[arg, ...], result]: each arg must be a type." args = tuple(_type_check(arg, msg) for arg in args) parameters = args + (result,) @@ -1332,7 +1324,11 @@ def cast(typ, val): def _get_defaults(func): """Internal helper to extract the default arguments, by name.""" - code = func.__code__ + try: + code = func.__code__ + except AttributeError: + # Some built-in functions don't have __code__, __defaults__, etc. + return {} pos_count = code.co_argcount arg_names = code.co_varnames arg_names = arg_names[:pos_count] @@ -1346,138 +1342,80 @@ def _get_defaults(func): return res -if sys.version_info[:2] >= (3, 3): - def get_type_hints(obj, globalns=None, localns=None): - """Return type hints for an object. +def get_type_hints(obj, globalns=None, localns=None): + """Return type hints for an object. - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, and if necessary - adds Optional[t] if a default value equal to None is set. + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, and if necessary + adds Optional[t] if a default value equal to None is set. - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary, or in the case of a class, a ChainMap of - dictionaries. + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. - - If no dict arguments are passed, an attempt is made to use the - globals from obj, and these are also used as the locals. If the - object does not appear to have globals, an exception is raised. + - If no dict arguments are passed, an attempt is made to use the + globals from obj, and these are also used as the locals. If the + object does not appear to have globals, an exception is raised. - - If one dict argument is passed, it is used for both globals and - locals. + - If one dict argument is passed, it is used for both globals and + locals. - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ - if getattr(obj, '__no_type_check__', None): - return {} - if globalns is None: - globalns = getattr(obj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: + if getattr(obj, '__no_type_check__', None): + return {} + if globalns is None: + globalns = getattr(obj, '__globals__', {}) + if localns is None: localns = globalns - - if (isinstance(obj, types.FunctionType) or - isinstance(obj, types.BuiltinFunctionType) or - isinstance(obj, types.MethodType)): - defaults = _get_defaults(obj) - hints = obj.__annotations__ - for name, value in hints.items(): - if value is None: - value = type(None) - if isinstance(value, str): - value = _ForwardRef(value) - value = _eval_type(value, globalns, localns) - if name in defaults and defaults[name] is None: - value = Optional[value] - hints[name] = value - return hints - - if isinstance(obj, types.ModuleType): - try: - hints = obj.__annotations__ - except AttributeError: - return {} - for name, value in hints.items(): + elif localns is None: + localns = globalns + # Classes require a special treatment. + if isinstance(obj, type): + hints = {} + for base in reversed(obj.__mro__): + ann = base.__dict__.get('__annotations__', {}) + for name, value in ann.items(): if value is None: value = type(None) if isinstance(value, str): value = _ForwardRef(value) value = _eval_type(value, globalns, localns) hints[name] = value - return hints - - if isinstance(object, type): - cmap = None - for base in reversed(obj.__mro__): - new_map = collections.ChainMap if cmap is None else cmap.new_child - try: - hints = base.__dict__['__annotations__'] - except KeyError: - cmap = new_map() - else: - for name, value in hints.items(): - if value is None: - value = type(None) - if isinstance(value, str): - value = _ForwardRef(value) - value = _eval_type(value, globalns, localns) - hints[name] = value - cmap = new_map(hints) - return cmap - - raise TypeError('{!r} is not a module, class, method, ' - 'or function.'.format(obj)) - -else: - def get_type_hints(obj, globalns=None, localns=None): - """Return type hints for a function or method object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, and if necessary - adds Optional[t] if a default value equal to None is set. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj, and these are also used as the locals. If the - object does not appear to have globals, an exception is raised. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - if getattr(obj, '__no_type_check__', None): - return {} - if globalns is None: - globalns = getattr(obj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: - localns = globalns - defaults = _get_defaults(obj) - hints = dict(obj.__annotations__) - for name, value in hints.items(): - if isinstance(value, str): - value = _ForwardRef(value) - value = _eval_type(value, globalns, localns) - if name in defaults and defaults[name] is None: - value = Optional[value] - hints[name] = value return hints + hints = getattr(obj, '__annotations__', None) + if hints is None: + # Return empty annotations for something that _could_ have them. + if (isinstance(obj, types.FunctionType) or + isinstance(obj, types.BuiltinFunctionType) or + isinstance(obj, types.MethodType) or + isinstance(obj, types.ModuleType)): + return {} + else: + raise TypeError('{!r} is not a module, class, method, ' + 'or function.'.format(obj)) + defaults = _get_defaults(obj) + hints = dict(hints) + for name, value in hints.items(): + if value is None: + value = type(None) + if isinstance(value, str): + value = _ForwardRef(value) + value = _eval_type(value, globalns, localns) + if name in defaults and defaults[name] is None: + value = Optional[value] + hints[name] = value + return hints def no_type_check(arg): @@ -2160,7 +2098,7 @@ class TextIO(IO[str]): pass @abstractproperty - def errors(self) -> str: + def errors(self) -> Optional[str]: pass @abstractproperty |