From 77e4e51a919c50e2847527aaffe67e8e19b970ae Mon Sep 17 00:00:00 2001 From: Stefan Israelsson Tampe Date: Sun, 15 Apr 2018 22:29:50 +0200 Subject: progressively imporoving the conformance with python3 --- modules/language/python/module/enum.py | 50 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'modules/language/python/module/enum.py') diff --git a/modules/language/python/module/enum.py b/modules/language/python/module/enum.py index 89047cd..1549862 100644 --- a/modules/language/python/module/enum.py +++ b/modules/language/python/module/enum.py @@ -11,7 +11,6 @@ try: except ImportError: from collections import OrderedDict - __all__ = [ 'EnumMeta', 'Enum', 'IntEnum', 'Flag', 'IntFlag', @@ -50,6 +49,8 @@ def _make_class_unpicklable(cls): cls.__module__ = '' _auto_null = object() + + class auto: """ Instances are replaced with an appropriate value in Enum class suites. @@ -117,10 +118,14 @@ class EnumMeta(type): def __prepare__(metacls, cls, bases): # create the namespace dict enum_dict = _EnumDict() + pk('got dict') + # inherit previous flags and _generate_next_value_ function member_type, first_enum = metacls._get_mixins_(bases) + if first_enum is not None: enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None) + return enum_dict def __new__(metacls, cls, bases, classdict): @@ -128,42 +133,45 @@ class EnumMeta(type): # cannot be mixed with other types (int, float, etc.) if it has an # inherited __new__ unless a new __new__ is defined (or the resulting # class will fail). + pk('new enum meta') member_type, first_enum = metacls._get_mixins_(bases) __new__, save_new, use_args = metacls._find_new_(classdict, member_type, first_enum) - + pk(1) # save enum items into separate mapping so they don't get baked into # the new class enum_members = {k: classdict[k] for k in classdict._member_names} for name in classdict._member_names: del classdict[name] - + pk(2) # adjust the sunders _order_ = classdict.pop('_order_', None) - + pk(3) # check for illegal enum names (any others?) invalid_names = set(enum_members) & {'mro', } if invalid_names: raise ValueError('Invalid enum member name: {0}'.format( ','.join(invalid_names))) - + pk(4) # create a default docstring if one has not been provided if '__doc__' not in classdict: classdict['__doc__'] = 'An enumeration.' - + pk(5) # create our new Enum type enum_class = super().__new__(metacls, cls, bases, classdict) + enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = OrderedDict() # name->value map enum_class._member_type_ = member_type - + pk(6) # save attributes from super classes so we know if we can take # the shortcut of storing members in the class dict + base_attributes = {a for b in enum_class.mro() for a in b.__dict__} # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} - + pk(7) # If a custom type is mixed into the Enum, and it does not know how # to pickle itself, pickle.dumps will succeed but pickle.loads will # fail. Rather than have the error show up later and possibly far @@ -180,7 +188,7 @@ class EnumMeta(type): '__reduce_ex__', '__reduce__') if not any(m in member_type.__dict__ for m in methods): _make_class_unpicklable(enum_class) - + pk(8) # instantiate them, checking for duplicates as we go # we instantiate first instead of checking for duplicates first in case # a custom __new__ is doing something funky with the values -- such as @@ -230,7 +238,7 @@ class EnumMeta(type): enum_class._value2member_map_[value] = enum_member except TypeError: pass - + pk(9) # double check that repr and friends are not the mixin's or various # things break (such as pickle) for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): @@ -239,7 +247,7 @@ class EnumMeta(type): enum_method = getattr(first_enum, name, None) if obj_method is not None and obj_method is class_method: setattr(enum_class, name, enum_method) - + pk(10) # replace any other __new__ with our own (as long as Enum is not None, # anyway) -- again, this is to support pickle if Enum is not None: @@ -248,14 +256,14 @@ class EnumMeta(type): if save_new: enum_class.__new_member__ = __new__ enum_class.__new__ = Enum.__new__ - + pk(11) # py3 support for definition order (helps keep py2/py3 code in sync) if _order_ is not None: if isinstance(_order_, str): _order_ = _order_.replace(',', ' ').split() if _order_ != enum_class._member_names_: raise TypeError('member order does not match _order_') - + pk(12) return enum_class def __bool__(self): @@ -424,9 +432,10 @@ class EnumMeta(type): bases: the tuple of bases that was given to __new__ """ + pk('bases',bases) if not bases: return object, Enum - + pk(2) # double check that we are not subclassing a class with existing # enumeration members; while we're at it, see if any other data # type has been mixed in so we can use the correct __new__ @@ -436,6 +445,9 @@ class EnumMeta(type): issubclass(base, Enum) and base._member_names_): raise TypeError("Cannot extend enumerations") + pk(3) + pk(base) + pk(bases) # base is now the last base in bases if not issubclass(base, Enum): raise TypeError("new enumerations must be created as " @@ -473,11 +485,12 @@ class EnumMeta(type): # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __new_member__ + pk(0) __new__ = classdict.get('__new__', None) - + pk(1) # should __new__ be saved as __new_member__ later? save_new = __new__ is not None - + pk(2) if __new__ is None: # check all possibles for __new_member__ before falling back to # __new__ @@ -496,7 +509,7 @@ class EnumMeta(type): break else: __new__ = object.__new__ - + pk(3) # if a non-object.__new__ is used then whatever value/tuple was # assigned to the enum member name will be passed to __new__ and to the # new enum member's __init__ @@ -504,7 +517,7 @@ class EnumMeta(type): use_args = False else: use_args = True - + pk(4) return __new__, save_new, use_args class Enum(metaclass=EnumMeta): @@ -636,6 +649,7 @@ class Enum(metaclass=EnumMeta): module_globals[name] = cls return cls +pk(6) class IntEnum(int, Enum): """Enum where members are also (and must be) ints""" -- cgit v1.2.3