diff --git a/docs/changelog.rst b/docs/changelog.rst index b0d958d49..ec8dc7203 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,9 @@ v2.3.0 (Not yet released) * Added support for write only properties. `#1144 `_. +* The ``value()`` method of ``py::enum_`` now accepts an optional docstring + that will be shown in the documentation of the associated enumeration. + v2.2.1 (September 14, 2017) ----------------------------------------------------- diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b489bb249..5bd2cccc4 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1375,15 +1375,30 @@ public: auto m_entries_ptr = m_entries.inc_ref().ptr(); def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str { for (const auto &kv : reinterpret_borrow(m_entries_ptr)) { - if (pybind11::cast(kv.second) == value) + if (pybind11::cast(kv.second[int_(0)]) == value) return pybind11::str("{}.{}").format(name, kv.first); } return pybind11::str("{}.???").format(name); }); - def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) { + def_property_readonly_static("__doc__", [m_entries_ptr](handle self) { + std::string docstring; + const char *tp_doc = ((PyTypeObject *) self.ptr())->tp_doc; + if (tp_doc) + docstring += std::string(tp_doc) + "\n\n"; + docstring += "Members:"; + for (const auto &kv : reinterpret_borrow(m_entries_ptr)) { + auto key = std::string(pybind11::str(kv.first)); + auto comment = kv.second[int_(1)]; + docstring += "\n\n " + key; + if (!comment.is_none()) + docstring += " : " + (std::string) pybind11::str(comment); + } + return docstring; + }); + def_property_readonly_static("__members__", [m_entries_ptr](handle /* self */) { dict m; for (const auto &kv : reinterpret_borrow(m_entries_ptr)) - m[kv.first] = kv.second; + m[kv.first] = kv.second[int_(0)]; return m; }, return_value_policy::copy); def(init([](Scalar i) { return static_cast(i); })); @@ -1431,15 +1446,15 @@ public: /// Export enumeration entries into the parent scope enum_& export_values() { for (const auto &kv : m_entries) - m_parent.attr(kv.first) = kv.second; + m_parent.attr(kv.first) = kv.second[int_(0)]; return *this; } /// Add an enumeration entry - enum_& value(char const* name, Type value) { + enum_& value(char const* name, Type value, const char *doc = nullptr) { auto v = pybind11::cast(value, return_value_policy::copy); this->attr(name) = v; - m_entries[pybind11::str(name)] = v; + m_entries[pybind11::str(name)] = std::make_pair(v, doc); return *this; } diff --git a/tests/test_enum.cpp b/tests/test_enum.cpp index 49f31ba1f..4cd14a96a 100644 --- a/tests/test_enum.cpp +++ b/tests/test_enum.cpp @@ -15,9 +15,9 @@ TEST_SUBMODULE(enums, m) { EOne = 1, ETwo }; - py::enum_(m, "UnscopedEnum", py::arithmetic()) - .value("EOne", EOne) - .value("ETwo", ETwo) + py::enum_(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") + .value("EOne", EOne, "Docstring for EOne") + .value("ETwo", ETwo, "Docstring for ETwo") .export_values(); // test_scoped_enum diff --git a/tests/test_enum.py b/tests/test_enum.py index d8eff5278..d3f5b4d1b 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -18,6 +18,22 @@ def test_unscoped_enum(): assert m.UnscopedEnum.__members__ == \ {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo} + assert m.UnscopedEnum.__doc__ == \ + '''An unscoped enumeration + +Members: + + EOne : Docstring for EOne + + ETwo : Docstring for ETwo''' or m.UnscopedEnum.__doc__ == \ + '''An unscoped enumeration + +Members: + + ETwo : Docstring for ETwo + + EOne : Docstring for EOne''' + # no TypeError exception for unscoped enum ==/!= int comparisons y = m.UnscopedEnum.ETwo assert y == 2