-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: squash-merge smart_holder branch into master #5542
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
feat: squash-merge smart_holder branch into master #5542
Conversation
…, advanced/classes.rst
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only reviewed documentation.
I note that the documentation doesn't mention PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
at all. In my usage of pybind11, I enable that macro because (a) I'm lazy and (b) I assumed that because smart holder is awesome that eventually when it got merged it would become the default and then we could get rid of the macro.
I don't understand the backwards compatibility argument for not making smart holder the default, but if there really are known backwards compatibility issues and it's not going to be the default I think I lean towards getting rid of the macro? When reading pybind11 code it would be good to know "this is definitely using smart holder" and "this is definitely not" without having to know which compile flags are set.
Edit: lol clearly I didn't read the PR description carefully enough
docs/classes.rst
Outdated
|
||
.. note:: | ||
|
||
Starting with pybind11v3, it is recommended to use `py::classh` in most |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's another PR, but since it's the recommended default, we probably should change all of the documentation to use it, since users often just copy/paste from the documentation without thinking about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was on the fence, thanks for the feedback! I'll change it around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit ac9d31e.
(I made a fast pass, followed by a careful slow pass reviewing the generated html.)
@virtuald As someone who's used the smart_holder branch for a long time, what's you opinion about this question?
It only makes a difference to people who have been using the smart_holder branch before (probably a relative small number?). When they switch to pbyind11v3, they'll be forced to adjust their code (remove pybind11/smart_holder.h includes). Is that a hardship, or just a minor inconvenience? |
.. seealso:: | ||
|
||
The file :file:`tests/test_smart_ptr.cpp` contains a complete example | ||
that demonstrates how to work with custom reference-counting holder types | ||
in more detail. | ||
|
||
|
||
Be careful not to accidentally undermine automatic lifetime management |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I missed it, but is this a new section that has nothing to do with smart holder? Maybe move it to a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's definitely odd here, but it's based on this existing part:
pybind11/docs/advanced/smart_ptrs.rst
Lines 50 to 113 in d8565ac
One potential stumbling block when using holder types is that they need to be | |
applied consistently. Can you guess what's broken about the following binding | |
code? | |
.. code-block:: cpp | |
class Child { }; | |
class Parent { | |
public: | |
Parent() : child(std::make_shared<Child>()) { } | |
Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ | |
private: | |
std::shared_ptr<Child> child; | |
}; | |
PYBIND11_MODULE(example, m) { | |
py::class_<Child, std::shared_ptr<Child>>(m, "Child"); | |
py::class_<Parent, std::shared_ptr<Parent>>(m, "Parent") | |
.def(py::init<>()) | |
.def("get_child", &Parent::get_child); | |
} | |
The following Python code will cause undefined behavior (and likely a | |
segmentation fault). | |
.. code-block:: python | |
from example import Parent | |
print(Parent().get_child()) | |
The problem is that ``Parent::get_child()`` returns a pointer to an instance of | |
``Child``, but the fact that this instance is already managed by | |
``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, | |
pybind11 will create a second independent ``std::shared_ptr<...>`` that also | |
claims ownership of the pointer. In the end, the object will be freed **twice** | |
since these shared pointers have no way of knowing about each other. | |
There are two ways to resolve this issue: | |
1. For types that are managed by a smart pointer class, never use raw pointers | |
in function arguments or return values. In other words: always consistently | |
wrap pointers into their designated holder types (such as | |
``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` | |
should be modified as follows: | |
.. code-block:: cpp | |
std::shared_ptr<Child> get_child() { return child; } | |
2. Adjust the definition of ``Child`` by specifying | |
``std::enable_shared_from_this<T>`` (see cppreference_ for details) as a | |
base class. This adds a small bit of information to ``Child`` that allows | |
pybind11 to realize that there is already an existing | |
``std::shared_ptr<...>`` and communicate with it. In this case, the | |
declaration of ``Child`` should look as follows: | |
.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this | |
.. code-block:: cpp | |
class Child : public std::enable_shared_from_this<Child> { }; |
I think it'll be best to move it only after this PR is merged, to not make this PR even more difficult to review.
No promises were really made about smart_holder and if one is using (what is effectively) a fork of a project then you just accept whatever comes with it, so I think whatever makes sense would be good. Since everything in that file is marked as deprecated, it seems good to get rid of it. Looking at my own usage, I used |
Thanks! I'm glad to get rid of it completely. I'll remove my note from the PR description.
I want to nudge people towards not ever using that macro in production situations, with this in mind:
One idea is to rename the macro, .e.g.: So in your case the old name would become a no-op, some tests would break, which you'd then fix by changing your I'm trying to think ahead, please chime in if I'm going off the tracks: You wouldn't be able to go back to an older pybind11 version easily. But then again, if your code requires the smart_holder feature, that wouldn't work anyway. So all good? But what will people do if I'm overlooking something and they have a reason to use They could go through their code to change |
…T_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
This should have been part of commit eb550d0.
@timohl, could you help with a second set of eyes reviewing the documentation changes and the PR description? |
@henryiii, can you think of anything that I might be overlooking? |
@lanctot, could you help reviewing the documentation changes and the PR description? Will this work for https://github.com/google-deepmind/open_spiel? |
@isuruf for awareness mainly. — But please let me know if you believe this PR will cause issues for Conda. (I don't think so; I believe any adjustments that may be needed on the Conda side (for migrating to pybind11 v3.0.0) will be for changes that exist on pybind11 master already.) |
Sure. I can check tomorrow. |
Apparently the mis-indentation was introduced when resolving merge conflicts for what became 1e646c9
FWIW, I think https://github.com/pybind/pybind11_protobuf/blob/main/pybind11_protobuf/tests/regression_wrappers_test.py failed before 4b05643 |
Thanks @henryiii! I'll merge this asap, but I want to do this first: ChatGPT prompt:
Response: https://chatgpt.com/share/67c77bef-c554-8008-b23d-3ebab2b1572b |
…ficant contributions)
…ions (for completeness, unrelated to smart_holder work).
…major and/or influential contributors to smart_holder branch * pybind#2904 by @rhaschke was merged on Mar 16, 2021 * pybind#3012 by @rhaschke was merged on May 28, 2021 * pybind#3039 by @jakobandersen was merged on Jun 29, 2021 * pybind#3048 by @Skylion007 was merged on Jun 18, 2021 * pybind#3588 by @virtuald was merged on Jan 3, 2022 * pybind#3633 by @wangxf123456 was merged on Jan 25, 2022 * pybind#3635 by @virtuald was merged on Jan 26, 2022 * pybind#3645 by @wangxf123456 was merged on Jan 25, 2022 * pybind#3796 by @wangxf123456 was merged on Mar 10, 2022 * pybind#3807 by @wangxf123456 was merged on Mar 18, 2022 * pybind#3838 by @wangxf123456 was merged on Apr 15, 2022 * pybind#3929 by @tomba was merged on May 7, 2022 * pybind#4031 by @wangxf123456 was merged on Jun 27, 2022 * pybind#4343 by @wangxf123456 was merged on Nov 18, 2022 * pybind#4381 by @wangxf123456 was merged on Dec 5, 2022 * pybind#4539 by @wangxf123456 was merged on Feb 28, 2023 * pybind#4609 by @wangxf123456 was merged on Apr 6, 2023 * pybind#4775 by @wangxf123456 was merged on Aug 3, 2023 * pybind#4921 by @iwanders was merged on Nov 7, 2023 * pybind#4924 by @iwanders was merged on Nov 6, 2023 * pybind#5401 by @msimacek was merged on Oct 8, 2024 Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com> Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com> Co-authored-by: Ivor Wanders <iwanders@users.noreply.github.com> Co-authored-by: Jakob Lykke Andersen <Jakob@caput.dk> Co-authored-by: Michael Šimáček <michael.simacek@oracle.com> Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com> Co-authored-by: Tomi Valkeinen <tomi.valkeinen@iki.fi> Co-authored-by: Xiaofei Wang <6218006+wangxf123456@users.noreply.github.com>
Not rerunning GitHub Actions before merging: The last three commits (9bb8d06, b9bf98a, 8e432e9) only update the top-level README.rst I added For visibility: |
I want to say thank you very much to:
My main goal was to reunify the entire pybind11 ecosystem, and I hope this work brings lasting benefits to everyone. |
Huge thanks to everyone involved here, everyone in the pybind11 team and rwgk especially! This branch and the pybind11 project are providing huge value to us, making many things possible which would otherwise be far out of reach for us! Huge thanks!!!! |
Is there a clear set of steps to update my code that was using the smart holder branch before? The changes I had made to use the smart holder branch are:
py::class_<MyClass, PYBIND11_SH_DEF(MyClass)>(m, "MyClass"); Is the solution here to just change this to:
? |
Yes.
Yes. It doesn't answer your exact questions, but I'm interested in feedback. |
One thing I ran into when removing PYBIND11_USE_SMART_HOLDER_AS_DEFAULT was that I had to explicitly add py::smart_holder to the helpers in std_bind like py::bind_vector. |
Like this, in your bindings code? py::bind_vector<CppType, py::smart_holder>(m, "CppTypeVector"); We should probably mention that in the upgrade guide. |
Exactly, the class_ -> classh does not cover that one. So some debugging was needed to figure out that ones was still using the old one. |
Does this guide exist already? |
In #5589. I think we should focus on recommending |
I just added this commit for the Upgrade guide:
Without calling out that I verified that this was actually the only situation of this kind:
@petersteneteg's situation is probably very unusual, because he is an early adopter and used to work with |
Description
EDIT: The smart_holder branch was archived here after this PR was merged.
Notes:
For benchmarking results, see PR [smart_holder] smart_holder / master benchmarking 2025-02-16 #5529.
The only one existing (on master) test that is changed slightly is test_class.cpp/py. This is only to accommodate testing with
PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
(this exists primarily to ensure thatpy::smart_holder
is fully compatible with all existing functionality).All code was formally reviewed at least once. Much of the code was formally reviewed multiple times (as it was moved around between branches).
The only changes not reviewed already were merged (into smart_holder) under PR [smart_holder] Remove obsolete
detail::type_info::default_holder
member. #5541. All other code has been in production use at Google since September 2024. The smart_holder branch has been in production use at Google since February 2021. I.e. this code is extremely thoroughly tested. Additionally, testing via PyCLIF-pybind11 provided thousands of diverse use cases that needed to satisfy many million unit tests (the PyCLIF-pybind11 success was about 99.999%).The only significant updates under
docs/
are indocs/advanced/smart_ptrs.rst
anddocs/advanced/classes.rst
. The rest of thedocs/
updates are mostly mechanical, to replacepy::class_
withpy::classh
(based on this rationale).For easy reference, other recent PRs enabling this one:
PYBIND11_INTERNALS_VERSION
s4
and5
#5530The following is for this PR at commit a4cfd38:
git diff
counts under include/:git diff master include/ | grep '^-' | grep -v '^---' | wc -l
)git diff master include/ | grep '^+' | grep -v '^+++' | wc -l
)I.e., the existing production code is barely touched.
Similarly for tests/:
For more detail, results produced by
cloc --diff
for include/ between the master branch and this PR:I.e., this PR increases the production code size by 7.8%.
The squash-commit cd1c9d4 includes these smart_holder PRs not authored by @rwgk, sorted chronologically:
return_as_bytes
#3838 by @wangxf123456 was merged on Apr 15, 2022unique_ptr<Derived>
asunique_ptr<Base>
. #4031 by @wangxf123456 was merged on Jun 27, 2022_clif_automatic
#4343 by @wangxf123456 was merged on Nov 18, 2022try_as_void_ptr_capsule
as a free function #4539 by @wangxf123456 was merged on Feb 28, 2023unique_ptr
acceptautomatic_reference
#4775 by @wangxf123456 was merged on Aug 3, 2023Suggested changelog entry:
To be covered in the upgrade guide:
copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled
move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled