FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-105570: Deprecate unusual ways of creating empty TypedDicts by AlexWaygood · Pull Request #105780 · python/cpython · GitHub

/ cpython Public
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (2) .rst  (3) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
8 changes: 8 additions & 0 deletions Doc/library/typing.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,14 @@ These are not used in annotations. They are building blocks for declaring types.
.. versionchanged:: 3.13
Removed support for the keyword-argument method of creating ``TypedDict``\ s.

.. deprecated-removed:: 3.13 3.15
When using the functional syntax to create a TypedDict class, failing to
pass a value to the 'fields' parameter (``TD = TypedDict("TD")``) is
deprecated. Passing ``None`` to the 'fields' parameter
(``TD = TypedDict("TD", None)``) is also deprecated. Both will be
disallowed in Python 3.15. To create a TypedDict class with 0 fields,
use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``.

Protocols
---------

Expand Down
15 changes: 9 additions & 6 deletions Doc/whatsnew/3.13.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,15 @@ Deprecated
be disallowed in Python 3.15. Use the class-based syntax or the functional
syntax instead. (Contributed by Alex Waygood in :gh:`105566`.)
* When using the functional syntax to create a :class:`typing.NamedTuple`
class, failing to pass a value to the 'fields' parameter
(``NT = NamedTuple("NT")``) is deprecated. Passing ``None`` to the 'fields'
parameter (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be
disallowed in Python 3.15. To create a NamedTuple class with 0 fields, use
``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``.
(Contributed by Alex Waygood in :gh:`105566`.)
class or a :class:`typing.TypedDict` class, failing to pass a value to the
'fields' parameter (``NT = NamedTuple("NT")`` or ``TD = TypedDict("TD")``) is
deprecated. Passing ``None`` to the 'fields' parameter
(``NT = NamedTuple("NT", None)`` or ``TD = TypedDict("TD", None)``) is also
deprecated. Both will be disallowed in Python 3.15. To create a NamedTuple
class with 0 fields, use ``class NT(NamedTuple): pass`` or
``NT = NamedTuple("NT", [])``. To create a TypedDict class with 0 fields, use
``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``.
(Contributed by Alex Waygood in :gh:`105566` and :gh:`105570`.)

* :mod:`array`'s ``'u'`` format code, deprecated in docs since Python 3.3,
emits :exc:`DeprecationWarning` since 3.13
Expand Down
34 changes: 34 additions & 0 deletions Lib/test/test_typing.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -7823,6 +7823,40 @@ class MultipleGenericBases(GenericParent[int], GenericParent[float]):
self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float]))
self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,))

def test_zero_fields_typeddicts(self):
T1 = TypedDict("T1", {})
class T2(TypedDict): pass
class T3[tvar](TypedDict): pass
S = TypeVar("S")
class T4(TypedDict, Generic[S]): pass

expected_warning = re.escape(
"Failing to pass a value for the 'fields' parameter is deprecated "
"and will be disallowed in Python 3.15. "
"To create a TypedDict class with 0 fields "
"using the functional syntax, "
"pass an empty dictionary, e.g. `T5 = TypedDict('T5', {})`."
)
with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"):
T5 = TypedDict('T5')

expected_warning = re.escape(
"Passing `None` as the 'fields' parameter is deprecated "
"and will be disallowed in Python 3.15. "
"To create a TypedDict class with 0 fields "
"using the functional syntax, "
"pass an empty dictionary, e.g. `T6 = TypedDict('T6', {})`."
)
with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"):
T6 = TypedDict('T6', None)

for klass in T1, T2, T3, T4, T5, T6:
with self.subTest(klass=klass.__name__):
self.assertEqual(klass.__annotations__, {})
self.assertEqual(klass.__required_keys__, set())
self.assertEqual(klass.__optional_keys__, set())
self.assertIsInstance(klass(), dict)


class RequiredTests(BaseTestCase):

Expand Down
19 changes: 17 additions & 2 deletions Lib/typing.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2908,7 +2908,7 @@ def __subclasscheck__(cls, other):
__instancecheck__ = __subclasscheck__


def TypedDict(typename, fields=None, /, *, total=True):
def TypedDict(typename, fields=_sentinel, /, *, total=True):
"""A simple typed namespace. At runtime it is equivalent to a plain dict.

TypedDict creates a dictionary type such that a type checker will expect all
Expand Down Expand Up @@ -2955,7 +2955,22 @@ class Point2D(TypedDict):

See PEP 655 for more details on Required and NotRequired.
"""
if fields is None:
if fields is _sentinel or fields is None:
import warnings

if fields is _sentinel:
deprecated_thing = "Failing to pass a value for the 'fields' parameter"
else:
deprecated_thing = "Passing `None` as the 'fields' parameter"

example = f"`{typename} = TypedDict({typename!r}, {{{{}}}})`"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"To create a TypedDict class with 0 fields "
"using the functional syntax, "
"pass an empty dictionary, e.g. "
) + example + "."
warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15))
fields = {}

ns = {'__annotations__': dict(fields)}
Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Deprecate two methods of creating :class:`typing.TypedDict` classes with 0
fields using the functional syntax: ``TD = TypedDict("TD")`` and
``TD = TypedDict("TD", None)``. Both will be disallowed in Python 3.15. To create a
``TypedDict`` class with 0 fields, either use ``class TD(TypedDict): pass``
or ``TD = TypedDict("TD", {})``.

Back | FazBrowse Home | New Git URL