forked from pybind/pybind11
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conversions between Python's native (stdlib) enum types and C++ enums…
…. (#30005) * Transfer PR pybind#4329 from master to smart_holder branch, STEP 1. The patch .rej below are resolved, but THIS STATE DOES NOT BUILD: ``` clang++ -o pybind11/tests/test_constants_and_functions.os -c -std=c++17 -fPIC -fvisibility=hidden -O0 -g -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated -Wundef -Wnon-virtual-dtor -Wunused-result -Werror -isystem /usr/include/python3.10 -isystem /usr/include/eigen3 -DPYBIND11_STRICT_ASSERTS_CLASS_HOLDER_VS_TYPE_CASTER_MIX -DPYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD_IF_AVAILABLE -DPYBIND11_TEST_BOOST -Ipybind11/include -I/usr/local/google/home/rwgk/forked/pybind11/include -I/usr/local/google/home/rwgk/clone/pybind11/include /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp In file included from /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp:11: In file included from /usr/local/google/home/rwgk/forked/pybind11/tests/pybind11_tests.h:3: In file included from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/eval.h:14: /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/pybind11.h:1781:9: error: static_assert failed due to requirement '!holder_is_smart_holder == type_caster_type_is_type_caster_base_subtype' "py::class_ holder vs type_caster mismatch: missing PYBIND11_TYPE_CASTER_BASE_HOLDER(T, ...) or collision with custom py::detail::type_caster<T>?" static_assert(!holder_is_smart_holder == type_caster_type_is_type_caster_base_subtype, ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/pybind11.h:2460:11: note: in instantiation of function template specialization 'pybind11::class_<MyEnum>::class_<>' requested here : class_<Type>(scope, name, extra...), m_base(*this, scope) { ^ /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp:106:5: note: in instantiation of function template specialization 'pybind11::enum_<MyEnum>::enum_<>' requested here py::enum_<MyEnum>(m, "MyEnum") ^ 1 error generated. ``` ________ ``` rwgk.c.googlers.com:~/forked/pybind11 $ patch -p 1 < ~/native_enum_git_diff_master_2022-11-19+131942.patch patching file .github/workflows/python312.yml patching file CMakeLists.txt Hunk #1 FAILED at 111. Hunk #2 succeeded at 138 (offset 5 lines). 1 out of 2 hunks FAILED -- saving rejects to file CMakeLists.txt.rej patching file include/pybind11/cast.h Hunk #1 FAILED at 12. Hunk #2 succeeded at 78 (offset 30 lines). Hunk #3 succeeded at 1173 (offset 41 lines). 1 out of 3 hunks FAILED -- saving rejects to file include/pybind11/cast.h.rej patching file include/pybind11/detail/abi_platform_id.h patching file include/pybind11/detail/cross_extension_shared_state.h patching file include/pybind11/detail/internals.h Hunk #1 FAILED at 16. Hunk #2 succeeded at 109 (offset 1 line). Hunk #3 FAILED at 203. Hunk #4 succeeded at 398 (offset 11 lines). Hunk #5 succeeded at 457 (offset 11 lines). 2 out of 5 hunks FAILED -- saving rejects to file include/pybind11/detail/internals.h.rej patching file include/pybind11/detail/native_enum_data.h patching file include/pybind11/detail/type_map.h patching file include/pybind11/embed.h patching file include/pybind11/native_enum.h patching file include/pybind11/pybind11.h Hunk #1 FAILED at 12. Hunk #2 succeeded at 1269 (offset 1 line). Hunk #3 succeeded at 2457 (offset 255 lines). 1 out of 3 hunks FAILED -- saving rejects to file include/pybind11/pybind11.h.rej patching file include/pybind11/pytypes.h patching file tests/CMakeLists.txt Hunk #1 succeeded at 160 (offset 18 lines). patching file tests/conftest.py patching file tests/extra_python_package/test_files.py Hunk #2 FAILED at 47. 1 out of 2 hunks FAILED -- saving rejects to file tests/extra_python_package/test_files.py.rej patching file tests/test_embed/test_interpreter.cpp patching file tests/test_enum.cpp patching file tests/test_enum.py patching file tests/test_native_enum.cpp patching file tests/test_native_enum.py ``` * Make `smart_holder` code compatible with `type_caster_enum_type` * Fix `if` condition guarding `Unable to cast native enum type to reference` * WIP native_enum_add_to_parent * PYBIND11_SILENCE_MSVC_C4127 * Transfer upstream.yml/python312.yml changes from PR pybind#4397 * clang-tidy (clang 15) auto-fix * Remove python312.yml: this is handled separately under PR #30006 * Fixes for ruff * Replace `PyEval_GetBuiltins()` in `finalize_interpreter()` with `get_python_state_dict()` * Bug fix: Ensure `state_dict` is destroyed before `Py_Finalize()` * Restore tests/test_embed/test_interpreter.cpp from google_pywrapcc_main * Restore include/pybind11/embed.h from google_pywrapcc_main * Undo unrelated one-line change (from `auto` to `internals`). * Add missing `test_class_with_enum` * Add note to docs/classes.rst pointing to PR #30005
- Loading branch information
Ralf W. Grosse-Kunstleve
authored
Mar 16, 2023
1 parent
92741e7
commit f8128f0
Showing
15 changed files
with
804 additions
and
17 deletions.
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
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,129 @@ | ||
// Copyright (c) 2022 The pybind Community. | ||
// All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
#pragma once | ||
|
||
#include "../pytypes.h" | ||
#include "abi_platform_id.h" | ||
#include "common.h" | ||
#include "cross_extension_shared_state.h" | ||
#include "type_map.h" | ||
|
||
#include <string> | ||
#include <typeindex> | ||
|
||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | ||
PYBIND11_NAMESPACE_BEGIN(detail) | ||
|
||
class native_enum_data { | ||
public: | ||
native_enum_data(const char *enum_name, | ||
const std::type_index &enum_type_index, | ||
bool use_int_enum) | ||
: enum_name_encoded{enum_name}, enum_type_index{enum_type_index}, | ||
use_int_enum{use_int_enum}, enum_name{enum_name} {} | ||
|
||
native_enum_data(const native_enum_data &) = delete; | ||
native_enum_data &operator=(const native_enum_data &) = delete; | ||
|
||
void disarm_correct_use_check() const { correct_use_check = false; } | ||
void arm_correct_use_check() const { correct_use_check = true; } | ||
|
||
// This is a separate public function only to enable easy unit testing. | ||
std::string was_not_added_error_message() const { | ||
return "`native_enum` was not added to any module." | ||
" Use e.g. `m += native_enum<...>(\"" | ||
+ enum_name_encoded + "\")` to fix."; | ||
} | ||
|
||
#if !defined(NDEBUG) | ||
// This dtor cannot easily be unit tested because it terminates the process. | ||
~native_enum_data() { | ||
if (correct_use_check) { | ||
pybind11_fail(was_not_added_error_message()); | ||
} | ||
} | ||
#endif | ||
|
||
private: | ||
mutable bool correct_use_check{false}; | ||
|
||
public: | ||
std::string enum_name_encoded; | ||
std::type_index enum_type_index; | ||
bool use_int_enum; | ||
bool export_values_flag{false}; | ||
str enum_name; | ||
list members; | ||
list docs; | ||
}; | ||
|
||
PYBIND11_NAMESPACE_END(detail) | ||
|
||
PYBIND11_NAMESPACE_BEGIN(cross_extension_shared_states) | ||
|
||
struct native_enum_type_map_v1_adapter { | ||
static constexpr const char *abi_id() { | ||
return "__pybind11_native_enum_type_map_v1" PYBIND11_PLATFORM_ABI_ID_V4 "__"; | ||
} | ||
|
||
using payload_type = detail::type_map<PyObject *>; | ||
|
||
static void payload_clear(payload_type &payload) { | ||
for (auto it : payload) { | ||
Py_DECREF(it.second); | ||
} | ||
payload.clear(); | ||
} | ||
}; | ||
|
||
using native_enum_type_map_v1 | ||
= detail::cross_extension_shared_state<native_enum_type_map_v1_adapter>; | ||
using native_enum_type_map = native_enum_type_map_v1; | ||
|
||
PYBIND11_NAMESPACE_END(cross_extension_shared_states) | ||
|
||
PYBIND11_NAMESPACE_BEGIN(detail) | ||
|
||
inline void native_enum_add_to_parent(object parent, const detail::native_enum_data &data) { | ||
data.disarm_correct_use_check(); | ||
if (hasattr(parent, data.enum_name)) { | ||
pybind11_fail("pybind11::native_enum<...>(\"" + data.enum_name_encoded | ||
+ "\"): an object with that name is already defined"); | ||
} | ||
auto enum_module = reinterpret_steal<object>(PyImport_ImportModule("enum")); | ||
if (!enum_module) { | ||
raise_from(PyExc_SystemError, | ||
"`import enum` FAILED at " __FILE__ ":" PYBIND11_TOSTRING(__LINE__)); | ||
} | ||
auto py_enum_type = enum_module.attr(data.use_int_enum ? "IntEnum" : "Enum"); | ||
auto py_enum = py_enum_type(data.enum_name, data.members); | ||
if (hasattr(parent, "__module__")) { | ||
// Enum nested in class: | ||
py_enum.attr("__module__") = parent.attr("__module__"); | ||
} else { | ||
py_enum.attr("__module__") = parent; | ||
} | ||
parent.attr(data.enum_name) = py_enum; | ||
if (data.export_values_flag) { | ||
for (auto member : data.members) { | ||
auto member_name = member[int_(0)]; | ||
if (hasattr(parent, member_name)) { | ||
pybind11_fail("pybind11::native_enum<...>(\"" + data.enum_name_encoded | ||
+ "\").value(\"" + member_name.cast<std::string>() | ||
+ "\"): an object with that name is already defined"); | ||
} | ||
parent.attr(member_name) = py_enum[member_name]; | ||
} | ||
} | ||
for (auto doc : data.docs) { | ||
py_enum[doc[int_(0)]].attr("__doc__") = doc[int_(1)]; | ||
} | ||
cross_extension_shared_states::native_enum_type_map::get()[data.enum_type_index] | ||
= py_enum.release().ptr(); | ||
} | ||
|
||
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
Oops, something went wrong.