mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Align import, numeric and warning edge cases with Python 3.15 (#9210)
* Align import, numeric and warning edge cases with Python 3.15 Carry four independent compatibility fixes from the 3.15 upgrade: preserve import cache lookup errors, handle surrogate module names, qualify numeric conversion diagnostics, and accept frozen warning globals. Match pinned CPython d220409a13b77de7a6c30abe16ea90db01528edc. Assisted-by: OpenAI Codex:model version unavailable * Preserve the integer contract of builtin module detection Return -1 for the separately initialized sys/builtins core modules, 1 for registered definitions and 0 for absent or unencodable names, matching pinned CPython import.c and its initialization table. Assisted-by: OpenAI Codex:model version unavailable * Normalize successful index conversions to exact integers Match PyNumber_Index after its internal protocol call: preserve exceptions and warning timing, then copy bool or int-subclass payloads to an exact int without calling __index__ again. Assisted-by: OpenAI Codex:model version unavailable * Retire passing surrogate-import expected failures Canonical cases now pass on the repaired import paths, including hosted Windows validation. Preserve their bodies and platform guards through update_lib. Assisted-by: OpenAI Codex:model version unavailable
This commit is contained in:
1 parent
75e77c30e3
commit
7f5cc0e35c
6 files changed
+46
-31
No files matched your search
Vendored
-1
@@ -1284,7 +1284,6 @@ class CmdLineTest(unittest.TestCase):
|
||||
assert_python_failure('-X', 'importtime=-1', '-c', code)
|
||||
assert_python_failure('-X', 'importtime=3', '-c', code)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; -X importtime=2 timing output and surrogate module import exception semantics are not implemented correctly
|
||||
def test_import_time_unencodable_module_name(self):
|
||||
code = textwrap.dedent("""
|
||||
import sys, types
|
||||
|
||||
Vendored
-1
@@ -2028,7 +2028,6 @@ class ImportTracebackTests(unittest.TestCase):
|
||||
finally:
|
||||
del importlib.SourceLoader.exec_module
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; subprocess fails on Windows
|
||||
@unittest.skipUnless(TESTFN_UNENCODABLE, 'need TESTFN_UNENCODABLE')
|
||||
def test_unencodable_filename(self):
|
||||
# Issue #11619: The Python parser and the import machinery must not
|
||||
|
||||
@@ -573,7 +573,11 @@ pub(crate) fn import_module_level(
|
||||
crate::lazy_import::clear_submodule(&abs_name, true, vm)?;
|
||||
m
|
||||
}
|
||||
_ => find_and_load(&abs_name, "_find_and_load", vm)?,
|
||||
Ok(_) => find_and_load(&abs_name, "_find_and_load", vm)?,
|
||||
Err(error) if error.fast_isinstance(vm.ctx.exceptions.key_error) => {
|
||||
find_and_load(&abs_name, "_find_and_load", vm)?
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
// Handle fromlist
|
||||
|
||||
@@ -53,7 +53,14 @@ impl PyObject {
|
||||
} else if let Some(i) = self.downcast_ref::<PyInt>() {
|
||||
Some(Ok(vm.ctx.new_bigint(i.as_bigint())))
|
||||
} else {
|
||||
self.number().index(vm)
|
||||
self.number().index(vm).map(|result| {
|
||||
let result = result?;
|
||||
if result.class().is(vm.ctx.types.int_type) {
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(vm.ctx.new_bigint(result.as_bigint()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,21 +710,22 @@ and may be removed in a future version of Python.",
|
||||
}
|
||||
|
||||
let ret_class = ret.class().to_owned();
|
||||
let message = format!(
|
||||
"{}.__index__() must return an int, not {}",
|
||||
self.class().fully_qualified_name(vm)?,
|
||||
ret_class.fully_qualified_name(vm)?
|
||||
);
|
||||
if let Some(ret) = ret.downcast_ref::<PyInt>() {
|
||||
let msg = format!(
|
||||
"__index__ returned non-int (type {}). \
|
||||
"{message}. \
|
||||
The ability to return an instance of a strict subclass of int is deprecated, \
|
||||
and may be removed in a future version of Python.",
|
||||
ret_class.slot_name()
|
||||
and may be removed in a future version of Python."
|
||||
);
|
||||
_warnings::warn(vm.ctx.exceptions.deprecation_warning, msg, 1, vm)?;
|
||||
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"__index__ returned non-int (type {})",
|
||||
ret_class.slot_name()
|
||||
)))
|
||||
Err(vm.new_type_error(message))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -732,23 +740,22 @@ and may be removed in a future version of Python.",
|
||||
}
|
||||
|
||||
let ret_class = ret.class().to_owned();
|
||||
let message = format!(
|
||||
"{}.__float__() must return a float, not {}",
|
||||
self.class().fully_qualified_name(vm)?,
|
||||
ret_class.fully_qualified_name(vm)?
|
||||
);
|
||||
if let Some(ret) = ret.downcast_ref::<PyFloat>() {
|
||||
let msg = format!(
|
||||
"{}.__float__ returned non-float (type {}). \
|
||||
"{message}. \
|
||||
The ability to return an instance of a strict subclass of float is deprecated, \
|
||||
and may be removed in a future version of Python.",
|
||||
self.class().slot_name(),
|
||||
ret_class.slot_name()
|
||||
and may be removed in a future version of Python."
|
||||
);
|
||||
_warnings::warn(vm.ctx.exceptions.deprecation_warning, msg, 1, vm)?;
|
||||
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__float__ returned non-float (type {})",
|
||||
self.class().slot_name(),
|
||||
ret_class.slot_name()
|
||||
)))
|
||||
Err(vm.new_type_error(message))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -243,13 +243,18 @@ mod _imp {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn is_builtin(name: PyUtf8StrRef, vm: &VirtualMachine) -> bool {
|
||||
vm.state.module_defs.contains_key(name.as_str())
|
||||
fn is_builtin(name: PyStrRef, vm: &VirtualMachine) -> i32 {
|
||||
match name.to_str() {
|
||||
Some("sys" | "builtins") => -1,
|
||||
Some(name) => i32::from(vm.state.module_defs.contains_key(name)),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn is_frozen(name: PyUtf8StrRef, vm: &VirtualMachine) -> bool {
|
||||
super::find_frozen(name.as_str(), vm).is_ok()
|
||||
fn is_frozen(name: PyStrRef, vm: &VirtualMachine) -> bool {
|
||||
name.to_str()
|
||||
.is_some_and(|name| super::find_frozen(name, vm).is_ok())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -481,7 +486,7 @@ mod _imp {
|
||||
#[derive(FromArgs)]
|
||||
struct FindFrozenArgs {
|
||||
#[pyarg(positional)]
|
||||
name: PyUtf8StrRef,
|
||||
name: PyStrRef,
|
||||
#[pyarg(named, default)]
|
||||
withdata: bool,
|
||||
}
|
||||
@@ -493,8 +498,9 @@ mod _imp {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<(Option<PyRef<PyMemoryView>>, bool, Option<PyStrRef>)>> {
|
||||
let FindFrozenArgs { name, withdata } = args;
|
||||
|
||||
let name_str = name.as_str();
|
||||
let Some(name_str) = name.to_str() else {
|
||||
return Ok(None);
|
||||
};
|
||||
let info = match super::find_frozen(name_str, vm) {
|
||||
Ok(info) => info,
|
||||
Err(FrozenError::NotFound | FrozenError::Disabled | FrozenError::BadName) => {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn warn(
|
||||
mod _warnings {
|
||||
use crate::{
|
||||
AsObject, PyObject, PyObjectRef, PyResult, VirtualMachine,
|
||||
builtins::{PyDict, PyDictRef, PyListRef, PyStrRef, PyTupleRef, PyTypeRef},
|
||||
builtins::{PyAnyDict, PyDictRef, PyListRef, PyStrRef, PyTupleRef, PyTypeRef},
|
||||
convert::TryFromObject,
|
||||
function::OptionalArg,
|
||||
};
|
||||
@@ -180,10 +180,10 @@ mod _warnings {
|
||||
let source_line = if let Some(mg) = args.module_globals.into_option() {
|
||||
if vm.is_none(&mg) {
|
||||
None
|
||||
} else if mg.downcast_ref::<PyDict>().is_none() {
|
||||
} else if PyAnyDict::from_object(&mg).is_none() {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"module_globals must be a dict, not '{}'",
|
||||
mg.class().name()
|
||||
"module_globals must be a dict or a frozendict, not {}",
|
||||
mg.class().fully_qualified_name(vm)?
|
||||
)));
|
||||
} else {
|
||||
crate::warn::get_source_line(&mg, args.lineno, vm)?
|
||||
|
||||
Reference in new issue
Block a user