Skip to content

Commit 339b2e6

Browse files
authored
Merge branch 'main' into pythongh-114271-remove-tstate_lock
2 parents 9a8ea9b + 86bc40d commit 339b2e6

12 files changed

+255
-48
lines changed

Lib/logging/handlers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ def computeRollover(self, currentTime):
340340
daysToWait = self.dayOfWeek - day
341341
else:
342342
daysToWait = 6 - day + self.dayOfWeek + 1
343-
result += daysToWait * (60 * 60 * 24)
343+
result += daysToWait * _MIDNIGHT
344+
result += self.interval - _MIDNIGHT * 7
345+
else:
346+
result += self.interval - _MIDNIGHT
344347
if not self.utc:
345348
dstNow = t[-1]
346349
dstAtRollover = time.localtime(result)[-1]

Lib/test/libregrtest/tsan.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
'test_syslog',
1515
'test_thread',
1616
'test_threadedtempfile',
17+
'test_threading',
1718
'test_threading_local',
1819
'test_threadsignals',
1920
]

Lib/test/support/script_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ class _PythonRunResult(collections.namedtuple("_PythonRunResult",
6363
"""Helper for reporting Python subprocess run results"""
6464
def fail(self, cmd_line):
6565
"""Provide helpful details about failed subcommand runs"""
66-
# Limit to 80 lines to ASCII characters
67-
maxlen = 80 * 100
66+
# Limit to 300 lines of ASCII characters
67+
maxlen = 300 * 100
6868
out, err = self.out, self.err
6969
if len(out) > maxlen:
7070
out = b'(... truncated stdout ...)' + out[-maxlen:]

Lib/test/test_logging.py

Lines changed: 166 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6577,6 +6577,129 @@ def test(current, expected):
65776577

65786578
fh.close()
65796579

6580+
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
6581+
# March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0).
6582+
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
6583+
def test_compute_rollover_MIDNIGHT_local_interval(self):
6584+
# DST begins at 2012-3-11T02:00:00 and ends at 2012-11-4T02:00:00.
6585+
DT = datetime.datetime
6586+
def test(current, expected):
6587+
actual = fh.computeRollover(current.timestamp())
6588+
diff = actual - expected.timestamp()
6589+
if diff:
6590+
self.assertEqual(diff, 0, datetime.timedelta(seconds=diff))
6591+
6592+
fh = logging.handlers.TimedRotatingFileHandler(
6593+
self.fn, encoding="utf-8", when='MIDNIGHT', utc=False, interval=3)
6594+
6595+
test(DT(2012, 3, 8, 23, 59, 59), DT(2012, 3, 11, 0, 0))
6596+
test(DT(2012, 3, 9, 0, 0), DT(2012, 3, 12, 0, 0))
6597+
test(DT(2012, 3, 9, 1, 0), DT(2012, 3, 12, 0, 0))
6598+
test(DT(2012, 3, 10, 23, 59, 59), DT(2012, 3, 13, 0, 0))
6599+
test(DT(2012, 3, 11, 0, 0), DT(2012, 3, 14, 0, 0))
6600+
test(DT(2012, 3, 11, 1, 0), DT(2012, 3, 14, 0, 0))
6601+
6602+
test(DT(2012, 11, 1, 23, 59, 59), DT(2012, 11, 4, 0, 0))
6603+
test(DT(2012, 11, 2, 0, 0), DT(2012, 11, 5, 0, 0))
6604+
test(DT(2012, 11, 2, 1, 0), DT(2012, 11, 5, 0, 0))
6605+
test(DT(2012, 11, 3, 23, 59, 59), DT(2012, 11, 6, 0, 0))
6606+
test(DT(2012, 11, 4, 0, 0), DT(2012, 11, 7, 0, 0))
6607+
test(DT(2012, 11, 4, 1, 0), DT(2012, 11, 7, 0, 0))
6608+
6609+
fh.close()
6610+
6611+
fh = logging.handlers.TimedRotatingFileHandler(
6612+
self.fn, encoding="utf-8", when='MIDNIGHT', utc=False, interval=3,
6613+
atTime=datetime.time(12, 0, 0))
6614+
6615+
test(DT(2012, 3, 8, 11, 59, 59), DT(2012, 3, 10, 12, 0))
6616+
test(DT(2012, 3, 8, 12, 0), DT(2012, 3, 11, 12, 0))
6617+
test(DT(2012, 3, 8, 13, 0), DT(2012, 3, 11, 12, 0))
6618+
test(DT(2012, 3, 10, 11, 59, 59), DT(2012, 3, 12, 12, 0))
6619+
test(DT(2012, 3, 10, 12, 0), DT(2012, 3, 13, 12, 0))
6620+
test(DT(2012, 3, 10, 13, 0), DT(2012, 3, 13, 12, 0))
6621+
6622+
test(DT(2012, 11, 1, 11, 59, 59), DT(2012, 11, 3, 12, 0))
6623+
test(DT(2012, 11, 1, 12, 0), DT(2012, 11, 4, 12, 0))
6624+
test(DT(2012, 11, 1, 13, 0), DT(2012, 11, 4, 12, 0))
6625+
test(DT(2012, 11, 3, 11, 59, 59), DT(2012, 11, 5, 12, 0))
6626+
test(DT(2012, 11, 3, 12, 0), DT(2012, 11, 6, 12, 0))
6627+
test(DT(2012, 11, 3, 13, 0), DT(2012, 11, 6, 12, 0))
6628+
6629+
fh.close()
6630+
6631+
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
6632+
# March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0).
6633+
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
6634+
def test_compute_rollover_W6_local_interval(self):
6635+
# DST begins at 2012-3-11T02:00:00 and ends at 2012-11-4T02:00:00.
6636+
DT = datetime.datetime
6637+
def test(current, expected):
6638+
actual = fh.computeRollover(current.timestamp())
6639+
diff = actual - expected.timestamp()
6640+
if diff:
6641+
self.assertEqual(diff, 0, datetime.timedelta(seconds=diff))
6642+
6643+
fh = logging.handlers.TimedRotatingFileHandler(
6644+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3)
6645+
6646+
test(DT(2012, 2, 19, 23, 59, 59), DT(2012, 3, 5, 0, 0))
6647+
test(DT(2012, 2, 20, 0, 0), DT(2012, 3, 12, 0, 0))
6648+
test(DT(2012, 2, 20, 1, 0), DT(2012, 3, 12, 0, 0))
6649+
test(DT(2012, 3, 4, 23, 59, 59), DT(2012, 3, 19, 0, 0))
6650+
test(DT(2012, 3, 5, 0, 0), DT(2012, 3, 26, 0, 0))
6651+
test(DT(2012, 3, 5, 1, 0), DT(2012, 3, 26, 0, 0))
6652+
6653+
test(DT(2012, 10, 14, 23, 59, 59), DT(2012, 10, 29, 0, 0))
6654+
test(DT(2012, 10, 15, 0, 0), DT(2012, 11, 5, 0, 0))
6655+
test(DT(2012, 10, 15, 1, 0), DT(2012, 11, 5, 0, 0))
6656+
test(DT(2012, 10, 28, 23, 59, 59), DT(2012, 11, 12, 0, 0))
6657+
test(DT(2012, 10, 29, 0, 0), DT(2012, 11, 19, 0, 0))
6658+
test(DT(2012, 10, 29, 1, 0), DT(2012, 11, 19, 0, 0))
6659+
6660+
fh.close()
6661+
6662+
fh = logging.handlers.TimedRotatingFileHandler(
6663+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3,
6664+
atTime=datetime.time(0, 0, 0))
6665+
6666+
test(DT(2012, 2, 25, 23, 59, 59), DT(2012, 3, 11, 0, 0))
6667+
test(DT(2012, 2, 26, 0, 0), DT(2012, 3, 18, 0, 0))
6668+
test(DT(2012, 2, 26, 1, 0), DT(2012, 3, 18, 0, 0))
6669+
test(DT(2012, 3, 10, 23, 59, 59), DT(2012, 3, 25, 0, 0))
6670+
test(DT(2012, 3, 11, 0, 0), DT(2012, 4, 1, 0, 0))
6671+
test(DT(2012, 3, 11, 1, 0), DT(2012, 4, 1, 0, 0))
6672+
6673+
test(DT(2012, 10, 20, 23, 59, 59), DT(2012, 11, 4, 0, 0))
6674+
test(DT(2012, 10, 21, 0, 0), DT(2012, 11, 11, 0, 0))
6675+
test(DT(2012, 10, 21, 1, 0), DT(2012, 11, 11, 0, 0))
6676+
test(DT(2012, 11, 3, 23, 59, 59), DT(2012, 11, 18, 0, 0))
6677+
test(DT(2012, 11, 4, 0, 0), DT(2012, 11, 25, 0, 0))
6678+
test(DT(2012, 11, 4, 1, 0), DT(2012, 11, 25, 0, 0))
6679+
6680+
fh.close()
6681+
6682+
fh = logging.handlers.TimedRotatingFileHandler(
6683+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3,
6684+
atTime=datetime.time(12, 0, 0))
6685+
6686+
test(DT(2012, 2, 18, 11, 59, 59), DT(2012, 3, 4, 12, 0))
6687+
test(DT(2012, 2, 19, 12, 0), DT(2012, 3, 11, 12, 0))
6688+
test(DT(2012, 2, 19, 13, 0), DT(2012, 3, 11, 12, 0))
6689+
test(DT(2012, 3, 4, 11, 59, 59), DT(2012, 3, 18, 12, 0))
6690+
test(DT(2012, 3, 4, 12, 0), DT(2012, 3, 25, 12, 0))
6691+
test(DT(2012, 3, 4, 13, 0), DT(2012, 3, 25, 12, 0))
6692+
6693+
test(DT(2012, 10, 14, 11, 59, 59), DT(2012, 10, 28, 12, 0))
6694+
test(DT(2012, 10, 14, 12, 0), DT(2012, 11, 4, 12, 0))
6695+
test(DT(2012, 10, 14, 13, 0), DT(2012, 11, 4, 12, 0))
6696+
test(DT(2012, 10, 28, 11, 59, 59), DT(2012, 11, 11, 12, 0))
6697+
test(DT(2012, 10, 28, 12, 0), DT(2012, 11, 18, 12, 0))
6698+
test(DT(2012, 10, 28, 13, 0), DT(2012, 11, 18, 12, 0))
6699+
6700+
fh.close()
6701+
6702+
65806703
def secs(**kw):
65816704
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
65826705

@@ -6588,40 +6711,49 @@ def secs(**kw):
65886711
# current time (epoch start) is a Thursday, W0 means Monday
65896712
('W0', secs(days=4, hours=24)),
65906713
):
6591-
def test_compute_rollover(self, when=when, exp=exp):
6592-
rh = logging.handlers.TimedRotatingFileHandler(
6593-
self.fn, encoding="utf-8", when=when, interval=1, backupCount=0, utc=True)
6594-
currentTime = 0.0
6595-
actual = rh.computeRollover(currentTime)
6596-
if exp != actual:
6597-
# Failures occur on some systems for MIDNIGHT and W0.
6598-
# Print detailed calculation for MIDNIGHT so we can try to see
6599-
# what's going on
6600-
if when == 'MIDNIGHT':
6601-
try:
6602-
if rh.utc:
6603-
t = time.gmtime(currentTime)
6604-
else:
6605-
t = time.localtime(currentTime)
6606-
currentHour = t[3]
6607-
currentMinute = t[4]
6608-
currentSecond = t[5]
6609-
# r is the number of seconds left between now and midnight
6610-
r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
6611-
currentMinute) * 60 +
6612-
currentSecond)
6613-
result = currentTime + r
6614-
print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
6615-
print('currentHour: %s' % currentHour, file=sys.stderr)
6616-
print('currentMinute: %s' % currentMinute, file=sys.stderr)
6617-
print('currentSecond: %s' % currentSecond, file=sys.stderr)
6618-
print('r: %s' % r, file=sys.stderr)
6619-
print('result: %s' % result, file=sys.stderr)
6620-
except Exception as e:
6621-
print('exception in diagnostic code: %s' % e, file=sys.stderr)
6622-
self.assertEqual(exp, actual)
6623-
rh.close()
6624-
setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
6714+
for interval in 1, 3:
6715+
def test_compute_rollover(self, when=when, interval=interval, exp=exp):
6716+
rh = logging.handlers.TimedRotatingFileHandler(
6717+
self.fn, encoding="utf-8", when=when, interval=interval, backupCount=0, utc=True)
6718+
currentTime = 0.0
6719+
actual = rh.computeRollover(currentTime)
6720+
if when.startswith('W'):
6721+
exp += secs(days=7*(interval-1))
6722+
else:
6723+
exp *= interval
6724+
if exp != actual:
6725+
# Failures occur on some systems for MIDNIGHT and W0.
6726+
# Print detailed calculation for MIDNIGHT so we can try to see
6727+
# what's going on
6728+
if when == 'MIDNIGHT':
6729+
try:
6730+
if rh.utc:
6731+
t = time.gmtime(currentTime)
6732+
else:
6733+
t = time.localtime(currentTime)
6734+
currentHour = t[3]
6735+
currentMinute = t[4]
6736+
currentSecond = t[5]
6737+
# r is the number of seconds left between now and midnight
6738+
r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
6739+
currentMinute) * 60 +
6740+
currentSecond)
6741+
result = currentTime + r
6742+
print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
6743+
print('currentHour: %s' % currentHour, file=sys.stderr)
6744+
print('currentMinute: %s' % currentMinute, file=sys.stderr)
6745+
print('currentSecond: %s' % currentSecond, file=sys.stderr)
6746+
print('r: %s' % r, file=sys.stderr)
6747+
print('result: %s' % result, file=sys.stderr)
6748+
except Exception as e:
6749+
print('exception in diagnostic code: %s' % e, file=sys.stderr)
6750+
self.assertEqual(exp, actual)
6751+
rh.close()
6752+
name = "test_compute_rollover_%s" % when
6753+
if interval > 1:
6754+
name += "_interval"
6755+
test_compute_rollover.__name__ = name
6756+
setattr(TimedRotatingFileHandlerTest, name, test_compute_rollover)
66256757

66266758

66276759
@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')

Lib/test/test_threading.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,11 @@ def skip_unless_reliable_fork(test):
4747
return unittest.skip("due to known OS bug related to thread+fork")(test)
4848
if support.HAVE_ASAN_FORK_BUG:
4949
return unittest.skip("libasan has a pthread_create() dead lock related to thread+fork")(test)
50+
if support.check_sanitizer(thread=True):
51+
return unittest.skip("TSAN doesn't support threads after fork")
5052
return test
5153

5254

53-
skip_if_tsan_fork = unittest.skipIf(
54-
support.check_sanitizer(thread=True),
55-
"TSAN doesn't support threads after fork")
56-
57-
5855
def requires_subinterpreters(meth):
5956
"""Decorator to skip a test if subinterpreters are not supported."""
6057
return unittest.skipIf(interpreters is None,
@@ -428,6 +425,10 @@ def test_finalize_running_thread(self):
428425
# Issue 1402: the PyGILState_Ensure / _Release functions may be called
429426
# very late on python exit: on deallocation of a running thread for
430427
# example.
428+
if support.check_sanitizer(thread=True):
429+
# the thread running `time.sleep(100)` below will still be alive
430+
# at process exit
431+
self.skipTest("TSAN would report thread leak")
431432
import_module("ctypes")
432433

433434
rc, out, err = assert_python_failure("-c", """if 1:
@@ -460,6 +461,11 @@ def waitingThread():
460461
def test_finalize_with_trace(self):
461462
# Issue1733757
462463
# Avoid a deadlock when sys.settrace steps into threading._shutdown
464+
if support.check_sanitizer(thread=True):
465+
# the thread running `time.sleep(2)` below will still be alive
466+
# at process exit
467+
self.skipTest("TSAN would report thread leak")
468+
463469
assert_python_ok("-c", """if 1:
464470
import sys, threading
465471
@@ -639,7 +645,6 @@ def test_daemon_param(self):
639645
self.assertTrue(t.daemon)
640646

641647
@skip_unless_reliable_fork
642-
@skip_if_tsan_fork
643648
def test_dummy_thread_after_fork(self):
644649
# Issue #14308: a dummy thread in the active list doesn't mess up
645650
# the after-fork mechanism.
@@ -709,7 +714,6 @@ def f():
709714

710715
@skip_unless_reliable_fork
711716
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
712-
@skip_if_tsan_fork
713717
def test_main_thread_after_fork(self):
714718
code = """if 1:
715719
import os, threading
@@ -1219,7 +1223,6 @@ def test_2_join_in_forked_process(self):
12191223
self._run_and_join(script)
12201224

12211225
@skip_unless_reliable_fork
1222-
@skip_if_tsan_fork
12231226
def test_3_join_in_forked_from_thread(self):
12241227
# Like the test above, but fork() was called from a worker thread
12251228
# In the forked process, the main Thread object must be marked as stopped.
@@ -1252,6 +1255,11 @@ def test_4_daemon_threads(self):
12521255
# Check that a daemon thread cannot crash the interpreter on shutdown
12531256
# by manipulating internal structures that are being disposed of in
12541257
# the main thread.
1258+
if support.check_sanitizer(thread=True):
1259+
# some of the threads running `random_io` below will still be alive
1260+
# at process exit
1261+
self.skipTest("TSAN would report thread leak")
1262+
12551263
script = """if True:
12561264
import os
12571265
import random

Lib/test/test_ttk/test_widgets.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,29 @@ def test_unique_variables(self):
285285
b.pack()
286286
buttons.append(b)
287287
variables = [str(b['variable']) for b in buttons]
288-
print(variables)
289288
self.assertEqual(len(set(variables)), 4, variables)
290289

290+
def test_unique_variables2(self):
291+
buttons = []
292+
f = ttk.Frame(self.root)
293+
f.pack()
294+
f = ttk.Frame(self.root)
295+
f.pack()
296+
for j in 'AB':
297+
b = tkinter.Checkbutton(f, text=j)
298+
b.pack()
299+
buttons.append(b)
300+
# Should be larger than the number of all previously created
301+
# tkinter.Checkbutton widgets:
302+
for j in range(100):
303+
b = ttk.Checkbutton(f, text=str(j))
304+
b.pack()
305+
buttons.append(b)
306+
names = [str(b) for b in buttons]
307+
self.assertEqual(len(set(names)), len(buttons), names)
308+
variables = [str(b['variable']) for b in buttons]
309+
self.assertEqual(len(set(variables)), len(buttons), variables)
310+
291311

292312
@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)
293313
class EntryTest(AbstractWidgetTest, unittest.TestCase):

Lib/test/test_urlparse.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,30 @@ def test_parse_qsl_separator(self):
10721072
result_bytes = urllib.parse.parse_qsl(orig, separator=b';')
10731073
self.assertEqual(result_bytes, expect, "Error parsing %r" % orig)
10741074

1075+
def test_parse_qsl_bytes(self):
1076+
self.assertEqual(urllib.parse.parse_qsl(b'a=b'), [(b'a', b'b')])
1077+
self.assertEqual(urllib.parse.parse_qsl(bytearray(b'a=b')), [(b'a', b'b')])
1078+
self.assertEqual(urllib.parse.parse_qsl(memoryview(b'a=b')), [(b'a', b'b')])
1079+
1080+
def test_parse_qsl_false_value(self):
1081+
kwargs = dict(keep_blank_values=True, strict_parsing=True)
1082+
for x in '', b'', None, 0, 0.0, [], {}, memoryview(b''):
1083+
self.assertEqual(urllib.parse.parse_qsl(x, **kwargs), [])
1084+
self.assertRaises(ValueError, urllib.parse.parse_qsl, x, separator=1)
1085+
1086+
def test_parse_qsl_errors(self):
1087+
self.assertRaises(TypeError, urllib.parse.parse_qsl, list(b'a=b'))
1088+
self.assertRaises(TypeError, urllib.parse.parse_qsl, iter(b'a=b'))
1089+
self.assertRaises(TypeError, urllib.parse.parse_qsl, 1)
1090+
self.assertRaises(TypeError, urllib.parse.parse_qsl, object())
1091+
1092+
for separator in '', b'', None, 0, 1, 0.0, 1.5:
1093+
with self.assertRaises(ValueError):
1094+
urllib.parse.parse_qsl('a=b', separator=separator)
1095+
with self.assertRaises(UnicodeEncodeError):
1096+
urllib.parse.parse_qsl(b'a=b', separator='\xa6')
1097+
with self.assertRaises(UnicodeDecodeError):
1098+
urllib.parse.parse_qsl('a=b', separator=b'\xa6')
10751099

10761100
def test_urlencode_sequences(self):
10771101
# Other tests incidentally urlencode things; test non-covered cases:

0 commit comments

Comments
 (0)