-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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: enable type-safe interoperability between different independent Python/C++ bindings systems. #5296
Merged
Merged
feat: enable type-safe interoperability between different independent Python/C++ bindings systems. #5296
Changes from all commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
3f522e5
`self.__cpp_transporter__()` proof of concept: Enable passing C++ poi…
900bc26
Include cleanup (mainly to resolve PyPy build failures).
2fbe930
Fix clang-tidy errors.
7c951c5
Merge branch 'master' into cpp_transporter
2dd6c7a
Resolve `error: extra
2617a04
Merge branch 'master' into cpp_transporter
87ebc39
factor out platform_abi_id.h from internals.h (no functional changes)
3ccea8c
factor out internals_version.h from internals.h (no functional changes)
a09d600
Update CMakeLists.txt, tests/extra_python_package/test_files.py
2fde1bd
Revert "factor out internals_version.h from internals.h (no functiona…
0a29d05
Remove internals_version.h from CMakeLists.txt, tests/extra_python_pa…
59f3036
Merge branch 'master' into cpp_transporter
d2479aa
`.__cpp_transporter__()` implementation: compare `pybind11_platform_a…
39ca2aa
Add PremiumTraveler
fc57b44
Rename test_cpp_transporter_traveler_type.h -> test_cpp_transporter_t…
3063c03
Expand tests: `PremiumTraveler`, `get_points()`
251bf91
Shuffle order of tests (no real changes).
2df540e
Move `__cpp_transporter__` lambda to `py::cpp_transporter()` regular …
757f885
Use `type_caster_generic::load(self)` instead of `cast<T *>(self)`
3951b63
Pass `const std::type_info *` via `py::capsule` (instead of `cpp_type…
14265bf
Merge branch 'master' into cpp_transporter
981a2a7
Make platform_abi_id.h completely stand-alone.
4e9a0c7
rename exo_planet.cpp -> exo_planet_pybind11.cpp
777ab9b
Add exo_planet_c_api.cpp (incomplete).
e220b42
Fix silly oversight (wrong filename in `#include`).
aa81066
Resolve clang-tidy errors:
caccc6f
Implement exo_planet_c_api GetLuggage(), GetPoints()
78c3c88
Move new code from test_cpp_transporter_traveler_bindings.h to pybind…
926c2ae
Fix oversight.
b442699
Unconditionally add `__cpp_transporter__` method to all `py::class_` …
e611471
Back out pybind11/detail/platform_abi_id.h for now. Maximizing reusab…
0a97c97
Small cleanup.
8a27b98
Restore and add to `test_call_cpp_transporter_*()`
80550a9
Ensure https://github.com/pybind/pybind11/issues/3788 does not bite a…
80ca683
`class_dunder_cpp_transporter()`: replace `obj.cast<std::string>()` w…
9cffdc9
Add (simple) copyright notices in all newly added files.
ce45db1
Globally replace cpp_transporter with cpp_conduit
4b77d6c
style: pre-commit fixes
pre-commit-ci[bot] 1bfb369
IWYU fixes
afb30a6
Rename `class_dunder_cpp_conduit()` -> `cpp_conduit_method()`
bae9959
Change `pybind11_platform_abi_id`, `pointer_kind` argument types from…
31134bc
Systematically rename `cap_cpp_type_info` -> `cpp_type_info_capsule` …
8ccddce
Systematically replace `cpp_type_info_capsule` `name`: `"const std::t…
b85bf0f
Fix sort order accident in tests/CMakeLists.txt
4b69dd8
Apply suggestions from code review
henryiii 19106f5
style: pre-commit fixes
pre-commit-ci[bot] 69890bb
refactor: rename to _pybind_conduit_v1_
henryiii 22dbfa6
Add test_home_planet_wrap_very_lonely_traveler(), test_exo_planet_pyb…
rwgk 62acc6b
Resolve clang-tidy errors:
rwgk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) 2024 The pybind Community. | ||
|
||
#pragma once | ||
|
||
#include <pybind11/pytypes.h> | ||
|
||
#include "common.h" | ||
#include "internals.h" | ||
|
||
#include <typeinfo> | ||
|
||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | ||
PYBIND11_NAMESPACE_BEGIN(detail) | ||
|
||
// Forward declaration needed here: Refactoring opportunity. | ||
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *); | ||
|
||
inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) { | ||
#if defined(PYPY_VERSION) | ||
auto &internals = get_internals(); | ||
return bool(internals.registered_types_py.find(type_obj) | ||
!= internals.registered_types_py.end()); | ||
#else | ||
return bool(type_obj->tp_new == pybind11_object_new); | ||
#endif | ||
} | ||
|
||
inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) { | ||
PyObject *descr = _PyType_Lookup(type_obj, attr_name); | ||
return bool((descr != nullptr) && PyInstanceMethod_Check(descr)); | ||
} | ||
|
||
inline object try_get_cpp_conduit_method(PyObject *obj) { | ||
if (PyType_Check(obj)) { | ||
return object(); | ||
} | ||
PyTypeObject *type_obj = Py_TYPE(obj); | ||
str attr_name("_pybind11_conduit_v1_"); | ||
bool assumed_to_be_callable = false; | ||
if (type_is_managed_by_our_internals(type_obj)) { | ||
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) { | ||
return object(); | ||
} | ||
assumed_to_be_callable = true; | ||
} | ||
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr()); | ||
if (method == nullptr) { | ||
PyErr_Clear(); | ||
return object(); | ||
} | ||
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) { | ||
Py_DECREF(method); | ||
return object(); | ||
} | ||
return reinterpret_steal<object>(method); | ||
} | ||
|
||
inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src, | ||
const std::type_info *cpp_type_info) { | ||
object method = try_get_cpp_conduit_method(src.ptr()); | ||
if (method) { | ||
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)), | ||
typeid(std::type_info).name()); | ||
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID), | ||
cpp_type_info_capsule, | ||
bytes("raw_pointer_ephemeral")); | ||
if (isinstance<capsule>(cpp_conduit)) { | ||
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer(); | ||
} | ||
} | ||
return nullptr; | ||
} | ||
|
||
#define PYBIND11_HAS_CPP_CONDUIT 1 | ||
|
||
PYBIND11_NAMESPACE_END(detail) | ||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// Copyright (c) 2024 The pybind Community. | ||
|
||
// THIS MUST STAY AT THE TOP! | ||
#include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID | ||
// Potential future direction to maximize reusability: | ||
// (e.g. for use from SWIG, Cython, PyCLIF, nanobind): | ||
// #include <pybind11/compat/platform_abi_id.h> | ||
// This would only depend on: | ||
// 1. A C++ compiler, WITHOUT requiring -fexceptions. | ||
// 2. Python.h | ||
|
||
#include "test_cpp_conduit_traveler_types.h" | ||
|
||
#include <Python.h> | ||
#include <typeinfo> | ||
|
||
namespace { | ||
|
||
void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) { | ||
PyObject *cpp_type_info_capsule | ||
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)), | ||
typeid(std::type_info).name(), | ||
nullptr); | ||
if (cpp_type_info_capsule == nullptr) { | ||
return nullptr; | ||
} | ||
PyObject *cpp_conduit = PyObject_CallMethod(py_obj, | ||
"_pybind11_conduit_v1_", | ||
"yOy", | ||
PYBIND11_PLATFORM_ABI_ID, | ||
cpp_type_info_capsule, | ||
"raw_pointer_ephemeral"); | ||
Py_DECREF(cpp_type_info_capsule); | ||
if (cpp_conduit == nullptr) { | ||
return nullptr; | ||
} | ||
void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name()); | ||
Py_DECREF(cpp_conduit); | ||
if (PyErr_Occurred()) { | ||
return nullptr; | ||
} | ||
return void_ptr; | ||
} | ||
|
||
template <typename T> | ||
T *get_cpp_conduit_type_ptr(PyObject *py_obj) { | ||
void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T)); | ||
if (void_ptr == nullptr) { | ||
return nullptr; | ||
} | ||
return static_cast<T *>(void_ptr); | ||
} | ||
|
||
extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) { | ||
const auto *cpp_traveler | ||
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler); | ||
if (cpp_traveler == nullptr) { | ||
return nullptr; | ||
} | ||
return PyUnicode_FromString(cpp_traveler->luggage.c_str()); | ||
} | ||
|
||
extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) { | ||
const auto *cpp_premium_traveler | ||
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>( | ||
premium_traveler); | ||
if (cpp_premium_traveler == nullptr) { | ||
return nullptr; | ||
} | ||
return PyLong_FromLong(static_cast<long>(cpp_premium_traveler->points)); | ||
} | ||
|
||
PyMethodDef ThisMethodDef[] = {{"GetLuggage", wrapGetLuggage, METH_O, nullptr}, | ||
{"GetPoints", wrapGetPoints, METH_O, nullptr}, | ||
{nullptr, nullptr, 0, nullptr}}; | ||
|
||
struct PyModuleDef ThisModuleDef = { | ||
PyModuleDef_HEAD_INIT, // m_base | ||
"exo_planet_c_api", // m_name | ||
nullptr, // m_doc | ||
-1, // m_size | ||
ThisMethodDef, // m_methods | ||
nullptr, // m_slots | ||
nullptr, // m_traverse | ||
nullptr, // m_clear | ||
nullptr // m_free | ||
}; | ||
|
||
} // namespace | ||
|
||
#if defined(WIN32) || defined(_WIN32) | ||
# define EXO_PLANET_C_API_EXPORT __declspec(dllexport) | ||
#else | ||
# define EXO_PLANET_C_API_EXPORT __attribute__((visibility("default"))) | ||
#endif | ||
|
||
extern "C" EXO_PLANET_C_API_EXPORT PyObject *PyInit_exo_planet_c_api() { | ||
PyObject *m = PyModule_Create(&ThisModuleDef); | ||
if (m == nullptr) { | ||
return nullptr; | ||
} | ||
return m; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright (c) 2024 The pybind Community. | ||
|
||
#if defined(PYBIND11_INTERNALS_VERSION) | ||
# undef PYBIND11_INTERNALS_VERSION | ||
#endif | ||
#define PYBIND11_INTERNALS_VERSION 900000001 | ||
|
||
#include "test_cpp_conduit_traveler_bindings.h" | ||
|
||
namespace pybind11_tests { | ||
namespace test_cpp_conduit { | ||
|
||
PYBIND11_MODULE(exo_planet_pybind11, m) { | ||
wrap_traveler(m); | ||
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); }); | ||
} | ||
|
||
} // namespace test_cpp_conduit | ||
} // namespace pybind11_tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) 2024 The pybind Community. | ||
|
||
#include "test_cpp_conduit_traveler_bindings.h" | ||
|
||
namespace pybind11_tests { | ||
namespace test_cpp_conduit { | ||
|
||
PYBIND11_MODULE(home_planet_very_lonely_traveler, m) { | ||
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); }); | ||
} | ||
|
||
} // namespace test_cpp_conduit | ||
} // namespace pybind11_tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright (c) 2024 The pybind Community. | ||
|
||
#include "pybind11_tests.h" | ||
#include "test_cpp_conduit_traveler_bindings.h" | ||
|
||
#include <typeinfo> | ||
|
||
namespace pybind11_tests { | ||
namespace test_cpp_conduit { | ||
|
||
TEST_SUBMODULE(cpp_conduit, m) { | ||
m.attr("PYBIND11_PLATFORM_ABI_ID") = py::bytes(PYBIND11_PLATFORM_ABI_ID); | ||
m.attr("cpp_type_info_capsule_Traveler") | ||
= py::capsule(&typeid(Traveler), typeid(std::type_info).name()); | ||
m.attr("cpp_type_info_capsule_int") = py::capsule(&typeid(int), typeid(std::type_info).name()); | ||
|
||
wrap_traveler(m); | ||
wrap_lonely_traveler(m); | ||
} | ||
|
||
} // namespace test_cpp_conduit | ||
} // namespace pybind11_tests |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 know it shows up a few other places, but I think this is frowned upon by lawyers from discussing this in context of other not-legally defined entities. What does the "The pybind Community" mean?