mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Revert "bpo-40066: [Enum] update str() and format() output (GH-30582)" (GH-30632)
This reverts commit acf7403f9b.
			
			
This commit is contained in:
		
							parent
							
								
									7f4b69b907
								
							
						
					
					
						commit
						42a64c03ec
					
				
					 14 changed files with 2021 additions and 2087 deletions
				
			
		|  | @ -2,10 +2,15 @@ | |||
| Enum HOWTO | ||||
| ========== | ||||
| 
 | ||||
| :Author: Ethan Furman <ethan at stoneleaf dot us> | ||||
| 
 | ||||
| .. _enum-basic-tutorial: | ||||
| 
 | ||||
| .. currentmodule:: enum | ||||
| 
 | ||||
| Basic Enum Tutorial | ||||
| ------------------- | ||||
| 
 | ||||
| An :class:`Enum` is a set of symbolic names bound to unique values.  They are | ||||
| similar to global variables, but they offer a more useful :func:`repr()`, | ||||
| grouping, type-safety, and a few other features. | ||||
|  | @ -23,14 +28,6 @@ selection of values.  For example, the days of the week:: | |||
|     ...     SATURDAY = 6 | ||||
|     ...     SUNDAY = 7 | ||||
| 
 | ||||
|  Or perhaps the RGB primary colors:: | ||||
| 
 | ||||
|     >>> from enum import Enum | ||||
|     >>> class Color(Enum): | ||||
|     ...     RED = 1 | ||||
|     ...     GREEN = 2 | ||||
|     ...     BLUE = 3 | ||||
| 
 | ||||
| As you can see, creating an :class:`Enum` is as simple as writing a class that | ||||
| inherits from :class:`Enum` itself. | ||||
| 
 | ||||
|  | @ -44,14 +41,13 @@ important, but either way that value can be used to get the corresponding | |||
| member:: | ||||
| 
 | ||||
|     >>> Weekday(3) | ||||
|     <Weekday.WEDNESDAY: 3> | ||||
|     Weekday.WEDNESDAY | ||||
| 
 | ||||
| As you can see, the ``repr()`` of a member shows the enum name, the member name, | ||||
| and the value.  The ``str()`` of a member shows only the enum name and member | ||||
| name:: | ||||
| As you can see, the ``repr()`` of a member shows the enum name and the | ||||
| member name.  The ``str()`` on a member shows only its name:: | ||||
| 
 | ||||
|     >>> print(Weekday.THURSDAY) | ||||
|     Weekday.THURSDAY | ||||
|     THURSDAY | ||||
| 
 | ||||
| The *type* of an enumeration member is the enum it belongs to:: | ||||
| 
 | ||||
|  | @ -101,8 +97,8 @@ The complete :class:`Weekday` enum now looks like this:: | |||
| Now we can find out what today is!  Observe:: | ||||
| 
 | ||||
|     >>> from datetime import date | ||||
|     >>> Weekday.from_date(date.today())     # doctest: +SKIP | ||||
|     <Weekday.TUESDAY: 2> | ||||
|     >>> Weekday.from_date(date.today()) | ||||
|     Weekday.TUESDAY | ||||
| 
 | ||||
| Of course, if you're reading this on some other day, you'll see that day instead. | ||||
| 
 | ||||
|  | @ -128,21 +124,21 @@ Just like the original :class:`Weekday` enum above, we can have a single selecti | |||
| 
 | ||||
|     >>> first_week_day = Weekday.MONDAY | ||||
|     >>> first_week_day | ||||
|     <Weekday.MONDAY: 1> | ||||
|     Weekday.MONDAY | ||||
| 
 | ||||
| But :class:`Flag` also allows us to combine several members into a single | ||||
| variable:: | ||||
| 
 | ||||
|     >>> weekend = Weekday.SATURDAY | Weekday.SUNDAY | ||||
|     >>> weekend | ||||
|     <Weekday.SATURDAY|SUNDAY: 96> | ||||
|     Weekday.SATURDAY|Weekday.SUNDAY | ||||
| 
 | ||||
| You can even iterate over a :class:`Flag` variable:: | ||||
| 
 | ||||
|     >>> for day in weekend: | ||||
|     ...     print(day) | ||||
|     Weekday.SATURDAY | ||||
|     Weekday.SUNDAY | ||||
|     SATURDAY | ||||
|     SUNDAY | ||||
| 
 | ||||
| Okay, let's get some chores set up:: | ||||
| 
 | ||||
|  | @ -177,7 +173,6 @@ yourself some work and use :func:`auto()` for the values:: | |||
| 
 | ||||
| .. _enum-advanced-tutorial: | ||||
| 
 | ||||
| 
 | ||||
| Programmatic access to enumeration members and their attributes | ||||
| --------------------------------------------------------------- | ||||
| 
 | ||||
|  | @ -186,16 +181,16 @@ situations where ``Color.RED`` won't do because the exact color is not known | |||
| at program-writing time).  ``Enum`` allows such access:: | ||||
| 
 | ||||
|     >>> Color(1) | ||||
|     <Color.RED: 1> | ||||
|     Color.RED | ||||
|     >>> Color(3) | ||||
|     <Color.BLUE: 3> | ||||
|     Color.BLUE | ||||
| 
 | ||||
| If you want to access enum members by *name*, use item access:: | ||||
| 
 | ||||
|     >>> Color['RED'] | ||||
|     <Color.RED: 1> | ||||
|     Color.RED | ||||
|     >>> Color['GREEN'] | ||||
|     <Color.GREEN: 2> | ||||
|     Color.GREEN | ||||
| 
 | ||||
| If you have an enum member and need its :attr:`name` or :attr:`value`:: | ||||
| 
 | ||||
|  | @ -217,7 +212,7 @@ Having two enum members with the same name is invalid:: | |||
|     ... | ||||
|     Traceback (most recent call last): | ||||
|     ... | ||||
|     TypeError: 'SQUARE' already defined as 2 | ||||
|     TypeError: 'SQUARE' already defined as: 2 | ||||
| 
 | ||||
| However, an enum member can have other names associated with it.  Given two | ||||
| entries ``A`` and ``B`` with the same value (and ``A`` defined first), ``B`` | ||||
|  | @ -232,11 +227,11 @@ By-name lookup of ``B`` will also return the member ``A``:: | |||
|     ...     ALIAS_FOR_SQUARE = 2 | ||||
|     ... | ||||
|     >>> Shape.SQUARE | ||||
|     <Shape.SQUARE: 2> | ||||
|     Shape.SQUARE | ||||
|     >>> Shape.ALIAS_FOR_SQUARE | ||||
|     <Shape.SQUARE: 2> | ||||
|     Shape.SQUARE | ||||
|     >>> Shape(2) | ||||
|     <Shape.SQUARE: 2> | ||||
|     Shape.SQUARE | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|  | @ -304,7 +299,7 @@ Iteration | |||
| Iterating over the members of an enum does not provide the aliases:: | ||||
| 
 | ||||
|     >>> list(Shape) | ||||
|     [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>] | ||||
|     [Shape.SQUARE, Shape.DIAMOND, Shape.CIRCLE] | ||||
| 
 | ||||
| The special attribute ``__members__`` is a read-only ordered mapping of names | ||||
| to members.  It includes all names defined in the enumeration, including the | ||||
|  | @ -313,10 +308,10 @@ aliases:: | |||
|     >>> for name, member in Shape.__members__.items(): | ||||
|     ...     name, member | ||||
|     ... | ||||
|     ('SQUARE', <Shape.SQUARE: 2>) | ||||
|     ('DIAMOND', <Shape.DIAMOND: 1>) | ||||
|     ('CIRCLE', <Shape.CIRCLE: 3>) | ||||
|     ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>) | ||||
|     ('SQUARE', Shape.SQUARE) | ||||
|     ('DIAMOND', Shape.DIAMOND) | ||||
|     ('CIRCLE', Shape.CIRCLE) | ||||
|     ('ALIAS_FOR_SQUARE', Shape.SQUARE) | ||||
| 
 | ||||
| The ``__members__`` attribute can be used for detailed programmatic access to | ||||
| the enumeration members.  For example, finding all the aliases:: | ||||
|  | @ -365,8 +360,8 @@ below):: | |||
| Allowed members and attributes of enumerations | ||||
| ---------------------------------------------- | ||||
| 
 | ||||
| Most of the examples above use integers for enumeration values.  Using integers | ||||
| is short and handy (and provided by default by the `Functional API`_), but not | ||||
| Most of the examples above use integers for enumeration values.  Using integers is | ||||
| short and handy (and provided by default by the `Functional API`_), but not | ||||
| strictly enforced.  In the vast majority of use-cases, one doesn't care what | ||||
| the actual value of an enumeration is.  But if the value *is* important, | ||||
| enumerations can have arbitrary values. | ||||
|  | @ -394,7 +389,7 @@ usual.  If we have this enumeration:: | |||
| Then:: | ||||
| 
 | ||||
|     >>> Mood.favorite_mood() | ||||
|     <Mood.HAPPY: 3> | ||||
|     Mood.HAPPY | ||||
|     >>> Mood.HAPPY.describe() | ||||
|     ('HAPPY', 3) | ||||
|     >>> str(Mood.FUNKY) | ||||
|  | @ -430,7 +425,7 @@ any members.  So this is forbidden:: | |||
|     ... | ||||
|     Traceback (most recent call last): | ||||
|     ... | ||||
|     TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'> | ||||
|     TypeError: MoreColor: cannot extend enumeration 'Color' | ||||
| 
 | ||||
| But this is allowed:: | ||||
| 
 | ||||
|  | @ -481,9 +476,11 @@ The :class:`Enum` class is callable, providing the following functional API:: | |||
|     >>> Animal | ||||
|     <enum 'Animal'> | ||||
|     >>> Animal.ANT | ||||
|     <Animal.ANT: 1> | ||||
|     Animal.ANT | ||||
|     >>> Animal.ANT.value | ||||
|     1 | ||||
|     >>> list(Animal) | ||||
|     [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>] | ||||
|     [Animal.ANT, Animal.BEE, Animal.CAT, Animal.DOG] | ||||
| 
 | ||||
| The semantics of this API resemble :class:`~collections.namedtuple`. The first | ||||
| argument of the call to :class:`Enum` is the name of the enumeration. | ||||
|  | @ -628,7 +625,16 @@ StrEnum | |||
| The second variation of :class:`Enum` that is provided is also a subclass of | ||||
| :class:`str`.  Members of a :class:`StrEnum` can be compared to strings; | ||||
| by extension, string enumerations of different types can also be compared | ||||
| to each other. | ||||
| to each other.  :class:`StrEnum` exists to help avoid the problem of getting | ||||
| an incorrect member:: | ||||
| 
 | ||||
|     >>> from enum import StrEnum | ||||
|     >>> class Directions(StrEnum): | ||||
|     ...     NORTH = 'north',    # notice the trailing comma | ||||
|     ...     SOUTH = 'south' | ||||
| 
 | ||||
| Before :class:`StrEnum`, ``Directions.NORTH`` would have been the :class:`tuple` | ||||
| ``('north',)``. | ||||
| 
 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
|  | @ -639,8 +645,9 @@ IntFlag | |||
| The next variation of :class:`Enum` provided, :class:`IntFlag`, is also based | ||||
| on :class:`int`.  The difference being :class:`IntFlag` members can be combined | ||||
| using the bitwise operators (&, \|, ^, ~) and the result is still an | ||||
| :class:`IntFlag` member, if possible.  Like :class:`IntEnum`, :class:`IntFlag` | ||||
| members are also integers and can be used wherever an :class:`int` is used. | ||||
| :class:`IntFlag` member, if possible.  However, as the name implies, :class:`IntFlag` | ||||
| members also subclass :class:`int` and can be used wherever an :class:`int` is | ||||
| used. | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|  | @ -663,7 +670,7 @@ Sample :class:`IntFlag` class:: | |||
|     ...     X = 1 | ||||
|     ... | ||||
|     >>> Perm.R | Perm.W | ||||
|     <Perm.R|W: 6> | ||||
|     Perm.R|Perm.W | ||||
|     >>> Perm.R + Perm.W | ||||
|     6 | ||||
|     >>> RW = Perm.R | Perm.W | ||||
|  | @ -678,11 +685,11 @@ It is also possible to name the combinations:: | |||
|     ...     X = 1 | ||||
|     ...     RWX = 7 | ||||
|     >>> Perm.RWX | ||||
|     <Perm.RWX: 7> | ||||
|     Perm.RWX | ||||
|     >>> ~Perm.RWX | ||||
|     <Perm: 0> | ||||
|     Perm(0) | ||||
|     >>> Perm(7) | ||||
|     <Perm.RWX: 7> | ||||
|     Perm.RWX | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|  | @ -695,7 +702,7 @@ Another important difference between :class:`IntFlag` and :class:`Enum` is that | |||
| if no flags are set (the value is 0), its boolean evaluation is :data:`False`:: | ||||
| 
 | ||||
|     >>> Perm.R & Perm.X | ||||
|     <Perm: 0> | ||||
|     Perm(0) | ||||
|     >>> bool(Perm.R & Perm.X) | ||||
|     False | ||||
| 
 | ||||
|  | @ -703,7 +710,7 @@ Because :class:`IntFlag` members are also subclasses of :class:`int` they can | |||
| be combined with them (but may lose :class:`IntFlag` membership:: | ||||
| 
 | ||||
|     >>> Perm.X | 4 | ||||
|     <Perm.R|X: 5> | ||||
|     Perm.R|Perm.X | ||||
| 
 | ||||
|     >>> Perm.X | 8 | ||||
|     9 | ||||
|  | @ -719,7 +726,7 @@ be combined with them (but may lose :class:`IntFlag` membership:: | |||
| :class:`IntFlag` members can also be iterated over:: | ||||
| 
 | ||||
|     >>> list(RW) | ||||
|     [<Perm.R: 4>, <Perm.W: 2>] | ||||
|     [Perm.R, Perm.W] | ||||
| 
 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
|  | @ -746,7 +753,7 @@ flags being set, the boolean evaluation is :data:`False`:: | |||
|     ...     GREEN = auto() | ||||
|     ... | ||||
|     >>> Color.RED & Color.GREEN | ||||
|     <Color: 0> | ||||
|     Color(0) | ||||
|     >>> bool(Color.RED & Color.GREEN) | ||||
|     False | ||||
| 
 | ||||
|  | @ -760,7 +767,7 @@ while combinations of flags won't:: | |||
|     ...     WHITE = RED | BLUE | GREEN | ||||
|     ... | ||||
|     >>> Color.WHITE | ||||
|     <Color.WHITE: 7> | ||||
|     Color.WHITE | ||||
| 
 | ||||
| Giving a name to the "no flags set" condition does not change its boolean | ||||
| value:: | ||||
|  | @ -772,7 +779,7 @@ value:: | |||
|     ...     GREEN = auto() | ||||
|     ... | ||||
|     >>> Color.BLACK | ||||
|     <Color.BLACK: 0> | ||||
|     Color.BLACK | ||||
|     >>> bool(Color.BLACK) | ||||
|     False | ||||
| 
 | ||||
|  | @ -780,7 +787,7 @@ value:: | |||
| 
 | ||||
|     >>> purple = Color.RED | Color.BLUE | ||||
|     >>> list(purple) | ||||
|     [<Color.RED: 1>, <Color.BLUE: 2>] | ||||
|     [Color.RED, Color.BLUE] | ||||
| 
 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
|  | @ -805,16 +812,16 @@ simple to implement independently:: | |||
|         pass | ||||
| 
 | ||||
| This demonstrates how similar derived enumerations can be defined; for example | ||||
| a :class:`FloatEnum` that mixes in :class:`float` instead of :class:`int`. | ||||
| a :class:`StrEnum` that mixes in :class:`str` instead of :class:`int`. | ||||
| 
 | ||||
| Some rules: | ||||
| 
 | ||||
| 1. When subclassing :class:`Enum`, mix-in types must appear before | ||||
|    :class:`Enum` itself in the sequence of bases, as in the :class:`IntEnum` | ||||
|    example above. | ||||
| 2. Mix-in types must be subclassable. For example, :class:`bool` and | ||||
|    :class:`range` are not subclassable and will throw an error during Enum | ||||
|    creation if used as the mix-in type. | ||||
| 2. Mix-in types must be subclassable. For example, | ||||
|    :class:`bool` and :class:`range` are not subclassable | ||||
|    and will throw an error during Enum creation if used as the mix-in type. | ||||
| 3. While :class:`Enum` can have members of any type, once you mix in an | ||||
|    additional type, all the members must have values of that type, e.g. | ||||
|    :class:`int` above.  This restriction does not apply to mix-ins which only | ||||
|  | @ -822,18 +829,15 @@ Some rules: | |||
| 4. When another data type is mixed in, the :attr:`value` attribute is *not the | ||||
|    same* as the enum member itself, although it is equivalent and will compare | ||||
|    equal. | ||||
| 5. %-style formatting:  ``%s`` and ``%r`` call the :class:`Enum` class's | ||||
| 5. %-style formatting:  `%s` and `%r` call the :class:`Enum` class's | ||||
|    :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as | ||||
|    ``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type. | ||||
|    `%i` or `%h` for IntEnum) treat the enum member as its mixed-in type. | ||||
| 6. :ref:`Formatted string literals <f-strings>`, :meth:`str.format`, | ||||
|    and :func:`format` will use the enum's :meth:`__str__` method. | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|    Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are | ||||
|    designed to be drop-in replacements for existing constants, their | ||||
|    :meth:`__str__` method has been reset to their data types | ||||
|    :meth:`__str__` method. | ||||
|    and :func:`format` will use the mixed-in type's :meth:`__format__` | ||||
|    unless :meth:`__str__` or :meth:`__format__` is overridden in the subclass, | ||||
|    in which case the overridden methods or :class:`Enum` methods will be used. | ||||
|    Use the !s and !r format codes to force usage of the :class:`Enum` class's | ||||
|    :meth:`__str__` and :meth:`__repr__` methods. | ||||
| 
 | ||||
| When to use :meth:`__new__` vs. :meth:`__init__` | ||||
| ------------------------------------------------ | ||||
|  | @ -862,10 +866,10 @@ want one of them to be the value:: | |||
|     ... | ||||
| 
 | ||||
|     >>> print(Coordinate['PY']) | ||||
|     Coordinate.PY | ||||
|     PY | ||||
| 
 | ||||
|     >>> print(Coordinate(3)) | ||||
|     Coordinate.VY | ||||
|     VY | ||||
| 
 | ||||
| 
 | ||||
| Finer Points | ||||
|  | @ -923,8 +927,8 @@ and raise an error if the two do not match:: | |||
|     Traceback (most recent call last): | ||||
|     ... | ||||
|     TypeError: member order does not match _order_: | ||||
|       ['RED', 'BLUE', 'GREEN'] | ||||
|       ['RED', 'GREEN', 'BLUE'] | ||||
|     ['RED', 'BLUE', 'GREEN'] | ||||
|     ['RED', 'GREEN', 'BLUE'] | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|  | @ -945,36 +949,35 @@ but remain normal attributes. | |||
| """""""""""""""""""" | ||||
| 
 | ||||
| Enum members are instances of their enum class, and are normally accessed as | ||||
| ``EnumClass.member``.  In Python versions ``3.5`` to ``3.10`` you could access | ||||
| members from other members -- this practice was discouraged, and in ``3.11`` | ||||
| :class:`Enum` returns to not allowing it:: | ||||
| ``EnumClass.member``.  In Python versions ``3.5`` to ``3.9`` you could access | ||||
| members from other members -- this practice was discouraged, and in ``3.12`` | ||||
| :class:`Enum` will return to not allowing it, while in ``3.10`` and ``3.11`` | ||||
| it will raise a :exc:`DeprecationWarning`:: | ||||
| 
 | ||||
|     >>> class FieldTypes(Enum): | ||||
|     ...     name = 0 | ||||
|     ...     value = 1 | ||||
|     ...     size = 2 | ||||
|     ... | ||||
|     >>> FieldTypes.value.size | ||||
|     Traceback (most recent call last): | ||||
|     ... | ||||
|     AttributeError: <enum 'FieldTypes'> member has no attribute 'size' | ||||
| 
 | ||||
|     >>> FieldTypes.value.size       # doctest: +SKIP | ||||
|     DeprecationWarning: accessing one member from another is not supported, | ||||
|       and will be disabled in 3.12 | ||||
|     <FieldTypes.size: 2> | ||||
| 
 | ||||
| .. versionchanged:: 3.5 | ||||
| .. versionchanged:: 3.11 | ||||
| 
 | ||||
| 
 | ||||
| Creating members that are mixed with other data types | ||||
| """"""""""""""""""""""""""""""""""""""""""""""""""""" | ||||
| 
 | ||||
| When subclassing other data types, such as :class:`int` or :class:`str`, with | ||||
| an :class:`Enum`, all values after the ``=`` are passed to that data type's | ||||
| an :class:`Enum`, all values after the `=` are passed to that data type's | ||||
| constructor.  For example:: | ||||
| 
 | ||||
|     >>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer | ||||
|     ...     example = '11', 16      # so x='11' and base=16 | ||||
|     ... | ||||
|     >>> MyEnum.example.value        # and hex(11) is... | ||||
|     >>> class MyEnum(IntEnum): | ||||
|     ...     example = '11', 16      # '11' will be interpreted as a hexadecimal | ||||
|     ...                             # number | ||||
|     >>> MyEnum.example.value | ||||
|     17 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -997,12 +1000,13 @@ Plain :class:`Enum` classes always evaluate as :data:`True`. | |||
| """"""""""""""""""""""""""""" | ||||
| 
 | ||||
| If you give your enum subclass extra methods, like the `Planet`_ | ||||
| class below, those methods will show up in a :func:`dir` of the member, | ||||
| but not of the class:: | ||||
| class below, those methods will show up in a :func:`dir` of the member and the | ||||
| class. Attributes defined in an :func:`__init__` method will only show up in a | ||||
| :func:`dir` of the member:: | ||||
| 
 | ||||
|     >>> dir(Planet)                         # doctest: +SKIP | ||||
|     ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__'] | ||||
|     >>> dir(Planet.EARTH)                   # doctest: +SKIP | ||||
|     >>> dir(Planet) | ||||
|     ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__init__', '__members__', '__module__', 'surface_gravity'] | ||||
|     >>> dir(Planet.EARTH) | ||||
|     ['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value'] | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1021,10 +1025,19 @@ are comprised of a single bit:: | |||
|     ...     CYAN = GREEN | BLUE | ||||
|     ... | ||||
|     >>> Color(3)  # named combination | ||||
|     <Color.YELLOW: 3> | ||||
|     Color.YELLOW | ||||
|     >>> Color(7)      # not named combination | ||||
|     <Color.RED|GREEN|BLUE: 7> | ||||
|     Color.RED|Color.GREEN|Color.BLUE | ||||
| 
 | ||||
| ``StrEnum`` and :meth:`str.__str__` | ||||
| """"""""""""""""""""""""""""""""""" | ||||
| 
 | ||||
| An important difference between :class:`StrEnum` and other Enums is the | ||||
| :meth:`__str__` method; because :class:`StrEnum` members are strings, some | ||||
| parts of Python will read the string data directly, while others will call | ||||
| :meth:`str()`. To make those two operations have the same result, | ||||
| :meth:`StrEnum.__str__` will be the same as :meth:`str.__str__` so that | ||||
| ``str(StrEnum.member) == StrEnum.member`` is true. | ||||
| 
 | ||||
| ``Flag`` and ``IntFlag`` minutia | ||||
| """""""""""""""""""""""""""""""" | ||||
|  | @ -1047,16 +1060,16 @@ the following are true: | |||
| - only canonical flags are returned during iteration:: | ||||
| 
 | ||||
|     >>> list(Color.WHITE) | ||||
|     [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>] | ||||
|     [Color.RED, Color.GREEN, Color.BLUE] | ||||
| 
 | ||||
| - negating a flag or flag set returns a new flag/flag set with the | ||||
|   corresponding positive integer value:: | ||||
| 
 | ||||
|     >>> Color.BLUE | ||||
|     <Color.BLUE: 4> | ||||
|     Color.BLUE | ||||
| 
 | ||||
|     >>> ~Color.BLUE | ||||
|     <Color.RED|GREEN: 3> | ||||
|     Color.RED|Color.GREEN | ||||
| 
 | ||||
| - names of pseudo-flags are constructed from their members' names:: | ||||
| 
 | ||||
|  | @ -1066,29 +1079,25 @@ the following are true: | |||
| - multi-bit flags, aka aliases, can be returned from operations:: | ||||
| 
 | ||||
|     >>> Color.RED | Color.BLUE | ||||
|     <Color.PURPLE: 5> | ||||
|     Color.PURPLE | ||||
| 
 | ||||
|     >>> Color(7)  # or Color(-1) | ||||
|     <Color.WHITE: 7> | ||||
|     Color.WHITE | ||||
| 
 | ||||
|     >>> Color(0) | ||||
|     <Color.BLACK: 0> | ||||
|     Color.BLACK | ||||
| 
 | ||||
| - membership / containment checking: zero-valued flags are always considered | ||||
|   to be contained:: | ||||
| - membership / containment checking has changed slightly -- zero-valued flags | ||||
|   are never considered to be contained:: | ||||
| 
 | ||||
|     >>> Color.BLACK in Color.WHITE | ||||
|     True | ||||
|     False | ||||
| 
 | ||||
|   otherwise, only if all bits of one flag are in the other flag will True | ||||
|   be returned:: | ||||
|   otherwise, if all bits of one flag are in the other flag, True is returned:: | ||||
| 
 | ||||
|     >>> Color.PURPLE in Color.WHITE | ||||
|     True | ||||
| 
 | ||||
|     >>> Color.GREEN in Color.PURPLE | ||||
|     False | ||||
| 
 | ||||
| There is a new boundary mechanism that controls how out-of-range / invalid | ||||
| bits are handled: ``STRICT``, ``CONFORM``, ``EJECT``, and ``KEEP``: | ||||
| 
 | ||||
|  | @ -1172,7 +1181,7 @@ Using :class:`auto` would look like:: | |||
|     ...     GREEN = auto() | ||||
|     ... | ||||
|     >>> Color.GREEN | ||||
|     <Color.GREEN: 3> | ||||
|     <Color.GREEN> | ||||
| 
 | ||||
| 
 | ||||
| Using :class:`object` | ||||
|  | @ -1185,24 +1194,10 @@ Using :class:`object` would look like:: | |||
|     ...     GREEN = object() | ||||
|     ...     BLUE = object() | ||||
|     ... | ||||
|     >>> Color.GREEN                         # doctest: +SKIP | ||||
|     <Color.GREEN: <object object at 0x...>> | ||||
| 
 | ||||
| This is also a good example of why you might want to write your own | ||||
| :meth:`__repr__`:: | ||||
| 
 | ||||
|     >>> class Color(Enum): | ||||
|     ...     RED = object() | ||||
|     ...     GREEN = object() | ||||
|     ...     BLUE = object() | ||||
|     ...     def __repr__(self): | ||||
|     ...         return "<%s.%s>" % (self.__class__.__name__, self._name_) | ||||
|     ... | ||||
|     >>> Color.GREEN | ||||
|     <Color.GREEN> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| Using a descriptive string | ||||
| """""""""""""""""""""""""" | ||||
| 
 | ||||
|  | @ -1214,7 +1209,9 @@ Using a string as the value would look like:: | |||
|     ...     BLUE = 'too fast!' | ||||
|     ... | ||||
|     >>> Color.GREEN | ||||
|     <Color.GREEN: 'go'> | ||||
|     <Color.GREEN> | ||||
|     >>> Color.GREEN.value | ||||
|     'go' | ||||
| 
 | ||||
| 
 | ||||
| Using a custom :meth:`__new__` | ||||
|  | @ -1235,7 +1232,9 @@ Using an auto-numbering :meth:`__new__` would look like:: | |||
|     ...     BLUE = () | ||||
|     ... | ||||
|     >>> Color.GREEN | ||||
|     <Color.GREEN: 2> | ||||
|     <Color.GREEN> | ||||
|     >>> Color.GREEN.value | ||||
|     2 | ||||
| 
 | ||||
| To make a more general purpose ``AutoNumber``, add ``*args`` to the signature:: | ||||
| 
 | ||||
|  | @ -1258,7 +1257,7 @@ to handle any extra arguments:: | |||
|     ...     BLEACHED_CORAL = () # New color, no Pantone code yet! | ||||
|     ... | ||||
|     >>> Swatch.SEA_GREEN | ||||
|     <Swatch.SEA_GREEN: 2> | ||||
|     <Swatch.SEA_GREEN> | ||||
|     >>> Swatch.SEA_GREEN.pantone | ||||
|     '1246' | ||||
|     >>> Swatch.BLEACHED_CORAL.pantone | ||||
|  | @ -1385,9 +1384,30 @@ An example to show the :attr:`_ignore_` attribute in use:: | |||
|     ...         Period['day_%d' % i] = i | ||||
|     ... | ||||
|     >>> list(Period)[:2] | ||||
|     [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>] | ||||
|     [Period.day_0, Period.day_1] | ||||
|     >>> list(Period)[-2:] | ||||
|     [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>] | ||||
|     [Period.day_365, Period.day_366] | ||||
| 
 | ||||
| 
 | ||||
| Conforming input to Flag | ||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||||
| 
 | ||||
| To create a :class:`Flag` enum that is more resilient to out-of-bounds results | ||||
| from mathematical operations, you can use the :attr:`FlagBoundary.CONFORM` | ||||
| setting:: | ||||
| 
 | ||||
|     >>> from enum import Flag, CONFORM, auto | ||||
|     >>> class Weekday(Flag, boundary=CONFORM): | ||||
|     ...     MONDAY = auto() | ||||
|     ...     TUESDAY = auto() | ||||
|     ...     WEDNESDAY = auto() | ||||
|     ...     THURSDAY = auto() | ||||
|     ...     FRIDAY = auto() | ||||
|     ...     SATURDAY = auto() | ||||
|     ...     SUNDAY = auto() | ||||
|     >>> today = Weekday.TUESDAY | ||||
|     >>> Weekday(today + 22)  # what day is three weeks from tomorrow? | ||||
|     >>> Weekday.WEDNESDAY | ||||
| 
 | ||||
| 
 | ||||
| .. _enumtype-examples: | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ An enumeration: | |||
| * uses *call* syntax to return members by value | ||||
| * uses *index* syntax to return members by name | ||||
| 
 | ||||
| Enumerations are created either by using :keyword:`class` syntax, or by | ||||
| Enumerations are created either by using the :keyword:`class` syntax, or by | ||||
| using function-call syntax:: | ||||
| 
 | ||||
|    >>> from enum import Enum | ||||
|  | @ -45,7 +45,7 @@ using function-call syntax:: | |||
|    >>> # functional syntax | ||||
|    >>> Color = Enum('Color', ['RED', 'GREEN', 'BLUE']) | ||||
| 
 | ||||
| Even though we can use :keyword:`class` syntax to create Enums, Enums | ||||
| Even though we can use the :keyword:`class` syntax to create Enums, Enums | ||||
| are not normal Python classes.  See | ||||
| :ref:`How are Enums different? <enum-class-differences>` for more details. | ||||
| 
 | ||||
|  | @ -53,7 +53,7 @@ are not normal Python classes.  See | |||
| 
 | ||||
|    - The class :class:`Color` is an *enumeration* (or *enum*) | ||||
|    - The attributes :attr:`Color.RED`, :attr:`Color.GREEN`, etc., are | ||||
|      *enumeration members* (or *members*) and are functionally constants. | ||||
|      *enumeration members* (or *enum members*) and are functionally constants. | ||||
|    - The enum members have *names* and *values* (the name of | ||||
|      :attr:`Color.RED` is ``RED``, the value of :attr:`Color.BLUE` is | ||||
|      ``3``, etc.) | ||||
|  | @ -110,10 +110,15 @@ Module Contents | |||
|       :class:`StrEnum` defaults to the lower-cased version of the member name, | ||||
|       while other Enums default to 1 and increase from there. | ||||
| 
 | ||||
|    :func:`property` | ||||
|    :func:`global_enum` | ||||
| 
 | ||||
|       :class:`Enum` class decorator to apply the appropriate global `__repr__`, | ||||
|       and export its members into the global name space. | ||||
| 
 | ||||
|    :func:`.property` | ||||
| 
 | ||||
|       Allows :class:`Enum` members to have attributes without conflicting with | ||||
|       member names. | ||||
|       other members' names. | ||||
| 
 | ||||
|    :func:`unique` | ||||
| 
 | ||||
|  | @ -126,7 +131,7 @@ Module Contents | |||
| 
 | ||||
| 
 | ||||
| .. versionadded:: 3.6  ``Flag``, ``IntFlag``, ``auto`` | ||||
| .. versionadded:: 3.11  ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property`` | ||||
| .. versionadded:: 3.11  ``StrEnum``, ``EnumCheck``, ``FlagBoundary`` | ||||
| 
 | ||||
| --------------- | ||||
| 
 | ||||
|  | @ -140,11 +145,6 @@ Data Types | |||
|    to subclass *EnumType* -- see :ref:`Subclassing EnumType <enumtype-examples>` | ||||
|    for details. | ||||
| 
 | ||||
|    *EnumType* is responsible for setting the correct :meth:`__repr__`, | ||||
|    :meth:`__str__`, :meth:`__format__`, and :meth:`__reduce__` methods on the | ||||
|    final *enum*, as well as creating the enum members, properly handling | ||||
|    duplicates, providing iteration over the enum class, etc. | ||||
| 
 | ||||
|    .. method:: EnumType.__contains__(cls, member) | ||||
| 
 | ||||
|       Returns ``True`` if member belongs to the ``cls``:: | ||||
|  | @ -162,31 +162,32 @@ Data Types | |||
|    .. method:: EnumType.__dir__(cls) | ||||
| 
 | ||||
|       Returns ``['__class__', '__doc__', '__members__', '__module__']`` and the | ||||
|       names of the members in *cls*:: | ||||
|       names of the members in ``cls``. User-defined methods and methods from | ||||
|       mixin classes will also be included:: | ||||
| 
 | ||||
|         >>> dir(Color) | ||||
|         ['BLUE', 'GREEN', 'RED', '__class__', '__contains__', '__doc__', '__getitem__', '__init_subclass__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__'] | ||||
|         ['BLUE', 'GREEN', 'RED', '__class__', '__doc__', '__members__', '__module__'] | ||||
| 
 | ||||
|    .. method:: EnumType.__getattr__(cls, name) | ||||
| 
 | ||||
|       Returns the Enum member in *cls* matching *name*, or raises an :exc:`AttributeError`:: | ||||
| 
 | ||||
|         >>> Color.GREEN | ||||
|         <Color.GREEN: 2> | ||||
|         Color.GREEN | ||||
| 
 | ||||
|    .. method:: EnumType.__getitem__(cls, name) | ||||
| 
 | ||||
|       Returns the Enum member in *cls* matching *name*, or raises an :exc:`KeyError`:: | ||||
|       Returns the Enum member in *cls* matching *name*, or raises a :exc:`KeyError`:: | ||||
| 
 | ||||
|         >>> Color['BLUE'] | ||||
|         <Color.BLUE: 3> | ||||
|         Color.BLUE | ||||
| 
 | ||||
|    .. method:: EnumType.__iter__(cls) | ||||
| 
 | ||||
|       Returns each member in *cls* in definition order:: | ||||
| 
 | ||||
|         >>> list(Color) | ||||
|         [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>] | ||||
|         [Color.RED, Color.GREEN, Color.BLUE] | ||||
| 
 | ||||
|    .. method:: EnumType.__len__(cls) | ||||
| 
 | ||||
|  | @ -200,7 +201,7 @@ Data Types | |||
|       Returns each member in *cls* in reverse definition order:: | ||||
| 
 | ||||
|         >>> list(reversed(Color)) | ||||
|         [<Color.BLUE: 3>, <Color.GREEN: 2>, <Color.RED: 1>] | ||||
|         [Color.BLUE, Color.GREEN, Color.RED] | ||||
| 
 | ||||
| 
 | ||||
| .. class:: Enum | ||||
|  | @ -231,7 +232,7 @@ Data Types | |||
|    .. attribute:: Enum._ignore_ | ||||
| 
 | ||||
|       ``_ignore_`` is only used during creation and is removed from the | ||||
|       enumeration once creation is complete. | ||||
|       enumeration once that is complete. | ||||
| 
 | ||||
|       ``_ignore_`` is a list of names that will not become members, and whose | ||||
|       names will also be removed from the completed enumeration.  See | ||||
|  | @ -260,7 +261,7 @@ Data Types | |||
|    .. method:: Enum.__dir__(self) | ||||
| 
 | ||||
|       Returns ``['__class__', '__doc__', '__module__', 'name', 'value']`` and | ||||
|       any public methods defined on *self.__class__*:: | ||||
|       any public methods defined on ``self.__class__`` or a mixin class:: | ||||
| 
 | ||||
|          >>> from datetime import date | ||||
|          >>> class Weekday(Enum): | ||||
|  | @ -275,7 +276,7 @@ Data Types | |||
|          ...     def today(cls): | ||||
|          ...         print('today is %s' % cls(date.today().isoweekday()).name) | ||||
|          >>> dir(Weekday.SATURDAY) | ||||
|          ['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'today', 'value'] | ||||
|          ['__class__', '__doc__', '__module__', 'name', 'today', 'value'] | ||||
| 
 | ||||
|    .. method:: Enum._generate_next_value_(name, start, count, last_values) | ||||
| 
 | ||||
|  | @ -297,11 +298,6 @@ Data Types | |||
|          >>> PowersOfThree.SECOND.value | ||||
|          6 | ||||
| 
 | ||||
|    .. method:: Enum.__init_subclass__(cls, \**kwds) | ||||
| 
 | ||||
|       A *classmethod* that is used to further configure subsequent subclasses. | ||||
|       By default, does nothing. | ||||
| 
 | ||||
|    .. method:: Enum._missing_(cls, value) | ||||
| 
 | ||||
|       A *classmethod* for looking up values not found in *cls*.  By default it | ||||
|  | @ -321,55 +317,42 @@ Data Types | |||
|          >>> Build.DEBUG.value | ||||
|          'debug' | ||||
|          >>> Build('deBUG') | ||||
|          <Build.DEBUG: 'debug'> | ||||
|          Build.DEBUG | ||||
| 
 | ||||
|    .. method:: Enum.__repr__(self) | ||||
| 
 | ||||
|       Returns the string used for *repr()* calls.  By default, returns the | ||||
|       *Enum* name, member name, and value, but can be overridden:: | ||||
|       *Enum* name and the member name, but can be overridden:: | ||||
| 
 | ||||
|          >>> class OtherStyle(Enum): | ||||
|          ...     ALTERNATE = auto() | ||||
|          ...     OTHER = auto() | ||||
|          ...     SOMETHING_ELSE = auto() | ||||
|          >>> class OldStyle(Enum): | ||||
|          ...     RETRO = auto() | ||||
|          ...     OLD_SCHOOl = auto() | ||||
|          ...     YESTERYEAR = auto() | ||||
|          ...     def __repr__(self): | ||||
|          ...         cls_name = self.__class__.__name__ | ||||
|          ...         return f'{cls_name}.{self.name}' | ||||
|          >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" | ||||
|          (OtherStyle.ALTERNATE, 'OtherStyle.ALTERNATE', 'OtherStyle.ALTERNATE') | ||||
|          ...         return f'<{cls_name}.{self.name}: {self.value}>' | ||||
|          >>> OldStyle.RETRO | ||||
|          <OldStyle.RETRO: 1> | ||||
| 
 | ||||
|    .. method:: Enum.__str__(self) | ||||
| 
 | ||||
|       Returns the string used for *str()* calls.  By default, returns the | ||||
|       *Enum* name and member name, but can be overridden:: | ||||
|       member name, but can be overridden:: | ||||
| 
 | ||||
|          >>> class OtherStyle(Enum): | ||||
|          ...     ALTERNATE = auto() | ||||
|          ...     OTHER = auto() | ||||
|          ...     SOMETHING_ELSE = auto() | ||||
|          >>> class OldStyle(Enum): | ||||
|          ...     RETRO = auto() | ||||
|          ...     OLD_SCHOOl = auto() | ||||
|          ...     YESTERYEAR = auto() | ||||
|          ...     def __str__(self): | ||||
|          ...         return f'{self.name}' | ||||
|          >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" | ||||
|          (<OtherStyle.ALTERNATE: 1>, 'ALTERNATE', 'ALTERNATE') | ||||
|          ...         cls_name = self.__class__.__name__ | ||||
|          ...         return f'{cls_name}.{self.name}' | ||||
|          >>> OldStyle.RETRO | ||||
|          OldStyle.RETRO | ||||
| 
 | ||||
|    .. method:: Enum.__format__(self) | ||||
| .. note:: | ||||
| 
 | ||||
|       Returns the string used for *format()* and *f-string* calls.  By default, | ||||
|       returns :meth:`__str__` returns, but can be overridden:: | ||||
| 
 | ||||
|          >>> class OtherStyle(Enum): | ||||
|          ...     ALTERNATE = auto() | ||||
|          ...     OTHER = auto() | ||||
|          ...     SOMETHING_ELSE = auto() | ||||
|          ...     def __format__(self, spec): | ||||
|          ...         return f'{self.name}' | ||||
|          >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" | ||||
|          (<OtherStyle.ALTERNATE: 1>, 'OtherStyle.ALTERNATE', 'ALTERNATE') | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|       Using :class:`auto` with :class:`Enum` results in integers of increasing value, | ||||
|       starting with ``1``. | ||||
|    Using :class:`auto` with :class:`Enum` results in integers of increasing value, | ||||
|    starting with ``1``. | ||||
| 
 | ||||
| 
 | ||||
| .. class:: IntEnum | ||||
|  | @ -384,7 +367,7 @@ Data Types | |||
|       ...     TWO = 2 | ||||
|       ...     THREE = 3 | ||||
|       >>> Numbers.THREE | ||||
|       <Numbers.THREE: 3> | ||||
|       Numbers.THREE | ||||
|       >>> Numbers.ONE + Numbers.TWO | ||||
|       3 | ||||
|       >>> Numbers.THREE + 5 | ||||
|  | @ -392,14 +375,10 @@ Data Types | |||
|       >>> Numbers.THREE == 3 | ||||
|       True | ||||
| 
 | ||||
|    .. note:: | ||||
| .. note:: | ||||
| 
 | ||||
|       Using :class:`auto` with :class:`IntEnum` results in integers of increasing | ||||
|       value, starting with ``1``. | ||||
| 
 | ||||
|    .. versionchanged:: 3.11 :meth:`__str__` is now :func:`int.__str__` to | ||||
|       better support the *replacement of existing constants* use-case. | ||||
|       :meth:`__format__` was already :func:`int.__format__` for that same reason. | ||||
|    Using :class:`auto` with :class:`IntEnum` results in integers of increasing value, | ||||
|    starting with ``1``. | ||||
| 
 | ||||
| 
 | ||||
| .. class:: StrEnum | ||||
|  | @ -413,16 +392,13 @@ Data Types | |||
|              instead of ``isinstance(str, unknown)``), and in those locations you | ||||
|              will need to use ``str(StrEnum.member)``. | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|       Using :class:`auto` with :class:`StrEnum` results in the lower-cased member | ||||
|       name as the value. | ||||
| .. note:: | ||||
| 
 | ||||
|    .. note:: :meth:`__str__` is :func:`str.__str__` to better support the | ||||
|       *replacement of existing constants* use-case.  :meth:`__format__` is likewise | ||||
|       :func:`int.__format__` for that same reason. | ||||
|    Using :class:`auto` with :class:`StrEnum` results in values of the member name, | ||||
|    lower-cased. | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| .. class:: Flag | ||||
| 
 | ||||
|  | @ -455,9 +431,9 @@ Data Types | |||
|       Returns all contained members:: | ||||
| 
 | ||||
|          >>> list(Color.RED) | ||||
|          [<Color.RED: 1>] | ||||
|          [Color.RED] | ||||
|          >>> list(purple) | ||||
|          [<Color.RED: 1>, <Color.BLUE: 4>] | ||||
|          [Color.RED, Color.BLUE] | ||||
| 
 | ||||
|    .. method:: __len__(self): | ||||
| 
 | ||||
|  | @ -485,52 +461,42 @@ Data Types | |||
|       Returns current flag binary or'ed with other:: | ||||
| 
 | ||||
|          >>> Color.RED | Color.GREEN | ||||
|          <Color.RED|GREEN: 3> | ||||
|          Color.RED|Color.GREEN | ||||
| 
 | ||||
|    .. method:: __and__(self, other) | ||||
| 
 | ||||
|       Returns current flag binary and'ed with other:: | ||||
| 
 | ||||
|          >>> purple & white | ||||
|          <Color.RED|BLUE: 5> | ||||
|          Color.RED|Color.BLUE | ||||
|          >>> purple & Color.GREEN | ||||
|          <Color: 0> | ||||
|          0x0 | ||||
| 
 | ||||
|    .. method:: __xor__(self, other) | ||||
| 
 | ||||
|       Returns current flag binary xor'ed with other:: | ||||
| 
 | ||||
|          >>> purple ^ white | ||||
|          <Color.GREEN: 2> | ||||
|          Color.GREEN | ||||
|          >>> purple ^ Color.GREEN | ||||
|          <Color.RED|GREEN|BLUE: 7> | ||||
|          Color.RED|Color.GREEN|Color.BLUE | ||||
| 
 | ||||
|    .. method:: __invert__(self): | ||||
| 
 | ||||
|       Returns all the flags in *type(self)* that are not in self:: | ||||
| 
 | ||||
|          >>> ~white | ||||
|          <Color: 0> | ||||
|          0x0 | ||||
|          >>> ~purple | ||||
|          <Color.GREEN: 2> | ||||
|          Color.GREEN | ||||
|          >>> ~Color.RED | ||||
|          <Color.GREEN|BLUE: 6> | ||||
|          Color.GREEN|Color.BLUE | ||||
| 
 | ||||
|    .. method:: _numeric_repr_ | ||||
| .. note:: | ||||
| 
 | ||||
|       Function used to format any remaining unnamed numeric values.  Default is | ||||
|       the value's repr; common choices are :func:`hex` and :func:`oct`. | ||||
|    Using :class:`auto` with :class:`Flag` results in integers that are powers | ||||
|    of two, starting with ``1``. | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|       Using :class:`auto` with :class:`Flag` results in integers that are powers | ||||
|       of two, starting with ``1``. | ||||
| 
 | ||||
|    .. versionchanged:: 3.11  The *repr()* of zero-valued flags has changed.  It | ||||
|       is now:: | ||||
| 
 | ||||
|           >>> Color(0) | ||||
|           <Color: 0> | ||||
| 
 | ||||
| .. class:: IntFlag | ||||
| 
 | ||||
|  | @ -543,9 +509,9 @@ Data Types | |||
|       ...     GREEN = auto() | ||||
|       ...     BLUE = auto() | ||||
|       >>> Color.RED & 2 | ||||
|       <Color: 0> | ||||
|       0x0 | ||||
|       >>> Color.RED | 2 | ||||
|       <Color.RED|GREEN: 3> | ||||
|       Color.RED|Color.GREEN | ||||
| 
 | ||||
|    If any integer operation is performed with an *IntFlag* member, the result is | ||||
|    not an *IntFlag*:: | ||||
|  | @ -558,25 +524,15 @@ Data Types | |||
|       * the result is a valid *IntFlag*: an *IntFlag* is returned | ||||
|       * the result is not a valid *IntFlag*: the result depends on the *FlagBoundary* setting | ||||
| 
 | ||||
|    The *repr()* of unnamed zero-valued flags has changed.  It is now: | ||||
| 
 | ||||
|       >>> Color(0) | ||||
|       <Color: 0> | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|       Using :class:`auto` with :class:`IntFlag` results in integers that are powers | ||||
|       of two, starting with ``1``. | ||||
| 
 | ||||
|    .. versionchanged:: 3.11 :meth:`__str__` is now :func:`int.__str__` to | ||||
|       better support the *replacement of existing constants* use-case. | ||||
|       :meth:`__format__` was already :func:`int.__format__` for that same reason. | ||||
| .. note:: | ||||
| 
 | ||||
|    Using :class:`auto` with :class:`IntFlag` results in integers that are powers | ||||
|    of two, starting with ``1``. | ||||
| 
 | ||||
| .. class:: EnumCheck | ||||
| 
 | ||||
|    *EnumCheck* contains the options used by the :func:`verify` decorator to ensure | ||||
|    various constraints; failed constraints result in a :exc:`ValueError`. | ||||
|    various constraints; failed constraints result in a :exc:`TypeError`. | ||||
| 
 | ||||
|    .. attribute:: UNIQUE | ||||
| 
 | ||||
|  | @ -626,11 +582,11 @@ Data Types | |||
|          ... | ||||
|          ValueError: invalid Flag 'Color': aliases WHITE and NEON are missing combined values of 0x18 [use enum.show_flag_values(value) for details] | ||||
| 
 | ||||
|    .. note:: | ||||
| .. note:: | ||||
| 
 | ||||
|       CONTINUOUS and NAMED_FLAGS are designed to work with integer-valued members. | ||||
|    CONTINUOUS and NAMED_FLAGS are designed to work with integer-valued members. | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| .. class:: FlagBoundary | ||||
| 
 | ||||
|  | @ -650,7 +606,7 @@ Data Types | |||
|          >>> StrictFlag(2**2 + 2**4) | ||||
|          Traceback (most recent call last): | ||||
|          ... | ||||
|          ValueError: <flag 'StrictFlag'> invalid value 20 | ||||
|          ValueError: StrictFlag: invalid value: 20 | ||||
|              given 0b0 10100 | ||||
|            allowed 0b0 00111 | ||||
| 
 | ||||
|  | @ -665,7 +621,7 @@ Data Types | |||
|          ...     GREEN = auto() | ||||
|          ...     BLUE = auto() | ||||
|          >>> ConformFlag(2**2 + 2**4) | ||||
|          <ConformFlag.BLUE: 4> | ||||
|          ConformFlag.BLUE | ||||
| 
 | ||||
|    .. attribute:: EJECT | ||||
| 
 | ||||
|  | @ -691,52 +647,12 @@ Data Types | |||
|          ...     GREEN = auto() | ||||
|          ...     BLUE = auto() | ||||
|          >>> KeepFlag(2**2 + 2**4) | ||||
|          <KeepFlag.BLUE|16: 20> | ||||
|          KeepFlag.BLUE|0x10 | ||||
| 
 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| --------------- | ||||
| 
 | ||||
| Supported ``__dunder__`` names | ||||
| """""""""""""""""""""""""""""" | ||||
| 
 | ||||
| :attr:`__members__` is a read-only ordered mapping of ``member_name``:``member`` | ||||
| items.  It is only available on the class. | ||||
| 
 | ||||
| :meth:`__new__`, if specified, must create and return the enum members; it is | ||||
| also a very good idea to set the member's :attr:`_value_` appropriately.  Once | ||||
| all the members are created it is no longer used. | ||||
| 
 | ||||
| 
 | ||||
| Supported ``_sunder_`` names | ||||
| """""""""""""""""""""""""""" | ||||
| 
 | ||||
| - ``_name_`` -- name of the member | ||||
| - ``_value_`` -- value of the member; can be set / modified in ``__new__`` | ||||
| 
 | ||||
| - ``_missing_`` -- a lookup function used when a value is not found; may be | ||||
|   overridden | ||||
| - ``_ignore_`` -- a list of names, either as a :class:`list` or a :class:`str`, | ||||
|   that will not be transformed into members, and will be removed from the final | ||||
|   class | ||||
| - ``_order_`` -- used in Python 2/3 code to ensure member order is consistent | ||||
|   (class attribute, removed during class creation) | ||||
| - ``_generate_next_value_`` -- used to get an appropriate value for an enum | ||||
|   member; may be overridden | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|        For standard :class:`Enum` classes the next value chosen is the last value seen | ||||
|        incremented by one. | ||||
| 
 | ||||
|        For :class:`Flag` classes the next value chosen will be the next highest | ||||
|        power-of-two, regardless of the last value seen. | ||||
| 
 | ||||
| .. versionadded:: 3.6 ``_missing_``, ``_order_``, ``_generate_next_value_`` | ||||
| .. versionadded:: 3.7 ``_ignore_`` | ||||
| 
 | ||||
| --------------- | ||||
| 
 | ||||
| Utilities and Decorators | ||||
| ------------------------ | ||||
| 
 | ||||
|  | @ -752,6 +668,15 @@ Utilities and Decorators | |||
|    ``_generate_next_value_`` can be overridden to customize the values used by | ||||
|    *auto*. | ||||
| 
 | ||||
| .. decorator:: global_enum | ||||
| 
 | ||||
|    A :keyword:`class` decorator specifically for enumerations.  It replaces the | ||||
|    :meth:`__repr__` method with one that shows *module_name*.*member_name*.  It | ||||
|    also injects the members, and their aliases, into the global namespace they | ||||
|    were defined in. | ||||
| 
 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| .. decorator:: property | ||||
| 
 | ||||
|    A decorator similar to the built-in *property*, but specifically for | ||||
|  | @ -763,7 +688,7 @@ Utilities and Decorators | |||
|              *Enum* class, and *Enum* subclasses can define members with the | ||||
|              names ``value`` and ``name``. | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| .. decorator:: unique | ||||
| 
 | ||||
|  | @ -789,7 +714,7 @@ Utilities and Decorators | |||
|    :class:`EnumCheck` are used to specify which constraints should be checked | ||||
|    on the decorated enumeration. | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| .. versionadded:: 3.11 | ||||
| 
 | ||||
| --------------- | ||||
| 
 | ||||
|  | @ -801,20 +726,14 @@ Notes | |||
|     These three enum types are designed to be drop-in replacements for existing | ||||
|     integer- and string-based values; as such, they have extra limitations: | ||||
| 
 | ||||
|     - ``__str__`` uses the value and not the name of the enum member | ||||
|     - ``format()`` will use the value of the enum member, unless ``__str__`` | ||||
|       has been overridden | ||||
| 
 | ||||
|     - ``__format__``, because it uses ``__str__``, will also use the value of | ||||
|       the enum member instead of its name | ||||
|     - ``StrEnum.__str__`` uses the value and not the name of the enum member | ||||
| 
 | ||||
|     If you do not need/want those limitations, you can either create your own | ||||
|     base class by mixing in the ``int`` or ``str`` type yourself:: | ||||
|     If you do not need/want those limitations, you can create your own base | ||||
|     class by mixing in the ``int`` or ``str`` type yourself:: | ||||
| 
 | ||||
|         >>> from enum import Enum | ||||
|         >>> class MyIntEnum(int, Enum): | ||||
|         ...     pass | ||||
| 
 | ||||
|    or you can reassign the appropriate :meth:`str`, etc., in your enum:: | ||||
| 
 | ||||
|         >>> from enum import IntEnum | ||||
|         >>> class MyIntEnum(IntEnum): | ||||
|         ...     __str__ = IntEnum.__str__ | ||||
|  |  | |||
|  | @ -2070,7 +2070,7 @@ to speed up repeated connections from the same clients. | |||
|       :attr:`SSLContext.verify_flags` returns :class:`VerifyFlags` flags: | ||||
| 
 | ||||
|          >>> ssl.create_default_context().verify_flags  # doctest: +SKIP | ||||
|          <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768> | ||||
|          ssl.VERIFY_X509_TRUSTED_FIRST | ||||
| 
 | ||||
| .. attribute:: SSLContext.verify_mode | ||||
| 
 | ||||
|  | @ -2082,7 +2082,7 @@ to speed up repeated connections from the same clients. | |||
|       :attr:`SSLContext.verify_mode` returns :class:`VerifyMode` enum: | ||||
| 
 | ||||
|          >>> ssl.create_default_context().verify_mode | ||||
|          <VerifyMode.CERT_REQUIRED: 2> | ||||
|          ssl.CERT_REQUIRED | ||||
| 
 | ||||
| .. index:: single: certificates | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										605
									
								
								Lib/enum.py
									
										
									
									
									
								
							
							
						
						
									
										605
									
								
								Lib/enum.py
									
										
									
									
									
								
							|  | @ -1,16 +1,16 @@ | |||
| import sys | ||||
| import builtins as bltns | ||||
| from types import MappingProxyType, DynamicClassAttribute | ||||
| from operator import or_ as _or_ | ||||
| from functools import reduce | ||||
| from builtins import property as _bltin_property, bin as _bltin_bin | ||||
| 
 | ||||
| 
 | ||||
| __all__ = [ | ||||
|         'EnumType', 'EnumMeta', | ||||
|         'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag', 'ReprEnum', | ||||
|         'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag', | ||||
|         'auto', 'unique', 'property', 'verify', | ||||
|         'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', | ||||
|         'global_flag_repr', 'global_enum_repr', 'global_str', 'global_enum', | ||||
|         'global_flag_repr', 'global_enum_repr', 'global_enum', | ||||
|         'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE', | ||||
|         ] | ||||
| 
 | ||||
|  | @ -18,7 +18,7 @@ | |||
| # Dummy value for Enum and Flag as there are explicit checks for them | ||||
| # before they have been created. | ||||
| # This is also why there are checks in EnumType like `if Enum is not None` | ||||
| Enum = Flag = EJECT = _stdlib_enums = ReprEnum = None | ||||
| Enum = Flag = EJECT = None | ||||
| 
 | ||||
| def _is_descriptor(obj): | ||||
|     """ | ||||
|  | @ -116,9 +116,9 @@ def bin(num, max_bits=None): | |||
| 
 | ||||
|     ceiling = 2 ** (num).bit_length() | ||||
|     if num >= 0: | ||||
|         s = bltns.bin(num + ceiling).replace('1', '0', 1) | ||||
|         s = _bltin_bin(num + ceiling).replace('1', '0', 1) | ||||
|     else: | ||||
|         s = bltns.bin(~num ^ (ceiling - 1) + ceiling) | ||||
|         s = _bltin_bin(~num ^ (ceiling - 1) + ceiling) | ||||
|     sign = s[:3] | ||||
|     digits = s[3:] | ||||
|     if max_bits is not None: | ||||
|  | @ -126,19 +126,6 @@ def bin(num, max_bits=None): | |||
|             digits = (sign[-1] * max_bits + digits)[-max_bits:] | ||||
|     return "%s %s" % (sign, digits) | ||||
| 
 | ||||
| def _dedent(text): | ||||
|     """ | ||||
|     Like textwrap.dedent.  Rewritten because we cannot import textwrap. | ||||
|     """ | ||||
|     lines = text.split('\n') | ||||
|     blanks = 0 | ||||
|     for i, ch in enumerate(lines[0]): | ||||
|         if ch != ' ': | ||||
|             break | ||||
|     for j, l in enumerate(lines): | ||||
|         lines[j] = l[i:] | ||||
|     return '\n'.join(lines) | ||||
| 
 | ||||
| 
 | ||||
| _auto_null = object() | ||||
| class auto: | ||||
|  | @ -162,12 +149,22 @@ def __get__(self, instance, ownerclass=None): | |||
|                 return ownerclass._member_map_[self.name] | ||||
|             except KeyError: | ||||
|                 raise AttributeError( | ||||
|                         '%r has no attribute %r' % (ownerclass, self.name) | ||||
|                         '%s: no class attribute %r' % (ownerclass.__name__, self.name) | ||||
|                         ) | ||||
|         else: | ||||
|             if self.fget is None: | ||||
|                 # check for member | ||||
|                 if self.name in ownerclass._member_map_: | ||||
|                     import warnings | ||||
|                     warnings.warn( | ||||
|                             "accessing one member from another is not supported, " | ||||
|                             " and will be disabled in 3.12", | ||||
|                             DeprecationWarning, | ||||
|                             stacklevel=2, | ||||
|                             ) | ||||
|                     return ownerclass._member_map_[self.name] | ||||
|                 raise AttributeError( | ||||
|                         '%r member has no attribute %r' % (ownerclass, self.name) | ||||
|                         '%s: no instance attribute %r' % (ownerclass.__name__, self.name) | ||||
|                         ) | ||||
|             else: | ||||
|                 return self.fget(instance) | ||||
|  | @ -175,7 +172,7 @@ def __get__(self, instance, ownerclass=None): | |||
|     def __set__(self, instance, value): | ||||
|         if self.fset is None: | ||||
|             raise AttributeError( | ||||
|                     "<enum %r> cannot set attribute %r" % (self.clsname, self.name) | ||||
|                     "%s: cannot set instance attribute %r" % (self.clsname, self.name) | ||||
|                     ) | ||||
|         else: | ||||
|             return self.fset(instance, value) | ||||
|  | @ -183,7 +180,7 @@ def __set__(self, instance, value): | |||
|     def __delete__(self, instance): | ||||
|         if self.fdel is None: | ||||
|             raise AttributeError( | ||||
|                     "<enum %r> cannot delete attribute %r" % (self.clsname, self.name) | ||||
|                     "%s: cannot delete instance attribute %r" % (self.clsname, self.name) | ||||
|                     ) | ||||
|         else: | ||||
|             return self.fdel(instance) | ||||
|  | @ -331,7 +328,7 @@ def __setitem__(self, key, value): | |||
|         elif _is_sunder(key): | ||||
|             if key not in ( | ||||
|                     '_order_', | ||||
|                     '_generate_next_value_', '_numeric_repr_', '_missing_', '_ignore_', | ||||
|                     '_generate_next_value_', '_missing_', '_ignore_', | ||||
|                     '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', | ||||
|                     ): | ||||
|                 raise ValueError( | ||||
|  | @ -361,13 +358,13 @@ def __setitem__(self, key, value): | |||
|                 key = '_order_' | ||||
|         elif key in self._member_names: | ||||
|             # descriptor overwriting an enum? | ||||
|             raise TypeError('%r already defined as %r' % (key, self[key])) | ||||
|             raise TypeError('%r already defined as: %r' % (key, self[key])) | ||||
|         elif key in self._ignore: | ||||
|             pass | ||||
|         elif not _is_descriptor(value): | ||||
|             if key in self: | ||||
|                 # enum overwriting a descriptor? | ||||
|                 raise TypeError('%r already defined as %r' % (key, self[key])) | ||||
|                 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( | ||||
|  | @ -398,7 +395,7 @@ class EnumType(type): | |||
|     @classmethod | ||||
|     def __prepare__(metacls, cls, bases, **kwds): | ||||
|         # check that previous enum members do not exist | ||||
|         metacls._check_for_existing_members_(cls, bases) | ||||
|         metacls._check_for_existing_members(cls, bases) | ||||
|         # create the namespace dict | ||||
|         enum_dict = _EnumDict() | ||||
|         enum_dict._cls_name = cls | ||||
|  | @ -416,10 +413,9 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|         # inherited __new__ unless a new __new__ is defined (or the resulting | ||||
|         # class will fail). | ||||
|         # | ||||
|         # remove any keys listed in _ignore_ | ||||
|         if _simple: | ||||
|             return super().__new__(metacls, cls, bases, classdict, **kwds) | ||||
|         # | ||||
|         # remove any keys listed in _ignore_ | ||||
|         classdict.setdefault('_ignore_', []).append('_ignore_') | ||||
|         ignore = classdict['_ignore_'] | ||||
|         for key in ignore: | ||||
|  | @ -431,8 +427,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|         # check for illegal enum names (any others?) | ||||
|         invalid_names = set(member_names) & {'mro', ''} | ||||
|         if invalid_names: | ||||
|             raise ValueError('invalid enum member name(s) '.format( | ||||
|                 ','.join(repr(n) for n in invalid_names))) | ||||
|             raise ValueError('Invalid enum member name: {0}'.format( | ||||
|                 ','.join(invalid_names))) | ||||
|         # | ||||
|         # adjust the sunders | ||||
|         _order_ = classdict.pop('_order_', None) | ||||
|  | @ -462,8 +458,6 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|         classdict['_value2member_map_'] = {} | ||||
|         classdict['_unhashable_values_'] = [] | ||||
|         classdict['_member_type_'] = member_type | ||||
|         # now set the __repr__ for the value | ||||
|         classdict['_value_repr_'] = metacls._find_data_repr_(cls, bases) | ||||
|         # | ||||
|         # Flag structures (will be removed if final class is not a Flag | ||||
|         classdict['_boundary_'] = ( | ||||
|  | @ -473,6 +467,10 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|         classdict['_flag_mask_'] = flag_mask | ||||
|         classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1 | ||||
|         classdict['_inverted_'] = None | ||||
|         # | ||||
|         # create a default docstring if one has not been provided | ||||
|         if '__doc__' not in classdict: | ||||
|             classdict['__doc__'] = 'An enumeration.' | ||||
|         try: | ||||
|             exc = None | ||||
|             enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) | ||||
|  | @ -483,140 +481,18 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|         if exc is not None: | ||||
|             raise exc | ||||
|         # | ||||
|         # update classdict with any changes made by __init_subclass__ | ||||
|         classdict.update(enum_class.__dict__) | ||||
|         # | ||||
|         # create a default docstring if one has not been provided | ||||
|         if enum_class.__doc__ is None: | ||||
|             if not member_names: | ||||
|                 enum_class.__doc__ = classdict['__doc__'] = _dedent("""\ | ||||
|                         Create a collection of name/value pairs. | ||||
| 
 | ||||
|                         Example enumeration: | ||||
| 
 | ||||
|                         >>> class Color(Enum): | ||||
|                         ...     RED = 1 | ||||
|                         ...     BLUE = 2 | ||||
|                         ...     GREEN = 3 | ||||
| 
 | ||||
|                         Access them by: | ||||
| 
 | ||||
|                         - attribute access:: | ||||
| 
 | ||||
|                         >>> Color.RED | ||||
|                         <Color.RED: 1> | ||||
| 
 | ||||
|                         - value lookup: | ||||
| 
 | ||||
|                         >>> Color(1) | ||||
|                         <Color.RED: 1> | ||||
| 
 | ||||
|                         - name lookup: | ||||
| 
 | ||||
|                         >>> Color['RED'] | ||||
|                         <Color.RED: 1> | ||||
| 
 | ||||
|                         Enumerations can be iterated over, and know how many members they have: | ||||
| 
 | ||||
|                         >>> len(Color) | ||||
|                         3 | ||||
| 
 | ||||
|                         >>> list(Color) | ||||
|                         [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>] | ||||
| 
 | ||||
|                         Methods can be added to enumerations, and members can have their own | ||||
|                         attributes -- see the documentation for details. | ||||
|                         """) | ||||
|             else: | ||||
|                 member = list(enum_class)[0] | ||||
|                 enum_length = len(enum_class) | ||||
|                 cls_name = enum_class.__name__ | ||||
|                 if enum_length == 1: | ||||
|                     list_line = 'list(%s)' % cls_name | ||||
|                     list_repr = '[<%s.%s: %r>]' % (cls_name, member.name, member.value) | ||||
|                 elif enum_length == 2: | ||||
|                     member2 = list(enum_class)[1] | ||||
|                     list_line = 'list(%s)' % cls_name | ||||
|                     list_repr = '[<%s.%s: %r>, <%s.%s: %r>]' % ( | ||||
|                             cls_name, member.name, member.value, | ||||
|                             cls_name, member2.name, member2.value, | ||||
|                             ) | ||||
|                 else: | ||||
|                     member2 = list(enum_class)[1] | ||||
|                     member3 = list(enum_class)[2] | ||||
|                     list_line = 'list(%s)%s' % (cls_name, ('','[:3]')[enum_length > 3]) | ||||
|                     list_repr = '[<%s.%s: %r>, <%s.%s: %r>, <%s.%s: %r>]' % ( | ||||
|                             cls_name, member.name, member.value, | ||||
|                             cls_name, member2.name, member2.value, | ||||
|                             cls_name, member3.name, member3.value, | ||||
|                             ) | ||||
|                 enum_class.__doc__ = classdict['__doc__'] = _dedent("""\ | ||||
|                         A collection of name/value pairs. | ||||
| 
 | ||||
|                         Access them by: | ||||
| 
 | ||||
|                         - attribute access:: | ||||
| 
 | ||||
|                         >>> %s.%s | ||||
|                         <%s.%s: %r> | ||||
| 
 | ||||
|                         - value lookup: | ||||
| 
 | ||||
|                         >>> %s(%r) | ||||
|                         <%s.%s: %r> | ||||
| 
 | ||||
|                         - name lookup: | ||||
| 
 | ||||
|                         >>> %s[%r] | ||||
|                         <%s.%s: %r> | ||||
| 
 | ||||
|                         Enumerations can be iterated over, and know how many members they have: | ||||
| 
 | ||||
|                         >>> len(%s) | ||||
|                         %r | ||||
| 
 | ||||
|                         >>> %s | ||||
|                         %s | ||||
| 
 | ||||
|                         Methods can be added to enumerations, and members can have their own | ||||
|                         attributes -- see the documentation for details. | ||||
|                         """ | ||||
|                         % (cls_name, member.name, | ||||
|                             cls_name, member.name, member.value, | ||||
|                             cls_name, member.value, | ||||
|                             cls_name, member.name, member.value, | ||||
|                             cls_name, member.name, | ||||
|                             cls_name, member.name, member.value, | ||||
|                             cls_name, enum_length, | ||||
|                             list_line, list_repr, | ||||
|                         )) | ||||
|         # | ||||
|         # double check that repr and friends are not the mixin's or various | ||||
|         # things break (such as pickle) | ||||
|         # however, if the method is defined in the Enum itself, don't replace | ||||
|         # it | ||||
|         # | ||||
|         # Also, special handling for ReprEnum | ||||
|         if ReprEnum is not None and ReprEnum in bases: | ||||
|             if member_type is object: | ||||
|                 raise TypeError( | ||||
|                         'ReprEnum subclasses must be mixed with a data type (i.e.' | ||||
|                         ' int, str, float, etc.)' | ||||
|                         ) | ||||
|             if '__format__' not in classdict: | ||||
|                 enum_class.__format__ = member_type.__format__ | ||||
|                 classdict['__format__'] = enum_class.__format__ | ||||
|             if '__str__' not in classdict: | ||||
|                 method = member_type.__str__ | ||||
|                 if method is object.__str__: | ||||
|                     # if member_type does not define __str__, object.__str__ will use | ||||
|                     # its __repr__ instead, so we'll also use its __repr__ | ||||
|                     method = member_type.__repr__ | ||||
|                 enum_class.__str__ = method | ||||
|                 classdict['__str__'] = enum_class.__str__ | ||||
|         for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): | ||||
|             if name not in classdict: | ||||
|                 setattr(enum_class, name, getattr(first_enum, name)) | ||||
|             if name in classdict: | ||||
|                 continue | ||||
|             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 | ||||
|  | @ -687,13 +563,13 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k | |||
|             # _order_ step 4: verify that _order_ and _member_names_ match | ||||
|             if _order_ != enum_class._member_names_: | ||||
|                 raise TypeError( | ||||
|                         'member order does not match _order_:\n  %r\n  %r' | ||||
|                         'member order does not match _order_:\n%r\n%r' | ||||
|                         % (enum_class._member_names_, _order_) | ||||
|                         ) | ||||
|         # | ||||
|         return enum_class | ||||
| 
 | ||||
|     def __bool__(cls): | ||||
|     def __bool__(self): | ||||
|         """ | ||||
|         classes/types should always be True. | ||||
|         """ | ||||
|  | @ -738,13 +614,6 @@ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, s | |||
|                 ) | ||||
| 
 | ||||
|     def __contains__(cls, member): | ||||
|         """ | ||||
|         Return True if member is a member of this enum | ||||
|         raises TypeError if member is not an enum member | ||||
| 
 | ||||
|         note: in 3.12 TypeError will no longer be raised, and True will also be | ||||
|         returned if member is the value of a member in this enum | ||||
|         """ | ||||
|         if not isinstance(member, Enum): | ||||
|             import warnings | ||||
|             warnings.warn( | ||||
|  | @ -762,33 +631,60 @@ def __delattr__(cls, attr): | |||
|         # nicer error message when someone tries to delete an attribute | ||||
|         # (see issue19025). | ||||
|         if attr in cls._member_map_: | ||||
|             raise AttributeError("%r cannot delete member %r." % (cls.__name__, attr)) | ||||
|             raise AttributeError("%s: cannot delete Enum member %r." % (cls.__name__, attr)) | ||||
|         super().__delattr__(attr) | ||||
| 
 | ||||
|     def __dir__(cls): | ||||
|         # TODO: check for custom __init__, __new__, __format__, __repr__, __str__, __init_subclass__ | ||||
|         # on object-based enums | ||||
|         if cls._member_type_ is object: | ||||
|             interesting = set(cls._member_names_) | ||||
|             if cls._new_member_ is not object.__new__: | ||||
|                 interesting.add('__new__') | ||||
|             if cls.__init_subclass__ is not object.__init_subclass__: | ||||
|                 interesting.add('__init_subclass__') | ||||
|             for method in ('__init__', '__format__', '__repr__', '__str__'): | ||||
|                 if getattr(cls, method) not in (getattr(Enum, method), getattr(Flag, method)): | ||||
|                     interesting.add(method) | ||||
|             return sorted(set([ | ||||
|                     '__class__', '__contains__', '__doc__', '__getitem__', | ||||
|                     '__iter__', '__len__', '__members__', '__module__', | ||||
|                     '__name__', '__qualname__', | ||||
|                     ]) | interesting | ||||
|                     ) | ||||
|         else: | ||||
|             # return whatever mixed-in data type has | ||||
|             return sorted(set( | ||||
|                     dir(cls._member_type_) | ||||
|                     + cls._member_names_ | ||||
|                     )) | ||||
|     def __dir__(self): | ||||
|         # Start off with the desired result for dir(Enum) | ||||
|         cls_dir = {'__class__', '__doc__', '__members__', '__module__'} | ||||
|         add_to_dir = cls_dir.add | ||||
|         mro = self.__mro__ | ||||
|         this_module = globals().values() | ||||
|         is_from_this_module = lambda cls: any(cls is thing for thing in this_module) | ||||
|         first_enum_base = next(cls for cls in mro if is_from_this_module(cls)) | ||||
|         enum_dict = Enum.__dict__ | ||||
|         sentinel = object() | ||||
|         # special-case __new__ | ||||
|         ignored = {'__new__', *filter(_is_sunder, enum_dict)} | ||||
|         add_to_ignored = ignored.add | ||||
| 
 | ||||
|         # We want these added to __dir__ | ||||
|         # if and only if they have been user-overridden | ||||
|         enum_dunders = set(filter(_is_dunder, enum_dict)) | ||||
| 
 | ||||
|         for cls in mro: | ||||
|             # Ignore any classes defined in this module | ||||
|             if cls is object or is_from_this_module(cls): | ||||
|                 continue | ||||
| 
 | ||||
|             cls_lookup = cls.__dict__ | ||||
| 
 | ||||
|             # If not an instance of EnumType, | ||||
|             # ensure all attributes excluded from that class's `dir()` are ignored here. | ||||
|             if not isinstance(cls, EnumType): | ||||
|                 cls_lookup = set(cls_lookup).intersection(dir(cls)) | ||||
| 
 | ||||
|             for attr_name in cls_lookup: | ||||
|                 # Already seen it? Carry on | ||||
|                 if attr_name in cls_dir or attr_name in ignored: | ||||
|                     continue | ||||
|                 # Sunders defined in Enum.__dict__ are already in `ignored`, | ||||
|                 # But sunders defined in a subclass won't be (we want all sunders excluded). | ||||
|                 elif _is_sunder(attr_name): | ||||
|                     add_to_ignored(attr_name) | ||||
|                 # Not an "enum dunder"? Add it to dir() output. | ||||
|                 elif attr_name not in enum_dunders: | ||||
|                     add_to_dir(attr_name) | ||||
|                 # Is an "enum dunder", and is defined by a class from enum.py? Ignore it. | ||||
|                 elif getattr(self, attr_name) is getattr(first_enum_base, attr_name, sentinel): | ||||
|                     add_to_ignored(attr_name) | ||||
|                 # Is an "enum dunder", and is either user-defined or defined by a mixin class? | ||||
|                 # Add it to dir() output. | ||||
|                 else: | ||||
|                     add_to_dir(attr_name) | ||||
| 
 | ||||
|         # sort the output before returning it, so that the result is deterministic. | ||||
|         return sorted(cls_dir) | ||||
| 
 | ||||
|     def __getattr__(cls, name): | ||||
|         """ | ||||
|  | @ -807,24 +703,18 @@ def __getattr__(cls, name): | |||
|             raise AttributeError(name) from None | ||||
| 
 | ||||
|     def __getitem__(cls, name): | ||||
|         """ | ||||
|         Return the member matching `name`. | ||||
|         """ | ||||
|         return cls._member_map_[name] | ||||
| 
 | ||||
|     def __iter__(cls): | ||||
|         """ | ||||
|         Return members in definition order. | ||||
|         Returns members in definition order. | ||||
|         """ | ||||
|         return (cls._member_map_[name] for name in cls._member_names_) | ||||
| 
 | ||||
|     def __len__(cls): | ||||
|         """ | ||||
|         Return the number of members (no aliases) | ||||
|         """ | ||||
|         return len(cls._member_names_) | ||||
| 
 | ||||
|     @bltns.property | ||||
|     @_bltin_property | ||||
|     def __members__(cls): | ||||
|         """ | ||||
|         Returns a mapping of member name->value. | ||||
|  | @ -842,7 +732,7 @@ def __repr__(cls): | |||
| 
 | ||||
|     def __reversed__(cls): | ||||
|         """ | ||||
|         Return members in reverse definition order. | ||||
|         Returns members in reverse definition order. | ||||
|         """ | ||||
|         return (cls._member_map_[name] for name in reversed(cls._member_names_)) | ||||
| 
 | ||||
|  | @ -856,7 +746,7 @@ def __setattr__(cls, name, value): | |||
|         """ | ||||
|         member_map = cls.__dict__.get('_member_map_', {}) | ||||
|         if name in member_map: | ||||
|             raise AttributeError('cannot reassign member %r' % (name, )) | ||||
|             raise AttributeError('Cannot reassign member %r.' % (name, )) | ||||
|         super().__setattr__(name, value) | ||||
| 
 | ||||
|     def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1, boundary=None): | ||||
|  | @ -911,7 +801,8 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s | |||
| 
 | ||||
|         return metacls.__new__(metacls, class_name, bases, classdict, boundary=boundary) | ||||
| 
 | ||||
|     def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_global=False): | ||||
|     def _convert_(cls, name, module, filter, source=None, *, boundary=None): | ||||
| 
 | ||||
|         """ | ||||
|         Create a new Enum subclass that replaces a collection of global constants | ||||
|         """ | ||||
|  | @ -943,25 +834,22 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa | |||
|         tmp_cls = type(name, (object, ), body) | ||||
|         cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls) | ||||
|         cls.__reduce_ex__ = _reduce_ex_by_global_name | ||||
|         if as_global: | ||||
|             global_enum(cls) | ||||
|         else: | ||||
|             sys.modules[cls.__module__].__dict__.update(cls.__members__) | ||||
|         global_enum(cls) | ||||
|         module_globals[name] = cls | ||||
|         return cls | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _check_for_existing_members_(mcls, class_name, bases): | ||||
|     @staticmethod | ||||
|     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( | ||||
|                             "<enum %r> cannot extend %r" | ||||
|                             % (class_name, base) | ||||
|                             "%s: cannot extend enumeration %r" | ||||
|                             % (class_name, base.__name__) | ||||
|                             ) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _get_mixins_(mcls, class_name, bases): | ||||
|     def _get_mixins_(cls, class_name, bases): | ||||
|         """ | ||||
|         Returns the type for creating enum members, and the first inherited | ||||
|         enum class. | ||||
|  | @ -971,7 +859,30 @@ def _get_mixins_(mcls, class_name, bases): | |||
|         if not bases: | ||||
|             return object, Enum | ||||
| 
 | ||||
|         mcls._check_for_existing_members_(class_name, bases) | ||||
|         def _find_data_type(bases): | ||||
|             data_types = set() | ||||
|             for chain in bases: | ||||
|                 candidate = None | ||||
|                 for base in chain.__mro__: | ||||
|                     if base is object: | ||||
|                         continue | ||||
|                     elif issubclass(base, Enum): | ||||
|                         if base._member_type_ is not object: | ||||
|                             data_types.add(base._member_type_) | ||||
|                             break | ||||
|                     elif '__new__' in base.__dict__: | ||||
|                         if issubclass(base, Enum): | ||||
|                             continue | ||||
|                         data_types.add(candidate or base) | ||||
|                         break | ||||
|                     else: | ||||
|                         candidate = candidate or base | ||||
|             if len(data_types) > 1: | ||||
|                 raise TypeError('%r: too many data types: %r' % (class_name, data_types)) | ||||
|             elif data_types: | ||||
|                 return data_types.pop() | ||||
|             else: | ||||
|                 return None | ||||
| 
 | ||||
|         # ensure final parent class is an Enum derivative, find any concrete | ||||
|         # data type, and check that Enum has no members | ||||
|  | @ -979,51 +890,12 @@ def _get_mixins_(mcls, class_name, bases): | |||
|         if not issubclass(first_enum, Enum): | ||||
|             raise TypeError("new enumerations should be created as " | ||||
|                     "`EnumName([mixin_type, ...] [data_type,] enum_type)`") | ||||
|         member_type = mcls._find_data_type_(class_name, bases) or object | ||||
|         cls._check_for_existing_members(class_name, bases) | ||||
|         member_type = _find_data_type(bases) or object | ||||
|         return member_type, first_enum | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _find_data_repr_(mcls, class_name, bases): | ||||
|         for chain in bases: | ||||
|             for base in chain.__mro__: | ||||
|                 if base is object: | ||||
|                     continue | ||||
|                 elif issubclass(base, Enum): | ||||
|                     # if we hit an Enum, use it's _value_repr_ | ||||
|                     return base._value_repr_ | ||||
|                 elif '__repr__' in base.__dict__: | ||||
|                     # this is our data repr | ||||
|                     return base.__dict__['__repr__'] | ||||
|         return None | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _find_data_type_(mcls, class_name, bases): | ||||
|         data_types = set() | ||||
|         for chain in bases: | ||||
|             candidate = None | ||||
|             for base in chain.__mro__: | ||||
|                 if base is object: | ||||
|                     continue | ||||
|                 elif issubclass(base, Enum): | ||||
|                     if base._member_type_ is not object: | ||||
|                         data_types.add(base._member_type_) | ||||
|                         break | ||||
|                 elif '__new__' in base.__dict__: | ||||
|                     if issubclass(base, Enum): | ||||
|                         continue | ||||
|                     data_types.add(candidate or base) | ||||
|                     break | ||||
|                 else: | ||||
|                     candidate = candidate or base | ||||
|         if len(data_types) > 1: | ||||
|             raise TypeError('too many data types for %r: %r' % (class_name, data_types)) | ||||
|         elif data_types: | ||||
|             return data_types.pop() | ||||
|         else: | ||||
|             return None | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _find_new_(mcls, classdict, member_type, first_enum): | ||||
|     @staticmethod | ||||
|     def _find_new_(classdict, member_type, first_enum): | ||||
|         """ | ||||
|         Returns the __new__ to be used for creating the enum members. | ||||
| 
 | ||||
|  | @ -1071,42 +943,9 @@ def _find_new_(mcls, classdict, member_type, first_enum): | |||
| 
 | ||||
| class Enum(metaclass=EnumType): | ||||
|     """ | ||||
|     Create a collection of name/value pairs. | ||||
|     Generic enumeration. | ||||
| 
 | ||||
|     Example enumeration: | ||||
| 
 | ||||
|     >>> class Color(Enum): | ||||
|     ...     RED = 1 | ||||
|     ...     BLUE = 2 | ||||
|     ...     GREEN = 3 | ||||
| 
 | ||||
|     Access them by: | ||||
| 
 | ||||
|     - attribute access:: | ||||
| 
 | ||||
|     >>> Color.RED | ||||
|     <Color.RED: 1> | ||||
| 
 | ||||
|     - value lookup: | ||||
| 
 | ||||
|     >>> Color(1) | ||||
|     <Color.RED: 1> | ||||
| 
 | ||||
|     - name lookup: | ||||
| 
 | ||||
|     >>> Color['RED'] | ||||
|     <Color.RED: 1> | ||||
| 
 | ||||
|     Enumerations can be iterated over, and know how many members they have: | ||||
| 
 | ||||
|     >>> len(Color) | ||||
|     3 | ||||
| 
 | ||||
|     >>> list(Color) | ||||
|     [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>] | ||||
| 
 | ||||
|     Methods can be added to enumerations, and members can have their own | ||||
|     attributes -- see the documentation for details. | ||||
|     Derive from this class to define new enumerations. | ||||
|     """ | ||||
| 
 | ||||
|     def __new__(cls, value): | ||||
|  | @ -1160,9 +999,6 @@ def __new__(cls, value): | |||
|             exc = None | ||||
|             ve_exc = None | ||||
| 
 | ||||
|     def __init__(self, *args, **kwds): | ||||
|         pass | ||||
| 
 | ||||
|     def _generate_next_value_(name, start, count, last_values): | ||||
|         """ | ||||
|         Generate the next value when not given. | ||||
|  | @ -1185,44 +1021,47 @@ def _missing_(cls, value): | |||
|         return None | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__ | ||||
|         return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) | ||||
|         return "%s.%s" % ( self.__class__.__name__, self._name_) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s.%s" % (self.__class__.__name__, self._name_, ) | ||||
|         return "%s" % (self._name_, ) | ||||
| 
 | ||||
|     def __dir__(self): | ||||
|         """ | ||||
|         Returns all members and all public methods | ||||
|         """ | ||||
|         if self.__class__._member_type_ is object: | ||||
|             interesting = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value']) | ||||
|         else: | ||||
|             interesting = set(object.__dir__(self)) | ||||
|         for name in getattr(self, '__dict__', []): | ||||
|             if name[0] != '_': | ||||
|                 interesting.add(name) | ||||
|         for cls in self.__class__.mro(): | ||||
|             for name, obj in cls.__dict__.items(): | ||||
|                 if name[0] == '_': | ||||
|                     continue | ||||
|                 if isinstance(obj, property): | ||||
|                     # that's an enum.property | ||||
|                     if obj.fget is not None or name not in self._member_map_: | ||||
|                         interesting.add(name) | ||||
|                     else: | ||||
|                         # in case it was added by `dir(self)` | ||||
|                         interesting.discard(name) | ||||
|                 else: | ||||
|                     interesting.add(name) | ||||
|         names = sorted( | ||||
|                 set(['__class__', '__doc__', '__eq__', '__hash__', '__module__']) | ||||
|                 | interesting | ||||
|                 ) | ||||
|         return names | ||||
|         cls = type(self) | ||||
|         to_exclude = {'__members__', '__init__', '__new__', *cls._member_names_} | ||||
|         filtered_self_dict = (name for name in self.__dict__ if not name.startswith('_')) | ||||
|         return sorted({'name', 'value', *dir(cls), *filtered_self_dict} - to_exclude) | ||||
| 
 | ||||
|     def __format__(self, format_spec): | ||||
|         return str.__format__(str(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 | ||||
|         # | ||||
|         # pure Enum branch, or branch with __str__ explicitly overridden | ||||
|         str_overridden = type(self).__str__ not in (Enum.__str__, IntEnum.__str__, Flag.__str__) | ||||
|         if self._member_type_ is object or str_overridden: | ||||
|             cls = str | ||||
|             val = str(self) | ||||
|         # mix-in branch | ||||
|         else: | ||||
|             if not format_spec or format_spec in ('{}','{:}'): | ||||
|                 import warnings | ||||
|                 warnings.warn( | ||||
|                         "in 3.12 format() will use the enum member, not the enum member's value;\n" | ||||
|                         "use a format specifier, such as :d for an integer-based Enum, to maintain " | ||||
|                         "the current display", | ||||
|                         DeprecationWarning, | ||||
|                         stacklevel=2, | ||||
|                         ) | ||||
|             cls = self._member_type_ | ||||
|             val = self._value_ | ||||
|         return cls.__format__(val, format_spec) | ||||
| 
 | ||||
|     def __hash__(self): | ||||
|         return hash(self._name_) | ||||
|  | @ -1249,25 +1088,34 @@ def value(self): | |||
|         return self._value_ | ||||
| 
 | ||||
| 
 | ||||
| class ReprEnum(Enum): | ||||
|     """ | ||||
|     Only changes the repr(), leaving str() and format() to the mixed-in type. | ||||
|     """ | ||||
| 
 | ||||
| 
 | ||||
| class IntEnum(int, ReprEnum): | ||||
| class IntEnum(int, Enum): | ||||
|     """ | ||||
|     Enum where members are also (and must be) ints | ||||
|     """ | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s" % (self._name_, ) | ||||
| 
 | ||||
| class StrEnum(str, ReprEnum): | ||||
|     def __format__(self, format_spec): | ||||
|         """ | ||||
|         Returns format using actual value unless __str__ has been overridden. | ||||
|         """ | ||||
|         str_overridden = type(self).__str__ != IntEnum.__str__ | ||||
|         if str_overridden: | ||||
|             cls = str | ||||
|             val = str(self) | ||||
|         else: | ||||
|             cls = self._member_type_ | ||||
|             val = self._value_ | ||||
|         return cls.__format__(val, format_spec) | ||||
| 
 | ||||
| 
 | ||||
| class StrEnum(str, Enum): | ||||
|     """ | ||||
|     Enum where members are also (and must be) strings | ||||
|     """ | ||||
| 
 | ||||
|     def __new__(cls, *values): | ||||
|         "values must already be of type `str`" | ||||
|         if len(values) > 3: | ||||
|             raise TypeError('too many arguments for str(): %r' % (values, )) | ||||
|         if len(values) == 1: | ||||
|  | @ -1287,6 +1135,10 @@ def __new__(cls, *values): | |||
|         member._value_ = value | ||||
|         return member | ||||
| 
 | ||||
|     __str__ = str.__str__ | ||||
| 
 | ||||
|     __format__ = str.__format__ | ||||
| 
 | ||||
|     def _generate_next_value_(name, start, count, last_values): | ||||
|         """ | ||||
|         Return the lower-cased version of the member name. | ||||
|  | @ -1317,8 +1169,6 @@ class Flag(Enum, boundary=STRICT): | |||
|     Support for flags | ||||
|     """ | ||||
| 
 | ||||
|     _numeric_repr_ = repr | ||||
| 
 | ||||
|     def _generate_next_value_(name, start, count, last_values): | ||||
|         """ | ||||
|         Generate the next value when not given. | ||||
|  | @ -1334,7 +1184,7 @@ def _generate_next_value_(name, start, count, last_values): | |||
|         try: | ||||
|             high_bit = _high_bit(last_value) | ||||
|         except Exception: | ||||
|             raise TypeError('invalid flag value %r' % last_value) from None | ||||
|             raise TypeError('Invalid Flag value: %r' % last_value) from None | ||||
|         return 2 ** (high_bit+1) | ||||
| 
 | ||||
|     @classmethod | ||||
|  | @ -1382,8 +1232,8 @@ def _missing_(cls, value): | |||
|             if cls._boundary_ is STRICT: | ||||
|                 max_bits = max(value.bit_length(), flag_mask.bit_length()) | ||||
|                 raise ValueError( | ||||
|                         "%r invalid value %r\n    given %s\n  allowed %s" % ( | ||||
|                             cls, value, bin(value, max_bits), bin(flag_mask, max_bits), | ||||
|                         "%s: invalid value: %r\n    given %s\n  allowed %s" % ( | ||||
|                             cls.__name__, value, bin(value, max_bits), bin(flag_mask, max_bits), | ||||
|                             )) | ||||
|             elif cls._boundary_ is CONFORM: | ||||
|                 value = value & flag_mask | ||||
|  | @ -1397,7 +1247,7 @@ def _missing_(cls, value): | |||
|                             ) | ||||
|             else: | ||||
|                 raise ValueError( | ||||
|                         '%r unknown flag boundary %r' % (cls, cls._boundary_, ) | ||||
|                         'unknown flag boundary: %r' % (cls._boundary_, ) | ||||
|                         ) | ||||
|         if value < 0: | ||||
|             neg_value = value | ||||
|  | @ -1424,7 +1274,7 @@ def _missing_(cls, value): | |||
|                 m._name_ for m in cls._iter_member_(member_value) | ||||
|                 ]) | ||||
|             if unknown: | ||||
|                 pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown) | ||||
|                 pseudo_member._name_ += '|0x%x' % unknown | ||||
|         else: | ||||
|             pseudo_member._name_ = None | ||||
|         # use setdefault in case another thread already created a composite | ||||
|  | @ -1442,8 +1292,10 @@ def __contains__(self, other): | |||
|         """ | ||||
|         if not isinstance(other, self.__class__): | ||||
|             raise TypeError( | ||||
|                 "unsupported operand type(s) for 'in': %r and %r" % ( | ||||
|                 "unsupported operand type(s) for 'in': '%s' and '%s'" % ( | ||||
|                     type(other).__qualname__, self.__class__.__qualname__)) | ||||
|         if other._value_ == 0 or self._value_ == 0: | ||||
|             return False | ||||
|         return other._value_ & self._value_ == other._value_ | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|  | @ -1457,18 +1309,27 @@ def __len__(self): | |||
| 
 | ||||
|     def __repr__(self): | ||||
|         cls_name = self.__class__.__name__ | ||||
|         v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__ | ||||
|         if self._name_ is None: | ||||
|             return "<%s: %s>" % (cls_name, v_repr(self._value_)) | ||||
|             return "0x%x" % (self._value_, ) | ||||
|         if _is_single_bit(self._value_): | ||||
|             return '%s.%s' % (cls_name, self._name_) | ||||
|         if self._boundary_ is not FlagBoundary.KEEP: | ||||
|             return '%s.' % cls_name + ('|%s.' % cls_name).join(self.name.split('|')) | ||||
|         else: | ||||
|             return "<%s.%s: %s>" % (cls_name, self._name_, v_repr(self._value_)) | ||||
|             name = [] | ||||
|             for n in self._name_.split('|'): | ||||
|                 if n.startswith('0'): | ||||
|                     name.append(n) | ||||
|                 else: | ||||
|                     name.append('%s.%s' % (cls_name, n)) | ||||
|             return '|'.join(name) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         cls_name = self.__class__.__name__ | ||||
|         cls = self.__class__ | ||||
|         if self._name_ is None: | ||||
|             return '%s(%r)' % (cls_name, self._value_) | ||||
|             return '%s(%x)' % (cls.__name__, self._value_) | ||||
|         else: | ||||
|             return "%s.%s" % (cls_name, self._name_) | ||||
|             return self._name_ | ||||
| 
 | ||||
|     def __bool__(self): | ||||
|         return bool(self._value_) | ||||
|  | @ -1501,11 +1362,20 @@ def __invert__(self): | |||
|         return self._inverted_ | ||||
| 
 | ||||
| 
 | ||||
| class IntFlag(int, ReprEnum, Flag, boundary=EJECT): | ||||
| class IntFlag(int, Flag, boundary=EJECT): | ||||
|     """ | ||||
|     Support for integer-based Flags | ||||
|     """ | ||||
| 
 | ||||
|     def __format__(self, format_spec): | ||||
|         """ | ||||
|         Returns format using actual value unless __str__ has been overridden. | ||||
|         """ | ||||
|         str_overridden = type(self).__str__ != Flag.__str__ | ||||
|         value = self | ||||
|         if not str_overridden: | ||||
|             value = self._value_ | ||||
|         return int.__format__(value, format_spec) | ||||
| 
 | ||||
|     def __or__(self, other): | ||||
|         if isinstance(other, self.__class__): | ||||
|  | @ -1542,7 +1412,6 @@ def __xor__(self, other): | |||
|     __rxor__ = __xor__ | ||||
|     __invert__ = Flag.__invert__ | ||||
| 
 | ||||
| 
 | ||||
| def _high_bit(value): | ||||
|     """ | ||||
|     returns index of highest bit, or -1 if value is zero or negative | ||||
|  | @ -1587,7 +1456,7 @@ def global_flag_repr(self): | |||
|     module = self.__class__.__module__.split('.')[-1] | ||||
|     cls_name = self.__class__.__name__ | ||||
|     if self._name_ is None: | ||||
|         return "%s.%s(%r)" % (module, cls_name, self._value_) | ||||
|         return "%s.%s(0x%x)" % (module, cls_name, self._value_) | ||||
|     if _is_single_bit(self): | ||||
|         return '%s.%s' % (module, self._name_) | ||||
|     if self._boundary_ is not FlagBoundary.KEEP: | ||||
|  | @ -1595,22 +1464,14 @@ def global_flag_repr(self): | |||
|     else: | ||||
|         name = [] | ||||
|         for n in self._name_.split('|'): | ||||
|             if n[0].isdigit(): | ||||
|             if n.startswith('0'): | ||||
|                 name.append(n) | ||||
|             else: | ||||
|                 name.append('%s.%s' % (module, n)) | ||||
|         return '|'.join(name) | ||||
| 
 | ||||
| def global_str(self): | ||||
|     """ | ||||
|     use enum_name instead of class.enum_name | ||||
|     """ | ||||
|     if self._name_ is None: | ||||
|         return "%s(%r)" % (cls_name, self._value_) | ||||
|     else: | ||||
|         return self._name_ | ||||
| 
 | ||||
| def global_enum(cls, update_str=False): | ||||
| def global_enum(cls): | ||||
|     """ | ||||
|     decorator that makes the repr() of an enum member reference its module | ||||
|     instead of its class; also exports all members to the enum's module's | ||||
|  | @ -1620,8 +1481,6 @@ def global_enum(cls, update_str=False): | |||
|         cls.__repr__ = global_flag_repr | ||||
|     else: | ||||
|         cls.__repr__ = global_enum_repr | ||||
|     if not issubclass(cls, ReprEnum) or update_str: | ||||
|         cls.__str__ = global_str | ||||
|     sys.modules[cls.__module__].__dict__.update(cls.__members__) | ||||
|     return cls | ||||
| 
 | ||||
|  | @ -1663,7 +1522,6 @@ def convert_class(cls): | |||
|         body['_value2member_map_'] = value2member_map = {} | ||||
|         body['_unhashable_values_'] = [] | ||||
|         body['_member_type_'] = member_type = etype._member_type_ | ||||
|         body['_value_repr_'] = etype._value_repr_ | ||||
|         if issubclass(etype, Flag): | ||||
|             body['_boundary_'] = boundary or etype._boundary_ | ||||
|             body['_flag_mask_'] = None | ||||
|  | @ -1685,8 +1543,13 @@ def convert_class(cls): | |||
|         # it | ||||
|         enum_class = type(cls_name, (etype, ), body, boundary=boundary, _simple=True) | ||||
|         for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): | ||||
|             if name not in body: | ||||
|                 setattr(enum_class, name, getattr(etype, name)) | ||||
|             if name in body: | ||||
|                 continue | ||||
|             class_method = getattr(enum_class, name) | ||||
|             obj_method = getattr(member_type, name, None) | ||||
|             enum_method = getattr(etype, name, None) | ||||
|             if obj_method is not None and obj_method is class_method: | ||||
|                 setattr(enum_class, name, enum_method) | ||||
|         gnv_last_values = [] | ||||
|         if issubclass(enum_class, Flag): | ||||
|             # Flag / IntFlag | ||||
|  | @ -1897,8 +1760,8 @@ def _test_simple_enum(checked_enum, simple_enum): | |||
|                 + list(simple_enum._member_map_.keys()) | ||||
|                 ) | ||||
|         for key in set(checked_keys + simple_keys): | ||||
|             if key in ('__module__', '_member_map_', '_value2member_map_', '__doc__'): | ||||
|                 # keys known to be different, or very long | ||||
|             if key in ('__module__', '_member_map_', '_value2member_map_'): | ||||
|                 # keys known to be different | ||||
|                 continue | ||||
|             elif key in member_names: | ||||
|                 # members are checked below | ||||
|  | @ -2019,5 +1882,3 @@ def _old_convert_(etype, name, module, filter, source=None, *, boundary=None): | |||
|     cls.__reduce_ex__ = _reduce_ex_by_global_name | ||||
|     cls.__repr__ = global_enum_repr | ||||
|     return cls | ||||
| 
 | ||||
| _stdlib_enums = IntEnum, StrEnum, IntFlag | ||||
|  |  | |||
|  | @ -2567,21 +2567,15 @@ class _empty: | |||
| 
 | ||||
| 
 | ||||
| class _ParameterKind(enum.IntEnum): | ||||
|     POSITIONAL_ONLY = 'positional-only' | ||||
|     POSITIONAL_OR_KEYWORD = 'positional or keyword' | ||||
|     VAR_POSITIONAL = 'variadic positional' | ||||
|     KEYWORD_ONLY = 'keyword-only' | ||||
|     VAR_KEYWORD = 'variadic keyword' | ||||
|     POSITIONAL_ONLY = 0 | ||||
|     POSITIONAL_OR_KEYWORD = 1 | ||||
|     VAR_POSITIONAL = 2 | ||||
|     KEYWORD_ONLY = 3 | ||||
|     VAR_KEYWORD = 4 | ||||
| 
 | ||||
|     def __new__(cls, description): | ||||
|         value = len(cls.__members__) | ||||
|         member = int.__new__(cls, value) | ||||
|         member._value_ = value | ||||
|         member.description = description | ||||
|         return member | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|     @property | ||||
|     def description(self): | ||||
|         return _PARAM_NAME_MAPPING[self] | ||||
| 
 | ||||
| _POSITIONAL_ONLY         = _ParameterKind.POSITIONAL_ONLY | ||||
| _POSITIONAL_OR_KEYWORD   = _ParameterKind.POSITIONAL_OR_KEYWORD | ||||
|  | @ -2589,6 +2583,14 @@ def __str__(self): | |||
| _KEYWORD_ONLY            = _ParameterKind.KEYWORD_ONLY | ||||
| _VAR_KEYWORD             = _ParameterKind.VAR_KEYWORD | ||||
| 
 | ||||
| _PARAM_NAME_MAPPING = { | ||||
|     _POSITIONAL_ONLY: 'positional-only', | ||||
|     _POSITIONAL_OR_KEYWORD: 'positional or keyword', | ||||
|     _VAR_POSITIONAL: 'variadic positional', | ||||
|     _KEYWORD_ONLY: 'keyword-only', | ||||
|     _VAR_KEYWORD: 'variadic keyword' | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class Parameter: | ||||
|     """Represents a parameter in a function signature. | ||||
|  |  | |||
|  | @ -61,8 +61,7 @@ | |||
| from xml.parsers.expat import ParserCreate | ||||
| 
 | ||||
| 
 | ||||
| PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__) | ||||
| globals().update(PlistFormat.__members__) | ||||
| PlistFormat = enum.global_enum(enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)) | ||||
| 
 | ||||
| 
 | ||||
| class UID: | ||||
|  |  | |||
|  | @ -155,8 +155,6 @@ class RegexFlag: | |||
|     # sre extensions (experimental, don't rely on these) | ||||
|     TEMPLATE = T = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking | ||||
|     DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation | ||||
|     __str__ = object.__str__ | ||||
|     _numeric_repr_ = hex | ||||
| 
 | ||||
| # sre exception | ||||
| error = sre_compile.error | ||||
|  |  | |||
|  | @ -119,6 +119,7 @@ | |||
| ) | ||||
| from _ssl import _DEFAULT_CIPHERS, _OPENSSL_API_VERSION | ||||
| 
 | ||||
| 
 | ||||
| _IntEnum._convert_( | ||||
|     '_SSLMethod', __name__, | ||||
|     lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23', | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -908,7 +908,7 @@ def handler(signum, frame): | |||
| 
 | ||||
|         %s | ||||
| 
 | ||||
|         blocked = %s | ||||
|         blocked = %r | ||||
|         signum = signal.SIGALRM | ||||
| 
 | ||||
|         # child: block and wait the signal | ||||
|  |  | |||
|  | @ -1517,11 +1517,9 @@ def testGetaddrinfo(self): | |||
|         infos = socket.getaddrinfo(HOST, 80, socket.AF_INET, socket.SOCK_STREAM) | ||||
|         for family, type, _, _, _ in infos: | ||||
|             self.assertEqual(family, socket.AF_INET) | ||||
|             self.assertEqual(repr(family), '<AddressFamily.AF_INET: 2>') | ||||
|             self.assertEqual(str(family), '2') | ||||
|             self.assertEqual(str(family), 'AF_INET') | ||||
|             self.assertEqual(type, socket.SOCK_STREAM) | ||||
|             self.assertEqual(repr(type), '<SocketKind.SOCK_STREAM: 1>') | ||||
|             self.assertEqual(str(type), '1') | ||||
|             self.assertEqual(str(type), 'SOCK_STREAM') | ||||
|         infos = socket.getaddrinfo(HOST, None, 0, socket.SOCK_STREAM) | ||||
|         for _, socktype, _, _, _ in infos: | ||||
|             self.assertEqual(socktype, socket.SOCK_STREAM) | ||||
|  | @ -1795,10 +1793,8 @@ def test_str_for_enums(self): | |||
|         # Make sure that the AF_* and SOCK_* constants have enum-like string | ||||
|         # reprs. | ||||
|         with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | ||||
|             self.assertEqual(repr(s.family), '<AddressFamily.AF_INET: 2>') | ||||
|             self.assertEqual(repr(s.type), '<SocketKind.SOCK_STREAM: 1>') | ||||
|             self.assertEqual(str(s.family), '2') | ||||
|             self.assertEqual(str(s.type), '1') | ||||
|             self.assertEqual(str(s.family), 'AF_INET') | ||||
|             self.assertEqual(str(s.type), 'SOCK_STREAM') | ||||
| 
 | ||||
|     def test_socket_consistent_sock_type(self): | ||||
|         SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0) | ||||
|  |  | |||
|  | @ -373,8 +373,7 @@ def test_str_for_enums(self): | |||
|         # Make sure that the PROTOCOL_* constants have enum-like string | ||||
|         # reprs. | ||||
|         proto = ssl.PROTOCOL_TLS_CLIENT | ||||
|         self.assertEqual(repr(proto), '<_SSLMethod.PROTOCOL_TLS_CLIENT: 16>') | ||||
|         self.assertEqual(str(proto), '16') | ||||
|         self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT') | ||||
|         ctx = ssl.SSLContext(proto) | ||||
|         self.assertIs(ctx.protocol, proto) | ||||
| 
 | ||||
|  | @ -623,7 +622,7 @@ def test_openssl111_deprecations(self): | |||
|                 with self.assertWarns(DeprecationWarning) as cm: | ||||
|                     ssl.SSLContext(protocol) | ||||
|                 self.assertEqual( | ||||
|                     f'ssl.{protocol.name} is deprecated', | ||||
|                     f'{protocol!r} is deprecated', | ||||
|                     str(cm.warning) | ||||
|                 ) | ||||
| 
 | ||||
|  | @ -632,9 +631,8 @@ def test_openssl111_deprecations(self): | |||
|                 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) | ||||
|                 with self.assertWarns(DeprecationWarning) as cm: | ||||
|                     ctx.minimum_version = version | ||||
|                 version_text = '%s.%s' % (version.__class__.__name__, version.name) | ||||
|                 self.assertEqual( | ||||
|                     f'ssl.{version_text} is deprecated', | ||||
|                     f'ssl.{version!r} is deprecated', | ||||
|                     str(cm.warning) | ||||
|                 ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1490,10 +1490,8 @@ def test_formatting_with_enum(self): | |||
|         # issue18780 | ||||
|         import enum | ||||
|         class Float(float, enum.Enum): | ||||
|             # a mixed-in type will use the name for %s etc. | ||||
|             PI = 3.1415926 | ||||
|         class Int(enum.IntEnum): | ||||
|             # IntEnum uses the value and not the name for %s etc. | ||||
|             IDES = 15 | ||||
|         class Str(enum.StrEnum): | ||||
|             # StrEnum uses the value and not the name for %s etc. | ||||
|  | @ -1510,10 +1508,8 @@ class Str(enum.StrEnum): | |||
|         # formatting jobs delegated from the string implementation: | ||||
|         self.assertEqual('...%(foo)s...' % {'foo':Str.ABC}, | ||||
|                          '...abc...') | ||||
|         self.assertEqual('...%(foo)r...' % {'foo':Int.IDES}, | ||||
|                          '...<Int.IDES: 15>...') | ||||
|         self.assertEqual('...%(foo)s...' % {'foo':Int.IDES}, | ||||
|                          '...15...') | ||||
|                          '...IDES...') | ||||
|         self.assertEqual('...%(foo)i...' % {'foo':Int.IDES}, | ||||
|                          '...15...') | ||||
|         self.assertEqual('...%(foo)d...' % {'foo':Int.IDES}, | ||||
|  |  | |||
|  | @ -1,2 +0,0 @@ | |||
| ``IntEnum``, ``IntFlag``, and ``StrEnum`` use the mixed-in type for their | ||||
| ``str()`` and ``format()`` output. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner