pyo3 icon indicating copy to clipboard operation
pyo3 copied to clipboard

Implementing `__richcmp__` makes object unhashable

Open kevinheavey opened this issue 3 years ago • 2 comments

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

kevinheavey avatar Jan 24 '22 13:01 kevinheavey

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.

davidhewitt avatar Jan 25 '22 07:01 davidhewitt

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

davidhewitt avatar Jan 25 '22 08:01 davidhewitt