@@ -33,8 +33,8 @@ mod sys {
3333 use crate :: {
3434 AsObject , PyObject , PyObjectRef , PyPayload , PyRef , PyRefExact , PyResult ,
3535 builtins:: {
36- PyBaseExceptionRef , PyDictRef , PyFrozenSet , PyNamespace , PyStr , PyStrRef , PyTupleRef ,
37- PyTypeRef ,
36+ PyBaseExceptionRef , PyDictRef , PyFrozenSet , PyNamespace , PyStr , PyStrRef , PyTuple ,
37+ PyTupleRef , PyTypeRef ,
3838 } ,
3939 common:: {
4040 ascii,
@@ -789,8 +789,22 @@ mod sys {
789789
790790 #[ pyfunction]
791791 fn exit ( code : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult {
792- let code = code. unwrap_or_none ( vm) ;
793- Err ( vm. new_exception ( vm. ctx . exceptions . system_exit . to_owned ( ) , vec ! [ code] ) )
792+ let status = code. unwrap_or_none ( vm) ;
793+ let args = if let Some ( status_tuple) = status. downcast_ref :: < PyTuple > ( ) {
794+ status_tuple. as_slice ( ) . to_vec ( )
795+ } else {
796+ vec ! [ status]
797+ } ;
798+ let exc = vm. invoke_exception ( vm. ctx . exceptions . system_exit . to_owned ( ) , args) ?;
799+ Err ( exc)
800+ }
801+
802+ #[ pyfunction]
803+ fn call_tracing ( func : PyObjectRef , args : PyTupleRef , vm : & VirtualMachine ) -> PyResult {
804+ // CPython temporarily enables tracing state around this call.
805+ // RustPython does not currently model the full C-level tracing toggles,
806+ // but call semantics (func(*args)) are matched.
807+ func. call ( PosArgs :: new ( args. as_slice ( ) . to_vec ( ) ) , vm)
794808 }
795809
796810 #[ pyfunction]
@@ -1024,6 +1038,36 @@ mod sys {
10241038 Ok ( dict)
10251039 }
10261040
1041+ /// Return a dictionary mapping each thread's identifier to its currently
1042+ /// active exception, or None if no exception is active.
1043+ #[ cfg( feature = "threading" ) ]
1044+ #[ pyfunction]
1045+ fn _current_exceptions ( vm : & VirtualMachine ) -> PyResult < PyDictRef > {
1046+ use crate :: AsObject ;
1047+
1048+ let dict = vm. ctx . new_dict ( ) ;
1049+ let exceptions = vm. state . thread_exceptions . lock ( ) ;
1050+
1051+ for ( thread_id, exc) in exceptions. iter ( ) {
1052+ let key = vm. ctx . new_int ( * thread_id) ;
1053+ let value = exc
1054+ . as_ref ( )
1055+ . map_or_else ( || vm. ctx . none ( ) , |e| e. clone ( ) . into ( ) ) ;
1056+ dict. set_item ( key. as_object ( ) , value, vm) ?;
1057+ }
1058+
1059+ Ok ( dict)
1060+ }
1061+
1062+ #[ cfg( not( feature = "threading" ) ) ]
1063+ #[ pyfunction]
1064+ fn _current_exceptions ( vm : & VirtualMachine ) -> PyResult < PyDictRef > {
1065+ let dict = vm. ctx . new_dict ( ) ;
1066+ let key = vm. ctx . new_int ( 0 ) ;
1067+ dict. set_item ( key. as_object ( ) , vm. topmost_exception ( ) . to_pyobject ( vm) , vm) ?;
1068+ Ok ( dict)
1069+ }
1070+
10271071 /// Stub for non-threading builds - returns empty dict
10281072 #[ cfg( not( feature = "threading" ) ) ]
10291073 #[ pyfunction]
@@ -1619,7 +1663,7 @@ mod sys {
16191663 } ;
16201664 }
16211665
1622- #[ pystruct_sequence( name = "float_info" , data = "FloatInfoData" , no_attr) ]
1666+ #[ pystruct_sequence( name = "float_info" , module = "sys" , data = "FloatInfoData" , no_attr) ]
16231667 pub ( super ) struct PyFloatInfo ;
16241668
16251669 #[ pyclass( with( PyStructSequence ) ) ]
0 commit comments