diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index ff696c5c153..bb9c88efec6 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -432,7 +432,6 @@ def f(): class CellTest(unittest.TestCase): - @unittest.expectedFailure # TODO: RUSTPYTHON def test_comparison(self): # These tests are here simply to exercise the comparison code; # their presence should not be interpreted as providing any diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index db3d87bd17a..22a55b57c07 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -237,7 +237,6 @@ def test_nesting(self): eq(r([[[[[[{}]]]]]]), "[[[[[[{}]]]]]]") eq(r([[[[[[[{}]]]]]]]), "[[[[[[[...]]]]]]]") - @unittest.expectedFailure # TODO: RUSTPYTHON def test_cell(self): def get_cell(): x = 42 diff --git a/crates/vm/src/builtins/function.rs b/crates/vm/src/builtins/function.rs index d1fa5222393..90315bcb194 100644 --- a/crates/vm/src/builtins/function.rs +++ b/crates/vm/src/builtins/function.rs @@ -15,7 +15,7 @@ use crate::{ class::PyClassImpl, common::wtf8::{Wtf8Buf, wtf8_concat}, frame::{FrameObject, FrameObjectRef}, - function::{FuncArgs, OptionalArg, PyComparisonValue, PySetterValue}, + function::{Either, FuncArgs, OptionalArg, PyComparisonValue, PySetterValue}, scope::Scope, types::{ Callable, Comparable, Constructor, GetAttr, GetDescriptor, Hashable, PyComparisonOp, @@ -1507,7 +1507,7 @@ impl Representable for PyBoundMethod { } } -#[pyclass(module = false, name = "cell", traverse)] +#[pyclass(module = false, name = "cell", unhashable = true, traverse)] #[derive(Debug, Default)] pub(crate) struct PyCell { contents: PyMutex>, @@ -1530,8 +1530,26 @@ impl Constructor for PyCell { } } -#[pyclass(with(Constructor))] +#[pyclass(with(Constructor, Representable))] impl PyCell { + #[pyslot] + fn slot_richcompare( + zelf: &PyObject, + other: &PyObject, + op: PyComparisonOp, + vm: &VirtualMachine, + ) -> PyResult> { + let (Some(zelf), Some(other)) = (zelf.downcast_ref::(), other.downcast_ref::()) + else { + return Ok(Either::B(PyComparisonValue::NotImplemented)); + }; + // compare cells by contents; empty cells come before anything else + match (zelf.get(), other.get()) { + (Some(a), Some(b)) => a.rich_compare(b, op, vm).map(Either::A), + (a, b) => Ok(Either::B(op.eval_ord(b.is_none().cmp(&a.is_none())).into())), + } + } + pub(crate) const fn new(contents: Option) -> Self { Self { contents: PyMutex::new(contents), @@ -1561,6 +1579,30 @@ impl PyCell { } } +impl Representable for PyCell { + #[inline] + fn repr_str(zelf: &Py, _vm: &VirtualMachine) -> PyResult { + let id = zelf.get_id(); + Ok(match zelf.get() { + Some(value) => { + let type_name = value.class().slot_name(); + // CPython renders the type name with "%.80s", which reads at + // most 80 bytes and drops a character left incomplete by the cut. + let mut end = type_name.len().min(80); + while !type_name.is_char_boundary(end) { + end -= 1; + } + format!( + "", + &type_name[..end], + value.get_id() + ) + } + None => format!(""), + }) + } +} + /// Vectorcall implementation for PyFunction (PEP 590). /// Takes owned args to avoid cloning when filling fastlocals. pub(crate) fn vectorcall_function(