mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Store StopIteration.value in a struct field instead of the instance dict (#8301)
* Store StopIteration.value in a struct field like SystemExit * Unmark test_pydoc's test_member_descriptor * Use expect instead of unwrap in new_stop_iteration
This commit is contained in:
3 files changed
+67
-20
No files matched your search
Vendored
-1
@@ -1797,7 +1797,6 @@ cm(x) class method of test.test_pydoc.test_pydoc.X
|
||||
self.assertEqual(self._get_summary_line(Exception.args), "args")
|
||||
self.assertEqual(self._get_summary_line(memoryview.obj), "obj")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@requires_docstrings
|
||||
def test_member_descriptor(self):
|
||||
# Currently these attributes are implemented as member descriptors
|
||||
|
||||
+64
-10
@@ -965,9 +965,7 @@ impl ExceptionZoo {
|
||||
|
||||
extend_exception!(PyException, ctx, excs.exception_type);
|
||||
|
||||
extend_exception!(PyStopIteration, ctx, excs.stop_iteration, {
|
||||
"value" => ctx.none(),
|
||||
});
|
||||
extend_exception!(PyStopIteration, ctx, excs.stop_iteration);
|
||||
extend_exception!(PyStopAsyncIteration, ctx, excs.stop_async_iteration);
|
||||
|
||||
extend_exception!(PyArithmeticError, ctx, excs.arithmetic_error);
|
||||
@@ -1702,18 +1700,57 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyException(PyBaseException);
|
||||
|
||||
#[pyexception(name, base = PyException, ctx = "stop_iteration")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyStopIteration(PyException);
|
||||
#[pyexception(name, base = PyException, ctx = "stop_iteration", traverse = "manual")]
|
||||
#[repr(C)]
|
||||
pub struct PyStopIteration {
|
||||
base: PyException,
|
||||
value: PyAtomicRef<Option<PyObject>>,
|
||||
}
|
||||
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyStopIteration {}
|
||||
impl crate::class::PySubclass for PyStopIteration {
|
||||
type Base = PyException;
|
||||
fn as_base(&self) -> &Self::Base {
|
||||
&self.base
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for PyStopIteration {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("PyStopIteration").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Traverse for PyStopIteration {
|
||||
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
|
||||
self.base.0.traverse(tracer_fn);
|
||||
if let Some(obj) = self.value.deref() {
|
||||
tracer_fn(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for PyStopIteration {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let base_exception = PyBaseException::new(args.args, vm);
|
||||
Ok(Self {
|
||||
base: PyException(base_exception),
|
||||
value: None.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PyStopIteration {
|
||||
type Args = FuncArgs;
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.set_attr("value", vm.unwrap_or_none(args.args.first().cloned()), vm)?;
|
||||
let value = match args.args.len() {
|
||||
0 => vm.ctx.none(),
|
||||
_ => args.args[0].clone(),
|
||||
};
|
||||
PyBaseException::slot_init(zelf.clone(), args, vm)?;
|
||||
let exc: &Py<Self> = zelf.downcast_ref::<Self>().unwrap();
|
||||
exc.value.swap_to_temporary_refs(Some(value), vm);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1722,6 +1759,23 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(with(Constructor, Initializer))]
|
||||
impl PyStopIteration {
|
||||
#[pygetset]
|
||||
fn value(&self) -> Option<PyObjectRef> {
|
||||
self.value.to_owned()
|
||||
}
|
||||
|
||||
#[pygetset(setter)]
|
||||
fn set_value(&self, setter_value: PySetterValue, vm: &VirtualMachine) {
|
||||
let value = match setter_value {
|
||||
PySetterValue::Assign(v) => Some(v),
|
||||
PySetterValue::Delete => None,
|
||||
};
|
||||
self.value.swap_to_temporary_refs(value, vm);
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyException, ctx = "stop_async_iteration", impl)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
|
||||
@@ -894,21 +894,15 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
pub fn new_stop_iteration(&self, value: Option<PyObjectRef>) -> PyBaseExceptionRef {
|
||||
let dict = self.ctx.new_dict();
|
||||
let stop_iteration_error = self.ctx.exceptions.stop_iteration.to_owned();
|
||||
let args = if let Some(value) = value {
|
||||
// manually set `value` attribute like StopIteration.__init__
|
||||
dict.set_item("value", value.clone(), self)
|
||||
.expect("dict.__setitem__ never fails");
|
||||
vec![value]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let exc = self.invoke_exception(stop_iteration_error, args);
|
||||
|
||||
PyRef::new_ref(
|
||||
PyBaseException::new(args, self),
|
||||
self.ctx.exceptions.stop_iteration.to_owned(),
|
||||
Some(dict),
|
||||
)
|
||||
exc.expect("StopIteration is a BaseException Subclass.")
|
||||
}
|
||||
|
||||
fn new_downcast_error(
|
||||
|
||||
Reference in new issue
Block a user