From 289e5d9cc2a4545d832d3c7fb50066476bce3c1d Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Mon, 2 Apr 2018 23:26:48 +0200 Subject: [PATCH] Implement an enum_ property "name" The property returns the enum_ value as a string. For example: >>> import module >>> module.enum.VALUE enum.VALUE >>> str(module.enum.VALUE) 'enum.VALUE' >>> module.enum.VALUE.name 'VALUE' This is actually the equivalent of Boost.Python "name" property. --- docs/classes.rst | 18 ++++++++++++++++++ include/pybind11/pybind11.h | 8 ++++++++ tests/test_enum.py | 13 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/docs/classes.rst b/docs/classes.rst index 890257d5d..75a8fb2c8 100644 --- a/docs/classes.rst +++ b/docs/classes.rst @@ -488,6 +488,24 @@ The entries defined by the enumeration type are exposed in the ``__members__`` p >>> Pet.Kind.__members__ {'Dog': Kind.Dog, 'Cat': Kind.Cat} +The ``name`` property returns the name of the enum value as a unicode string. + +.. note:: + + It is also possible to use ``str(enum)``, however these accomplish different + goals. The following shows how these two approaches differ. + + .. code-block:: pycon + + >>> p = Pet( "Lucy", Pet.Cat ) + >>> pet_type = p.type + >>> pet_type + Pet.Cat + >>> str(pet_type) + 'Pet.Cat' + >>> pet_type.name + 'Cat' + .. note:: When the special tag ``py::arithmetic()`` is specified to the ``enum_`` diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c7751eb29..6947d440f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1364,6 +1364,7 @@ detail::initimpl::pickle_factory pickle(GetState &&g, SetSta template class enum_ : public class_ { public: using class_::def; + using class_::def_property_readonly; using class_::def_property_readonly_static; using Scalar = typename std::underlying_type::type; @@ -1381,6 +1382,13 @@ public: } return pybind11::str("{}.???").format(name); }); + def_property_readonly("name", [m_entries_ptr](Type value) -> pybind11::str { + for (const auto &kv : reinterpret_borrow(m_entries_ptr)) { + if (pybind11::cast(kv.second[int_(0)]) == value) + return pybind11::str(kv.first); + } + return pybind11::str("???"); + }); def_property_readonly_static("__doc__", [m_entries_ptr](handle self) { std::string docstring; const char *tp_doc = ((PyTypeObject *) self.ptr())->tp_doc; diff --git a/tests/test_enum.py b/tests/test_enum.py index d3f5b4d1b..c2c272a25 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -6,6 +6,19 @@ def test_unscoped_enum(): assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" assert str(m.EOne) == "UnscopedEnum.EOne" + + # name property + assert m.UnscopedEnum.EOne.name == "EOne" + assert m.UnscopedEnum.ETwo.name == "ETwo" + assert m.EOne.name == "EOne" + # name readonly + with pytest.raises(AttributeError): + m.UnscopedEnum.EOne.name = "" + # name returns a copy + foo = m.UnscopedEnum.EOne.name + foo = "bar" + assert m.UnscopedEnum.EOne.name == "EOne" + # __members__ property assert m.UnscopedEnum.__members__ == \ {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}