Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pickle setstate: setattr __dict__ only if not empty #2972

Merged
merged 8 commits into from
Jun 30, 2021

Conversation

rwgk
Copy link
Collaborator

@rwgk rwgk commented Apr 22, 2021

Description

The motivation for this PR is to not force the use of py::dynamic_attr() unnecessarily. Concrete use case:

https://github.com/deepmind/open_spiel/blob/643dfd2a5ef023e796e20d06758800ec34a1204b/open_spiel/python/pybind11/pyspiel.cc#L309

py::dynamic_attr() comes with the disadvantage that it enables adding arbitrary attributes, which opens the door to accidents that tend to be subtle and time-consuming to debug (example situation below). The cost for avoiding this disadvantage is minuscule: just one additional if with 2 simple conditions in pybind11/detail/init.h.

The newly added unit tests reflect a typical situation in which this PR helps: a wrapped C++ virtual base class with a trampoline, combined with the use of base class pointers to C++ derived classes.

Example situation:

  • You need to pickle a C++ derived class (as in the new test), but without this PR that is only possible if you use py::dynamic_attr().
  • Therefore you decide to add py::dynamic_attr().
  • Time goes by ...
  • Someone accidentally assigns a misspelled attribute, but because of py::dynamic_attr() the code runs and produces nonsensical results. It takes you N hours to trace that out.

Suggested changelog entry:

Pickle support enhancement: ``setstate`` implementation will attempt to ``setattr`` ``__dict__`` only
if the unpickled ``dict`` object is not empty, to not force use of ``py::dynamic_attr()`` unnecessarily.

@EricCousineau-TRI
Copy link
Collaborator

EricCousineau-TRI commented Apr 22, 2021

Sweet!

At high-level, motivation not immediately obvious for me - was it speed, or correctness, and can you mention publicly visible stakeholder (Google) or proj name (deepspiel open_spiel or what not)?

@EricCousineau-TRI
Copy link
Collaborator

And for given motivation, is it possible to give precise numbers (or rough) in terms of performance gain (if it was speed / memory)?

@rwgk
Copy link
Collaborator Author

rwgk commented Apr 22, 2021

And for given motivation, is it possible to give precise numbers (or rough) in terms of performance gain (if it was speed / memory)?

Performance isn't the main concerns, but py::dynamic_attr() enables adding arbitrary attributes, which opens the door to accidents (often subtle and therefore difficult/time-consuming to debug).

Yes, this is for DeepMinds open_spiel: https://github.com/deepmind/open_spiel
This will become public later. Currently it's still an internal pending change. Once submitted it'll get pushed out on some weekly schedule, therefore nothing concrete to point to yet.

Thanks for looking Eric, I'll go ahead working on the unit test and will add the motivation to the description.

@EricCousineau-TRI EricCousineau-TRI self-requested a review April 22, 2021 19:24
@rwgk rwgk force-pushed the master_pickle_setstate branch from 61007e9 to a4bd790 Compare May 7, 2021 21:02
@rwgk rwgk requested a review from henryiii as a code owner May 7, 2021 21:02
@rwgk
Copy link
Collaborator Author

rwgk commented May 7, 2021

Hi @EricCousineau-TRI and @elkhrt, this PR is complete now. Could you please review?

@rwgk
Copy link
Collaborator Author

rwgk commented May 7, 2021

The one CI failure is just our most common flake (see #2995).

Copy link
Contributor

@elkhrt elkhrt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Ralf - this is great.

Copy link
Collaborator

@EricCousineau-TRI EricCousineau-TRI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you for providing context (and soz for delay!)

Requesting more concrete testing, with nits on consistent styling w/ existing and usage of more explicitly conditionals in lieu of try/catch. (Feel free to punt on nits!)

For the overview, I can see two possible "debugging" issue:
(1) you accidentally assign a non-existent attribute but py::dynamic_attr() allows it (thus "ouch", you gotta trace that out)
(2) is that you cannot unpickle a C++ derived class, motivating py::dynamic_attr(), forcing you to run into (1).

Is it possible for you to rewrite the overview / commit stmt to expliclty focus on (2)?
(then (1) becomes an obvious side effect?)

Lemme know if you have any Q's or would like push back on this!

include/pybind11/detail/init.h Show resolved Hide resolved
tests/CMakeLists.txt Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.cpp Outdated Show resolved Hide resolved
@rwgk rwgk force-pushed the master_pickle_setstate branch from 61e2ba7 to cc0cefe Compare May 21, 2021 22:12
Copy link
Collaborator Author

@rwgk rwgk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Eric! I updated the code and the PR description starting from your suggestion.

include/pybind11/detail/init.h Show resolved Hide resolved
tests/CMakeLists.txt Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.cpp Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
tests/test_pickling_trampoline.py Outdated Show resolved Hide resolved
@rwgk rwgk force-pushed the master_pickle_setstate branch from cc0cefe to ad96e32 Compare June 4, 2021 05:24
@rwgk
Copy link
Collaborator Author

rwgk commented Jun 5, 2021

Apparently the Centos 8 build broke for external reasons on 6/3. Trying again (PR Close-Reopen) to see if it fixed itself.

@rwgk rwgk closed this Jun 5, 2021
@rwgk rwgk reopened this Jun 5, 2021
@rwgk rwgk force-pushed the master_pickle_setstate branch 3 times, most recently from ddcab22 to 2cbf77a Compare June 22, 2021 19:14
Copy link
Collaborator

@EricCousineau-TRI EricCousineau-TRI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! However, I think you possibly uncovered a new bug 😿
I don't think we need to block this PR on it, but we should at least leave paper trail (issue+TODO) for it!

include/pybind11/detail/init.h Show resolved Hide resolved
tests/test_pickling.py Show resolved Hide resolved
@rwgk rwgk force-pushed the master_pickle_setstate branch from ef433dc to f6c1df8 Compare June 26, 2021 06:17
@rwgk
Copy link
Collaborator Author

rwgk commented Jun 29, 2021

Closing-Reopening to trigger CI.

@rwgk rwgk closed this Jun 29, 2021
@rwgk rwgk reopened this Jun 29, 2021
@rwgk rwgk merged commit fbae8f3 into pybind:master Jun 30, 2021
@rwgk rwgk deleted the master_pickle_setstate branch June 30, 2021 19:34
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Jun 30, 2021
@henryiii henryiii removed the needs changelog Possibly needs a changelog entry label Jul 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants