Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Lib/test/test_pydoc/test_pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,6 @@ def test_getset_descriptor(self):
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
Expand Down
74 changes: 64 additions & 10 deletions crates/vm/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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>>,
}
Comment on lines +1705 to +1708

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


#[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(())
}

Expand All @@ -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)]
Expand Down
12 changes: 3 additions & 9 deletions crates/vm/src/vm/vm_new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading