Why do I have to implement __hash__() for a Rust enum with derived Hash trait? #3557
-
Hi, PyO3 is awesome but there is a little detail that I don't understand. I want to expose a Rust enum #[derive(Eq, PartialEq, Hash)]
#[pyclass]
enum Foo {
First,
Second,
Third
}
#[pymethods]
impl Foo {
#[classmethod]
fn all(_cls: &PyType) -> HashSet<Self> {
let mut hs = HashSet::new();
hs.insert(Foo::First);
hs.insert(Foo::Second);
hs.insert(Foo::Third);
hs
}
} This code compiles just fine. But when I try to run this method from Python, it fails: >>> from my_module import Foo
>>> Foo.all()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
pyo3_runtime.PanicException:
Failed to create Python set from HashSet:
PyErr { type: <class 'TypeError'>, value: TypeError("unhashable type: 'builtins.Foo'"), traceback: None } The solution I found was to override Python's #[pymethods]
impl Foo {
fn __hash__(&self) -> u64 {
let mut hasher = DefaultHasher::new();
self.hash(&mut hasher);
hasher.finish()
}
#[classmethod]
fn all(_cls: &PyType) -> HashSet<Self> {
let mut hs = HashSet::new();
hs.insert(Foo::First);
hs.insert(Foo::Second);
hs.insert(Foo::Third);
hs
}
} Now
If this sentence is true, then why do I have to override |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
Oof, I'm pretty sure that this is caused because we generate a default implementation of ordering for you. As per the docs for
So I'd consider this a bug. I'll create an issue now. |
Beta Was this translation helpful? Give feedback.
-
@davidhewitt know you are a busy guy, any plans for this to be fixed yet? Thanks. |
Beta Was this translation helpful? Give feedback.
Oof, I'm pretty sure that this is caused because we generate a default implementation of ordering for you. As per the docs for
__eq__
and friends:So I'd consider this a bug. I'll create an issue now.