Skip to content

Commit dd9bce5

Browse files
authored
Fix thread UnraisableException object to be None (#8326)
Assisted-by: Codex:gpt-5
1 parent d2da5a2 commit dd9bce5

3 files changed

Lines changed: 35 additions & 22 deletions

File tree

‎Lib/test/test_thread.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ def task():
151151
support.gc_collect() # For PyPy or other GCs.
152152
self.assertEqual(thread._count(), orig)
153153

154-
@unittest.expectedFailure # TODO: RUSTPYTHON
155154
def test_unraisable_exception(self):
156155
def task():
157156
started.release()

‎crates/vm/src/stdlib/_thread.rs‎

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ pub(crate) mod _thread {
2020

2121
use crate::{
2222
AsObject, Py, PyPayload, PyRef, PyResult, VirtualMachine,
23-
builtins::{PyDictRef, PyIntRef, PyStr, PyTupleRef, PyType, PyTypeRef, PyUtf8StrRef},
23+
builtins::{
24+
PyBaseExceptionRef, PyDictRef, PyIntRef, PyStr, PyTupleRef, PyType, PyTypeRef,
25+
PyUtf8StrRef,
26+
},
2427
common::wtf8::Wtf8Buf,
2528
frame::FrameRef,
2629
function::{ArgCallable, FuncArgs, KwArgs, OptionalArg, PySetterValue, TimeoutSeconds},
@@ -558,6 +561,19 @@ pub(crate) mod _thread {
558561
.map_err(|_err| vm.new_runtime_error("can't start new thread"))
559562
}
560563

564+
fn report_unraisable_thread_exception(
565+
exc: PyBaseExceptionRef,
566+
func: &ArgCallable,
567+
vm: &VirtualMachine,
568+
) {
569+
let msg = func
570+
.as_ref()
571+
.repr(vm)
572+
.ok()
573+
.map(|repr| format!("Exception ignored in thread started by {}", repr.as_wtf8()));
574+
vm.run_unraisable(exc, msg, vm.ctx.none());
575+
}
576+
561577
fn run_thread(func: ArgCallable, args: FuncArgs, vm: &VirtualMachine) {
562578
// Increment thread count when thread actually starts executing
563579
vm.state.thread_count.fetch_add(1);
@@ -572,11 +588,7 @@ pub(crate) mod _thread {
572588
if let Err(exc) = func.invoke(args, vm)
573589
&& !exc.fast_isinstance(vm.ctx.exceptions.system_exit)
574590
{
575-
vm.run_unraisable(
576-
exc,
577-
Some("Exception ignored in thread started by".to_owned()),
578-
func.into(),
579-
);
591+
report_unraisable_thread_exception(exc, &func, vm);
580592
}
581593
}
582594
for lock in SENTINELS.take() {
@@ -1755,11 +1767,7 @@ pub(crate) mod _thread {
17551767
if let Err(exc) = func.invoke((), vm)
17561768
&& !exc.fast_isinstance(vm.ctx.exceptions.system_exit)
17571769
{
1758-
vm.run_unraisable(
1759-
exc,
1760-
Some("Exception ignored in thread started by".to_owned()),
1761-
func.into(),
1762-
);
1770+
report_unraisable_thread_exception(exc, &func, vm);
17631771
}
17641772
}
17651773
}))

‎crates/vm/src/vm/mod.rs‎

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,18 +1296,24 @@ impl VirtualMachine {
12961296
}
12971297
};
12981298

1299-
let msg_str = if let Some(msg) = msg {
1300-
format!("{msg}: ")
1299+
if self.is_none(object) {
1300+
if let Some(msg) = msg {
1301+
write_to_stderr(&format!("{msg}:\n"), &stderr, self);
1302+
}
13011303
} else {
1302-
"Exception ignored in: ".to_owned()
1303-
};
1304-
write_to_stderr(&msg_str, &stderr, self);
1304+
let msg_str = if let Some(msg) = msg {
1305+
format!("{msg}: ")
1306+
} else {
1307+
"Exception ignored in: ".to_owned()
1308+
};
1309+
write_to_stderr(&msg_str, &stderr, self);
13051310

1306-
let repr_result = object.repr(self);
1307-
let repr_wtf8 = repr_result
1308-
.as_ref()
1309-
.map_or_else(|_| "<object repr failed>".as_ref(), |s| s.as_wtf8());
1310-
write_to_stderr(&format!("{repr_wtf8}\n"), &stderr, self);
1311+
let repr_result = object.repr(self);
1312+
let repr_wtf8 = repr_result
1313+
.as_ref()
1314+
.map_or_else(|_| "<object repr failed>".as_ref(), |s| s.as_wtf8());
1315+
write_to_stderr(&format!("{repr_wtf8}\n"), &stderr, self);
1316+
}
13111317

13121318
// Write exception type and message
13131319
let exc_type_name = e.class().name();

0 commit comments

Comments
 (0)