diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2020-04-08 08:03:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-08 08:03:27 (GMT) |
commit | f228bf2300a9d3bf833b1a89336581822e864ae5 (patch) | |
tree | f6250218b093d71c553236eadd9ac68863f84fba /Lib | |
parent | a2ec06938f46683e33692615aca3875d8b8e110c (diff) | |
download | cpython-f228bf2300a9d3bf833b1a89336581822e864ae5.zip cpython-f228bf2300a9d3bf833b1a89336581822e864ae5.tar.gz cpython-f228bf2300a9d3bf833b1a89336581822e864ae5.tar.bz2 |
bpo-40187: Refactor typing.TypedDict. (GH-19372)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/typing.py | 67 |
1 files changed, 33 insertions, 34 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index bcb2233..9cacaa8 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1792,44 +1792,20 @@ def _namedtuple_mro_entries(bases): NamedTuple.__mro_entries__ = _namedtuple_mro_entries -def _dict_new(cls, /, *args, **kwargs): - return dict(*args, **kwargs) - - -def _typeddict_new(cls, typename, fields=None, /, *, total=True, **kwargs): - if fields is None: - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - - ns = {'__annotations__': dict(fields), '__total__': total} - try: - # Setting correct module is necessary to make typed dict classes pickleable. - ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - - return _TypedDictMeta(typename, (), ns) - - -def _check_fails(cls, other): - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - - class _TypedDictMeta(type): def __new__(cls, name, bases, ns, total=True): """Create new typed dict class object. - This method is called directly when TypedDict is subclassed, - or via _typeddict_new when TypedDict is instantiated. This way + This method is called when TypedDict is subclassed, + or when TypedDict is instantiated. This way TypedDict supports all three syntax forms described in its docstring. - Subclasses and instances of TypedDict return actual dictionaries - via _dict_new. + Subclasses and instances of TypedDict return actual dictionaries. """ - ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new - tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) + for base in bases: + if type(base) is not _TypedDictMeta: + raise TypeError('cannot inherit from both a TypedDict type ' + 'and a non-TypedDict base class') + tp_dict = type.__new__(_TypedDictMeta, name, (dict,), ns) annotations = {} own_annotations = ns.get('__annotations__', {}) @@ -1859,10 +1835,16 @@ class _TypedDictMeta(type): tp_dict.__total__ = total return tp_dict - __instancecheck__ = __subclasscheck__ = _check_fails + __call__ = dict # static method + + def __subclasscheck__(cls, other): + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + __instancecheck__ = __subclasscheck__ -class TypedDict(dict, metaclass=_TypedDictMeta): + +def TypedDict(typename, fields=None, /, *, total=True, **kwargs): """A simple typed namespace. At runtime it is equivalent to a plain dict. TypedDict creates a dictionary type that expects all of its @@ -1904,6 +1886,23 @@ class TypedDict(dict, metaclass=_TypedDictMeta): The class syntax is only supported in Python 3.6+, while two other syntax forms work for Python 2.7 and 3.2+ """ + if fields is None: + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(fields), '__total__': total} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(typename, (), ns) + +_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) +TypedDict.__mro_entries__ = lambda bases: (_TypedDict,) def NewType(name, tp): |