Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6844,6 +6844,28 @@ def f(x): return x*x
self.assertEqual("332833500", out.decode('utf-8').strip())
self.assertFalse(err, msg=err.decode('utf-8'))

def test_forked_thread_not_started(self):
# gh-134381: Ensure that a thread that has not been started yet in
# the parent process can be started within a forked child process.

if multiprocessing.get_start_method() != "fork":
self.skipTest("fork specific test")

q = multiprocessing.Queue()
t = threading.Thread(target=lambda: q.put("done"), daemon=True)

def child():
t.start()
t.join()

p = multiprocessing.Process(target=child)
p.start()
p.join(support.SHORT_TIMEOUT)

self.assertEqual(p.exitcode, 0)
self.assertEqual(q.get_nowait(), "done")
close_queue(q)


#
# Mixins
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/interpreters/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def list_all():
if not hasattr(send, '_unboundop'):
send._set_unbound(unboundop)
else:
assert send._unbound[0] == unboundop
assert send._unbound[0] == op
channels.append(chan)
return channels

Expand Down
25 changes: 9 additions & 16 deletions Lib/test/test__interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,15 +474,13 @@ def setUp(self):

def test_signatures(self):
# See https://github.com/python/cpython/issues/126654
msg = r'_interpreters.exec\(\) argument 3 must be dict, not int'
msg = "expected 'shared' to be a dict"
with self.assertRaisesRegex(TypeError, msg):
_interpreters.exec(self.id, 'a', 1)
with self.assertRaisesRegex(TypeError, msg):
_interpreters.exec(self.id, 'a', shared=1)
msg = r'_interpreters.run_string\(\) argument 3 must be dict, not int'
with self.assertRaisesRegex(TypeError, msg):
_interpreters.run_string(self.id, 'a', shared=1)
msg = r'_interpreters.run_func\(\) argument 3 must be dict, not int'
with self.assertRaisesRegex(TypeError, msg):
_interpreters.run_func(self.id, lambda: None, shared=1)

Expand Down Expand Up @@ -954,8 +952,7 @@ def test_invalid_syntax(self):
""")

with self.subTest('script'):
with self.assertRaises(SyntaxError):
_interpreters.run_string(self.id, script)
self.assert_run_failed(SyntaxError, script)

with self.subTest('module'):
modname = 'spam_spam_spam'
Expand Down Expand Up @@ -1022,19 +1019,12 @@ def script():
with open(w, 'w', encoding="utf-8") as spipe:
with contextlib.redirect_stdout(spipe):
print('it worked!', end='')
failed = None
def f():
nonlocal failed
try:
_interpreters.set___main___attrs(self.id, dict(w=w))
_interpreters.run_func(self.id, script)
except Exception as exc:
failed = exc
_interpreters.set___main___attrs(self.id, dict(w=w))
_interpreters.run_func(self.id, script)
t = threading.Thread(target=f)
t.start()
t.join()
if failed:
raise Exception from failed

with open(r, encoding="utf-8") as outfile:
out = outfile.read()
Expand Down Expand Up @@ -1063,16 +1053,19 @@ def test_closure(self):
spam = True
def script():
assert spam
with self.assertRaises(ValueError):

with self.assertRaises(TypeError):
_interpreters.run_func(self.id, script)

# XXX This hasn't been fixed yet.
@unittest.expectedFailure
def test_return_value(self):
def script():
return 'spam'
with self.assertRaises(ValueError):
_interpreters.run_func(self.id, script)

# @unittest.skip("we're not quite there yet")
@unittest.skip("we're not quite there yet")
def test_args(self):
with self.subTest('args'):
def script(a, b=0):
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -3292,6 +3292,7 @@ def check_output(self, source, expect, *flags):
expect = self.text_normalize(expect)
self.assertEqual(res, expect)

@support.requires_resource('cpu')
def test_invocation(self):
# test various combinations of parameters
base_flags = (
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_capi/test_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def test_decref_freed_object(self):
"""
self.check_negative_refcount(code)

@support.requires_resource('cpu')
def test_decref_delayed(self):
# gh-130519: Test that _PyObject_XDecRefDelayed() and QSBR code path
# handles destructors that are possibly re-entrant or trigger a GC.
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ def test_odd_sizes(self):
self.assertEqual(Dot(1)._replace(d=999), (999,))
self.assertEqual(Dot(1)._fields, ('d',))

@support.requires_resource('cpu')
def test_large_size(self):
n = support.exceeds_recursion_limit()
names = list(set(''.join([choice(string.ascii_letters)
for j in range(10)]) for i in range(n)))
Expand Down
23 changes: 8 additions & 15 deletions Lib/test/test_interpreters/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,16 +839,9 @@ def test_bad_script(self):
interp.exec(10)

def test_bytes_for_script(self):
r, w = self.pipe()
RAN = b'R'
DONE = b'D'
interp = interpreters.create()
interp.exec(f"""if True:
import os
os.write({w}, {RAN!r})
""")
os.write(w, DONE)
self.assertEqual(os.read(r, 1), RAN)
with self.assertRaises(TypeError):
interp.exec(b'print("spam")')

def test_with_background_threads_still_running(self):
r_interp, w_interp = self.pipe()
Expand Down Expand Up @@ -1017,6 +1010,8 @@ def test_call(self):

for i, (callable, args, kwargs) in enumerate([
(call_func_noop, (), {}),
(call_func_return_shareable, (), {}),
(call_func_return_not_shareable, (), {}),
(Spam.noop, (), {}),
]):
with self.subTest(f'success case #{i+1}'):
Expand All @@ -1041,8 +1036,6 @@ def test_call(self):
(call_func_complex, ('custom', 'spam!'), {}),
(call_func_complex, ('custom-inner', 'eggs!'), {}),
(call_func_complex, ('???',), {'exc': ValueError('spam')}),
(call_func_return_shareable, (), {}),
(call_func_return_not_shareable, (), {}),
]):
with self.subTest(f'invalid case #{i+1}'):
with self.assertRaises(Exception):
Expand All @@ -1058,6 +1051,8 @@ def test_call_in_thread(self):

for i, (callable, args, kwargs) in enumerate([
(call_func_noop, (), {}),
(call_func_return_shareable, (), {}),
(call_func_return_not_shareable, (), {}),
(Spam.noop, (), {}),
]):
with self.subTest(f'success case #{i+1}'):
Expand All @@ -1084,8 +1079,6 @@ def test_call_in_thread(self):
(call_func_complex, ('custom', 'spam!'), {}),
(call_func_complex, ('custom-inner', 'eggs!'), {}),
(call_func_complex, ('???',), {'exc': ValueError('spam')}),
(call_func_return_shareable, (), {}),
(call_func_return_not_shareable, (), {}),
]):
with self.subTest(f'invalid case #{i+1}'):
if args or kwargs:
Expand Down Expand Up @@ -1625,8 +1618,8 @@ def test_exec(self):
def test_call(self):
with self.subTest('no args'):
interpid = _interpreters.create()
with self.assertRaises(ValueError):
_interpreters.call(interpid, call_func_return_shareable)
exc = _interpreters.call(interpid, call_func_return_shareable)
self.assertIs(exc, None)

with self.subTest('uncaught exception'):
interpid = _interpreters.create()
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_json/test_recursion.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test_highly_nested_objects_decoding(self):

@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
@support.requires_resource('cpu')
def test_highly_nested_objects_encoding(self):
# See #12051
l, d = [], {}
Expand Down
20 changes: 11 additions & 9 deletions Lib/test/test_memoryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,19 +743,21 @@ def test_racing_getbuf_and_releasebuf(self):
from multiprocessing.managers import SharedMemoryManager
except ImportError:
self.skipTest("Test requires multiprocessing")
from threading import Thread
from threading import Thread, Event

n = 100
start = Event()
with SharedMemoryManager() as smm:
obj = smm.ShareableList(range(100))
threads = []
for _ in range(n):
# Issue gh-127085, the `ShareableList.count` is just a convenient way to mess the `exports`
# counter of `memoryview`, this issue has no direct relation with `ShareableList`.
threads.append(Thread(target=obj.count, args=(1,)))

def test():
# Issue gh-127085, the `ShareableList.count` is just a
# convenient way to mess the `exports` counter of `memoryview`,
# this issue has no direct relation with `ShareableList`.
start.wait(support.SHORT_TIMEOUT)
for i in range(10):
obj.count(1)
threads = [Thread(target=test) for _ in range(10)]
with threading_helper.start_threads(threads):
pass
start.set()

del obj

Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,7 @@ def test_mixed_int_and_float(self):

class TestKDE(unittest.TestCase):

@support.requires_resource('cpu')
def test_kde(self):
kde = statistics.kde
StatisticsError = statistics.StatisticsError
Expand Down
37 changes: 34 additions & 3 deletions Lib/test/test_unittest/test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -1282,14 +1282,22 @@ def setUpModule():
suite(result)
expected_out = '\nStdout:\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 1)
self.assertEqual(len(result.errors), 2)
description = 'tearDownModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)

test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)

def testBufferSetUpModule_DoModuleCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
Expand All @@ -1313,22 +1321,34 @@ def setUpModule():
suite(result)
expected_out = '\nStdout:\nset up module\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
self.assertEqual(len(result.errors), 3)
description = 'setUpModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\nset up module\n', formatted_exc)

test_case, formatted_exc = result.errors[1]
self.assertIn(expected_out, formatted_exc)
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)

test_case, formatted_exc = result.errors[2]
self.assertIn(expected_out, formatted_exc)
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)

def testBufferTearDownModule_DoModuleCleanups(self):
with captured_stdout() as stdout:
result = unittest.TestResult()
Expand All @@ -1355,21 +1375,32 @@ def tearDownModule():
suite(result)
expected_out = '\nStdout:\ntear down module\ndo cleanup2\ndo cleanup1\n'
self.assertEqual(stdout.getvalue(), expected_out)
self.assertEqual(len(result.errors), 2)
self.assertEqual(len(result.errors), 3)
description = 'tearDownModule (Module)'
test_case, formatted_exc = result.errors[0]
self.assertEqual(test_case.description, description)
self.assertIn('ZeroDivisionError: division by zero', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn('\nStdout:\ntear down module\n', formatted_exc)

test_case, formatted_exc = result.errors[1]
self.assertEqual(test_case.description, description)
self.assertIn('ValueError: bad cleanup2', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('TypeError', formatted_exc)
self.assertIn(expected_out, formatted_exc)

test_case, formatted_exc = result.errors[2]
self.assertEqual(test_case.description, description)
self.assertIn('TypeError: bad cleanup1', formatted_exc)
self.assertNotIn('ExceptionGroup', formatted_exc)
self.assertNotIn('ZeroDivisionError', formatted_exc)
self.assertNotIn('ValueError', formatted_exc)
self.assertIn(expected_out, formatted_exc)


if __name__ == '__main__':
unittest.main()
Loading
Loading