Merge pull request #7075 from youknowone/sys

Update test_sys from v3.14.3 and impl more sys module
This commit is contained in:
Jeong, YunWon
2026-02-21 19:26:58 +09:00
committed by GitHub
6 changed files with 83 additions and 28 deletions

View File

@@ -243,8 +243,6 @@ class LocaleConfigurationTests(_LocaleHandlingTestCase):
if not AVAILABLE_TARGETS:
raise unittest.SkipTest("No C-with-UTF-8 locale available")
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_external_target_locale_configuration(self):
# Explicitly setting a target locale should give the same behaviour as

30
Lib/test/test_sys.py vendored
View File

@@ -1,6 +1,5 @@
import builtins
import codecs
# import _datetime # TODO: RUSTPYTHON
import gc
import io
import locale
@@ -210,7 +209,7 @@ class SysModuleTest(unittest.TestCase):
def tearDown(self):
test.support.reap_children()
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; latin-1 codec not registered
def test_exit(self):
# call with two arguments
self.assertRaises(TypeError, sys.exit, 42, 42)
@@ -352,7 +351,7 @@ class SysModuleTest(unittest.TestCase):
finally:
sys.setrecursionlimit(old_limit)
@unittest.skipIf(getattr(sys, '_rustpython_debugbuild', False), 'TODO: RUSTPYTHON; stack overflow on debug build')
@unittest.skipIf(getattr(sys, "_rustpython_debugbuild", False), "TODO: RUSTPYTHON; stack overflow on debug build")
def test_recursionlimit_recovery(self):
if hasattr(sys, 'gettrace') and sys.gettrace():
self.skipTest('fatal error if run with a trace function')
@@ -433,7 +432,6 @@ class SysModuleTest(unittest.TestCase):
# still has 5 elements
maj, min, buildno, plat, csd = sys.getwindowsversion()
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'sys' has no attribute 'call_tracing'
def test_call_tracing(self):
self.assertRaises(TypeError, sys.call_tracing, type, 2)
@@ -499,8 +497,6 @@ class SysModuleTest(unittest.TestCase):
self.assertIsNone(sys._getframemodulename(i))
# sys._current_frames() is a CPython-only gimmick.
# XXX RUSTPYTHON: above comment is from original cpython test; not sure why the cpython_only decorator wasn't added
@test.support.cpython_only
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_current_frames(self):
@@ -568,7 +564,6 @@ class SysModuleTest(unittest.TestCase):
leave_g.set()
t.join()
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'sys' has no attribute '_current_exceptions'
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_current_exceptions(self):
@@ -856,7 +851,7 @@ class SysModuleTest(unittest.TestCase):
'''))
self.assertTrue(sys._is_interned(s))
@unittest.expectedFailure # TODO: RUSTPYTHON; needs update for context_aware_warnings
@unittest.expectedFailure # TODO: RUSTPYTHON; needs update for context_aware_warnings
def test_sys_flags(self):
self.assertTrue(sys.flags)
attrs = ("debug",
@@ -897,7 +892,7 @@ class SysModuleTest(unittest.TestCase):
r"sys\._clear_type_cache\(\) is deprecated.*"):
sys._clear_type_cache()
@unittest.skip('TODO: RUSTPYTHON; cp424 encoding not supported, causes panic')
@unittest.skip("TODO: RUSTPYTHON; cp424 encoding not supported, causes panic")
@force_not_colorized
@support.requires_subprocess()
def test_ioencoding(self):
@@ -1062,12 +1057,12 @@ class SysModuleTest(unittest.TestCase):
'stdout: surrogateescape\n'
'stderr: backslashreplace\n')
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; stderr: backslashreplace
@support.requires_subprocess()
def test_c_locale_surrogateescape(self):
self.check_locale_surrogateescape('C')
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; stderr: backslashreplace
@support.requires_subprocess()
def test_posix_locale_surrogateescape(self):
self.check_locale_surrogateescape('POSIX')
@@ -1192,7 +1187,6 @@ class SysModuleTest(unittest.TestCase):
rc, stdout, stderr = assert_python_ok('-c', code)
self.assertEqual(stdout.rstrip(), b'True')
@unittest.expectedFailure # TODO: RUSTPYTHON; IndexError: list index out of range
def test_issue20602(self):
# sys.flags and sys.float_info were wiped during shutdown.
code = """if 1:
@@ -1225,7 +1219,7 @@ class SysModuleTest(unittest.TestCase):
self.assertEqual(stdout.rstrip(), b"")
self.assertEqual(stderr.rstrip(), b"")
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'sys' has no attribute 'getandroidapilevel'
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'sys' has no attribute 'getandroidapilevel'
@unittest.skipUnless(sys.platform == "android", "Android only")
def test_getandroidapilevel(self):
level = sys.getandroidapilevel()
@@ -1494,6 +1488,7 @@ class UnraisableHookTest(unittest.TestCase):
def test_custom_unraisablehook_fail(self):
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import err_writeunraisable
def hook_func(*args):
raise Exception("hook_func failed")
@@ -1742,7 +1737,12 @@ class SizeofTest(unittest.TestCase):
x = property(getx, setx, delx, "")
check(x, size('5Pi'))
# PyCapsule
check(_datetime.datetime_CAPI, size('6P'))
try:
import _datetime
except ModuleNotFoundError:
pass
else:
check(_datetime.datetime_CAPI, size('6P'))
# rangeiterator
check(iter(range(1)), size('3l'))
check(iter(range(2**65)), size('3P'))
@@ -2227,7 +2227,7 @@ class TestSysJIT(unittest.TestCase):
assert_python_ok("-c", script.format(enabled=False), PYTHON_JIT="0")
assert_python_ok("-c", script.format(enabled=available), PYTHON_JIT="1")
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; ---
def test_jit_is_active(self):
available = sys._jit.is_available()
script = textwrap.dedent(

View File

@@ -1078,10 +1078,7 @@ impl PyObject {
Some(true) => Ok(()),
// we've been resurrected by __del__
Some(false) => Err(()),
None => {
warn!("couldn't run __del__ method for object");
Ok(())
}
None => Ok(()),
}
}

View File

@@ -33,8 +33,8 @@ mod sys {
use crate::{
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult,
builtins::{
PyBaseExceptionRef, PyDictRef, PyFrozenSet, PyNamespace, PyStr, PyStrRef, PyTupleRef,
PyTypeRef,
PyBaseExceptionRef, PyDictRef, PyFrozenSet, PyNamespace, PyStr, PyStrRef, PyTuple,
PyTupleRef, PyTypeRef,
},
common::{
ascii,
@@ -789,8 +789,22 @@ mod sys {
#[pyfunction]
fn exit(code: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
let code = code.unwrap_or_none(vm);
Err(vm.new_exception(vm.ctx.exceptions.system_exit.to_owned(), vec![code]))
let status = code.unwrap_or_none(vm);
let args = if let Some(status_tuple) = status.downcast_ref::<PyTuple>() {
status_tuple.as_slice().to_vec()
} else {
vec![status]
};
let exc = vm.invoke_exception(vm.ctx.exceptions.system_exit.to_owned(), args)?;
Err(exc)
}
#[pyfunction]
fn call_tracing(func: PyObjectRef, args: PyTupleRef, vm: &VirtualMachine) -> PyResult {
// CPython temporarily enables tracing state around this call.
// RustPython does not currently model the full C-level tracing toggles,
// but call semantics (func(*args)) are matched.
func.call(PosArgs::new(args.as_slice().to_vec()), vm)
}
#[pyfunction]
@@ -1031,6 +1045,33 @@ mod sys {
Ok(dict)
}
/// Return a dictionary mapping each thread's identifier to its currently
/// active exception, or None if no exception is active.
#[cfg(feature = "threading")]
#[pyfunction]
fn _current_exceptions(vm: &VirtualMachine) -> PyResult<PyDictRef> {
use crate::AsObject;
use crate::vm::thread::get_all_current_exceptions;
let dict = vm.ctx.new_dict();
for (thread_id, exc) in get_all_current_exceptions(vm) {
let key = vm.ctx.new_int(thread_id);
let value = exc.map_or_else(|| vm.ctx.none(), |e| e.into());
dict.set_item(key.as_object(), value, vm)?;
}
Ok(dict)
}
#[cfg(not(feature = "threading"))]
#[pyfunction]
fn _current_exceptions(vm: &VirtualMachine) -> PyResult<PyDictRef> {
let dict = vm.ctx.new_dict();
let key = vm.ctx.new_int(0);
dict.set_item(key.as_object(), vm.topmost_exception().to_pyobject(vm), vm)?;
Ok(dict)
}
/// Stub for non-threading builds - returns empty dict
#[cfg(not(feature = "threading"))]
#[pyfunction]

View File

@@ -1,7 +1,7 @@
use crate::common::lock::LazyLock;
use crate::{
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, atomic_func,
builtins::{PyBaseExceptionRef, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef},
builtins::{PyBaseExceptionRef, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef},
class::{PyClassImpl, StaticType},
function::{Either, FuncArgs, PyComparisonValue, PyMethodDef, PyMethodFlags},
iter::PyExactSizeIterator,
@@ -225,7 +225,21 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
} else {
(String::new(), "...")
};
let repr_str = format!("{}({}{})", Self::TP_NAME, body, suffix);
// Build qualified name: if MODULE_NAME is already in TP_NAME, use it directly.
// Otherwise, check __module__ attribute (set by #[pymodule] at runtime).
let type_name = if Self::MODULE_NAME.is_some() {
alloc::borrow::Cow::Borrowed(Self::TP_NAME)
} else {
let typ = zelf.class();
match typ.get_attr(identifier!(vm.ctx, __module__)) {
Some(module) if module.downcastable::<PyStr>() => {
let module_str = module.downcast_ref::<PyStr>().unwrap();
alloc::borrow::Cow::Owned(format!("{}.{}", module_str.as_str(), Self::NAME))
}
_ => alloc::borrow::Cow::Borrowed(Self::TP_NAME),
}
};
let repr_str = format!("{}({}{})", type_name, body, suffix);
Ok(vm.ctx.new_str(repr_str))
}

View File

@@ -397,7 +397,12 @@ impl VirtualMachine {
let errors = if fd == 2 {
Some("backslashreplace")
} else {
self.state.config.settings.stdio_errors.as_deref()
self.state
.config
.settings
.stdio_errors
.as_deref()
.or(Some("surrogateescape"))
};
let stdio = self.call_method(