Skip to content

Commit d64d33c

Browse files
authored
Merge pull request #5009 from DimitrisJim/pylibs_upgrade_dos
Update more libraries from 3.11
2 parents a6a9212 + b875057 commit d64d33c

17 files changed

+622
-229
lines changed

Lib/heapq.py

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
item = heappop(heap) # pops the smallest item from the heap
1313
item = heap[0] # smallest item on the heap without popping it
1414
heapify(x) # transforms list into a heap, in-place, in linear time
15+
item = heappushpop(heap, item) # pushes a new item and then returns
16+
# the smallest item; the heap size is unchanged
1517
item = heapreplace(heap, item) # pops and returns smallest item, and adds
1618
# new item; the heap size is unchanged
1719

Lib/imghdr.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""Recognize image file formats based on their first few bytes."""
22

33
from os import PathLike
4+
import warnings
45

56
__all__ = ["what"]
67

7-
# should replace using FileIO into file
8-
from io import FileIO
8+
9+
warnings._deprecated(__name__, remove=(3, 13))
10+
11+
912
#-------------------------#
1013
# Recognize image headers #
1114
#-------------------------#
@@ -15,7 +18,7 @@ def what(file, h=None):
1518
try:
1619
if h is None:
1720
if isinstance(file, (str, PathLike)):
18-
f = FileIO(file, 'rb')
21+
f = open(file, 'rb')
1922
h = f.read(32)
2023
else:
2124
location = file.tell()
@@ -37,9 +40,11 @@ def what(file, h=None):
3740
tests = []
3841

3942
def test_jpeg(h, f):
40-
"""JPEG data in JFIF or Exif format"""
43+
"""JPEG data with JFIF or Exif markers; and raw JPEG"""
4144
if h[6:10] in (b'JFIF', b'Exif'):
4245
return 'jpeg'
46+
elif h[:4] == b'\xff\xd8\xff\xdb':
47+
return 'jpeg'
4348

4449
tests.append(test_jpeg)
4550

@@ -154,7 +159,7 @@ def testall(list, recursive, toplevel):
154159
if recursive or toplevel:
155160
print('recursing down:')
156161
import glob
157-
names = glob.glob(os.path.join(filename, '*'))
162+
names = glob.glob(os.path.join(glob.escape(filename), '*'))
158163
testall(names, recursive, 0)
159164
else:
160165
print('*** directory (use -r) ***')

Lib/ipaddress.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def v4_int_to_packed(address):
132132
133133
"""
134134
try:
135-
return address.to_bytes(4, 'big')
135+
return address.to_bytes(4) # big endian
136136
except OverflowError:
137137
raise ValueError("Address negative or too large for IPv4")
138138

@@ -148,7 +148,7 @@ def v6_int_to_packed(address):
148148
149149
"""
150150
try:
151-
return address.to_bytes(16, 'big')
151+
return address.to_bytes(16) # big endian
152152
except OverflowError:
153153
raise ValueError("Address negative or too large for IPv6")
154154

@@ -1077,15 +1077,16 @@ def is_link_local(self):
10771077

10781078
@property
10791079
def is_private(self):
1080-
"""Test if this address is allocated for private networks.
1080+
"""Test if this network belongs to a private range.
10811081
10821082
Returns:
1083-
A boolean, True if the address is reserved per
1083+
A boolean, True if the network is reserved per
10841084
iana-ipv4-special-registry or iana-ipv6-special-registry.
10851085
10861086
"""
1087-
return (self.network_address.is_private and
1088-
self.broadcast_address.is_private)
1087+
return any(self.network_address in priv_network and
1088+
self.broadcast_address in priv_network
1089+
for priv_network in self._constants._private_networks)
10891090

10901091
@property
10911092
def is_global(self):
@@ -1122,6 +1123,15 @@ def is_loopback(self):
11221123
return (self.network_address.is_loopback and
11231124
self.broadcast_address.is_loopback)
11241125

1126+
1127+
class _BaseConstants:
1128+
1129+
_private_networks = []
1130+
1131+
1132+
_BaseNetwork._constants = _BaseConstants
1133+
1134+
11251135
class _BaseV4:
11261136

11271137
"""Base IPv4 object.
@@ -1294,7 +1304,7 @@ def __init__(self, address):
12941304
# Constructing from a packed address
12951305
if isinstance(address, bytes):
12961306
self._check_packed_address(address, 4)
1297-
self._ip = int.from_bytes(address, 'big')
1307+
self._ip = int.from_bytes(address) # big endian
12981308
return
12991309

13001310
# Assume input argument to be string or any object representation
@@ -1561,6 +1571,7 @@ class _IPv4Constants:
15611571

15621572

15631573
IPv4Address._constants = _IPv4Constants
1574+
IPv4Network._constants = _IPv4Constants
15641575

15651576

15661577
class _BaseV6:
@@ -2285,3 +2296,4 @@ class _IPv6Constants:
22852296

22862297

22872298
IPv6Address._constants = _IPv6Constants
2299+
IPv6Network._constants = _IPv6Constants

Lib/linecache.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77

88
import functools
99
import sys
10-
try:
11-
import os
12-
except ImportError:
13-
import _dummy_os as os
10+
import os
1411
import tokenize
1512

1613
__all__ = ["getline", "clearcache", "checkcache", "lazycache"]

Lib/netrc.py

+90-41
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,50 @@ def __str__(self):
1919
return "%s (%s, line %s)" % (self.msg, self.filename, self.lineno)
2020

2121

22+
class _netrclex:
23+
def __init__(self, fp):
24+
self.lineno = 1
25+
self.instream = fp
26+
self.whitespace = "\n\t\r "
27+
self.pushback = []
28+
29+
def _read_char(self):
30+
ch = self.instream.read(1)
31+
if ch == "\n":
32+
self.lineno += 1
33+
return ch
34+
35+
def get_token(self):
36+
if self.pushback:
37+
return self.pushback.pop(0)
38+
token = ""
39+
fiter = iter(self._read_char, "")
40+
for ch in fiter:
41+
if ch in self.whitespace:
42+
continue
43+
if ch == '"':
44+
for ch in fiter:
45+
if ch == '"':
46+
return token
47+
elif ch == "\\":
48+
ch = self._read_char()
49+
token += ch
50+
else:
51+
if ch == "\\":
52+
ch = self._read_char()
53+
token += ch
54+
for ch in fiter:
55+
if ch in self.whitespace:
56+
return token
57+
elif ch == "\\":
58+
ch = self._read_char()
59+
token += ch
60+
return token
61+
62+
def push_token(self, token):
63+
self.pushback.append(token)
64+
65+
2266
class netrc:
2367
def __init__(self, file=None):
2468
default_netrc = file is None
@@ -34,9 +78,7 @@ def __init__(self, file=None):
3478
self._parse(file, fp, default_netrc)
3579

3680
def _parse(self, file, fp, default_netrc):
37-
lexer = shlex.shlex(fp)
38-
lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
39-
lexer.commenters = lexer.commenters.replace('#', '')
81+
lexer = _netrclex(fp)
4082
while 1:
4183
# Look for a machine, default, or macdef top-level keyword
4284
saved_lineno = lexer.lineno
@@ -51,68 +93,75 @@ def _parse(self, file, fp, default_netrc):
5193
entryname = lexer.get_token()
5294
elif tt == 'default':
5395
entryname = 'default'
54-
elif tt == 'macdef': # Just skip to end of macdefs
96+
elif tt == 'macdef':
5597
entryname = lexer.get_token()
5698
self.macros[entryname] = []
57-
lexer.whitespace = ' \t'
5899
while 1:
59100
line = lexer.instream.readline()
60-
if not line or line == '\012':
61-
lexer.whitespace = ' \t\r\n'
101+
if not line:
102+
raise NetrcParseError(
103+
"Macro definition missing null line terminator.",
104+
file, lexer.lineno)
105+
if line == '\n':
106+
# a macro definition finished with consecutive new-line
107+
# characters. The first \n is encountered by the
108+
# readline() method and this is the second \n.
62109
break
63110
self.macros[entryname].append(line)
64111
continue
65112
else:
66113
raise NetrcParseError(
67114
"bad toplevel token %r" % tt, file, lexer.lineno)
68115

116+
if not entryname:
117+
raise NetrcParseError("missing %r name" % tt, file, lexer.lineno)
118+
69119
# We're looking at start of an entry for a named machine or default.
70-
login = ''
71-
account = password = None
120+
login = account = password = ''
72121
self.hosts[entryname] = {}
73122
while 1:
123+
prev_lineno = lexer.lineno
74124
tt = lexer.get_token()
75-
if (tt.startswith('#') or
76-
tt in {'', 'machine', 'default', 'macdef'}):
77-
if password:
78-
self.hosts[entryname] = (login, account, password)
79-
lexer.push_token(tt)
80-
break
81-
else:
82-
raise NetrcParseError(
83-
"malformed %s entry %s terminated by %s"
84-
% (toplevel, entryname, repr(tt)),
85-
file, lexer.lineno)
125+
if tt.startswith('#'):
126+
if lexer.lineno == prev_lineno:
127+
lexer.instream.readline()
128+
continue
129+
if tt in {'', 'machine', 'default', 'macdef'}:
130+
self.hosts[entryname] = (login, account, password)
131+
lexer.push_token(tt)
132+
break
86133
elif tt == 'login' or tt == 'user':
87134
login = lexer.get_token()
88135
elif tt == 'account':
89136
account = lexer.get_token()
90137
elif tt == 'password':
91-
if os.name == 'posix' and default_netrc:
92-
prop = os.fstat(fp.fileno())
93-
if prop.st_uid != os.getuid():
94-
import pwd
95-
try:
96-
fowner = pwd.getpwuid(prop.st_uid)[0]
97-
except KeyError:
98-
fowner = 'uid %s' % prop.st_uid
99-
try:
100-
user = pwd.getpwuid(os.getuid())[0]
101-
except KeyError:
102-
user = 'uid %s' % os.getuid()
103-
raise NetrcParseError(
104-
("~/.netrc file owner (%s) does not match"
105-
" current user (%s)") % (fowner, user),
106-
file, lexer.lineno)
107-
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
108-
raise NetrcParseError(
109-
"~/.netrc access too permissive: access"
110-
" permissions must restrict access to only"
111-
" the owner", file, lexer.lineno)
112138
password = lexer.get_token()
113139
else:
114140
raise NetrcParseError("bad follower token %r" % tt,
115141
file, lexer.lineno)
142+
self._security_check(fp, default_netrc, self.hosts[entryname][0])
143+
144+
def _security_check(self, fp, default_netrc, login):
145+
if os.name == 'posix' and default_netrc and login != "anonymous":
146+
prop = os.fstat(fp.fileno())
147+
if prop.st_uid != os.getuid():
148+
import pwd
149+
try:
150+
fowner = pwd.getpwuid(prop.st_uid)[0]
151+
except KeyError:
152+
fowner = 'uid %s' % prop.st_uid
153+
try:
154+
user = pwd.getpwuid(os.getuid())[0]
155+
except KeyError:
156+
user = 'uid %s' % os.getuid()
157+
raise NetrcParseError(
158+
(f"~/.netrc file owner ({fowner}, {user}) does not match"
159+
" current user"))
160+
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
161+
raise NetrcParseError(
162+
"~/.netrc access too permissive: access"
163+
" permissions must restrict access to only"
164+
" the owner")
116165

117166
def authenticators(self, host):
118167
"""Return a (user, account, password) tuple for given host."""

Lib/nntplib.py

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import collections
6969
import datetime
7070
import sys
71+
import warnings
7172

7273
try:
7374
import ssl
@@ -85,6 +86,8 @@
8586
"decode_header",
8687
]
8788

89+
warnings._deprecated(__name__, remove=(3, 13))
90+
8891
# maximal line length when calling readline(). This is to prevent
8992
# reading arbitrary length lines. RFC 3977 limits NNTP line length to
9093
# 512 characters, including CRLF. We have selected 2048 just to be on

0 commit comments

Comments
 (0)