-
Notifications
You must be signed in to change notification settings - Fork 875
Description
🐛 Bug Reports
Hello,
During the holidays I spent some spare time experimenting with pyo3. I found something didn't work as I would have expected, fom a non-rust programmer point of view, this looks really strange. Since I run out of holiday spare time, I setup a reproducer and I send this bugreport to notify about this. Overall I'm curious to hear why it is happening, if it's a fixable bug, if it's a unfixable bug or if it's just a bug in my test code.
What feels like is that python side or the rust side are silently losing writes. At the very least I'd expect to see some runtime error from either side and not just silent data loss.
Taking a look at similar cases like in tests/test_class_conversion.rs I see Py is used, that's how I got the classB2 setup and then it works, but it's not clear if it's just working by luck in such case or if Py is used precisely for that purpose of activating all BaseClass methods like pyo3(set).
🌍 Environment
- Your python version: 3.8.6
- How did you install python (e.g. apt or pyenv)? Did you use a virtualenv?: system python on Gentoo
- Your Rust version (
rustc --version
): 1.47.0 - Your PyO3 version: 0.13.0
- Have you tried using latest PyO3 master (replace
version = "0.x.y"
withgit = "https://github.com/PyO3/pyo3")?
: yes
💥 Reproducing
$ git clone https://github.com/aagit/pyo3-reproducer.git
$ cd pyo3-reproducer
$ firejail --private=pwd
--seccomp # optional
$ cargo build
$ ./test.py
case1 B 0
0 False
case2 A 0
1 True
case3 B 0
0 False
case4 B 0
1 True
1 False
case1 B2 0
1 True
case3 B2 0
1 True
case4 B2 0
1 True
2 True
case4 B workaround 0
1 True
All lines with False show the unexpected silent write lost.
In all False cases the pyo3(set) for member "x" of ClassA is silently not invoked when python sets b.a.x .
ClassB2 shows how Py stabilizes the python object lifetime and doing so also happen to re-activate pyo3(set) method of ClassA and then everything works as expected.
It's just not clear if Py should be necessary to make it work and why "set" doesn't trigger an error if cannot hit the memory of the real ClassA rust side.
The workaround method of using a setter for b.a.x, but implemented in ClassB, also works, showing "get" of ClassA works fine and ClassA is referenced correctly on the rust side, it's just "set" failing silently, if invoked through ClassB.
Interestingly even a = b.a ; a.x = 1 isn't enough to invoke ClassA set method on b.a.x, despite a.x modified a successfully.
ClassB2 works, but Py then prevents to derive serialize/deserialize so it's far from ideal. Or would it be possible to filter out Py<> from the serializer and put Py<> back on in the deserializer? Isn't that task part of what pyo3 can do without having to code it on the rust side?
Thanks!