mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-29 16:37:13 +00:00
Merge pull request #666 from mdcb/master
Expose enum_ entries as new "__members__" attribute
This commit is contained in:
commit
414ee163cc
@ -423,6 +423,12 @@ typed enums.
|
|||||||
>>> int(p.type)
|
>>> int(p.type)
|
||||||
1L
|
1L
|
||||||
|
|
||||||
|
The entries defined by the enumeration type are exposed in the ``__members__`` property:
|
||||||
|
|
||||||
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
>>> Pet.Kind.__members__
|
||||||
|
{'Dog': Kind.Dog, 'Cat': Kind.Cat}
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -1116,24 +1116,32 @@ private:
|
|||||||
template <typename Type> class enum_ : public class_<Type> {
|
template <typename Type> class enum_ : public class_<Type> {
|
||||||
public:
|
public:
|
||||||
using class_<Type>::def;
|
using class_<Type>::def;
|
||||||
|
using class_<Type>::def_property_readonly_static;
|
||||||
using Scalar = typename std::underlying_type<Type>::type;
|
using Scalar = typename std::underlying_type<Type>::type;
|
||||||
template <typename T> using arithmetic_tag = std::is_same<T, arithmetic>;
|
template <typename T> using arithmetic_tag = std::is_same<T, arithmetic>;
|
||||||
|
|
||||||
template <typename... Extra>
|
template <typename... Extra>
|
||||||
enum_(const handle &scope, const char *name, const Extra&... extra)
|
enum_(const handle &scope, const char *name, const Extra&... extra)
|
||||||
: class_<Type>(scope, name, extra...), m_parent(scope) {
|
: class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) {
|
||||||
|
|
||||||
constexpr bool is_arithmetic =
|
constexpr bool is_arithmetic =
|
||||||
!std::is_same<detail::first_of_t<arithmetic_tag, void, Extra...>,
|
!std::is_same<detail::first_of_t<arithmetic_tag, void, Extra...>,
|
||||||
void>::value;
|
void>::value;
|
||||||
|
|
||||||
auto entries = new std::unordered_map<Scalar, const char *>();
|
auto m_entries_ptr = m_entries.inc_ref().ptr();
|
||||||
def("__repr__", [name, entries](Type value) -> std::string {
|
def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
|
||||||
auto it = entries->find((Scalar) value);
|
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
|
||||||
return std::string(name) + "." +
|
if (pybind11::cast<Type>(kv.second) == value)
|
||||||
((it == entries->end()) ? std::string("???")
|
return pybind11::str("{}.{}").format(name, kv.first);
|
||||||
: std::string(it->second));
|
}
|
||||||
|
return pybind11::str("{}.???").format(name);
|
||||||
});
|
});
|
||||||
|
def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) {
|
||||||
|
dict m;
|
||||||
|
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
|
||||||
|
m[kv.first] = kv.second;
|
||||||
|
return m;
|
||||||
|
}, return_value_policy::copy);
|
||||||
def("__init__", [](Type& value, Scalar i) { value = (Type)i; });
|
def("__init__", [](Type& value, Scalar i) { value = (Type)i; });
|
||||||
def("__init__", [](Type& value, Scalar i) { new (&value) Type((Type) i); });
|
def("__init__", [](Type& value, Scalar i) { new (&value) Type((Type) i); });
|
||||||
def("__int__", [](Type value) { return (Scalar) value; });
|
def("__int__", [](Type value) { return (Scalar) value; });
|
||||||
@ -1172,26 +1180,25 @@ public:
|
|||||||
// Pickling and unpickling -- needed for use with the 'multiprocessing' module
|
// Pickling and unpickling -- needed for use with the 'multiprocessing' module
|
||||||
def("__getstate__", [](const Type &value) { return pybind11::make_tuple((Scalar) value); });
|
def("__getstate__", [](const Type &value) { return pybind11::make_tuple((Scalar) value); });
|
||||||
def("__setstate__", [](Type &p, tuple t) { new (&p) Type((Type) t[0].cast<Scalar>()); });
|
def("__setstate__", [](Type &p, tuple t) { new (&p) Type((Type) t[0].cast<Scalar>()); });
|
||||||
m_entries = entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export enumeration entries into the parent scope
|
/// Export enumeration entries into the parent scope
|
||||||
enum_ &export_values() {
|
enum_& export_values() {
|
||||||
for (auto item : reinterpret_borrow<dict>(((PyTypeObject *) this->m_ptr)->tp_dict)) {
|
for (const auto &kv : m_entries)
|
||||||
if (isinstance(item.second, this->m_ptr))
|
m_parent.attr(kv.first) = kv.second;
|
||||||
m_parent.attr(item.first) = item.second;
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an enumeration entry
|
/// Add an enumeration entry
|
||||||
enum_& value(char const* name, Type value) {
|
enum_& value(char const* name, Type value) {
|
||||||
this->attr(name) = pybind11::cast(value, return_value_policy::copy);
|
auto v = pybind11::cast(value, return_value_policy::copy);
|
||||||
(*m_entries)[(Scalar) value] = name;
|
this->attr(name) = v;
|
||||||
|
m_entries[pybind11::str(name)] = v;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<Scalar, const char *> *m_entries;
|
dict m_entries;
|
||||||
handle m_parent;
|
handle m_parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,6 +7,15 @@ def test_unscoped_enum():
|
|||||||
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne"
|
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne"
|
||||||
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
|
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
|
||||||
assert str(EOne) == "UnscopedEnum.EOne"
|
assert str(EOne) == "UnscopedEnum.EOne"
|
||||||
|
# __members__ property
|
||||||
|
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo}
|
||||||
|
# __members__ readonly
|
||||||
|
with pytest.raises(AttributeError):
|
||||||
|
UnscopedEnum.__members__ = {}
|
||||||
|
# __members__ returns a copy
|
||||||
|
foo = UnscopedEnum.__members__
|
||||||
|
foo["bar"] = "baz"
|
||||||
|
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo}
|
||||||
|
|
||||||
# no TypeError exception for unscoped enum ==/!= int comparisons
|
# no TypeError exception for unscoped enum ==/!= int comparisons
|
||||||
y = UnscopedEnum.ETwo
|
y = UnscopedEnum.ETwo
|
||||||
|
Loading…
Reference in New Issue
Block a user