diff --git a/include/pybind11/detail/native_enum_data.h b/include/pybind11/detail/native_enum_data.h index 7055054b..fc60f127 100644 --- a/include/pybind11/detail/native_enum_data.h +++ b/include/pybind11/detail/native_enum_data.h @@ -36,7 +36,7 @@ class native_enum_data { 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."; + + enum_name_encoded + "\", ...)` to fix."; } #if !defined(NDEBUG) diff --git a/include/pybind11/native_enum.h b/include/pybind11/native_enum.h index 13c15ab9..00a317e5 100644 --- a/include/pybind11/native_enum.h +++ b/include/pybind11/native_enum.h @@ -15,18 +15,17 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +enum class native_enum_kind { Enum, IntEnum }; + /// Conversions between Python's native (stdlib) enum types and C++ enums. template class native_enum : public detail::native_enum_data { public: using Underlying = typename std::underlying_type::type; - explicit native_enum(const char *name) - : detail::native_enum_data(name, - std::type_index(typeid(Type)), - std::numeric_limits::is_integer - && !std::is_same::value - && !detail::is_std_char_type::value) { + explicit native_enum(const char *name, native_enum_kind kind) + : detail::native_enum_data( + name, std::type_index(typeid(Type)), kind == native_enum_kind::IntEnum) { if (detail::get_local_type_info(typeid(Type)) != nullptr || detail::get_global_type_info(typeid(Type)) != nullptr) { pybind11_fail( diff --git a/tests/test_native_enum.cpp b/tests/test_native_enum.cpp index b0c1aae8..385c3a42 100644 --- a/tests/test_native_enum.cpp +++ b/tests/test_native_enum.cpp @@ -74,35 +74,36 @@ TEST_SUBMODULE(native_enum, m) { m.attr("native_enum_type_map_abi_id_c_str") = py::cross_extension_shared_states::native_enum_type_map::abi_id(); - m += py::native_enum("smallenum") + m += py::native_enum("smallenum", py::native_enum_kind::IntEnum) .value("a", smallenum::a) .value("b", smallenum::b) .value("c", smallenum::c); - m += py::native_enum("color") + m += py::native_enum("color", py::native_enum_kind::IntEnum) .value("red", color::red) .value("yellow", color::yellow) .value("green", color::green) .value("blue", color::blue); - m += py::native_enum("altitude") + m += py::native_enum("altitude", py::native_enum_kind::Enum) .value("high", altitude::high) .value("low", altitude::low); - m += py::native_enum("export_values") + m += py::native_enum("export_values", py::native_enum_kind::IntEnum) .value("exv0", export_values::exv0) .value("exv1", export_values::exv1) .export_values(); - m += py::native_enum("member_doc") + m += py::native_enum("member_doc", py::native_enum_kind::IntEnum) .value("mem0", member_doc::mem0, "docA") .value("mem1", member_doc::mem1) .value("mem2", member_doc::mem2, "docC"); py::class_ py_class_with_enum(m, "class_with_enum"); - py_class_with_enum += py::native_enum("in_class") - .value("one", class_with_enum::in_class::one) - .value("two", class_with_enum::in_class::two); + py_class_with_enum + += py::native_enum("in_class", py::native_enum_kind::IntEnum) + .value("one", class_with_enum::in_class::one) + .value("two", class_with_enum::in_class::two); m.def("isinstance_color", [](const py::object &obj) { return py::isinstance(obj); }); @@ -136,28 +137,33 @@ TEST_SUBMODULE(native_enum, m) { m.def("native_enum_ctor_malformed_utf8", [](const char *malformed_utf8) { enum fake { x }; - py::native_enum{malformed_utf8}; + py::native_enum{malformed_utf8, py::native_enum_kind::IntEnum}; }); m.def("native_enum_value_malformed_utf8", [](const char *malformed_utf8) { enum fake { x }; - py::native_enum("fake").value(malformed_utf8, fake::x); + py::native_enum("fake", py::native_enum_kind::IntEnum) + .value(malformed_utf8, fake::x); }); m.def("double_registration_native_enum", [](py::module_ m) { enum fake { x }; - m += py::native_enum("fake_double_registration_native_enum").value("x", fake::x); - py::native_enum("fake_double_registration_native_enum"); + m += py::native_enum("fake_double_registration_native_enum", + py::native_enum_kind::IntEnum) + .value("x", fake::x); + py::native_enum("fake_double_registration_native_enum", py::native_enum_kind::Enum); }); m.def("native_enum_name_clash", [](py::module_ m) { enum fake { x }; - m += py::native_enum("fake_native_enum_name_clash").value("x", fake::x); + m += py::native_enum("fake_native_enum_name_clash", py::native_enum_kind::IntEnum) + .value("x", fake::x); }); m.def("native_enum_value_name_clash", [](py::module_ m) { enum fake { x }; - m += py::native_enum("fake_native_enum_value_name_clash") + m += py::native_enum("fake_native_enum_value_name_clash", + py::native_enum_kind::IntEnum) .value("fake_native_enum_value_name_clash_x", fake::x) .export_values(); }); @@ -165,19 +171,23 @@ TEST_SUBMODULE(native_enum, m) { m.def("double_registration_enum_before_native_enum", [](const py::module_ &m) { enum fake { x }; py::enum_(m, "fake_enum_first").value("x", fake::x); - py::native_enum("fake_enum_first").value("x", fake::x); + py::native_enum("fake_enum_first", py::native_enum_kind::IntEnum) + .value("x", fake::x); }); m.def("double_registration_native_enum_before_enum", [](py::module_ m) { enum fake { x }; - m += py::native_enum("fake_native_enum_first").value("x", fake::x); + m += py::native_enum("fake_native_enum_first", py::native_enum_kind::IntEnum) + .value("x", fake::x); py::enum_(m, "name_must_be_different_to_reach_desired_code_path"); }); #if defined(PYBIND11_NEGATE_THIS_CONDITION_FOR_LOCAL_TESTING) && !defined(NDEBUG) m.def("native_enum_correct_use_failure", []() { enum fake { x }; - py::native_enum("fake_native_enum_correct_use_failure").value("x", fake::x); + py::native_enum("fake_native_enum_correct_use_failure", + py::native_enum_kind::IntEnum) + .value("x", fake::x); }); #else m.attr("native_enum_correct_use_failure") = "For local testing only: terminates process"; diff --git a/tests/test_native_enum.py b/tests/test_native_enum.py index 3e0bf7ed..da2d25c3 100644 --- a/tests/test_native_enum.py +++ b/tests/test_native_enum.py @@ -154,7 +154,7 @@ def test_native_enum_data_was_not_added_error_message(): msg = m.native_enum_data_was_not_added_error_message("Fake") assert msg == ( "`native_enum` was not added to any module." - ' Use e.g. `m += native_enum<...>("Fake")` to fix.' + ' Use e.g. `m += native_enum<...>("Fake", ...)` to fix.' )