Skip to content

Commit 98624e4

Browse files
committed
WIP: Deprecate tuple API in namedtuple
1 parent 89d3b20 commit 98624e4

21 files changed

Lines changed: 78 additions & 55 deletions

Lib/collections/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def __ror__(self, other):
358358
except ImportError:
359359
_tuplegetter = lambda index, doc: property(_itemgetter(index), doc=doc)
360360

361-
def namedtuple(typename, field_names, *, rename=False, defaults=None, module=None):
361+
def namedtuple(typename, field_names, *, rename=False, defaults=None, module=None, deprecate_tuple_api=True):
362362
"""Returns a new subclass of tuple with named fields.
363363
364364
>>> Point = namedtuple('Point', ['x', 'y'])
@@ -512,6 +512,15 @@ def __getnewargs__(self):
512512
doc = _sys.intern(f'Alias for field number {index}')
513513
class_namespace[name] = _tuplegetter(index, doc)
514514

515+
if deprecate_tuple_api:
516+
def __getitem__(self, key):
517+
import warnings
518+
warnings.warn('tuple API is deprecated, use named attributes',
519+
DeprecationWarning, stacklevel=2)
520+
return tuple.__getitem__(self, key)
521+
522+
class_namespace['__getitem__'] = __getitem__
523+
515524
result = type(typename, (tuple,), class_namespace)
516525

517526
# For pickling to work, the __module__ variable needs to be set to the frame

Lib/difflib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ def ratio(self):
617617
1.0
618618
"""
619619

620-
matches = sum(triple[-1] for triple in self.get_matching_blocks())
620+
matches = sum(triple.size for triple in self.get_matching_blocks())
621621
return _calculate_ratio(matches, len(self.a) + len(self.b))
622622

623623
def quick_ratio(self):

Lib/getpass.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ def getuser():
428428

429429
try:
430430
import pwd
431-
return pwd.getpwuid(os.getuid())[0]
431+
return pwd.getpwuid(os.getuid()).pw_name
432432
except (ImportError, KeyError) as e:
433433
raise OSError('No username set in the environment') from e
434434

Lib/http/cookiejar.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ def request_host(request):
626626
627627
"""
628628
url = request.get_full_url()
629-
host = urllib.parse.urlparse(url)[1]
629+
host = urllib.parse.urlparse(url).netloc
630630
if host == "":
631631
host = request.get_header("Host", "")
632632

Lib/http/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,8 @@ def send_head(self):
796796
if not parts.path.endswith(('/', '%2f', '%2F')):
797797
# redirect browser - doing basically what apache does
798798
self.send_response(HTTPStatus.MOVED_PERMANENTLY)
799-
new_parts = (parts[0], parts[1], parts[2] + '/',
800-
parts[3], parts[4])
799+
new_parts = (parts.scheme, parts.netloc, parts.path + '/',
800+
parts.query, parts.fragment)
801801
new_url = urllib.parse.urlunsplit(new_parts)
802802
self.send_header("Location", new_url)
803803
self.send_header("Content-Length", "0")

Lib/shutil.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,7 @@ def _get_gid(name):
983983
except KeyError:
984984
result = None
985985
if result is not None:
986-
return result[2]
986+
return result.gr_gid
987987
return None
988988

989989
def _get_uid(name):
@@ -1001,7 +1001,7 @@ def _get_uid(name):
10011001
except KeyError:
10021002
result = None
10031003
if result is not None:
1004-
return result[2]
1004+
return result.pw_uid
10051005
return None
10061006

10071007
def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,

Lib/tarfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,14 +2282,14 @@ def gettarinfo(self, name=None, arcname=None, fileobj=None):
22822282
if pwd:
22832283
if tarinfo.uid not in self._unames:
22842284
try:
2285-
self._unames[tarinfo.uid] = pwd.getpwuid(tarinfo.uid)[0]
2285+
self._unames[tarinfo.uid] = pwd.getpwuid(tarinfo.uid).pw_name
22862286
except KeyError:
22872287
self._unames[tarinfo.uid] = ''
22882288
tarinfo.uname = self._unames[tarinfo.uid]
22892289
if grp:
22902290
if tarinfo.gid not in self._gnames:
22912291
try:
2292-
self._gnames[tarinfo.gid] = grp.getgrgid(tarinfo.gid)[0]
2292+
self._gnames[tarinfo.gid] = grp.getgrgid(tarinfo.gid).gr_name
22932293
except KeyError:
22942294
self._gnames[tarinfo.gid] = ''
22952295
tarinfo.gname = self._gnames[tarinfo.gid]

Lib/test/ssl_servers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def translate_path(self, path):
6161
6262
"""
6363
# abandon query parameters
64-
path = urllib.parse.urlparse(path)[2]
64+
path = urllib.parse.urlparse(path).path
6565
path = os.path.normpath(urllib.parse.unquote(path))
6666
words = path.split('/')
6767
words = filter(None, words)

Lib/test/support/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ def open_urlresource(url, *args, **kw):
868868

869869
check = kw.pop('check', None)
870870

871-
filename = urllib.parse.urlparse(url)[2].split('/')[-1] # '/': it's URL!
871+
filename = urllib.parse.urlparse(url).path.split('/')[-1] # '/': it's URL!
872872

873873
fn = os.path.join(TEST_DATA_DIR, filename)
874874

Lib/test/test_dataclasses/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import sys
1717
import textwrap
1818
import unittest
19+
import warnings
1920
from unittest.mock import Mock
2021
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict
2122
from typing import get_type_hints
@@ -1779,7 +1780,9 @@ class C:
17791780

17801781
# Make sure that the returned dicts are actually OrderedDicts.
17811782
self.assertIs(type(d), OrderedDict)
1782-
self.assertIs(type(d['y'][1]), OrderedDict)
1783+
with warnings.catch_warnings(category=DeprecationWarning):
1784+
warnings.simplefilter("ignore", category=DeprecationWarning)
1785+
self.assertIs(type(d['y'][1]), OrderedDict)
17831786

17841787
def test_helper_asdict_namedtuple_key(self):
17851788
# Ensure that a field that contains a dict which has a

0 commit comments

Comments
 (0)