Uh oh!
There was an error while loading. Please reload this page.
WIP: Python 3 enums - #781
Conversation
aldanor
commented
Apr 5, 2017
Another point, implementation-wise, I guess it could be possible to avoid the unordered map of registered py3 enums ( |
jagerman
commented
Apr 6, 2017
Thoughts on having this replace the current It would break some potential backwards compatibility in that you can't use I definitely like the idea of storing a the values in a static variable in the |
jagerman
commented
Apr 6, 2017
It's caused by the |
jagerman
commented
Apr 6, 2017
I just had a thought about recreating the object each time you call template <typename T>
classpy3_enum {
...
classvalue_loader {
private:
py3_enum &owner;
friendclasspy3_enum;
value_loader(py3_enum &e) : owner{e} {}
public:
value_loader &value(constchar *name, T value) {
owner.entries[name] = cast(static_cast...);
return *this;
}
~value_loader() { owner.update(); }
};
value_loader value(constchar *name, T value) {
value_loader vl(*this);
vl.value(name, value);
return vl;
}
...
};Then the common approach: py_enum3<MyEnum>(m, "MyEnum")
.value("v1", MyEnum.v1)
.value("v2", MyEnum.v2)
.value("v3", MyEnum.v3)
;will only do the |
aldanor
commented
Apr 6, 2017
Thanks -- yes, that fixes it.
This could work if you still call |
a5d6d27 to
c5b5b58Comparealdanor
commented
Apr 6, 2017
The only disadvantage of the current implementation, as I see it, is that you can't define methods / properties on the newly created enum class, because it's not a Hypothetically, here's also an alternative implementation: define py3 enums through
Also, in this case you won't be able to do |
2fe1849 to
a4381aaComparefc629e2 to
d5e39cfCompareI've fixed a few things like setting @jagerman I've also tried out a very cheesy way of allowing to define properties and methods on Python 3 enums -- surprisingly it seemed to work, at least for simple cases I've tested -- so I pushed it as WIP in the last commit. If it's too hacky, can always roll it back. Basically, this seems to work: py3_enum<Foo>(m, "Foo")
.value("A", Foo::A)
.value("B", Foo::B)
.extend() // requires rvalue *this
.def_property_readonly("is_a", [](Foo x) { return x == Foo::A; }); |
aldanor
commented
Apr 6, 2017
Darn AppVeyor complaining all the time... |
jagerman
commented
Apr 6, 2017
I wonder if we should just turn off C4456 through C4459 warnings within pybind code. I don't really subscribe to the every-variable-must-be-unique idea of MS coding mentality that leads to silly things like prefixing all class members with some random character. |
aldanor
commented
Apr 6, 2017
I'd be +1 for sure, those warnings are very opinionated. |
Sound good to me. |
wjakob
commented
Apr 6, 2017
Actually, on second thought: let's try to keep pybind11 clean with respect to these warnings. Other projects may choose to activate a similarly strict set of warnings, and it would be unfortunate if pybind11 causes issues in that context. |
jagerman
commented
Apr 6, 2017
It won't cause external issues: the warnings are pushed at the beginning of pybind11.h and popped off at the end. |
wjakob
commented
Apr 6, 2017
Right.. I was thinking of |
dean0x7d
commented
Apr 6, 2017
I'd keep the warnings. C++ core guidelines / |
jagerman
commented
Apr 6, 2017
Fair enough. |
aldanor
commented
Apr 28, 2017
Guys, any ideas on this? I'd be willing to finish it (if anything) but there's a few unclear points. |
jagerman
commented
Apr 28, 2017
Assuming you mean your original post checklist, I vote for calling it But I vote for it being neither distinct nor public. Rather I think that I'm not sure it's really worth it to worry about supporting additional definitions and attributes on the bound enum. (Or in other words, I'm perfectly happy for this to be a documented limitation, possibly to be revisited later if someone has a strong use case for it). |
I agree with @jagerman: |
If we roll it into one
The biggest question re: backwards-compatibility here is what to do with Basically, declaration semantics are slightly different as enum34 needs to be "finalised" (currently, the type is fully recreated when you call py::enum_<Foo>(m, "Foo").value("A", Foo::A).def("f", ...).value("B", Foo::B).def("g", ...);-- I can't see how to make it work with enum34 implementation. |
dean0x7d
commented
May 1, 2017
That doesn't actually compile with the current I think the more important things for maintaining compatibility are: |
Hmm, seems like I've managed to make this work: py3_enum<Foo>(m, "Foo").value(...).value(...).def(...).def(...)-- however it required slight changes to If this is acceptable, I'll take a look at Re: |
jagerman
commented
May 2, 2017
Is there a significant value in being able to define custom methods on an enum? It feels a bit like chasing backwards compatibility with a feature which was never really intended or advertised, which I think we'd be reasonably justified to just stop supporting given the complexity that it adds. |
Well, idk, there's definitely some value. We actually have quite a few in our pybind11 codebase, it's quite handy -- mostly |
dean0x7d
commented
May 3, 2017
If adding methods to py::enum_<Foo>(m, "Foo")
.value("First", Foo::First)
.value("Second", Foo::Second)
.classify() // `class_` functions permitted after this point; no more `enum_`
.def("__str__", [](Foo const&) { ... });The classenum_ : publicclass_ { ... };to: classenum_ {
public:
class_& clasify() { return cls; }
private:
class_ cls;
};Using composition here instead of inheritance would simplify things overall since there would be no need for CRTP. |
@dean0x7d That's definitely reasonable and involves less hacks. In fact, that's exactly what I did initially if you look at the commit history for this branch (the only difference was that the method was called Note that there are potential edge cases with your suggested implementation, like: auto e = py::enum_<Foo>(m, "Foo")
.value("First", Foo::First)
.value("Second", Foo::Second);
auto c = e.classify()
.def("__str__", [](Foo const&) { ... });
e.value("Third", Foo::Third); // ???To avoid this, I tried marking P.S. |
aldanor
commented
May 7, 2017
wjakob
commented
Jun 10, 2019
I'll close this PR.: While wrapping Python 3 enums would be nice, it was never quite clear how to do this in a backwards-compatible way that preserves the semantics of the current enums. pybind11 now uses a less bloaty way of creating |
This adds support for wrapping C/C++ enums as Python 3's
enum.IntEnum(with@uniquedecorator applied). It would also work withenum34backport. If neither is available,ImportErrorwill be thrown. The existingenum_wrappers are untouched and should work as before.enum_fromclass_value().value().def().def()API, like the existingenum_<>class_interface<>APIpy::arithmetic.export_values()enum34enum_andenum34(Closes#530)