Skip to content

Commit fb6744d

Browse files
committed
merge
Merge branch 'main' of github.com:python/cpython
2 parents b10f912 + 55b78ce commit fb6744d

21 files changed

+126
-98
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ jobs:
177177
strategy:
178178
fail-fast: false
179179
matrix:
180-
openssl_ver: [1.1.1k, 3.0.0-alpha15]
180+
openssl_ver: [1.1.1k, 3.0.0-alpha16]
181181
env:
182182
OPENSSL_VER: ${{ matrix.openssl_ver }}
183183
MULTISSL_DIR: ${{ github.workspace }}/multissl

Lib/doctest.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,17 @@ def _from_module(self, module, object):
973973
else:
974974
raise ValueError("object must be a class or function")
975975

976+
def _is_routine(self, obj):
977+
"""
978+
Safely unwrap objects and determine if they are functions.
979+
"""
980+
maybe_routine = obj
981+
try:
982+
maybe_routine = inspect.unwrap(maybe_routine)
983+
except ValueError:
984+
pass
985+
return inspect.isroutine(maybe_routine)
986+
976987
def _find(self, tests, obj, name, module, source_lines, globs, seen):
977988
"""
978989
Find tests for the given object and any contained objects, and
@@ -995,9 +1006,9 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
9951006
if inspect.ismodule(obj) and self._recurse:
9961007
for valname, val in obj.__dict__.items():
9971008
valname = '%s.%s' % (name, valname)
1009+
9981010
# Recurse to functions & classes.
999-
if ((inspect.isroutine(inspect.unwrap(val))
1000-
or inspect.isclass(val)) and
1011+
if ((self._is_routine(val) or inspect.isclass(val)) and
10011012
self._from_module(module, val)):
10021013
self._find(tests, val, valname, module, source_lines,
10031014
globs, seen)

Lib/http/client.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,11 @@ def getallmatchingheaders(self, name):
202202
lst.append(line)
203203
return lst
204204

205-
def parse_headers(fp, _class=HTTPMessage):
206-
"""Parses only RFC2822 headers from a file pointer.
207-
208-
email Parser wants to see strings rather than bytes.
209-
But a TextIOWrapper around self.rfile would buffer too many bytes
210-
from the stream, bytes which we later need to read as bytes.
211-
So we read the correct bytes here, as bytes, for email Parser
212-
to parse.
205+
def _read_headers(fp):
206+
"""Reads potential header lines into a list from a file pointer.
213207
208+
Length of line is limited by _MAXLINE, and number of
209+
headers is limited by _MAXHEADERS.
214210
"""
215211
headers = []
216212
while True:
@@ -222,6 +218,19 @@ def parse_headers(fp, _class=HTTPMessage):
222218
raise HTTPException("got more than %d headers" % _MAXHEADERS)
223219
if line in (b'\r\n', b'\n', b''):
224220
break
221+
return headers
222+
223+
def parse_headers(fp, _class=HTTPMessage):
224+
"""Parses only RFC2822 headers from a file pointer.
225+
226+
email Parser wants to see strings rather than bytes.
227+
But a TextIOWrapper around self.rfile would buffer too many bytes
228+
from the stream, bytes which we later need to read as bytes.
229+
So we read the correct bytes here, as bytes, for email Parser
230+
to parse.
231+
232+
"""
233+
headers = _read_headers(fp)
225234
hstring = b''.join(headers).decode('iso-8859-1')
226235
return email.parser.Parser(_class=_class).parsestr(hstring)
227236

@@ -309,15 +318,10 @@ def begin(self):
309318
if status != CONTINUE:
310319
break
311320
# skip the header from the 100 response
312-
while True:
313-
skip = self.fp.readline(_MAXLINE + 1)
314-
if len(skip) > _MAXLINE:
315-
raise LineTooLong("header line")
316-
skip = skip.strip()
317-
if not skip:
318-
break
319-
if self.debuglevel > 0:
320-
print("header:", skip)
321+
skipped_headers = _read_headers(self.fp)
322+
if self.debuglevel > 0:
323+
print("headers:", skipped_headers)
324+
del skipped_headers
321325

322326
self.code = self.status = status
323327
self.reason = reason.strip()

Lib/pathlib.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ def is_dir(self):
12951295
if not _ignore_error(e):
12961296
raise
12971297
# Path doesn't exist or is a broken symlink
1298-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1298+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
12991299
return False
13001300
except ValueError:
13011301
# Non-encodable path
@@ -1312,7 +1312,7 @@ def is_file(self):
13121312
if not _ignore_error(e):
13131313
raise
13141314
# Path doesn't exist or is a broken symlink
1315-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1315+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
13161316
return False
13171317
except ValueError:
13181318
# Non-encodable path
@@ -1363,7 +1363,7 @@ def is_block_device(self):
13631363
if not _ignore_error(e):
13641364
raise
13651365
# Path doesn't exist or is a broken symlink
1366-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1366+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
13671367
return False
13681368
except ValueError:
13691369
# Non-encodable path
@@ -1379,7 +1379,7 @@ def is_char_device(self):
13791379
if not _ignore_error(e):
13801380
raise
13811381
# Path doesn't exist or is a broken symlink
1382-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1382+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
13831383
return False
13841384
except ValueError:
13851385
# Non-encodable path
@@ -1395,7 +1395,7 @@ def is_fifo(self):
13951395
if not _ignore_error(e):
13961396
raise
13971397
# Path doesn't exist or is a broken symlink
1398-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1398+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
13991399
return False
14001400
except ValueError:
14011401
# Non-encodable path
@@ -1411,7 +1411,7 @@ def is_socket(self):
14111411
if not _ignore_error(e):
14121412
raise
14131413
# Path doesn't exist or is a broken symlink
1414-
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1414+
# (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
14151415
return False
14161416
except ValueError:
14171417
# Non-encodable path

Lib/statistics.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -952,11 +952,16 @@ def linear_regression(regressor, dependent_variable, /):
952952
raise StatisticsError('linear regression requires that both inputs have same number of data points')
953953
if n < 2:
954954
raise StatisticsError('linear regression requires at least two data points')
955+
x, y = regressor, dependent_variable
956+
xbar = fsum(x) / n
957+
ybar = fsum(y) / n
958+
sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y))
959+
s2x = fsum((xi - xbar) ** 2.0 for xi in x)
955960
try:
956-
slope = covariance(regressor, dependent_variable) / variance(regressor)
961+
slope = sxy / s2x
957962
except ZeroDivisionError:
958963
raise StatisticsError('regressor is constant')
959-
intercept = fmean(dependent_variable) - slope * fmean(regressor)
964+
intercept = ybar - slope * xbar
960965
return LinearRegression(intercept=intercept, slope=slope)
961966

962967

Lib/test/test_contextlib_async.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,16 +369,14 @@ class TestAsyncExitStack(TestBaseExitStack, unittest.TestCase):
369369
class SyncAsyncExitStack(AsyncExitStack):
370370
@staticmethod
371371
def run_coroutine(coro):
372-
loop = asyncio.get_event_loop()
373-
374-
f = asyncio.ensure_future(coro)
375-
f.add_done_callback(lambda f: loop.stop())
372+
loop = asyncio.get_event_loop_policy().get_event_loop()
373+
t = loop.create_task(coro)
374+
t.add_done_callback(lambda f: loop.stop())
376375
loop.run_forever()
377376

378-
exc = f.exception()
379-
377+
exc = t.exception()
380378
if not exc:
381-
return f.result()
379+
return t.result()
382380
else:
383381
context = exc.__context__
384382

Lib/test/test_doctest.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import unittest
1616
import tempfile
1717
import shutil
18+
import types
1819
import contextlib
1920

2021
# NOTE: There are some additional tests relating to interaction with
@@ -443,7 +444,7 @@ def basics(): r"""
443444
>>> tests = finder.find(sample_func)
444445
445446
>>> print(tests) # doctest: +ELLIPSIS
446-
[<DocTest sample_func from ...:27 (1 example)>]
447+
[<DocTest sample_func from test_doctest.py:28 (1 example)>]
447448
448449
The exact name depends on how test_doctest was invoked, so allow for
449450
leading path components.
@@ -698,6 +699,18 @@ def non_Python_modules(): r"""
698699

699700
class TestDocTestFinder(unittest.TestCase):
700701

702+
def test_issue35753(self):
703+
# This import of `call` should trigger issue35753 when
704+
# `support.run_doctest` is called due to unwrap failing,
705+
# however with a patched doctest this should succeed.
706+
from unittest.mock import call
707+
dummy_module = types.ModuleType("dummy")
708+
dummy_module.__dict__['inject_call'] = call
709+
try:
710+
support.run_doctest(dummy_module, verbosity=True)
711+
except ValueError as e:
712+
raise support.TestFailed("Doctest unwrap failed") from e
713+
701714
def test_empty_namespace_package(self):
702715
pkg_name = 'doctest_empty_pkg'
703716
with tempfile.TemporaryDirectory() as parent_dir:

Lib/test/test_httplib.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,14 @@ def test_overflowing_header_line(self):
11801180
resp = client.HTTPResponse(FakeSocket(body))
11811181
self.assertRaises(client.LineTooLong, resp.begin)
11821182

1183+
def test_overflowing_header_limit_after_100(self):
1184+
body = (
1185+
'HTTP/1.1 100 OK\r\n'
1186+
'r\n' * 32768
1187+
)
1188+
resp = client.HTTPResponse(FakeSocket(body))
1189+
self.assertRaises(client.HTTPException, resp.begin)
1190+
11831191
def test_overflowing_chunked_line(self):
11841192
body = (
11851193
'HTTP/1.1 200 OK\r\n'
@@ -1581,7 +1589,7 @@ def readline(self, limit):
15811589
class OfflineTest(TestCase):
15821590
def test_all(self):
15831591
# Documented objects defined in the module should be in __all__
1584-
expected = {"responses"} # White-list documented dict() object
1592+
expected = {"responses"} # Allowlist documented dict() object
15851593
# HTTPMessage, parse_headers(), and the HTTP status code constants are
15861594
# intentionally omitted for simplicity
15871595
denylist = {"HTTPMessage", "parse_headers"}

Lib/test/test_urlparse.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -614,32 +614,40 @@ def test_urlsplit_attributes(self):
614614

615615
def test_urlsplit_remove_unsafe_bytes(self):
616616
# Remove ASCII tabs and newlines from input
617-
url = "http://www.python.org/java\nscript:\talert('msg\r\n')/#frag"
617+
url = "http\t://www.python\n.org\t/java\nscript:\talert('msg\r\n')/?query\n=\tsomething#frag\nment"
618618
p = urllib.parse.urlsplit(url)
619619
self.assertEqual(p.scheme, "http")
620620
self.assertEqual(p.netloc, "www.python.org")
621621
self.assertEqual(p.path, "/javascript:alert('msg')/")
622-
self.assertEqual(p.query, "")
623-
self.assertEqual(p.fragment, "frag")
622+
self.assertEqual(p.query, "query=something")
623+
self.assertEqual(p.fragment, "fragment")
624624
self.assertEqual(p.username, None)
625625
self.assertEqual(p.password, None)
626626
self.assertEqual(p.hostname, "www.python.org")
627627
self.assertEqual(p.port, None)
628-
self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/#frag")
628+
self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment")
629629

630630
# Remove ASCII tabs and newlines from input as bytes.
631-
url = b"http://www.python.org/java\nscript:\talert('msg\r\n')/#frag"
631+
url = b"http\t://www.python\n.org\t/java\nscript:\talert('msg\r\n')/?query\n=\tsomething#frag\nment"
632632
p = urllib.parse.urlsplit(url)
633633
self.assertEqual(p.scheme, b"http")
634634
self.assertEqual(p.netloc, b"www.python.org")
635635
self.assertEqual(p.path, b"/javascript:alert('msg')/")
636-
self.assertEqual(p.query, b"")
637-
self.assertEqual(p.fragment, b"frag")
636+
self.assertEqual(p.query, b"query=something")
637+
self.assertEqual(p.fragment, b"fragment")
638638
self.assertEqual(p.username, None)
639639
self.assertEqual(p.password, None)
640640
self.assertEqual(p.hostname, b"www.python.org")
641641
self.assertEqual(p.port, None)
642-
self.assertEqual(p.geturl(), b"http://www.python.org/javascript:alert('msg')/#frag")
642+
self.assertEqual(p.geturl(), b"http://www.python.org/javascript:alert('msg')/?query=something#fragment")
643+
644+
# with scheme as cache-key
645+
url = "http://www.python.org/java\nscript:\talert('msg\r\n')/?query\n=\tsomething#frag\nment"
646+
scheme = "ht\ntp"
647+
for _ in range(2):
648+
p = urllib.parse.urlsplit(url, scheme=scheme)
649+
self.assertEqual(p.scheme, "http")
650+
self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment")
643651

644652
def test_attributes_bad_port(self):
645653
"""Check handling of invalid ports."""

Lib/typing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
'NamedTuple', # Not really a type.
100100
'TypedDict', # Not really a type.
101101
'Generator',
102-
102+
103103
# Other concrete types.
104104
'BinaryIO',
105105
'IO',

0 commit comments

Comments
 (0)