pyo3
pyo3 copied to clipboard
Implementing `__richcmp__` makes object unhashable
Bug Description
If you try to call Python's hash function on an object for which you've implemented __richcmp__
, it fails with unhashable type
. The only fix I've found is to also implement __hash__
.
This also happens if you implement __eq__
though I've heard __eq__
isn't supported anyway.
Steps to Reproduce
use pyo3::{basic::CompareOp, prelude::*};
#[pyclass]
#[derive(PartialEq, PartialOrd, Debug, Default)]
pub struct DoesNotHash(u32);
#[pymethods]
impl DoesNotHash {
#[new]
pub fn new() -> Self {
Self(3)
}
// Uncomment the below to break hashing.
// fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool {
// match op {
// CompareOp::Eq => self == other,
// CompareOp::Ne => self != other,
// CompareOp::Lt => self < other,
// CompareOp::Gt => self > other,
// CompareOp::Le => self <= other,
// CompareOp::Ge => self >= other,
// }
// }
}
/// A Python module implemented in Rust.
#[pymodule]
fn hash_example(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<DoesNotHash>()?;
Ok(())
}
Backtrace
No response
Your operating system and version
Ubuntu 20.04.3 LTS
Your Python version (python --version
)
Python 3.9
Your Rust version (rustc --version
)
rustc 1.59.0-nightly (7abab1efb 2021-12-17)
Your PyO3 version
0.15.1
How did you install python? Did you use a virtualenv?
Installed in fresh conda environment.
Additional Info
No response
Thanks for reporting. As the default hash implementation comes from CPython, this is most likely by design and simply an oversight in our documentation. Just needs some investigation to confirm.
Yep looks like it's expected that the default object equality and hashing are not provided if any of these methods are implemented: https://github.com/python/cpython/blob/a1444f43584af0f7a0af72aa06ba0a86ae5a87a2/Objects/typeobject.c#L6011