Enum Class Method With Default Enum Value Fails
Solution 1:
While it's definitely a workaround, this seemed to work well for me:
@classmethod
def get_all_releases(cls, release: "Release" = Canary): # Default Value = Release.Canary
if release == (Release.Canary.value,):
return Release.Canary.current
return release.current
It does work for whatever value you assign to Canary
. So as long as that is your default I believe it will work.
To be more general so that you'd only have to adjust the default in the class definition instead of each function, you could do it as follows:
class Release(Enum):
Canary = 6,
Beta = 2,
RC = 3,
Stable = 4
default = Canary
...
@classmethod
def get_all_releases(cls, release: "Release" = default):
if release == (Release.Canary.value,):
return Release.Canary.current
return release.current
Solution 2:
Took a hint from @ufoxDan with his answer, but tried to make it less workaround-y and more natural.
Basically, I started by checking the type(release)
before return
ing and noticed that I got the results of..
<enum 'Release'>
<enum 'Release'>
<enum 'Release'>
<enum 'Release'>
<class 'tuple'>
I noticed that if the type was Release
then I can just execute the code, however if it was anything else, like None
instead of the uncreated Canary
type, then I could assume it was asking for Canary
. So I did the following...
@classmethod
def get_all_releases(cls, release: "Release" = None):
if type(release) is Release:
return release.current
return Release.Canary.current
# Now these all work
print(Release.get_all_releases())
print(Release.get_all_releases(Release.Canary))
print(Release.get_all_releases(Release.Stable))
This appears to be the most pythonic way of achieving the results. This seems to also be the best way while reading the code and without repeating code. Anyone should be able to implement something similar it seems.
Solution 3:
There are a couple things you can do in your Release
Enum
to make life easier, the first being a technique shown here:
def __new__(cls, value, cascade):
obj = object.__new__(cls)
obj._value_ = value
obj.current = ["Release" * value] # not sure what this should actually be
# if always the previous versions (don't need cascade defined)
obj.cascade = sorted(list(cls), reverse=True)
# if some already defined subset (need cascade defined)
obj.cascade = [cls._value2member_map_(c) for c in cascade]
return obj
The second technique can go two ways -- your default is always the first Enum
member:
@classmethod
def get_all_releases(cls):
return list(cls[0]).current
or, if the default could be any member, then something similar to this answer should work:
class add_default:
"""
add DEFAULT psuedo-member to enumeration; use first member if none specified
(default should be name of member)
"""
def __init__(self, default=''):
self._default = default
def __call__(self, enumeration):
if self._default:
member = enumeration[self._default]
else:
member = enumeration[enumeration._member_names_[0]]
enumeration._member_map_['DEFAULT'] = member
return enumeration
Your final Enum
would then look like (assuming cascade
is all previous members and using the decorator approach):
@add_default('Canary')
class Release(Enum):
Canary = 1
Beta = 2
RC = 3
Stable = 4
def __new__(cls, value):
obj = object.__new__(cls)
obj._value_ = value
obj.current = ["Release" * value] # not sure what this should actually be or how it's calculated
obj.cascade = list(cls)[::-1]
return obj
@classmethod
def get_all_releases(cls, release: "Release" = None):
if release is None:
release = cls.DEFAULT
return release.current
and in use:
>>> Release.DEFAULT
<Release.Canary: 1>
>>> Release.get_all_releases()
['Release']
>>> Release.get_all_releases(Release.RC)
['ReleaseReleaseRelease']
Original Answer
The problem you are having with your code is here:
class Release(Enum):
Canary = 1,
By including that extra comma you have made the value for Canary
be (1, )
. Remove that comma to get rid of the tuple
exception.
Post a Comment for "Enum Class Method With Default Enum Value Fails"