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

gh-133817: remove keyword argument syntax for NamedTuple objects by picnixz · Pull Request #133822 · 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  (2) 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
12 changes: 8 additions & 4 deletions Doc/whatsnew/3.15.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 @@ -118,10 +118,14 @@ Deprecated
Removed
=======

module_name
-----------

* TODO
typing
------

* The undocumented keyword argument syntax for creating
:class:`~typing.NamedTuple` classes (for example,
``Point = NamedTuple("Point", x=int, y=int)``).
Use the class-based syntax or the functional syntax instead.
(Contributed by Bénédikt Tran in :gh:`133817`.)


Porting to Python 3.15
Expand Down
95 changes: 22 additions & 73 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 @@ -8080,78 +8080,13 @@ class Group(NamedTuple):
self.assertIs(type(a), Group)
self.assertEqual(a, (1, [2]))

def test_namedtuple_keyword_usage(self):
with self.assertWarnsRegex(
DeprecationWarning,
"Creating NamedTuple classes using keyword arguments is deprecated"
):
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)

nick = LocalEmployee('Nick', 25)
self.assertIsInstance(nick, tuple)
self.assertEqual(nick.name, 'Nick')
self.assertEqual(LocalEmployee.__name__, 'LocalEmployee')
self.assertEqual(LocalEmployee._fields, ('name', 'age'))
self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int))

with self.assertRaisesRegex(
TypeError,
"Either list of fields or keywords can be provided to NamedTuple, not both"
):
NamedTuple('Name', [('x', int)], y=str)

with self.assertRaisesRegex(
TypeError,
"Either list of fields or keywords can be provided to NamedTuple, not both"
):
NamedTuple('Name', [], y=str)

with self.assertRaisesRegex(
TypeError,
(
r"Cannot pass `None` as the 'fields' parameter "
r"and also specify fields using keyword arguments"
)
):
NamedTuple('Name', None, x=int)

def test_namedtuple_special_keyword_names(self):
with self.assertWarnsRegex(
DeprecationWarning,
"Creating NamedTuple classes using keyword arguments is deprecated"
):
NT = NamedTuple("NT", cls=type, self=object, typename=str, fields=list)

self.assertEqual(NT.__name__, 'NT')
self.assertEqual(NT._fields, ('cls', 'self', 'typename', 'fields'))
a = NT(cls=str, self=42, typename='foo', fields=[('bar', tuple)])
self.assertEqual(a.cls, str)
self.assertEqual(a.self, 42)
self.assertEqual(a.typename, 'foo')
self.assertEqual(a.fields, [('bar', tuple)])

def test_empty_namedtuple(self):
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 NamedTuple class with 0 fields "
"using the functional syntax, "
"pass an empty list, e.g. `NT1 = NamedTuple('NT1', [])`."
)
with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"):
NT1 = NamedTuple('NT1')

expected_warning = re.escape(
"Passing `None` as the 'fields' parameter is deprecated "
"and will be disallowed in Python 3.15. "
"To create a NamedTuple class with 0 fields "
"using the functional syntax, "
"pass an empty list, e.g. `NT2 = NamedTuple('NT2', [])`."
)
with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"):
NT2 = NamedTuple('NT2', None)
with self.assertRaisesRegex(TypeError, "missing.*required.*argument"):
BAD = NamedTuple('BAD')

NT3 = NamedTuple('NT2', [])
NT1 = NamedTuple('NT1', {})
NT2 = NamedTuple('NT2', ())
NT3 = NamedTuple('NT3', [])

class CNT(NamedTuple):
pass # empty body
Expand All @@ -8166,16 +8101,18 @@ class CNT(NamedTuple):
def test_namedtuple_errors(self):
with self.assertRaises(TypeError):
NamedTuple.__new__()
with self.assertRaisesRegex(TypeError, "object is not iterable"):
NamedTuple('Name', None)

with self.assertRaisesRegex(
TypeError,
"missing 1 required positional argument"
"missing 2 required positional arguments"
):
NamedTuple()

with self.assertRaisesRegex(
TypeError,
"takes from 1 to 2 positional arguments but 3 were given"
"takes 2 positional arguments but 3 were given"
):
NamedTuple('Emp', [('name', str)], None)

Expand All @@ -8187,10 +8124,22 @@ def test_namedtuple_errors(self):

with self.assertRaisesRegex(
TypeError,
"missing 1 required positional argument: 'typename'"
"got some positional-only arguments passed as keyword arguments"
):
NamedTuple(typename='Emp', name=str, id=int)

with self.assertRaisesRegex(
TypeError,
"got an unexpected keyword argument"
):
NamedTuple('Name', [('x', int)], y=str)

with self.assertRaisesRegex(
TypeError,
"got an unexpected keyword argument"
):
NamedTuple('Name', [], y=str)

def test_copy_and_pickle(self):
global Emp # pickle wants to reference the class by name
Emp = NamedTuple('Emp', [('name', str), ('cool', int)])
Expand Down
41 changes: 1 addition & 40 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 @@ -2968,7 +2968,7 @@ def annotate(format):
return nm_tpl


def NamedTuple(typename, fields=_sentinel, /, **kwargs):
def NamedTuple(typename, fields, /):
"""Typed version of namedtuple.

Usage::
Expand All @@ -2988,48 +2988,9 @@ class Employee(NamedTuple):

Employee = NamedTuple('Employee', [('name', str), ('id', int)])
"""
if fields is _sentinel:
if kwargs:
deprecated_thing = "Creating NamedTuple classes using keyword arguments"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"Use the class-based or functional syntax instead."
)
else:
deprecated_thing = "Failing to pass a value for the 'fields' parameter"
example = f"`{typename} = NamedTuple({typename!r}, [])`"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"To create a NamedTuple class with 0 fields "
"using the functional syntax, "
"pass an empty list, e.g. "
) + example + "."
elif fields is None:
if kwargs:
raise TypeError(
"Cannot pass `None` as the 'fields' parameter "
"and also specify fields using keyword arguments"
)
else:
deprecated_thing = "Passing `None` as the 'fields' parameter"
example = f"`{typename} = NamedTuple({typename!r}, [])`"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"To create a NamedTuple class with 0 fields "
"using the functional syntax, "
"pass an empty list, e.g. "
) + example + "."
elif kwargs:
raise TypeError("Either list of fields or keywords"
" can be provided to NamedTuple, not both")
if fields is _sentinel or fields is None:
import warnings
warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15))
fields = kwargs.items()
types = {n: _type_check(t, f"field {n} annotation must be a type")
for n, t in fields}
field_names = [n for n, _ in fields]

nt = _make_nmtuple(typename, field_names, _make_eager_annotate(types), module=_caller())
nt.__orig_bases__ = (NamedTuple,)
return nt
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,2 @@
Remove support for creating :class:`~typing.NamedTuple` classes via the
undocumented keyword argument syntax. Patch by Bénédikt Tran.

Back | FazBrowse Home | New Git URL