def test_exploding_pickle(self): BadPickle = Enum('BadPickle', 'dill sweet bread-n-butter') enum._make_class_unpicklable(BadPickle) globals()['BadPickle'] = BadPickle with self.assertRaises(TypeError): dumps(BadPickle.dill) with self.assertRaises(PicklingError): dumps(BadPickle)
def __new__(metacls, cls, bases, classdict): # an Enum class is final once enumeration items have been defined; it # 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). # # remove any keys listed in _ignore_ classdict.setdefault('_ignore_', []).append('_ignore_') ignore = classdict['_ignore_'] for key in ignore: classdict.pop(key, None) member_type, first_enum = metacls._get_mixins_(bases) __new__, save_new, use_args = metacls._find_new_( classdict, member_type, first_enum) # save enum items into separate mapping so they don't get baked into # the new class enum_members = classdict.members for name in enum_members: del classdict[name] # adjust the sunders _order_ = classdict.pop('_order_', None) # check for illegal enum names (any others?) invalid_names = enum_members.keys() & {'mro', ''} if invalid_names: raise ValueError('Invalid enum member name: {0}'.format( ','.join(invalid_names))) # create a default docstring if one has not been provided if '__doc__' not in classdict: classdict['__doc__'] = 'An enumeration.' # create our new Enum type enum_class = type.__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = {} # name->value map enum_class._unique_member_map_ = {} enum_class._member_type_ = member_type dynamic_attributes = { k: v for c in enum_class.mro() for k, v in c.__dict__.items() if isinstance(v, DynamicClassAttribute) } # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} # 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 # from the source, sabotage the pickle protocol for this class so # that pickle.dumps also fails. # # However, if the new class implements its own __reduce_ex__, do not # sabotage -- it's on them to make sure it works correctly. We use # __reduce_ex__ instead of any of the others as it is preferred by # pickle over __reduce__, and it handles all pickle protocols. if '__reduce_ex__' not in classdict: if member_type is not object: methods = { '__getnewargs_ex__', '__getnewargs__', '__reduce_ex__', '__reduce__' } if not any(m in member_type.__dict__ for m in methods): _make_class_unpicklable(enum_class) # 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 # auto-numbering ;) for member_name, value in enum_members.items(): if not isinstance(value, tuple): args = (value, ) else: args = value if member_type is tuple: # special case for tuple enums args = (args, ) # wrap it one more time if not use_args: enum_member = __new__(enum_class) if not hasattr(enum_member, 'value'): enum_member._value_ = value else: enum_member = __new__(enum_class, *args) if not hasattr(enum_member, 'value'): if member_type is object: enum_member._value_ = value else: enum_member._value_ = member_type(*args) value = enum_member.value enum_member._name_ = member_name # setting protected attributes enum_member.__objclass__ = enum_class enum_member.__init__(*args) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. for name, canonical_member in enum_class._member_map_.items(): if canonical_member.value == enum_member.value: enum_member = canonical_member break else: # Aliases don't appear in member names (only in __members__). enum_class._unique_member_map_[member_name] = enum_member enum_class._member_names_.append(member_name) dynamic_attr = dynamic_attributes.get(member_name) if dynamic_attr is not None: # Setting attrs respectively to dynamic attribute so access member_name # through a class will be routed to enum_member # setattr(enum_class, dynamic_attr.class_attr_name, enum_member) dynamic_attr.set_class_attr(enum_class, enum_member) else: setattr(enum_class, member_name, enum_member) # now add to _member_map_ enum_class._member_map_[member_name] = enum_member try: # This may fail if value is not hashable. We can't add the value # to the map, and by-value lookups for this value will be # linear. enum_class._value2member_map_[value] = enum_member except TypeError: pass # 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__'}: class_method = getattr(enum_class, name) obj_method = getattr(member_type, name, None) 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) # 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: # if the user defined their own __new__, save it before it gets # clobbered in case they subclass later if save_new: enum_class.__new_member__ = __new__ enum_class.__new__ = Enum.__new__ # 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_ != list(enum_class._unique_member_map_): raise TypeError('member order does not match _order_') return enum_class
def update_event(self, inp=-1): self.set_output_val(0, enum._make_class_unpicklable(self.input(0)))