summaryrefslogtreecommitdiffstats
path: root/Lib/typing.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2016-11-09 21:12:51 (GMT)
committerGuido van Rossum <guido@python.org>2016-11-09 21:12:51 (GMT)
commit991d14fee1805e17647940a2a8cbf4f62f0f09ea (patch)
treef4fe29631fd94f9e309ee7a9c454ed64487f40d8 /Lib/typing.py
parenta1a8b7d3d7f628aec31be364c77cbb3e21cdbc0b (diff)
downloadcpython-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.py206
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