Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add deprecation flag and warning
  • Loading branch information
97littleleaf11 committed Feb 7, 2022
commit f3588ac8ba55ec7d629eac36b7f504d2ba9d3c3b
9 changes: 7 additions & 2 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1388,10 +1388,15 @@ These are not used in annotations. They are building blocks for declaring types.
``Point2D.__total__``, ``Point2D.__required_keys__``, and
``Point2D.__optional_keys__``.
To allow using this feature with older versions of Python that do not
support :pep:`526`, ``TypedDict`` supports an additional equivalent
syntactic form::
support :pep:`526`, ``TypedDict`` supports two additional equivalent
syntactic forms::

Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
Point2D = TypedDict('Point2D', x=int, y=int, label=str)

.. deprecated-removed:: 3.11 3.13
Comment thread
97littleleaf11 marked this conversation as resolved.
The keyword arguments syntax is deprecated in 3.11 and will be removed
in 3.13. Currently it might not be supported by typecheckers like ``mypy``.

By default, all keys must be present in a ``TypedDict``. It is possible to
override this by specifying totality.
Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4299,6 +4299,34 @@ def test_basics_functional_syntax(self):
self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
self.assertEqual(Emp.__total__, True)

def test_basics_keywords_syntax(self):
with self.assertWarns(DeprecationWarning):
Emp = TypedDict('Emp', name=str, id=int)
self.assertIsSubclass(Emp, dict)
self.assertIsSubclass(Emp, typing.MutableMapping)
self.assertNotIsSubclass(Emp, collections.abc.Sequence)
jim = Emp(name='Jim', id=1)
self.assertIs(type(jim), dict)
self.assertEqual(jim['name'], 'Jim')
self.assertEqual(jim['id'], 1)
self.assertEqual(Emp.__name__, 'Emp')
self.assertEqual(Emp.__module__, __name__)
self.assertEqual(Emp.__bases__, (dict,))
self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
self.assertEqual(Emp.__total__, True)
Comment thread
97littleleaf11 marked this conversation as resolved.
Outdated

def test_typeddict_special_keyword_names(self):
TD = TypedDict("TD", {'cls': type, 'self': object, 'typename': str, '_typename': int, 'fields': list, '_fields': dict})
Comment thread
97littleleaf11 marked this conversation as resolved.
Outdated
self.assertEqual(TD.__name__, 'TD')
self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str, '_typename': int, 'fields': list, '_fields': dict})
a = TD(cls=str, self=42, typename='foo', _typename=53, fields=[('bar', tuple)], _fields={'baz', set})
self.assertEqual(a['cls'], str)
self.assertEqual(a['self'], 42)
self.assertEqual(a['typename'], 'foo')
self.assertEqual(a['_typename'], 53)
self.assertEqual(a['fields'], [('bar', tuple)])
self.assertEqual(a['_fields'], {'baz', set})

def test_typeddict_create_errors(self):
with self.assertRaises(TypeError):
TypedDict.__new__()
Expand Down
14 changes: 13 additions & 1 deletion Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2378,7 +2378,7 @@ def __subclasscheck__(cls, other):
__instancecheck__ = __subclasscheck__


def TypedDict(typename, fields=None, /, *, total=True):
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
Expand Down Expand Up @@ -2419,6 +2419,18 @@ class body be required.
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")
if kwargs:
Comment thread
97littleleaf11 marked this conversation as resolved.
warnings.warn(
"The kwargs-based syntax for TypedDict definition is deprecated "
" in Python 3.11 and will be removed in Python 3.13.",
Comment thread
97littleleaf11 marked this conversation as resolved.
Outdated
DeprecationWarning,
stacklevel=2,
)

ns = {'__annotations__': dict(fields)}
module = _caller()
Expand Down