Skip to content

Commit 46b97b4

Browse files
authored
Merge branch 'main' into optimize-call-type-1
2 parents 705fbc8 + 39859fc commit 46b97b4

File tree

9 files changed

+312
-345
lines changed

9 files changed

+312
-345
lines changed

Doc/c-api/arg.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ Building values
685685
686686
``p`` (:class:`bool`) [int]
687687
Convert a C :c:expr:`int` to a Python :class:`bool` object.
688+
688689
.. versionadded:: 3.14
689690
690691
``c`` (:class:`bytes` of length 1) [char]

Lib/os.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def _add(str, fn):
118118
_add("HAVE_FCHMODAT", "chmod")
119119
_add("HAVE_FCHOWNAT", "chown")
120120
_add("HAVE_FSTATAT", "stat")
121+
_add("HAVE_LSTAT", "lstat")
121122
_add("HAVE_FUTIMESAT", "utime")
122123
_add("HAVE_LINKAT", "link")
123124
_add("HAVE_MKDIRAT", "mkdir")

Lib/test/support/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,31 @@ def check_sizeof(test, o, size):
945945
% (type(o), result, size)
946946
test.assertEqual(result, size, msg)
947947

948+
def subTests(arg_names, arg_values, /, *, _do_cleanups=False):
949+
"""Run multiple subtests with different parameters.
950+
"""
951+
single_param = False
952+
if isinstance(arg_names, str):
953+
arg_names = arg_names.replace(',',' ').split()
954+
if len(arg_names) == 1:
955+
single_param = True
956+
arg_values = tuple(arg_values)
957+
def decorator(func):
958+
if isinstance(func, type):
959+
raise TypeError('subTests() can only decorate methods, not classes')
960+
@functools.wraps(func)
961+
def wrapper(self, /, *args, **kwargs):
962+
for values in arg_values:
963+
if single_param:
964+
values = (values,)
965+
subtest_kwargs = dict(zip(arg_names, values))
966+
with self.subTest(**subtest_kwargs):
967+
func(self, *args, **kwargs, **subtest_kwargs)
968+
if _do_cleanups:
969+
self.doCleanups()
970+
return wrapper
971+
return decorator
972+
948973
#=======================================================================
949974
# Decorator/context manager for running a code in a different locale,
950975
# correctly resetting it afterwards.

Lib/test/test_http_cookiejar.py

Lines changed: 88 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import stat
55
import sys
66
import re
7+
from test import support
78
from test.support import os_helper
89
from test.support import warnings_helper
910
import time
@@ -105,8 +106,7 @@ def test_http2time_formats(self):
105106
self.assertEqual(http2time(s.lower()), test_t, s.lower())
106107
self.assertEqual(http2time(s.upper()), test_t, s.upper())
107108

108-
def test_http2time_garbage(self):
109-
for test in [
109+
@support.subTests('test', [
110110
'',
111111
'Garbage',
112112
'Mandag 16. September 1996',
@@ -121,10 +121,9 @@ def test_http2time_garbage(self):
121121
'08-01-3697739',
122122
'09 Feb 19942632 22:23:32 GMT',
123123
'Wed, 09 Feb 1994834 22:23:32 GMT',
124-
]:
125-
self.assertIsNone(http2time(test),
126-
"http2time(%s) is not None\n"
127-
"http2time(test) %s" % (test, http2time(test)))
124+
])
125+
def test_http2time_garbage(self, test):
126+
self.assertIsNone(http2time(test))
128127

129128
def test_http2time_redos_regression_actually_completes(self):
130129
# LOOSE_HTTP_DATE_RE was vulnerable to malicious input which caused catastrophic backtracking (REDoS).
@@ -149,9 +148,7 @@ def parse_date(text):
149148
self.assertEqual(parse_date("1994-02-03 19:45:29 +0530"),
150149
(1994, 2, 3, 14, 15, 29))
151150

152-
def test_iso2time_formats(self):
153-
# test iso2time for supported dates.
154-
tests = [
151+
@support.subTests('s', [
155152
'1994-02-03 00:00:00 -0000', # ISO 8601 format
156153
'1994-02-03 00:00:00 +0000', # ISO 8601 format
157154
'1994-02-03 00:00:00', # zone is optional
@@ -164,16 +161,15 @@ def test_iso2time_formats(self):
164161
# A few tests with extra space at various places
165162
' 1994-02-03 ',
166163
' 1994-02-03T00:00:00 ',
167-
]
168-
164+
])
165+
def test_iso2time_formats(self, s):
166+
# test iso2time for supported dates.
169167
test_t = 760233600 # assume broken POSIX counting of seconds
170-
for s in tests:
171-
self.assertEqual(iso2time(s), test_t, s)
172-
self.assertEqual(iso2time(s.lower()), test_t, s.lower())
173-
self.assertEqual(iso2time(s.upper()), test_t, s.upper())
168+
self.assertEqual(iso2time(s), test_t, s)
169+
self.assertEqual(iso2time(s.lower()), test_t, s.lower())
170+
self.assertEqual(iso2time(s.upper()), test_t, s.upper())
174171

175-
def test_iso2time_garbage(self):
176-
for test in [
172+
@support.subTests('test', [
177173
'',
178174
'Garbage',
179175
'Thursday, 03-Feb-94 00:00:00 GMT',
@@ -186,9 +182,9 @@ def test_iso2time_garbage(self):
186182
'01-01-1980 00:00:62',
187183
'01-01-1980T00:00:62',
188184
'19800101T250000Z',
189-
]:
190-
self.assertIsNone(iso2time(test),
191-
"iso2time(%r)" % test)
185+
])
186+
def test_iso2time_garbage(self, test):
187+
self.assertIsNone(iso2time(test))
192188

193189
def test_iso2time_performance_regression(self):
194190
# If ISO_DATE_RE regresses to quadratic complexity, this test will take a very long time to succeed.
@@ -199,24 +195,23 @@ def test_iso2time_performance_regression(self):
199195

200196
class HeaderTests(unittest.TestCase):
201197

202-
def test_parse_ns_headers(self):
203-
# quotes should be stripped
204-
expected = [[('foo', 'bar'), ('expires', 2209069412), ('version', '0')]]
205-
for hdr in [
198+
@support.subTests('hdr', [
206199
'foo=bar; expires=01 Jan 2040 22:23:32 GMT',
207200
'foo=bar; expires="01 Jan 2040 22:23:32 GMT"',
208-
]:
209-
self.assertEqual(parse_ns_headers([hdr]), expected)
210-
211-
def test_parse_ns_headers_version(self):
212-
201+
])
202+
def test_parse_ns_headers(self, hdr):
213203
# quotes should be stripped
214-
expected = [[('foo', 'bar'), ('version', '1')]]
215-
for hdr in [
204+
expected = [[('foo', 'bar'), ('expires', 2209069412), ('version', '0')]]
205+
self.assertEqual(parse_ns_headers([hdr]), expected)
206+
207+
@support.subTests('hdr', [
216208
'foo=bar; version="1"',
217209
'foo=bar; Version="1"',
218-
]:
219-
self.assertEqual(parse_ns_headers([hdr]), expected)
210+
])
211+
def test_parse_ns_headers_version(self, hdr):
212+
# quotes should be stripped
213+
expected = [[('foo', 'bar'), ('version', '1')]]
214+
self.assertEqual(parse_ns_headers([hdr]), expected)
220215

221216
def test_parse_ns_headers_special_names(self):
222217
# names such as 'expires' are not special in first name=value pair
@@ -226,8 +221,7 @@ def test_parse_ns_headers_special_names(self):
226221
expected = [[("expires", "01 Jan 2040 22:23:32 GMT"), ("version", "0")]]
227222
self.assertEqual(parse_ns_headers([hdr]), expected)
228223

229-
def test_join_header_words(self):
230-
for src, expected in [
224+
@support.subTests('src,expected', [
231225
([[("foo", None), ("bar", "baz")]], "foo; bar=baz"),
232226
(([]), ""),
233227
(([[]]), ""),
@@ -237,12 +231,11 @@ def test_join_header_words(self):
237231
'n; foo="foo;_", bar=foo_bar'),
238232
([[("n", "m"), ("foo", None)], [("bar", "foo_bar")]],
239233
'n=m; foo, bar=foo_bar'),
240-
]:
241-
with self.subTest(src=src):
242-
self.assertEqual(join_header_words(src), expected)
234+
])
235+
def test_join_header_words(self, src, expected):
236+
self.assertEqual(join_header_words(src), expected)
243237

244-
def test_split_header_words(self):
245-
tests = [
238+
@support.subTests('arg,expect', [
246239
("foo", [[("foo", None)]]),
247240
("foo=bar", [[("foo", "bar")]]),
248241
(" foo ", [[("foo", None)]]),
@@ -259,24 +252,22 @@ def test_split_header_words(self):
259252
(r'foo; bar=baz, spam=, foo="\,\;\"", bar= ',
260253
[[("foo", None), ("bar", "baz")],
261254
[("spam", "")], [("foo", ',;"')], [("bar", "")]]),
262-
]
263-
264-
for arg, expect in tests:
265-
try:
266-
result = split_header_words([arg])
267-
except:
268-
import traceback, io
269-
f = io.StringIO()
270-
traceback.print_exc(None, f)
271-
result = "(error -- traceback follows)\n\n%s" % f.getvalue()
272-
self.assertEqual(result, expect, """
255+
])
256+
def test_split_header_words(self, arg, expect):
257+
try:
258+
result = split_header_words([arg])
259+
except:
260+
import traceback, io
261+
f = io.StringIO()
262+
traceback.print_exc(None, f)
263+
result = "(error -- traceback follows)\n\n%s" % f.getvalue()
264+
self.assertEqual(result, expect, """
273265
When parsing: '%s'
274266
Expected: '%s'
275267
Got: '%s'
276268
""" % (arg, expect, result))
277269

278-
def test_roundtrip(self):
279-
tests = [
270+
@support.subTests('arg,expect', [
280271
("foo", "foo"),
281272
("foo=bar", "foo=bar"),
282273
(" foo ", "foo"),
@@ -309,12 +300,11 @@ def test_roundtrip(self):
309300
310301
('n; foo="foo;_", bar="foo,_"',
311302
'n; foo="foo;_", bar="foo,_"'),
312-
]
313-
314-
for arg, expect in tests:
315-
input = split_header_words([arg])
316-
res = join_header_words(input)
317-
self.assertEqual(res, expect, """
303+
])
304+
def test_roundtrip(self, arg, expect):
305+
input = split_header_words([arg])
306+
res = join_header_words(input)
307+
self.assertEqual(res, expect, """
318308
When parsing: '%s'
319309
Expected: '%s'
320310
Got: '%s'
@@ -516,14 +506,7 @@ class CookieTests(unittest.TestCase):
516506
## just the 7 special TLD's listed in their spec. And folks rely on
517507
## that...
518508

519-
def test_domain_return_ok(self):
520-
# test optimization: .domain_return_ok() should filter out most
521-
# domains in the CookieJar before we try to access them (because that
522-
# may require disk access -- in particular, with MSIECookieJar)
523-
# This is only a rough check for performance reasons, so it's not too
524-
# critical as long as it's sufficiently liberal.
525-
pol = DefaultCookiePolicy()
526-
for url, domain, ok in [
509+
@support.subTests('url,domain,ok', [
527510
("http://foo.bar.com/", "blah.com", False),
528511
("http://foo.bar.com/", "rhubarb.blah.com", False),
529512
("http://foo.bar.com/", "rhubarb.foo.bar.com", False),
@@ -543,11 +526,18 @@ def test_domain_return_ok(self):
543526
("http://foo/", ".local", True),
544527
("http://barfoo.com", ".foo.com", False),
545528
("http://barfoo.com", "foo.com", False),
546-
]:
547-
request = urllib.request.Request(url)
548-
r = pol.domain_return_ok(domain, request)
549-
if ok: self.assertTrue(r)
550-
else: self.assertFalse(r)
529+
])
530+
def test_domain_return_ok(self, url, domain, ok):
531+
# test optimization: .domain_return_ok() should filter out most
532+
# domains in the CookieJar before we try to access them (because that
533+
# may require disk access -- in particular, with MSIECookieJar)
534+
# This is only a rough check for performance reasons, so it's not too
535+
# critical as long as it's sufficiently liberal.
536+
pol = DefaultCookiePolicy()
537+
request = urllib.request.Request(url)
538+
r = pol.domain_return_ok(domain, request)
539+
if ok: self.assertTrue(r)
540+
else: self.assertFalse(r)
551541

552542
def test_missing_value(self):
553543
# missing = sign in Cookie: header is regarded by Mozilla as a missing
@@ -581,10 +571,7 @@ def test_missing_value(self):
581571
self.assertEqual(interact_netscape(c, "http://www.acme.com/foo/"),
582572
'"spam"; eggs')
583573

584-
def test_rfc2109_handling(self):
585-
# RFC 2109 cookies are handled as RFC 2965 or Netscape cookies,
586-
# dependent on policy settings
587-
for rfc2109_as_netscape, rfc2965, version in [
574+
@support.subTests('rfc2109_as_netscape,rfc2965,version', [
588575
# default according to rfc2965 if not explicitly specified
589576
(None, False, 0),
590577
(None, True, 1),
@@ -593,24 +580,27 @@ def test_rfc2109_handling(self):
593580
(False, True, 1),
594581
(True, False, 0),
595582
(True, True, 0),
596-
]:
597-
policy = DefaultCookiePolicy(
598-
rfc2109_as_netscape=rfc2109_as_netscape,
599-
rfc2965=rfc2965)
600-
c = CookieJar(policy)
601-
interact_netscape(c, "http://www.example.com/", "ni=ni; Version=1")
602-
try:
603-
cookie = c._cookies["www.example.com"]["/"]["ni"]
604-
except KeyError:
605-
self.assertIsNone(version) # didn't expect a stored cookie
606-
else:
607-
self.assertEqual(cookie.version, version)
608-
# 2965 cookies are unaffected
609-
interact_2965(c, "http://www.example.com/",
610-
"foo=bar; Version=1")
611-
if rfc2965:
612-
cookie2965 = c._cookies["www.example.com"]["/"]["foo"]
613-
self.assertEqual(cookie2965.version, 1)
583+
])
584+
def test_rfc2109_handling(self, rfc2109_as_netscape, rfc2965, version):
585+
# RFC 2109 cookies are handled as RFC 2965 or Netscape cookies,
586+
# dependent on policy settings
587+
policy = DefaultCookiePolicy(
588+
rfc2109_as_netscape=rfc2109_as_netscape,
589+
rfc2965=rfc2965)
590+
c = CookieJar(policy)
591+
interact_netscape(c, "http://www.example.com/", "ni=ni; Version=1")
592+
try:
593+
cookie = c._cookies["www.example.com"]["/"]["ni"]
594+
except KeyError:
595+
self.assertIsNone(version) # didn't expect a stored cookie
596+
else:
597+
self.assertEqual(cookie.version, version)
598+
# 2965 cookies are unaffected
599+
interact_2965(c, "http://www.example.com/",
600+
"foo=bar; Version=1")
601+
if rfc2965:
602+
cookie2965 = c._cookies["www.example.com"]["/"]["foo"]
603+
self.assertEqual(cookie2965.version, 1)
614604

615605
def test_ns_parser(self):
616606
c = CookieJar()
@@ -778,8 +768,7 @@ def test_default_path_with_query(self):
778768
# Cookie is sent back to the same URI.
779769
self.assertEqual(interact_netscape(cj, uri), value)
780770

781-
def test_escape_path(self):
782-
cases = [
771+
@support.subTests('arg,result', [
783772
# quoted safe
784773
("/foo%2f/bar", "/foo%2F/bar"),
785774
("/foo%2F/bar", "/foo%2F/bar"),
@@ -799,9 +788,9 @@ def test_escape_path(self):
799788
("/foo/bar\u00fc", "/foo/bar%C3%BC"), # UTF-8 encoded
800789
# unicode
801790
("/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded
802-
]
803-
for arg, result in cases:
804-
self.assertEqual(escape_path(arg), result)
791+
])
792+
def test_escape_path(self, arg, result):
793+
self.assertEqual(escape_path(arg), result)
805794

806795
def test_request_path(self):
807796
# with parameters

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy