mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	[3.9] [Enum] reformat and add doc strings (GH-23705). (GH-23707)
* [3.9] [Enum] reformat and add doc strings (GH-23705).
This commit is contained in:
		
							parent
							
								
									14eaa7d752
								
							
						
					
					
						commit
						4b37228823
					
				
					 1 changed files with 127 additions and 51 deletions
				
			
		
							
								
								
									
										178
									
								
								Lib/enum.py
									
										
									
									
									
								
							
							
						
						
									
										178
									
								
								Lib/enum.py
									
										
									
									
									
								
							|  | @ -10,31 +10,41 @@ | |||
| 
 | ||||
| 
 | ||||
| def _is_descriptor(obj): | ||||
|     """Returns True if obj is a descriptor, False otherwise.""" | ||||
|     """ | ||||
|     Returns True if obj is a descriptor, False otherwise. | ||||
|     """ | ||||
|     return ( | ||||
|             hasattr(obj, '__get__') or | ||||
|             hasattr(obj, '__set__') or | ||||
|             hasattr(obj, '__delete__')) | ||||
| 
 | ||||
|             hasattr(obj, '__delete__') | ||||
|             ) | ||||
| 
 | ||||
| def _is_dunder(name): | ||||
|     """Returns True if a __dunder__ name, False otherwise.""" | ||||
|     return (len(name) > 4 and | ||||
|     """ | ||||
|     Returns True if a __dunder__ name, False otherwise. | ||||
|     """ | ||||
|     return ( | ||||
|             len(name) > 4 and | ||||
|             name[:2] == name[-2:] == '__' and | ||||
|             name[2] != '_' and | ||||
|             name[-3] != '_') | ||||
| 
 | ||||
|             name[-3] != '_' | ||||
|             ) | ||||
| 
 | ||||
| def _is_sunder(name): | ||||
|     """Returns True if a _sunder_ name, False otherwise.""" | ||||
|     return (len(name) > 2 and | ||||
|     """ | ||||
|     Returns True if a _sunder_ name, False otherwise. | ||||
|     """ | ||||
|     return ( | ||||
|             len(name) > 2 and | ||||
|             name[0] == name[-1] == '_' and | ||||
|             name[1:2] != '_' and | ||||
|             name[-2:-1] != '_') | ||||
| 
 | ||||
|             name[-2:-1] != '_' | ||||
|             ) | ||||
| 
 | ||||
| def _make_class_unpicklable(cls): | ||||
|     """Make the given class un-picklable.""" | ||||
|     """ | ||||
|     Make the given class un-picklable. | ||||
|     """ | ||||
|     def _break_on_call_reduce(self, proto): | ||||
|         raise TypeError('%r cannot be pickled' % self) | ||||
|     cls.__reduce_ex__ = _break_on_call_reduce | ||||
|  | @ -49,11 +59,11 @@ class auto: | |||
| 
 | ||||
| 
 | ||||
| class _EnumDict(dict): | ||||
|     """Track enum member order and ensure member names are not reused. | ||||
|     """ | ||||
|     Track enum member order and ensure member names are not reused. | ||||
| 
 | ||||
|     EnumMeta will use the names found in self._member_names as the | ||||
|     enumeration member names. | ||||
| 
 | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|  | @ -63,13 +73,13 @@ def __init__(self): | |||
|         self._auto_called = False | ||||
| 
 | ||||
|     def __setitem__(self, key, value): | ||||
|         """Changes anything not dundered or not a descriptor. | ||||
|         """ | ||||
|         Changes anything not dundered or not a descriptor. | ||||
| 
 | ||||
|         If an enum member name is used twice, an error is raised; duplicate | ||||
|         values are not checked for. | ||||
| 
 | ||||
|         Single underscore (sunder) names are reserved. | ||||
| 
 | ||||
|         """ | ||||
|         if _is_sunder(key): | ||||
|             if key not in ( | ||||
|  | @ -90,7 +100,10 @@ def __setitem__(self, key, value): | |||
|                 self._ignore = value | ||||
|                 already = set(value) & set(self._member_names) | ||||
|                 if already: | ||||
|                     raise ValueError('_ignore_ cannot specify already set names: %r' % (already, )) | ||||
|                     raise ValueError( | ||||
|                             '_ignore_ cannot specify already set names: %r' | ||||
|                             % (already, ) | ||||
|                             ) | ||||
|         elif _is_dunder(key): | ||||
|             if key == '__order__': | ||||
|                 key = '_order_' | ||||
|  | @ -105,7 +118,12 @@ def __setitem__(self, key, value): | |||
|                 raise TypeError('%r already defined as: %r' % (key, self[key])) | ||||
|             if isinstance(value, auto): | ||||
|                 if value.value == _auto_null: | ||||
|                     value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:]) | ||||
|                     value.value = self._generate_next_value( | ||||
|                             key, | ||||
|                             1, | ||||
|                             len(self._member_names), | ||||
|                             self._last_values[:], | ||||
|                             ) | ||||
|                     self._auto_called = True | ||||
|                 value = value.value | ||||
|             self._member_names.append(key) | ||||
|  | @ -118,9 +136,10 @@ def __setitem__(self, key, value): | |||
| # This is also why there are checks in EnumMeta like `if Enum is not None` | ||||
| Enum = None | ||||
| 
 | ||||
| 
 | ||||
| class EnumMeta(type): | ||||
|     """Metaclass for Enum""" | ||||
|     """ | ||||
|     Metaclass for Enum | ||||
|     """ | ||||
|     @classmethod | ||||
|     def __prepare__(metacls, cls, bases): | ||||
|         # check that previous enum members do not exist | ||||
|  | @ -130,7 +149,9 @@ def __prepare__(metacls, cls, bases): | |||
|         # inherit previous flags and _generate_next_value_ function | ||||
|         member_type, first_enum = metacls._get_mixins_(cls, bases) | ||||
|         if first_enum is not None: | ||||
|             enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None) | ||||
|             enum_dict['_generate_next_value_'] = getattr( | ||||
|                     first_enum, '_generate_next_value_', None, | ||||
|                     ) | ||||
|         return enum_dict | ||||
| 
 | ||||
|     def __new__(metacls, cls, bases, classdict): | ||||
|  | @ -176,9 +197,11 @@ def __new__(metacls, cls, bases, classdict): | |||
| 
 | ||||
|         # save DynamicClassAttribute attributes from super classes so we know | ||||
|         # if we can take the shortcut of storing members in the class dict | ||||
|         dynamic_attributes = {k for c in enum_class.mro() | ||||
|                               for k, v in c.__dict__.items() | ||||
|                               if isinstance(v, DynamicClassAttribute)} | ||||
|         dynamic_attributes = { | ||||
|                 k 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_ = {} | ||||
|  | @ -288,7 +311,8 @@ def __bool__(self): | |||
|         return True | ||||
| 
 | ||||
|     def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1): | ||||
|         """Either returns an existing member, or creates a new enum class. | ||||
|         """ | ||||
|         Either returns an existing member, or creates a new enum class. | ||||
| 
 | ||||
|         This method is used both when an enum class is given a value to match | ||||
|         to an enumeration member (i.e. Color(3)) and for the functional API | ||||
|  | @ -310,12 +334,18 @@ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, s | |||
|         not correct, unpickling will fail in some circumstances. | ||||
| 
 | ||||
|         `type`, if set, will be mixed in as the first base class. | ||||
| 
 | ||||
|         """ | ||||
|         if names is None:  # simple value lookup | ||||
|             return cls.__new__(cls, value) | ||||
|         # otherwise, functional API: we're creating a new Enum type | ||||
|         return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start) | ||||
|         return cls._create_( | ||||
|                 value, | ||||
|                 names, | ||||
|                 module=module, | ||||
|                 qualname=qualname, | ||||
|                 type=type, | ||||
|                 start=start, | ||||
|                 ) | ||||
| 
 | ||||
|     def __contains__(cls, member): | ||||
|         if not isinstance(member, Enum): | ||||
|  | @ -328,22 +358,23 @@ def __delattr__(cls, attr): | |||
|         # nicer error message when someone tries to delete an attribute | ||||
|         # (see issue19025). | ||||
|         if attr in cls._member_map_: | ||||
|             raise AttributeError( | ||||
|                     "%s: cannot delete Enum member." % cls.__name__) | ||||
|             raise AttributeError("%s: cannot delete Enum member." % cls.__name__) | ||||
|         super().__delattr__(attr) | ||||
| 
 | ||||
|     def __dir__(self): | ||||
|         return (['__class__', '__doc__', '__members__', '__module__'] + | ||||
|                 self._member_names_) | ||||
|         return ( | ||||
|                 ['__class__', '__doc__', '__members__', '__module__'] | ||||
|                 + self._member_names_ | ||||
|                 ) | ||||
| 
 | ||||
|     def __getattr__(cls, name): | ||||
|         """Return the enum member matching `name` | ||||
|         """ | ||||
|         Return the enum member matching `name` | ||||
| 
 | ||||
|         We use __getattr__ instead of descriptors or inserting into the enum | ||||
|         class' __dict__ in order to support `name` and `value` being both | ||||
|         properties for enum members (which live in the class' __dict__) and | ||||
|         enum members themselves. | ||||
| 
 | ||||
|         """ | ||||
|         if _is_dunder(name): | ||||
|             raise AttributeError(name) | ||||
|  | @ -356,6 +387,9 @@ def __getitem__(cls, name): | |||
|         return cls._member_map_[name] | ||||
| 
 | ||||
|     def __iter__(cls): | ||||
|         """ | ||||
|         Returns members in definition order. | ||||
|         """ | ||||
|         return (cls._member_map_[name] for name in cls._member_names_) | ||||
| 
 | ||||
|     def __len__(cls): | ||||
|  | @ -363,11 +397,11 @@ def __len__(cls): | |||
| 
 | ||||
|     @property | ||||
|     def __members__(cls): | ||||
|         """Returns a mapping of member name->value. | ||||
|         """ | ||||
|         Returns a mapping of member name->value. | ||||
| 
 | ||||
|         This mapping lists all enum members, including aliases. Note that this | ||||
|         is a read-only view of the internal mapping. | ||||
| 
 | ||||
|         """ | ||||
|         return MappingProxyType(cls._member_map_) | ||||
| 
 | ||||
|  | @ -375,15 +409,18 @@ def __repr__(cls): | |||
|         return "<enum %r>" % cls.__name__ | ||||
| 
 | ||||
|     def __reversed__(cls): | ||||
|         """ | ||||
|         Returns members in reverse definition order. | ||||
|         """ | ||||
|         return (cls._member_map_[name] for name in reversed(cls._member_names_)) | ||||
| 
 | ||||
|     def __setattr__(cls, name, value): | ||||
|         """Block attempts to reassign Enum members. | ||||
|         """ | ||||
|         Block attempts to reassign Enum members. | ||||
| 
 | ||||
|         A simple assignment to the class namespace only changes one of the | ||||
|         several possible ways to get an Enum member from the Enum class, | ||||
|         resulting in an inconsistent Enumeration. | ||||
| 
 | ||||
|         """ | ||||
|         member_map = cls.__dict__.get('_member_map_', {}) | ||||
|         if name in member_map: | ||||
|  | @ -391,7 +428,8 @@ def __setattr__(cls, name, value): | |||
|         super().__setattr__(name, value) | ||||
| 
 | ||||
|     def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1): | ||||
|         """Convenience method to create a new Enum class. | ||||
|         """ | ||||
|         Convenience method to create a new Enum class. | ||||
| 
 | ||||
|         `names` can be: | ||||
| 
 | ||||
|  | @ -400,7 +438,6 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s | |||
|         * An iterable of member names.  Values are incremented by 1 from `start`. | ||||
|         * An iterable of (member name, value) pairs. | ||||
|         * A mapping of member name -> value pairs. | ||||
| 
 | ||||
|         """ | ||||
|         metacls = cls.__class__ | ||||
|         bases = (cls, ) if type is None else (type, cls) | ||||
|  | @ -481,15 +518,18 @@ def _check_for_existing_members(class_name, bases): | |||
|         for chain in bases: | ||||
|             for base in chain.__mro__: | ||||
|                 if issubclass(base, Enum) and base._member_names_: | ||||
|                     raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__)) | ||||
|                     raise TypeError( | ||||
|                             "%s: cannot extend enumeration %r" | ||||
|                             % (class_name, base.__name__) | ||||
|                             ) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_mixins_(class_name, bases): | ||||
|         """Returns the type for creating enum members, and the first inherited | ||||
|         """ | ||||
|         Returns the type for creating enum members, and the first inherited | ||||
|         enum class. | ||||
| 
 | ||||
|         bases: the tuple of bases that was given to __new__ | ||||
| 
 | ||||
|         """ | ||||
|         if not bases: | ||||
|             return object, Enum | ||||
|  | @ -532,12 +572,12 @@ def _find_data_type(bases): | |||
| 
 | ||||
|     @staticmethod | ||||
|     def _find_new_(classdict, member_type, first_enum): | ||||
|         """Returns the __new__ to be used for creating the enum members. | ||||
|         """ | ||||
|         Returns the __new__ to be used for creating the enum members. | ||||
| 
 | ||||
|         classdict: the class dictionary given to __new__ | ||||
|         member_type: the data type whose __new__ will be used by default | ||||
|         first_enum: enumeration to check for an overriding __new__ | ||||
| 
 | ||||
|         """ | ||||
|         # 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 | ||||
|  | @ -577,10 +617,10 @@ def _find_new_(classdict, member_type, first_enum): | |||
| 
 | ||||
| 
 | ||||
| class Enum(metaclass=EnumMeta): | ||||
|     """Generic enumeration. | ||||
|     """ | ||||
|     Generic enumeration. | ||||
| 
 | ||||
|     Derive from this class to define new enumerations. | ||||
| 
 | ||||
|     """ | ||||
|     def __new__(cls, value): | ||||
|         # all enum instances are actually created during class construction | ||||
|  | @ -623,6 +663,14 @@ def __new__(cls, value): | |||
|             raise exc | ||||
| 
 | ||||
|     def _generate_next_value_(name, start, count, last_values): | ||||
|         """ | ||||
|         Generate the next value when not given. | ||||
| 
 | ||||
|         name: the name of the member | ||||
|         start: the initial start value or None | ||||
|         count: the number of existing members | ||||
|         last_value: the last value assigned or None | ||||
|         """ | ||||
|         for last_value in reversed(last_values): | ||||
|             try: | ||||
|                 return last_value + 1 | ||||
|  | @ -643,6 +691,9 @@ def __str__(self): | |||
|         return "%s.%s" % (self.__class__.__name__, self._name_) | ||||
| 
 | ||||
|     def __dir__(self): | ||||
|         """ | ||||
|         Returns all members and all public methods | ||||
|         """ | ||||
|         added_behavior = [ | ||||
|                 m | ||||
|                 for cls in self.__class__.mro() | ||||
|  | @ -652,6 +703,9 @@ def __dir__(self): | |||
|         return (['__class__', '__doc__', '__module__'] + added_behavior) | ||||
| 
 | ||||
|     def __format__(self, format_spec): | ||||
|         """ | ||||
|         Returns format using actual value type unless __str__ has been overridden. | ||||
|         """ | ||||
|         # mixed-in Enums should use the mixed-in type's __format__, otherwise | ||||
|         # we can get strange results with the Enum name showing up instead of | ||||
|         # the value | ||||
|  | @ -699,7 +753,9 @@ def _reduce_ex_by_name(self, proto): | |||
|     return self.name | ||||
| 
 | ||||
| class Flag(Enum): | ||||
|     """Support for flags""" | ||||
|     """ | ||||
|     Support for flags | ||||
|     """ | ||||
| 
 | ||||
|     def _generate_next_value_(name, start, count, last_values): | ||||
|         """ | ||||
|  | @ -722,6 +778,9 @@ def _generate_next_value_(name, start, count, last_values): | |||
| 
 | ||||
|     @classmethod | ||||
|     def _missing_(cls, value): | ||||
|         """ | ||||
|         Returns member (possibly creating it) if one can be found for value. | ||||
|         """ | ||||
|         original_value = value | ||||
|         if value < 0: | ||||
|             value = ~value | ||||
|  | @ -751,6 +810,9 @@ def _create_pseudo_member_(cls, value): | |||
|         return pseudo_member | ||||
| 
 | ||||
|     def __contains__(self, other): | ||||
|         """ | ||||
|         Returns True if self has at least the same flags set as other. | ||||
|         """ | ||||
|         if not isinstance(other, self.__class__): | ||||
|             raise TypeError( | ||||
|                 "unsupported operand type(s) for 'in': '%s' and '%s'" % ( | ||||
|  | @ -809,10 +871,15 @@ def __invert__(self): | |||
| 
 | ||||
| 
 | ||||
| class IntFlag(int, Flag): | ||||
|     """Support for integer-based Flags""" | ||||
|     """ | ||||
|     Support for integer-based Flags | ||||
|     """ | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _missing_(cls, value): | ||||
|         """ | ||||
|         Returns member (possibly creating it) if one can be found for value. | ||||
|         """ | ||||
|         if not isinstance(value, int): | ||||
|             raise ValueError("%r is not a valid %s" % (value, cls.__qualname__)) | ||||
|         new_member = cls._create_pseudo_member_(value) | ||||
|  | @ -820,6 +887,9 @@ def _missing_(cls, value): | |||
| 
 | ||||
|     @classmethod | ||||
|     def _create_pseudo_member_(cls, value): | ||||
|         """ | ||||
|         Create a composite member iff value contains only members. | ||||
|         """ | ||||
|         pseudo_member = cls._value2member_map_.get(value, None) | ||||
|         if pseudo_member is None: | ||||
|             need_to_create = [value] | ||||
|  | @ -874,11 +944,15 @@ def __invert__(self): | |||
| 
 | ||||
| 
 | ||||
| def _high_bit(value): | ||||
|     """returns index of highest bit, or -1 if value is zero or negative""" | ||||
|     """ | ||||
|     returns index of highest bit, or -1 if value is zero or negative | ||||
|     """ | ||||
|     return value.bit_length() - 1 | ||||
| 
 | ||||
| def unique(enumeration): | ||||
|     """Class decorator for enumerations ensuring unique member values.""" | ||||
|     """ | ||||
|     Class decorator for enumerations ensuring unique member values. | ||||
|     """ | ||||
|     duplicates = [] | ||||
|     for name, member in enumeration.__members__.items(): | ||||
|         if name != member.name: | ||||
|  | @ -891,7 +965,9 @@ def unique(enumeration): | |||
|     return enumeration | ||||
| 
 | ||||
| def _decompose(flag, value): | ||||
|     """Extract all members from the value.""" | ||||
|     """ | ||||
|     Extract all members from the value. | ||||
|     """ | ||||
|     # _decompose is only called if the value is not named | ||||
|     not_covered = value | ||||
|     negative = value < 0 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ethan Furman
						Ethan Furman