[Python-checkins] Revert "bpo-40066: [Enum] update str() and format() output (GH-30582)" (GH-30632)

vstinner webhook-mailer at python.org
Mon Jan 17 07:58:45 EST 2022


https://github.com/python/cpython/commit/42a64c03ec5c443f2a5c2ee4284622f5d1f5326c
commit: 42a64c03ec5c443f2a5c2ee4284622f5d1f5326c
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022-01-17T13:58:40+01:00
summary:

Revert "bpo-40066:  [Enum] update str() and format() output (GH-30582)" (GH-30632)

This reverts commit acf7403f9baea3ae1119fc6b4a3298522188bf96.

files:
D Misc/NEWS.d/next/Library/2022-01-13-11-41-24.bpo-40066.1QuVli.rst
M Doc/howto/enum.rst
M Doc/library/enum.rst
M Doc/library/ssl.rst
M Lib/enum.py
M Lib/inspect.py
M Lib/plistlib.py
M Lib/re.py
M Lib/ssl.py
M Lib/test/test_enum.py
M Lib/test/test_signal.py
M Lib/test/test_socket.py
M Lib/test/test_ssl.py
M Lib/test/test_unicode.py

diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst
index fa0e2283ebc10..6c09b9925c1de 100644
--- a/Doc/howto/enum.rst
+++ b/Doc/howto/enum.rst
@@ -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:
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
index 906c60bc3efe3..8bb19dcdf2b61 100644
--- a/Doc/library/enum.rst
+++ b/Doc/library/enum.rst
@@ -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')
-
-   .. method:: Enum.__format__(self)
-
-      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')
+         ...         cls_name = self.__class__.__name__
+         ...         return f'{cls_name}.{self.name}'
+         >>> OldStyle.RETRO
+         OldStyle.RETRO
 
-   .. note::
+.. 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>
-
-   .. method:: _numeric_repr_
-
-      Function used to format any remaining unnamed numeric values.  Default is
-      the value's repr; common choices are :func:`hex` and :func:`oct`.
-
-   .. note::
+         Color.GREEN|Color.BLUE
 
-      Using :class:`auto` with :class:`Flag` results in integers that are powers
-      of two, starting with ``1``.
+.. note::
 
-   .. versionchanged:: 3.11  The *repr()* of zero-valued flags has changed.  It
-      is now::
+   Using :class:`auto` with :class:`Flag` results in integers that are powers
+   of two, starting with ``1``.
 
-          >>> 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__
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 4d8488a4a28de..eb33d7e1778a7 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -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
 
diff --git a/Lib/enum.py b/Lib/enum.py
index 772e1eac0e1e6..93ea1bea36db7 100644
--- a/Lib/enum.py
+++ b/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.
-
-    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>
+    Generic enumeration.
 
-    - 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):
+class IntEnum(int, Enum):
     """
-    Only changes the repr(), leaving str() and format() to the mixed-in type.
+    Enum where members are also (and must be) ints
     """
 
+    def __str__(self):
+        return "%s" % (self._name_, )
 
-class IntEnum(int, ReprEnum):
-    """
-    Enum where members are also (and must be) ints
-    """
+    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, ReprEnum):
+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
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 8236698b8de0f..5d33f0d445fb9 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -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'
-
-    def __new__(cls, description):
-        value = len(cls.__members__)
-        member = int.__new__(cls, value)
-        member._value_ = value
-        member.description = description
-        return member
+    POSITIONAL_ONLY = 0
+    POSITIONAL_OR_KEYWORD = 1
+    VAR_POSITIONAL = 2
+    KEYWORD_ONLY = 3
+    VAR_KEYWORD = 4
 
-    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.
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index 4862355b2252c..3ab71edc320af 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -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:
diff --git a/Lib/re.py b/Lib/re.py
index a7ab9b3706748..ea41217ce08c2 100644
--- a/Lib/re.py
+++ b/Lib/re.py
@@ -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
diff --git a/Lib/ssl.py b/Lib/ssl.py
index dafb70a67864c..207925166efa3 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -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',
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index a0953fb960f33..43f98c1c1efb6 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,18 +6,15 @@
 import sys
 import unittest
 import threading
-import builtins as bltns
 from collections import OrderedDict
-from datetime import date
 from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
 from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
-from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
+from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS
 from io import StringIO
 from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
 from test import support
 from test.support import ALWAYS_EQ
 from test.support import threading_helper
-from textwrap import dedent
 from datetime import timedelta
 
 python_version = sys.version_info[:2]
@@ -110,12 +107,6 @@ def test_pickle_exception(assertion, exception, obj):
 class TestHelpers(unittest.TestCase):
     # _is_descriptor, _is_sunder, _is_dunder
 
-    sunder_names = '_bad_', '_good_', '_what_ho_'
-    dunder_names = '__mal__', '__bien__', '__que_que__'
-    private_names = '_MyEnum__private', '_MyEnum__still_private'
-    private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
-    random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
-
     def test_is_descriptor(self):
         class foo:
             pass
@@ -125,36 +116,21 @@ class foo:
             setattr(obj, attr, 1)
             self.assertTrue(enum._is_descriptor(obj))
 
-    def test_sunder(self):
-        for name in self.sunder_names + self.private_and_sunder_names:
-            self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
-        for name in self.dunder_names + self.private_names + self.random_names:
-            self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
+    def test_is_sunder(self):
         for s in ('_a_', '_aa_'):
             self.assertTrue(enum._is_sunder(s))
+
         for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
                 '__', '___', '____', '_____',):
             self.assertFalse(enum._is_sunder(s))
 
-    def test_dunder(self):
-        for name in self.dunder_names:
-            self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
-        for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
-            self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
+    def test_is_dunder(self):
         for s in ('__a__', '__aa__'):
             self.assertTrue(enum._is_dunder(s))
         for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
                 '__', '___', '____', '_____',):
             self.assertFalse(enum._is_dunder(s))
 
-
-    def test_is_private(self):
-        for name in self.private_names + self.private_and_sunder_names:
-            self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
-        for name in self.sunder_names + self.dunder_names + self.random_names:
-            self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
-
-
 # for subclassing tests
 
 class classproperty:
@@ -190,658 +166,473 @@ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
 
 # tests
 
-class _EnumTests:
-    """
-    Test for behavior that is the same across the different types of enumerations.
-    """
-
-    values = None
+class TestEnum(unittest.TestCase):
 
     def setUp(self):
-        class BaseEnum(self.enum_type):
-            @enum.property
-            def first(self):
-                return '%s is first!' % self.name
-        class MainEnum(BaseEnum):
-            first = auto()
-            second = auto()
-            third = auto()
-            if issubclass(self.enum_type, Flag):
-                dupe = 3
-            else:
-                dupe = third
-        self.MainEnum = MainEnum
-        #
-        class NewStrEnum(self.enum_type):
-            def __str__(self):
-                return self.name.upper()
-            first = auto()
-        self.NewStrEnum = NewStrEnum
-        #
-        class NewFormatEnum(self.enum_type):
-            def __format__(self, spec):
-                return self.name.upper()
-            first = auto()
-        self.NewFormatEnum = NewFormatEnum
-        #
-        class NewStrFormatEnum(self.enum_type):
-            def __str__(self):
-                return self.name.title()
-            def __format__(self, spec):
-                return ''.join(reversed(self.name))
-            first = auto()
-        self.NewStrFormatEnum = NewStrFormatEnum
-        #
-        class NewBaseEnum(self.enum_type):
-            def __str__(self):
-                return self.name.title()
-            def __format__(self, spec):
-                return ''.join(reversed(self.name))
-        class NewSubEnum(NewBaseEnum):
-            first = auto()
-        self.NewSubEnum = NewSubEnum
-        #
-        self.is_flag = False
-        self.names = ['first', 'second', 'third']
-        if issubclass(MainEnum, StrEnum):
-            self.values = self.names
-        elif MainEnum._member_type_ is str:
-            self.values = ['1', '2', '3']
-        elif issubclass(self.enum_type, Flag):
-            self.values = [1, 2, 4]
-            self.is_flag = True
-            self.dupe2 = MainEnum(5)
-        else:
-            self.values = self.values or [1, 2, 3]
-        #
-        if not getattr(self, 'source_values', False):
-            self.source_values = self.values
-
-    def assertFormatIsValue(self, spec, member):
-        self.assertEqual(spec.format(member), spec.format(member.value))
-
-    def assertFormatIsStr(self, spec, member):
-        self.assertEqual(spec.format(member), spec.format(str(member)))
-
-    def test_attribute_deletion(self):
-        class Season(self.enum_type):
-            SPRING = auto()
-            SUMMER = auto()
-            AUTUMN = auto()
-            #
-            def spam(cls):
-                pass
-        #
-        self.assertTrue(hasattr(Season, 'spam'))
-        del Season.spam
-        self.assertFalse(hasattr(Season, 'spam'))
-        #
-        with self.assertRaises(AttributeError):
-            del Season.SPRING
-        with self.assertRaises(AttributeError):
-            del Season.DRY
-        with self.assertRaises(AttributeError):
-            del Season.SPRING.name
-
-    def test_basics(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(repr(TE), "<flag 'MainEnum'>")
-            self.assertEqual(str(TE), "<flag 'MainEnum'>")
-            self.assertEqual(format(TE), "<flag 'MainEnum'>")
-            self.assertTrue(TE(5) is self.dupe2)
-        else:
-            self.assertEqual(repr(TE), "<enum 'MainEnum'>")
-            self.assertEqual(str(TE), "<enum 'MainEnum'>")
-            self.assertEqual(format(TE), "<enum 'MainEnum'>")
-        self.assertEqual(list(TE), [TE.first, TE.second, TE.third])
-        self.assertEqual(
-                [m.name for m in TE],
-                self.names,
-                )
-        self.assertEqual(
-                [m.value for m in TE],
-                self.values,
-                )
-        self.assertEqual(
-                [m.first for m in TE],
-                ['first is first!', 'second is first!', 'third is first!']
-                )
-        for member, name in zip(TE, self.names, strict=True):
-            self.assertIs(TE[name], member)
-        for member, value in zip(TE, self.values, strict=True):
-            self.assertIs(TE(value), member)
-        if issubclass(TE, StrEnum):
-            self.assertTrue(TE.dupe is TE('third') is TE['dupe'])
-        elif TE._member_type_ is str:
-            self.assertTrue(TE.dupe is TE('3') is TE['dupe'])
-        elif issubclass(TE, Flag):
-            self.assertTrue(TE.dupe is TE(3) is TE['dupe'])
-        else:
-            self.assertTrue(TE.dupe is TE(self.values[2]) is TE['dupe'])
+        class Season(Enum):
+            SPRING = 1
+            SUMMER = 2
+            AUTUMN = 3
+            WINTER = 4
+        self.Season = Season
 
-    def test_bool_is_true(self):
-        class Empty(self.enum_type):
-            pass
-        self.assertTrue(Empty)
-        #
-        self.assertTrue(self.MainEnum)
-        for member in self.MainEnum:
-            self.assertTrue(member)
+        class Konstants(float, Enum):
+            E = 2.7182818
+            PI = 3.1415926
+            TAU = 2 * PI
+        self.Konstants = Konstants
 
-    def test_changing_member_fails(self):
-        MainEnum = self.MainEnum
-        with self.assertRaises(AttributeError):
-            self.MainEnum.second = 'really first'
+        class Grades(IntEnum):
+            A = 5
+            B = 4
+            C = 3
+            D = 2
+            F = 0
+        self.Grades = Grades
 
-    @unittest.skipIf(
-            python_version >= (3, 12),
-            '__contains__ now returns True/False for all inputs',
-            )
-    def test_contains_er(self):
-        MainEnum = self.MainEnum
-        self.assertIn(MainEnum.third, MainEnum)
-        with self.assertRaises(TypeError):
-            with self.assertWarns(DeprecationWarning):
-                self.source_values[1] in MainEnum
-        with self.assertRaises(TypeError):
-            with self.assertWarns(DeprecationWarning):
-                'first' in MainEnum
-        val = MainEnum.dupe
-        self.assertIn(val, MainEnum)
-        #
-        class OtherEnum(Enum):
-            one = auto()
-            two = auto()
-        self.assertNotIn(OtherEnum.two, MainEnum)
+        class Directional(str, Enum):
+            EAST = 'east'
+            WEST = 'west'
+            NORTH = 'north'
+            SOUTH = 'south'
+        self.Directional = Directional
 
-    @unittest.skipIf(
-            python_version < (3, 12),
-            '__contains__ works only with enum memmbers before 3.12',
-            )
-    def test_contains_tf(self):
-        MainEnum = self.MainEnum
-        self.assertIn(MainEnum.first, MainEnum)
-        self.assertTrue(self.source_values[0] in MainEnum)
-        self.assertFalse('first' in MainEnum)
-        val = MainEnum.dupe
-        self.assertIn(val, MainEnum)
-        #
-        class OtherEnum(Enum):
-            one = auto()
-            two = auto()
-        self.assertNotIn(OtherEnum.two, MainEnum)
+        from datetime import date
+        class Holiday(date, Enum):
+            NEW_YEAR = 2013, 1, 1
+            IDES_OF_MARCH = 2013, 3, 15
+        self.Holiday = Holiday
 
-    def test_dir_on_class(self):
-        TE = self.MainEnum
-        self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
+        class DateEnum(date, Enum): pass
+        self.DateEnum = DateEnum
 
-    def test_dir_on_item(self):
-        TE = self.MainEnum
-        self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
+        class FloatEnum(float, Enum): pass
+        self.FloatEnum = FloatEnum
 
-    def test_dir_with_added_behavior(self):
-        class Test(self.enum_type):
-            this = auto()
-            these = auto()
+        class Wowser(Enum):
+            this = 'that'
+            these = 'those'
+            def wowser(self):
+                """Wowser docstring"""
+                return ("Wowser! I'm %s!" % self.name)
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        self.Wowser = Wowser
+
+        class IntWowser(IntEnum):
+            this = 1
+            these = 2
+            def wowser(self):
+                """Wowser docstring"""
+                return ("Wowser! I'm %s!" % self.name)
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        self.IntWowser = IntWowser
+
+        class FloatWowser(float, Enum):
+            this = 3.14
+            these = 4.2
             def wowser(self):
+                """Wowser docstring"""
                 return ("Wowser! I'm %s!" % self.name)
-        self.assertTrue('wowser' not in dir(Test))
-        self.assertTrue('wowser' in dir(Test.this))
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        self.FloatWowser = FloatWowser
+
+        class WowserNoMembers(Enum):
+            def wowser(self): pass
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        class SubclassOfWowserNoMembers(WowserNoMembers): pass
+        self.WowserNoMembers = WowserNoMembers
+        self.SubclassOfWowserNoMembers = SubclassOfWowserNoMembers
+
+        class IntWowserNoMembers(IntEnum):
+            def wowser(self): pass
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        self.IntWowserNoMembers = IntWowserNoMembers
+
+        class FloatWowserNoMembers(float, Enum):
+            def wowser(self): pass
+            @classmethod
+            def classmethod_wowser(cls): pass
+            @staticmethod
+            def staticmethod_wowser(): pass
+        self.FloatWowserNoMembers = FloatWowserNoMembers
+
+        class EnumWithInit(Enum):
+            def __init__(self, greeting, farewell):
+                self.greeting = greeting
+                self.farewell = farewell
+            ENGLISH = 'hello', 'goodbye'
+            GERMAN = 'Guten Morgen', 'Auf Wiedersehen'
+            def some_method(self): pass
+        self.EnumWithInit = EnumWithInit
 
-    def test_dir_on_sub_with_behavior_on_super(self):
         # see issue22506
-        class SuperEnum(self.enum_type):
+        class SuperEnum1(Enum):
             def invisible(self):
                 return "did you see me?"
-        class SubEnum(SuperEnum):
-            sample = auto()
-        self.assertTrue('invisible' not in dir(SubEnum))
-        self.assertTrue('invisible' in dir(SubEnum.sample))
+        class SubEnum1(SuperEnum1):
+            sample = 5
+        self.SubEnum1 = SubEnum1
 
-    def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
-        # see issue40084
-        class SuperEnum(self.enum_type):
-            def __new__(cls, *value, **kwds):
-                new = self.enum_type._member_type_.__new__
-                if self.enum_type._member_type_ is object:
-                    obj = new(cls)
-                else:
-                    if isinstance(value[0], tuple):
-                        create_value ,= value[0]
-                    else:
-                        create_value = value
-                    obj = new(cls, *create_value)
-                obj._value_ = value[0] if len(value) == 1 else value
-                obj.description = 'test description'
+        class SuperEnum2(IntEnum):
+            def __new__(cls, value, description=""):
+                obj = int.__new__(cls, value)
+                obj._value_ = value
+                obj.description = description
                 return obj
-        class SubEnum(SuperEnum):
-            sample = self.source_values[1]
-        self.assertTrue('description' not in dir(SubEnum))
-        self.assertTrue('description' in dir(SubEnum.sample), dir(SubEnum.sample))
-
-    def test_enum_in_enum_out(self):
-        Main = self.MainEnum
-        self.assertIs(Main(Main.first), Main.first)
-
-    def test_hash(self):
-        MainEnum = self.MainEnum
-        mapping = {}
-        mapping[MainEnum.first] = '1225'
-        mapping[MainEnum.second] = '0315'
-        mapping[MainEnum.third] = '0704'
-        self.assertEqual(mapping[MainEnum.second], '0315')
-
-    def test_invalid_names(self):
-        with self.assertRaises(ValueError):
-            class Wrong(self.enum_type):
-                mro = 9
-        with self.assertRaises(ValueError):
-            class Wrong(self.enum_type):
-                _create_= 11
-        with self.assertRaises(ValueError):
-            class Wrong(self.enum_type):
-                _get_mixins_ = 9
-        with self.assertRaises(ValueError):
-            class Wrong(self.enum_type):
-                _find_new_ = 1
-        with self.assertRaises(ValueError):
-            class Wrong(self.enum_type):
-                _any_name_ = 9
-
-    def test_object_str_override(self):
-        "check that setting __str__ to object's is not reset to Enum's"
-        class Generic(self.enum_type):
-            item = self.source_values[2]
-            def __repr__(self):
-                return "%s.test" % (self._name_, )
-            __str__ = object.__str__
-        self.assertEqual(str(Generic.item), 'item.test')
-
-    def test_overridden_str(self):
-        NS = self.NewStrEnum
-        self.assertEqual(str(NS.first), NS.first.name.upper())
-        self.assertEqual(format(NS.first), NS.first.name.upper())
+        class SubEnum2(SuperEnum2):
+            sample = 5
+        self.SubEnum2 = SubEnum2
+
+    def test_dir_basics_for_all_enums(self):
+        enums_for_tests = (
+            # Generic enums in enum.py
+            Enum,
+            IntEnum,
+            StrEnum,
+            # Generic enums defined outside of enum.py
+            self.DateEnum,
+            self.FloatEnum,
+            # Concrete enums derived from enum.py generics
+            self.Grades,
+            self.Season,
+            # Concrete enums derived from generics defined outside of enum.py
+            self.Konstants,
+            self.Holiday,
+            # Standard enum with added behaviour & members
+            self.Wowser,
+            # Mixin-enum-from-enum.py with added behaviour & members
+            self.IntWowser,
+            # Mixin-enum-from-oustide-enum.py with added behaviour & members
+            self.FloatWowser,
+            # Equivalents of the three immediately above, but with no members
+            self.WowserNoMembers,
+            self.IntWowserNoMembers,
+            self.FloatWowserNoMembers,
+            # Enum with members and an __init__ method
+            self.EnumWithInit,
+            # Special cases to test
+            self.SubEnum1,
+            self.SubEnum2
+        )
+
+        for cls in enums_for_tests:
+            with self.subTest(cls=cls):
+                cls_dir = dir(cls)
+                # test that dir is deterministic
+                self.assertEqual(cls_dir, dir(cls))
+                # test that dir is sorted
+                self.assertEqual(list(cls_dir), sorted(cls_dir))
+                # test that there are no dupes in dir
+                self.assertEqual(len(cls_dir), len(set(cls_dir)))
+                # test that there are no sunders in dir
+                self.assertFalse(any(enum._is_sunder(attr) for attr in cls_dir))
+                self.assertNotIn('__new__', cls_dir)
+
+                for attr in ('__class__', '__doc__', '__members__', '__module__'):
+                    with self.subTest(attr=attr):
+                        self.assertIn(attr, cls_dir)
+
+    def test_dir_for_enum_with_members(self):
+        enums_for_test = (
+            # Enum with members
+            self.Season,
+            # IntEnum with members
+            self.Grades,
+            # Two custom-mixin enums with members
+            self.Konstants,
+            self.Holiday,
+            # several enums-with-added-behaviour and members
+            self.Wowser,
+            self.IntWowser,
+            self.FloatWowser,
+            # An enum with an __init__ method and members
+            self.EnumWithInit,
+            # Special cases to test
+            self.SubEnum1,
+            self.SubEnum2
+        )
+
+        for cls in enums_for_test:
+            cls_dir = dir(cls)
+            member_names = cls._member_names_
+            with self.subTest(cls=cls):
+                self.assertTrue(all(member_name in cls_dir for member_name in member_names))
+                for member in cls:
+                    member_dir = dir(member)
+                    # test that dir is deterministic
+                    self.assertEqual(member_dir, dir(member))
+                    # test that dir is sorted
+                    self.assertEqual(list(member_dir), sorted(member_dir))
+                    # test that there are no dupes in dir
+                    self.assertEqual(len(member_dir), len(set(member_dir)))
+
+                    for attr_name in cls_dir:
+                        with self.subTest(attr_name=attr_name):
+                            if attr_name in {'__members__', '__init__', '__new__', *member_names}:
+                                self.assertNotIn(attr_name, member_dir)
+                            else:
+                                self.assertIn(attr_name, member_dir)
+
+                    self.assertFalse(any(enum._is_sunder(attr) for attr in member_dir))
+
+    def test_dir_for_enums_with_added_behaviour(self):
+        enums_for_test = (
+            self.Wowser,
+            self.IntWowser,
+            self.FloatWowser,
+            self.WowserNoMembers,
+            self.SubclassOfWowserNoMembers,
+            self.IntWowserNoMembers,
+            self.FloatWowserNoMembers
+        )
+
+        for cls in enums_for_test:
+            with self.subTest(cls=cls):
+                self.assertIn('wowser', dir(cls))
+                self.assertIn('classmethod_wowser', dir(cls))
+                self.assertIn('staticmethod_wowser', dir(cls))
+                self.assertTrue(all(
+                    all(attr in dir(member) for attr in ('wowser', 'classmethod_wowser', 'staticmethod_wowser'))
+                    for member in cls
+                ))
 
-    def test_overridden_str_format(self):
-        NSF = self.NewStrFormatEnum
-        self.assertEqual(str(NSF.first), NSF.first.name.title())
-        self.assertEqual(format(NSF.first), ''.join(reversed(NSF.first.name)))
+        self.assertEqual(dir(self.WowserNoMembers), dir(self.SubclassOfWowserNoMembers))
+        # Check classmethods are present
+        self.assertIn('from_bytes', dir(self.IntWowser))
+        self.assertIn('from_bytes', dir(self.IntWowserNoMembers))
+
+    def test_help_output_on_enum_members(self):
+        added_behaviour_enums = (
+            self.Wowser,
+            self.IntWowser,
+            self.FloatWowser
+        )
+
+        for cls in added_behaviour_enums:
+            with self.subTest(cls=cls):
+                rendered_doc = pydoc.render_doc(cls.this)
+                self.assertIn('Wowser docstring', rendered_doc)
+                if cls in {self.IntWowser, self.FloatWowser}:
+                    self.assertIn('float(self)', rendered_doc)
+
+    def test_dir_for_enum_with_init(self):
+        EnumWithInit = self.EnumWithInit
+
+        cls_dir = dir(EnumWithInit)
+        self.assertIn('__init__', cls_dir)
+        self.assertIn('some_method', cls_dir)
+        self.assertNotIn('greeting', cls_dir)
+        self.assertNotIn('farewell', cls_dir)
+
+        member_dir = dir(EnumWithInit.ENGLISH)
+        self.assertNotIn('__init__', member_dir)
+        self.assertIn('some_method', member_dir)
+        self.assertIn('greeting', member_dir)
+        self.assertIn('farewell', member_dir)
+
+    def test_mixin_dirs(self):
+        from datetime import date
 
-    def test_overridden_str_format_inherited(self):
-        NSE = self.NewSubEnum
-        self.assertEqual(str(NSE.first), NSE.first.name.title())
-        self.assertEqual(format(NSE.first), ''.join(reversed(NSE.first.name)))
+        enums_for_test = (
+            # generic mixins from enum.py
+            (IntEnum, int),
+            (StrEnum, str),
+            # generic mixins from outside enum.py
+            (self.FloatEnum, float),
+            (self.DateEnum, date),
+            # concrete mixin from enum.py
+            (self.Grades, int),
+            # concrete mixin from outside enum.py
+            (self.Holiday, date),
+            # concrete mixin from enum.py with added behaviour
+            (self.IntWowser, int),
+            # concrete mixin from outside enum.py with added behaviour
+            (self.FloatWowser, float)
+        )
+
+        enum_dict = Enum.__dict__
+        enum_dir = dir(Enum)
+        enum_module_names = enum.__all__
+        is_from_enum_module = lambda cls: cls.__name__ in enum_module_names
+        is_enum_dunder = lambda attr: enum._is_dunder(attr) and attr in enum_dict
+
+        def attr_is_inherited_from_object(cls, attr_name):
+            for base in cls.__mro__:
+                if attr_name in base.__dict__:
+                    return base is object
+            return False
+
+        # General tests
+        for enum_cls, mixin_cls in enums_for_test:
+            with self.subTest(enum_cls=enum_cls):
+                cls_dir = dir(enum_cls)
+                cls_dict = enum_cls.__dict__
+
+                mixin_attrs = [
+                    x for x in dir(mixin_cls)
+                    if not attr_is_inherited_from_object(cls=mixin_cls, attr_name=x)
+                ]
 
-    def test_programmatic_function_string(self):
-        MinorEnum = self.enum_type('MinorEnum', 'june july august')
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
+                first_enum_base = next(
+                    base for base in enum_cls.__mro__
+                    if is_from_enum_module(base)
                 )
-        values = self.values
-        if self.enum_type is StrEnum:
-            values = ['june','july','august']
-        for month, av in zip('june july august'.split(), values):
-            e = MinorEnum[month]
-            self.assertEqual(e.value, av, list(MinorEnum))
-            self.assertEqual(e.name, month)
-            if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
-                self.assertEqual(e, av)
-            else:
-                self.assertNotEqual(e, av)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-            self.assertIs(e, MinorEnum(av))
 
-    def test_programmatic_function_string_list(self):
-        MinorEnum = self.enum_type('MinorEnum', ['june', 'july', 'august'])
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        values = self.values
-        if self.enum_type is StrEnum:
-            values = ['june','july','august']
-        for month, av in zip('june july august'.split(), values):
-            e = MinorEnum[month]
-            self.assertEqual(e.value, av)
-            self.assertEqual(e.name, month)
-            if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
-                self.assertEqual(e, av)
-            else:
-                self.assertNotEqual(e, av)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-            self.assertIs(e, MinorEnum(av))
+                for attr in mixin_attrs:
+                    with self.subTest(attr=attr):
+                        if enum._is_sunder(attr):
+                            # Unlikely, but no harm in testing
+                            self.assertNotIn(attr, cls_dir)
+                        elif attr in {'__class__', '__doc__', '__members__', '__module__'}:
+                            self.assertIn(attr, cls_dir)
+                        elif is_enum_dunder(attr):
+                            if is_from_enum_module(enum_cls):
+                                self.assertNotIn(attr, cls_dir)
+                            elif getattr(enum_cls, attr) is getattr(first_enum_base, attr):
+                                self.assertNotIn(attr, cls_dir)
+                            else:
+                                self.assertIn(attr, cls_dir)
+                        else:
+                            self.assertIn(attr, cls_dir)
+
+        # Some specific examples
+        int_enum_dir = dir(IntEnum)
+        self.assertIn('imag', int_enum_dir)
+        self.assertIn('__rfloordiv__', int_enum_dir)
+        self.assertNotIn('__format__', int_enum_dir)
+        self.assertNotIn('__hash__', int_enum_dir)
+        self.assertNotIn('__init_subclass__', int_enum_dir)
+        self.assertNotIn('__subclasshook__', int_enum_dir)
+
+        class OverridesFormatOutsideEnumModule(Enum):
+            def __format__(self, *args, **kwargs):
+                return super().__format__(*args, **kwargs)
+            SOME_MEMBER = 1
+
+        self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule))
+        self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule.SOME_MEMBER))
 
-    def test_programmatic_function_iterable(self):
-        MinorEnum = self.enum_type(
-                'MinorEnum',
-                (('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2]))
-                )
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
+    def test_dir_on_sub_with_behavior_on_super(self):
+        # see issue22506
         self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
+                set(dir(self.SubEnum1.sample)),
+                set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
                 )
-        for month, av in zip('june july august'.split(), self.values):
-            e = MinorEnum[month]
-            self.assertEqual(e.value, av)
-            self.assertEqual(e.name, month)
-            if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
-                self.assertEqual(e, av)
-            else:
-                self.assertNotEqual(e, av)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-            self.assertIs(e, MinorEnum(av))
 
-    def test_programmatic_function_from_dict(self):
-        MinorEnum = self.enum_type(
-                'MinorEnum',
-                OrderedDict((('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2])))
-                )
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for month, av in zip('june july august'.split(), self.values):
-            e = MinorEnum[month]
-            if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
-                self.assertEqual(e, av)
-            else:
-                self.assertNotEqual(e, av)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-            self.assertIs(e, MinorEnum(av))
+    def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
+        # see issue40084
+        self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
 
-    def test_repr(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(repr(TE(0)), "<MainEnum: 0>")
-            self.assertEqual(repr(TE.dupe), "<MainEnum.dupe: 3>")
-            self.assertEqual(repr(self.dupe2), "<MainEnum.first|third: 5>")
-        elif issubclass(TE, StrEnum):
-            self.assertEqual(repr(TE.dupe), "<MainEnum.third: 'third'>")
-        else:
-            self.assertEqual(repr(TE.dupe), "<MainEnum.third: %r>" % (self.values[2], ), TE._value_repr_)
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(repr(member), "<MainEnum.%s: %r>" % (member.name, member.value))
+    def test_enum_in_enum_out(self):
+        Season = self.Season
+        self.assertIs(Season(Season.WINTER), Season.WINTER)
 
-    def test_repr_override(self):
-        class Generic(self.enum_type):
-            first = auto()
-            second = auto()
-            third = auto()
-            def __repr__(self):
-                return "don't you just love shades of %s?" % self.name
-        self.assertEqual(
-                repr(Generic.third),
-                "don't you just love shades of third?",
-                )
+    def test_enum_value(self):
+        Season = self.Season
+        self.assertEqual(Season.SPRING.value, 1)
 
-    def test_inherited_repr(self):
-        class MyEnum(self.enum_type):
-            def __repr__(self):
-                return "My name is %s." % self.name
-        class MySubEnum(MyEnum):
-            this = auto()
-            that = auto()
-            theother = auto()
-        self.assertEqual(repr(MySubEnum.that), "My name is that.")
+    def test_intenum_value(self):
+        self.assertEqual(IntStooges.CURLY.value, 2)
 
-    def test_reversed_iteration_order(self):
+    def test_enum(self):
+        Season = self.Season
+        lst = list(Season)
+        self.assertEqual(len(lst), len(Season))
+        self.assertEqual(len(Season), 4, Season)
         self.assertEqual(
-                list(reversed(self.MainEnum)),
-                [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
-                )
-
-class _PlainOutputTests:
-
-    def test_str(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(str(TE.dupe), "MainEnum.dupe")
-            self.assertEqual(str(self.dupe2), "MainEnum.first|third")
-        else:
-            self.assertEqual(str(TE.dupe), "MainEnum.third")
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
-    def test_format(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(format(TE.dupe), "MainEnum.dupe")
-            self.assertEqual(format(self.dupe2), "MainEnum.first|third")
-        else:
-            self.assertEqual(format(TE.dupe), "MainEnum.third")
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
-    def test_overridden_format(self):
-        NF = self.NewFormatEnum
-        self.assertEqual(str(NF.first), "NewFormatEnum.first", '%s %r' % (NF.__str__, NF.first))
-        self.assertEqual(format(NF.first), "FIRST")
-
-    def test_format_specs(self):
-        TE = self.MainEnum
-        self.assertFormatIsStr('{}', TE.second)
-        self.assertFormatIsStr('{:}', TE.second)
-        self.assertFormatIsStr('{:20}', TE.second)
-        self.assertFormatIsStr('{:^20}', TE.second)
-        self.assertFormatIsStr('{:>20}', TE.second)
-        self.assertFormatIsStr('{:<20}', TE.second)
-        self.assertFormatIsStr('{:5.2}', TE.second)
+            [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
 
+        for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
+            e = Season(i)
+            self.assertEqual(e, getattr(Season, season))
+            self.assertEqual(e.value, i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, season)
+            self.assertIn(e, Season)
+            self.assertIs(type(e), Season)
+            self.assertIsInstance(e, Season)
+            self.assertEqual(str(e), season)
+            self.assertEqual(repr(e), 'Season.{0}'.format(season))
+
+    def test_value_name(self):
+        Season = self.Season
+        self.assertEqual(Season.SPRING.name, 'SPRING')
+        self.assertEqual(Season.SPRING.value, 1)
+        with self.assertRaises(AttributeError):
+            Season.SPRING.name = 'invierno'
+        with self.assertRaises(AttributeError):
+            Season.SPRING.value = 2
 
-class _MixedOutputTests:
-
-    def test_str(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(str(TE.dupe), "MainEnum.dupe")
-            self.assertEqual(str(self.dupe2), "MainEnum.first|third")
-        else:
-            self.assertEqual(str(TE.dupe), "MainEnum.third")
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
-    def test_format(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(format(TE.dupe), "MainEnum.dupe")
-            self.assertEqual(format(self.dupe2), "MainEnum.first|third")
-        else:
-            self.assertEqual(format(TE.dupe), "MainEnum.third")
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
-    def test_overridden_format(self):
-        NF = self.NewFormatEnum
-        self.assertEqual(str(NF.first), "NewFormatEnum.first")
-        self.assertEqual(format(NF.first), "FIRST")
-
-    def test_format_specs(self):
-        TE = self.MainEnum
-        self.assertFormatIsStr('{}', TE.first)
-        self.assertFormatIsStr('{:}', TE.first)
-        self.assertFormatIsStr('{:20}', TE.first)
-        self.assertFormatIsStr('{:^20}', TE.first)
-        self.assertFormatIsStr('{:>20}', TE.first)
-        self.assertFormatIsStr('{:<20}', TE.first)
-        self.assertFormatIsStr('{:5.2}', TE.first)
-
-
-class _MinimalOutputTests:
-
-    def test_str(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(str(TE.dupe), "3")
-            self.assertEqual(str(self.dupe2), "5")
-        else:
-            self.assertEqual(str(TE.dupe), str(self.values[2]))
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(str(member), str(value))
-
-    def test_format(self):
-        TE = self.MainEnum
-        if self.is_flag:
-            self.assertEqual(format(TE.dupe), "3")
-            self.assertEqual(format(self.dupe2), "5")
-        else:
-            self.assertEqual(format(TE.dupe), format(self.values[2]))
-        for name, value, member in zip(self.names, self.values, TE, strict=True):
-            self.assertEqual(format(member), format(value))
-
-    def test_overridden_format(self):
-        NF = self.NewFormatEnum
-        self.assertEqual(str(NF.first), str(self.values[0]))
-        self.assertEqual(format(NF.first), "FIRST")
-
-    def test_format_specs(self):
-        TE = self.MainEnum
-        self.assertFormatIsValue('{}', TE.third)
-        self.assertFormatIsValue('{:}', TE.third)
-        self.assertFormatIsValue('{:20}', TE.third)
-        self.assertFormatIsValue('{:^20}', TE.third)
-        self.assertFormatIsValue('{:>20}', TE.third)
-        self.assertFormatIsValue('{:<20}', TE.third)
-        if TE._member_type_ is float:
-            self.assertFormatIsValue('{:n}', TE.third)
-            self.assertFormatIsValue('{:5.2}', TE.third)
-            self.assertFormatIsValue('{:f}', TE.third)
-
-
-class _FlagTests:
-
-    def test_default_missing_with_wrong_type_value(self):
-        with self.assertRaisesRegex(
-            ValueError,
-            "'RED' is not a valid TestFlag.Color",
-            ) as ctx:
-            self.MainEnum('RED')
-        self.assertIs(ctx.exception.__context__, None)
-
-class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase):
-    enum_type = Enum
-
-
-class TestPlainFlag(_EnumTests, _PlainOutputTests, unittest.TestCase):
-    enum_type = Flag
-
-
-class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-    enum_type = IntEnum
-
-
-class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-    enum_type = StrEnum
-
-
-class TestIntFlag(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-    enum_type = IntFlag
-
-
-class TestMixedInt(_EnumTests, _MixedOutputTests, unittest.TestCase):
-    class enum_type(int, Enum): pass
-
-
-class TestMixedStr(_EnumTests, _MixedOutputTests, unittest.TestCase):
-    class enum_type(str, Enum): pass
-
-
-class TestMixedIntFlag(_EnumTests, _MixedOutputTests, unittest.TestCase):
-    class enum_type(int, Flag): pass
-
-
-class TestMixedDate(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
-    values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)]
-    source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
-
-    class enum_type(date, Enum):
-        def _generate_next_value_(name, start, count, last_values):
-            values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
-            return values[count]
-
-
-class TestMinimalDate(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-
-    values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)]
-    source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
-
-    class enum_type(date, ReprEnum):
-        def _generate_next_value_(name, start, count, last_values):
-            values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
-            return values[count]
-
-
-class TestMixedFloat(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
-    values = [1.1, 2.2, 3.3]
-
-    class enum_type(float, Enum):
-        def _generate_next_value_(name, start, count, last_values):
-            values = [1.1, 2.2, 3.3]
-            return values[count]
+    def test_changing_member(self):
+        Season = self.Season
+        with self.assertRaises(AttributeError):
+            Season.WINTER = 'really cold'
 
+    def test_attribute_deletion(self):
+        class Season(Enum):
+            SPRING = 1
+            SUMMER = 2
+            AUTUMN = 3
+            WINTER = 4
 
-class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
+            def spam(cls):
+                pass
 
-    values = [4.4, 5.5, 6.6]
+        self.assertTrue(hasattr(Season, 'spam'))
+        del Season.spam
+        self.assertFalse(hasattr(Season, 'spam'))
 
-    class enum_type(float, ReprEnum):
-        def _generate_next_value_(name, start, count, last_values):
-            values = [4.4, 5.5, 6.6]
-            return values[count]
+        with self.assertRaises(AttributeError):
+            del Season.SPRING
+        with self.assertRaises(AttributeError):
+            del Season.DRY
+        with self.assertRaises(AttributeError):
+            del Season.SPRING.name
 
+    def test_bool_of_class(self):
+        class Empty(Enum):
+            pass
+        self.assertTrue(bool(Empty))
 
-class TestSpecial(unittest.TestCase):
-    """
-    various operations that are not attributable to every possible enum
-    """
+    def test_bool_of_member(self):
+        class Count(Enum):
+            zero = 0
+            one = 1
+            two = 2
+        for member in Count:
+            self.assertTrue(bool(member))
 
-    def setUp(self):
-        class Season(Enum):
-            SPRING = 1
-            SUMMER = 2
-            AUTUMN = 3
-            WINTER = 4
-        self.Season = Season
-        #
-        class Grades(IntEnum):
-            A = 5
-            B = 4
-            C = 3
-            D = 2
-            F = 0
-        self.Grades = Grades
-        #
-        class Directional(str, Enum):
-            EAST = 'east'
-            WEST = 'west'
-            NORTH = 'north'
-            SOUTH = 'south'
-        self.Directional = Directional
-        #
-        from datetime import date
-        class Holiday(date, Enum):
-            NEW_YEAR = 2013, 1, 1
-            IDES_OF_MARCH = 2013, 3, 15
-        self.Holiday = Holiday
+    def test_invalid_names(self):
+        with self.assertRaises(ValueError):
+            class Wrong(Enum):
+                mro = 9
+        with self.assertRaises(ValueError):
+            class Wrong(Enum):
+                _create_= 11
+        with self.assertRaises(ValueError):
+            class Wrong(Enum):
+                _get_mixins_ = 9
+        with self.assertRaises(ValueError):
+            class Wrong(Enum):
+                _find_new_ = 1
+        with self.assertRaises(ValueError):
+            class Wrong(Enum):
+                _any_name_ = 9
 
     def test_bool(self):
         # plain Enum members are always True
@@ -865,56 +656,92 @@ class IntLogic(int, Enum):
         self.assertTrue(IntLogic.true)
         self.assertFalse(IntLogic.false)
 
+    @unittest.skipIf(
+            python_version >= (3, 12),
+            '__contains__ now returns True/False for all inputs',
+            )
+    def test_contains_er(self):
+        Season = self.Season
+        self.assertIn(Season.AUTUMN, Season)
+        with self.assertRaises(TypeError):
+            with self.assertWarns(DeprecationWarning):
+                3 in Season
+        with self.assertRaises(TypeError):
+            with self.assertWarns(DeprecationWarning):
+                'AUTUMN' in Season
+        val = Season(3)
+        self.assertIn(val, Season)
+        #
+        class OtherEnum(Enum):
+            one = 1; two = 2
+        self.assertNotIn(OtherEnum.two, Season)
+
+    @unittest.skipIf(
+            python_version < (3, 12),
+            '__contains__ only works with enum memmbers before 3.12',
+            )
+    def test_contains_tf(self):
+        Season = self.Season
+        self.assertIn(Season.AUTUMN, Season)
+        self.assertTrue(3 in Season)
+        self.assertFalse('AUTUMN' in Season)
+        val = Season(3)
+        self.assertIn(val, Season)
+        #
+        class OtherEnum(Enum):
+            one = 1; two = 2
+        self.assertNotIn(OtherEnum.two, Season)
+
     def test_comparisons(self):
         Season = self.Season
         with self.assertRaises(TypeError):
             Season.SPRING < Season.WINTER
         with self.assertRaises(TypeError):
             Season.SPRING > 4
-        #
+
         self.assertNotEqual(Season.SPRING, 1)
-        #
+
         class Part(Enum):
             SPRING = 1
             CLIP = 2
             BARREL = 3
-        #
+
         self.assertNotEqual(Season.SPRING, Part.SPRING)
         with self.assertRaises(TypeError):
             Season.SPRING < Part.CLIP
 
-    def test_dir_with_custom_dunders(self):
-        class PlainEnum(Enum):
-            pass
-        cls_dir = dir(PlainEnum)
-        self.assertNotIn('__repr__', cls_dir)
-        self.assertNotIn('__str__', cls_dir)
-        self.assertNotIn('__repr__', cls_dir)
-        self.assertNotIn('__repr__', cls_dir)
-        #
-        class MyEnum(Enum):
-            def __repr__(self):
-                return object.__repr__(self)
-            def __str__(self):
-                return object.__repr__(self)
-            def __format__(self):
-                return object.__repr__(self)
-            def __init__(self):
-                pass
-        cls_dir = dir(MyEnum)
-        self.assertIn('__repr__', cls_dir)
-        self.assertIn('__str__', cls_dir)
-        self.assertIn('__repr__', cls_dir)
-        self.assertIn('__repr__', cls_dir)
+    def test_enum_duplicates(self):
+        class Season(Enum):
+            SPRING = 1
+            SUMMER = 2
+            AUTUMN = FALL = 3
+            WINTER = 4
+            ANOTHER_SPRING = 1
+        lst = list(Season)
+        self.assertEqual(
+            lst,
+            [Season.SPRING, Season.SUMMER,
+             Season.AUTUMN, Season.WINTER,
+            ])
+        self.assertIs(Season.FALL, Season.AUTUMN)
+        self.assertEqual(Season.FALL.value, 3)
+        self.assertEqual(Season.AUTUMN.value, 3)
+        self.assertIs(Season(3), Season.AUTUMN)
+        self.assertIs(Season(1), Season.SPRING)
+        self.assertEqual(Season.FALL.name, 'AUTUMN')
+        self.assertEqual(
+                [k for k,v in Season.__members__.items() if v.name != k],
+                ['FALL', 'ANOTHER_SPRING'],
+                )
 
-    def test_duplicate_name_error(self):
+    def test_duplicate_name(self):
         with self.assertRaises(TypeError):
             class Color(Enum):
                 red = 1
                 green = 2
                 blue = 3
                 red = 4
-        #
+
         with self.assertRaises(TypeError):
             class Color(Enum):
                 red = 1
@@ -922,45 +749,232 @@ class Color(Enum):
                 blue = 3
                 def red(self):
                     return 'red'
-        #
+
         with self.assertRaises(TypeError):
             class Color(Enum):
-                @enum.property
+                @property
                 def red(self):
                     return 'redder'
                 red = 1
                 green = 2
                 blue = 3
 
-    def test_enum_function_with_qualname(self):
-        if isinstance(Theory, Exception):
-            raise Theory
-        self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+    def test_reserved__sunder_(self):
+        with self.assertRaisesRegex(
+                ValueError,
+                '_sunder_ names, such as ._bad_., are reserved',
+            ):
+            class Bad(Enum):
+                _bad_ = 1
 
     def test_enum_with_value_name(self):
         class Huh(Enum):
             name = 1
             value = 2
-        self.assertEqual(list(Huh), [Huh.name, Huh.value])
+        self.assertEqual(
+            list(Huh),
+            [Huh.name, Huh.value],
+            )
         self.assertIs(type(Huh.name), Huh)
         self.assertEqual(Huh.name.name, 'name')
         self.assertEqual(Huh.name.value, 1)
 
+    def test_format_enum(self):
+        Season = self.Season
+        self.assertEqual('{}'.format(Season.SPRING),
+                         '{}'.format(str(Season.SPRING)))
+        self.assertEqual( '{:}'.format(Season.SPRING),
+                          '{:}'.format(str(Season.SPRING)))
+        self.assertEqual('{:20}'.format(Season.SPRING),
+                         '{:20}'.format(str(Season.SPRING)))
+        self.assertEqual('{:^20}'.format(Season.SPRING),
+                         '{:^20}'.format(str(Season.SPRING)))
+        self.assertEqual('{:>20}'.format(Season.SPRING),
+                         '{:>20}'.format(str(Season.SPRING)))
+        self.assertEqual('{:<20}'.format(Season.SPRING),
+                         '{:<20}'.format(str(Season.SPRING)))
+
+    def test_str_override_enum(self):
+        class EnumWithStrOverrides(Enum):
+            one = auto()
+            two = auto()
+
+            def __str__(self):
+                return 'Str!'
+        self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
+        self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
+
+    def test_format_override_enum(self):
+        class EnumWithFormatOverride(Enum):
+            one = 1.0
+            two = 2.0
+            def __format__(self, spec):
+                return 'Format!!'
+        self.assertEqual(str(EnumWithFormatOverride.one), 'one')
+        self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
+
+    def test_str_and_format_override_enum(self):
+        class EnumWithStrFormatOverrides(Enum):
+            one = auto()
+            two = auto()
+            def __str__(self):
+                return 'Str!'
+            def __format__(self, spec):
+                return 'Format!'
+        self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
+        self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
+
+    def test_str_override_mixin(self):
+        class MixinEnumWithStrOverride(float, Enum):
+            one = 1.0
+            two = 2.0
+            def __str__(self):
+                return 'Overridden!'
+        self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
+        self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
+
+    def test_str_and_format_override_mixin(self):
+        class MixinWithStrFormatOverrides(float, Enum):
+            one = 1.0
+            two = 2.0
+            def __str__(self):
+                return 'Str!'
+            def __format__(self, spec):
+                return 'Format!'
+        self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
+        self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
+
+    def test_format_override_mixin(self):
+        class TestFloat(float, Enum):
+            one = 1.0
+            two = 2.0
+            def __format__(self, spec):
+                return 'TestFloat success!'
+        self.assertEqual(str(TestFloat.one), 'one')
+        self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
+
+    @unittest.skipIf(
+            python_version < (3, 12),
+            'mixin-format is still using member.value',
+            )
+    def test_mixin_format_warning(self):
+        class Grades(int, Enum):
+            A = 5
+            B = 4
+            C = 3
+            D = 2
+            F = 0
+        self.assertEqual(f'{self.Grades.B}', 'B')
+
+    @unittest.skipIf(
+            python_version >= (3, 12),
+            'mixin-format now uses member instead of member.value',
+            )
+    def test_mixin_format_warning(self):
+        class Grades(int, Enum):
+            A = 5
+            B = 4
+            C = 3
+            D = 2
+            F = 0
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(f'{Grades.B}', '4')
+
+    def assertFormatIsValue(self, spec, member):
+        if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
+            with self.assertWarns(DeprecationWarning):
+                self.assertEqual(spec.format(member), spec.format(member.value))
+        else:
+            self.assertEqual(spec.format(member), spec.format(member.value))
+
+    def test_format_enum_date(self):
+        Holiday = self.Holiday
+        self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
+        self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
+
+    def test_format_enum_float(self):
+        Konstants = self.Konstants
+        self.assertFormatIsValue('{}', Konstants.TAU)
+        self.assertFormatIsValue('{:}', Konstants.TAU)
+        self.assertFormatIsValue('{:20}', Konstants.TAU)
+        self.assertFormatIsValue('{:^20}', Konstants.TAU)
+        self.assertFormatIsValue('{:>20}', Konstants.TAU)
+        self.assertFormatIsValue('{:<20}', Konstants.TAU)
+        self.assertFormatIsValue('{:n}', Konstants.TAU)
+        self.assertFormatIsValue('{:5.2}', Konstants.TAU)
+        self.assertFormatIsValue('{:f}', Konstants.TAU)
+
+    def test_format_enum_int(self):
+        class Grades(int, Enum):
+            A = 5
+            B = 4
+            C = 3
+            D = 2
+            F = 0
+        self.assertFormatIsValue('{}', Grades.C)
+        self.assertFormatIsValue('{:}', Grades.C)
+        self.assertFormatIsValue('{:20}', Grades.C)
+        self.assertFormatIsValue('{:^20}', Grades.C)
+        self.assertFormatIsValue('{:>20}', Grades.C)
+        self.assertFormatIsValue('{:<20}', Grades.C)
+        self.assertFormatIsValue('{:+}', Grades.C)
+        self.assertFormatIsValue('{:08X}', Grades.C)
+        self.assertFormatIsValue('{:b}', Grades.C)
+
+    def test_format_enum_str(self):
+        Directional = self.Directional
+        self.assertFormatIsValue('{}', Directional.WEST)
+        self.assertFormatIsValue('{:}', Directional.WEST)
+        self.assertFormatIsValue('{:20}', Directional.WEST)
+        self.assertFormatIsValue('{:^20}', Directional.WEST)
+        self.assertFormatIsValue('{:>20}', Directional.WEST)
+        self.assertFormatIsValue('{:<20}', Directional.WEST)
+
+    def test_object_str_override(self):
+        class Colors(Enum):
+            RED, GREEN, BLUE = 1, 2, 3
+            def __repr__(self):
+                return "test.%s" % (self._name_, )
+            __str__ = object.__str__
+        self.assertEqual(str(Colors.RED), 'test.RED')
+
+    def test_enum_str_override(self):
+        class MyStrEnum(Enum):
+            def __str__(self):
+                return 'MyStr'
+        class MyMethodEnum(Enum):
+            def hello(self):
+                return 'Hello!  My name is %s' % self.name
+        class Test1Enum(MyMethodEnum, int, MyStrEnum):
+            One = 1
+            Two = 2
+        self.assertTrue(Test1Enum._member_type_ is int)
+        self.assertEqual(str(Test1Enum.One), 'MyStr')
+        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+        #
+        class Test2Enum(MyStrEnum, MyMethodEnum):
+            One = 1
+            Two = 2
+        self.assertEqual(str(Test2Enum.One), 'MyStr')
+        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+
     def test_inherited_data_type(self):
         class HexInt(int):
-            __qualname__ = 'HexInt'
             def __repr__(self):
                 return hex(self)
         class MyEnum(HexInt, enum.Enum):
-            __qualname__ = 'MyEnum'
             A = 1
             B = 2
             C = 3
+            def __repr__(self):
+                return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
         self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
-        globals()['HexInt'] = HexInt
-        globals()['MyEnum'] = MyEnum
-        test_pickle_dump_load(self.assertIs, MyEnum.A)
-        test_pickle_dump_load(self.assertIs, MyEnum)
         #
         class SillyInt(HexInt):
             __qualname__ = 'SillyInt'
@@ -976,7 +990,7 @@ class MyOtherEnum(SillyInt, enum.Enum):
         test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
         test_pickle_dump_load(self.assertIs, MyOtherEnum)
         #
-        # This did not work in 3.10, but does now with pickling by name
+        # This did not work in 3.9, but does now with pickling by name
         class UnBrokenInt(int):
             __qualname__ = 'UnBrokenInt'
             def __new__(cls, value):
@@ -993,124 +1007,6 @@ class MyUnBrokenEnum(UnBrokenInt, Enum):
         test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
         test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
 
-    def test_floatenum_fromhex(self):
-        h = float.hex(FloatStooges.MOE.value)
-        self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
-        h = float.hex(FloatStooges.MOE.value + 0.01)
-        with self.assertRaises(ValueError):
-            FloatStooges.fromhex(h)
-
-    def test_programmatic_function_type(self):
-        MinorEnum = Enum('MinorEnum', 'june july august', type=int)
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 1):
-            e = MinorEnum(i)
-            self.assertEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_programmatic_function_string_with_start(self):
-        MinorEnum = Enum('MinorEnum', 'june july august', start=10)
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 10):
-            e = MinorEnum(i)
-            self.assertEqual(int(e.value), i)
-            self.assertNotEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_programmatic_function_type_with_start(self):
-        MinorEnum = Enum('MinorEnum', 'june july august', type=int, start=30)
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 30):
-            e = MinorEnum(i)
-            self.assertEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_programmatic_function_string_list_with_start(self):
-        MinorEnum = Enum('MinorEnum', ['june', 'july', 'august'], start=20)
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 20):
-            e = MinorEnum(i)
-            self.assertEqual(int(e.value), i)
-            self.assertNotEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_programmatic_function_type_from_subclass(self):
-        MinorEnum = IntEnum('MinorEnum', 'june july august')
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 1):
-            e = MinorEnum(i)
-            self.assertEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_programmatic_function_type_from_subclass_with_start(self):
-        MinorEnum = IntEnum('MinorEnum', 'june july august', start=40)
-        lst = list(MinorEnum)
-        self.assertEqual(len(lst), len(MinorEnum))
-        self.assertEqual(len(MinorEnum), 3, MinorEnum)
-        self.assertEqual(
-                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
-                lst,
-                )
-        for i, month in enumerate('june july august'.split(), 40):
-            e = MinorEnum(i)
-            self.assertEqual(e, i)
-            self.assertEqual(e.name, month)
-            self.assertIn(e, MinorEnum)
-            self.assertIs(type(e), MinorEnum)
-
-    def test_intenum_from_bytes(self):
-        self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
-        with self.assertRaises(ValueError):
-            IntStooges.from_bytes(b'\x00\x05', 'big')
-
-    def test_reserved_sunder_error(self):
-        with self.assertRaisesRegex(
-                ValueError,
-                '_sunder_ names, such as ._bad_., are reserved',
-            ):
-            class Bad(Enum):
-                _bad_ = 1
-
     def test_too_many_data_types(self):
         with self.assertRaisesRegex(TypeError, 'too many data types'):
             class Huh(str, int, Enum):
@@ -1126,6 +1022,122 @@ def repr(self):
             class Huh(MyStr, MyInt, Enum):
                 One = 1
 
+    def test_value_auto_assign(self):
+        class Some(Enum):
+            def __new__(cls, val):
+                return object.__new__(cls)
+            x = 1
+            y = 2
+
+        self.assertEqual(Some.x.value, 1)
+        self.assertEqual(Some.y.value, 2)
+
+    def test_hash(self):
+        Season = self.Season
+        dates = {}
+        dates[Season.WINTER] = '1225'
+        dates[Season.SPRING] = '0315'
+        dates[Season.SUMMER] = '0704'
+        dates[Season.AUTUMN] = '1031'
+        self.assertEqual(dates[Season.AUTUMN], '1031')
+
+    def test_intenum_from_scratch(self):
+        class phy(int, Enum):
+            pi = 3
+            tau = 2 * pi
+        self.assertTrue(phy.pi < phy.tau)
+
+    def test_intenum_inherited(self):
+        class IntEnum(int, Enum):
+            pass
+        class phy(IntEnum):
+            pi = 3
+            tau = 2 * pi
+        self.assertTrue(phy.pi < phy.tau)
+
+    def test_floatenum_from_scratch(self):
+        class phy(float, Enum):
+            pi = 3.1415926
+            tau = 2 * pi
+        self.assertTrue(phy.pi < phy.tau)
+
+    def test_floatenum_inherited(self):
+        class FloatEnum(float, Enum):
+            pass
+        class phy(FloatEnum):
+            pi = 3.1415926
+            tau = 2 * pi
+        self.assertTrue(phy.pi < phy.tau)
+
+    def test_strenum_from_scratch(self):
+        class phy(str, Enum):
+            pi = 'Pi'
+            tau = 'Tau'
+        self.assertTrue(phy.pi < phy.tau)
+
+    def test_strenum_inherited_methods(self):
+        class phy(StrEnum):
+            pi = 'Pi'
+            tau = 'Tau'
+        self.assertTrue(phy.pi < phy.tau)
+        self.assertEqual(phy.pi.upper(), 'PI')
+        self.assertEqual(phy.tau.count('a'), 1)
+
+    def test_intenum(self):
+        class WeekDay(IntEnum):
+            SUNDAY = 1
+            MONDAY = 2
+            TUESDAY = 3
+            WEDNESDAY = 4
+            THURSDAY = 5
+            FRIDAY = 6
+            SATURDAY = 7
+
+        self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
+        self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
+
+        lst = list(WeekDay)
+        self.assertEqual(len(lst), len(WeekDay))
+        self.assertEqual(len(WeekDay), 7)
+        target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
+        target = target.split()
+        for i, weekday in enumerate(target, 1):
+            e = WeekDay(i)
+            self.assertEqual(e, i)
+            self.assertEqual(int(e), i)
+            self.assertEqual(e.name, weekday)
+            self.assertIn(e, WeekDay)
+            self.assertEqual(lst.index(e)+1, i)
+            self.assertTrue(0 < e < 8)
+            self.assertIs(type(e), WeekDay)
+            self.assertIsInstance(e, int)
+            self.assertIsInstance(e, Enum)
+
+    def test_intenum_duplicates(self):
+        class WeekDay(IntEnum):
+            SUNDAY = 1
+            MONDAY = 2
+            TUESDAY = TEUSDAY = 3
+            WEDNESDAY = 4
+            THURSDAY = 5
+            FRIDAY = 6
+            SATURDAY = 7
+        self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
+        self.assertEqual(WeekDay(3).name, 'TUESDAY')
+        self.assertEqual([k for k,v in WeekDay.__members__.items()
+                if v.name != k], ['TEUSDAY', ])
+
+    def test_intenum_from_bytes(self):
+        self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
+        with self.assertRaises(ValueError):
+            IntStooges.from_bytes(b'\x00\x05', 'big')
+
+    def test_floatenum_fromhex(self):
+        h = float.hex(FloatStooges.MOE.value)
+        self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
+        h = float.hex(FloatStooges.MOE.value + 0.01)
+        with self.assertRaises(ValueError):
+            FloatStooges.fromhex(h)
 
     def test_pickle_enum(self):
         if isinstance(Stooges, Exception):
@@ -1157,7 +1169,12 @@ def test_pickle_enum_function_with_module(self):
         test_pickle_dump_load(self.assertIs, Question.who)
         test_pickle_dump_load(self.assertIs, Question)
 
-    def test_pickle_nested_class(self):
+    def test_enum_function_with_qualname(self):
+        if isinstance(Theory, Exception):
+            raise Theory
+        self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+
+    def test_class_nested_enum_and_pickle_protocol_four(self):
         # would normally just have this directly in the class namespace
         class NestedEnum(Enum):
             twigs = 'common'
@@ -1175,7 +1192,7 @@ class ReplaceGlobalInt(IntEnum):
         for proto in range(HIGHEST_PROTOCOL):
             self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
 
-    def test_pickle_explodes(self):
+    def test_exploding_pickle(self):
         BadPickle = Enum(
                 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
         globals()['BadPickle'] = BadPickle
@@ -1184,37 +1201,216 @@ def test_pickle_explodes(self):
         test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
         test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
 
-    def test_string_enum(self):
-        class SkillLevel(str, Enum):
-            master = 'what is the sound of one hand clapping?'
-            journeyman = 'why did the chicken cross the road?'
-            apprentice = 'knock, knock!'
-        self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
+    def test_string_enum(self):
+        class SkillLevel(str, Enum):
+            master = 'what is the sound of one hand clapping?'
+            journeyman = 'why did the chicken cross the road?'
+            apprentice = 'knock, knock!'
+        self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
+
+    def test_getattr_getitem(self):
+        class Period(Enum):
+            morning = 1
+            noon = 2
+            evening = 3
+            night = 4
+        self.assertIs(Period(2), Period.noon)
+        self.assertIs(getattr(Period, 'night'), Period.night)
+        self.assertIs(Period['morning'], Period.morning)
+
+    def test_getattr_dunder(self):
+        Season = self.Season
+        self.assertTrue(getattr(Season, '__eq__'))
+
+    def test_iteration_order(self):
+        class Season(Enum):
+            SUMMER = 2
+            WINTER = 4
+            AUTUMN = 3
+            SPRING = 1
+        self.assertEqual(
+                list(Season),
+                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
+                )
+
+    def test_reversed_iteration_order(self):
+        self.assertEqual(
+                list(reversed(self.Season)),
+                [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
+                 self.Season.SPRING]
+                )
+
+    def test_programmatic_function_string(self):
+        SummerMonth = Enum('SummerMonth', 'june july august')
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_string_with_start(self):
+        SummerMonth = Enum('SummerMonth', 'june july august', start=10)
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 10):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_string_list(self):
+        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_string_list_with_start(self):
+        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 20):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_iterable(self):
+        SummerMonth = Enum(
+                'SummerMonth',
+                (('june', 1), ('july', 2), ('august', 3))
+                )
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_from_dict(self):
+        SummerMonth = Enum(
+                'SummerMonth',
+                OrderedDict((('june', 1), ('july', 2), ('august', 3)))
+                )
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(int(e.value), i)
+            self.assertNotEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
+
+    def test_programmatic_function_type(self):
+        SummerMonth = Enum('SummerMonth', 'june july august', type=int)
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
 
-    def test_getattr_getitem(self):
-        class Period(Enum):
-            morning = 1
-            noon = 2
-            evening = 3
-            night = 4
-        self.assertIs(Period(2), Period.noon)
-        self.assertIs(getattr(Period, 'night'), Period.night)
-        self.assertIs(Period['morning'], Period.morning)
+    def test_programmatic_function_type_with_start(self):
+        SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 30):
+            e = SummerMonth(i)
+            self.assertEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
 
-    def test_getattr_dunder(self):
-        Season = self.Season
-        self.assertTrue(getattr(Season, '__eq__'))
+    def test_programmatic_function_type_from_subclass(self):
+        SummerMonth = IntEnum('SummerMonth', 'june july august')
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
+        self.assertEqual(
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
+                )
+        for i, month in enumerate('june july august'.split(), 1):
+            e = SummerMonth(i)
+            self.assertEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
 
-    def test_iteration_order(self):
-        class Season(Enum):
-            SUMMER = 2
-            WINTER = 4
-            AUTUMN = 3
-            SPRING = 1
+    def test_programmatic_function_type_from_subclass_with_start(self):
+        SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
+        lst = list(SummerMonth)
+        self.assertEqual(len(lst), len(SummerMonth))
+        self.assertEqual(len(SummerMonth), 3, SummerMonth)
         self.assertEqual(
-                list(Season),
-                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
+                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+                lst,
                 )
+        for i, month in enumerate('june july august'.split(), 40):
+            e = SummerMonth(i)
+            self.assertEqual(e, i)
+            self.assertEqual(e.name, month)
+            self.assertIn(e, SummerMonth)
+            self.assertIs(type(e), SummerMonth)
 
     def test_subclassing(self):
         if isinstance(Name, Exception):
@@ -1229,18 +1425,15 @@ class Color(Enum):
             red = 1
             green = 2
             blue = 3
-        #
         with self.assertRaises(TypeError):
             class MoreColor(Color):
                 cyan = 4
                 magenta = 5
                 yellow = 6
-        #
-        with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
+        with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
             class EvenMoreColor(Color, IntEnum):
                 chartruese = 7
-        #
-        with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
+        with self.assertRaisesRegex(TypeError, "Foo: cannot extend enumeration 'Color'"):
             Color('Foo', ('pink', 'black'))
 
     def test_exclude_methods(self):
@@ -1344,7 +1537,27 @@ class Color(Enum):
         with self.assertRaises(KeyError):
             Color['chartreuse']
 
-    # tests that need to be evalualted for moving
+    def test_new_repr(self):
+        class Color(Enum):
+            red = 1
+            green = 2
+            blue = 3
+            def __repr__(self):
+                return "don't you just love shades of %s?" % self.name
+        self.assertEqual(
+                repr(Color.blue),
+                "don't you just love shades of blue?",
+                )
+
+    def test_inherited_repr(self):
+        class MyEnum(Enum):
+            def __repr__(self):
+                return "My name is %s." % self.name
+        class MyIntEnum(int, MyEnum):
+            this = 1
+            that = 2
+            theother = 3
+        self.assertEqual(repr(MyIntEnum.that), "My name is that.")
 
     def test_multiple_mixin_mro(self):
         class auto_enum(type(Enum)):
@@ -1397,7 +1610,7 @@ def __new__(cls, *args):
                 return self
             def __getnewargs__(self):
                 return self._args
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1457,7 +1670,7 @@ def __new__(cls, *args):
                 return self
             def __getnewargs_ex__(self):
                 return self._args, {}
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1517,7 +1730,7 @@ def __new__(cls, *args):
                 return self
             def __reduce__(self):
                 return self.__class__, self._args
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1577,7 +1790,7 @@ def __new__(cls, *args):
                 return self
             def __reduce_ex__(self, proto):
                 return self.__class__, self._args
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1634,7 +1847,7 @@ def __new__(cls, *args):
                 self._intname = name
                 self._args = _args
                 return self
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1689,7 +1902,7 @@ def __new__(cls, *args):
                 self._intname = name
                 self._args = _args
                 return self
-            @bltns.property
+            @property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1878,7 +2091,6 @@ def test(self):
         class Test(Base):
             test = 1
         self.assertEqual(Test.test.test, 'dynamic')
-        self.assertEqual(Test.test.value, 1)
         class Base2(Enum):
             @enum.property
             def flash(self):
@@ -1886,7 +2098,6 @@ def flash(self):
         class Test(Base2):
             flash = 1
         self.assertEqual(Test.flash.flash, 'flashy dynamic')
-        self.assertEqual(Test.flash.value, 1)
 
     def test_no_duplicates(self):
         class UniqueEnum(Enum):
@@ -1923,7 +2134,7 @@ class Planet(Enum):
             def __init__(self, mass, radius):
                 self.mass = mass       # in kilograms
                 self.radius = radius   # in meters
-            @enum.property
+            @property
             def surface_gravity(self):
                 # universal gravitational constant  (m3 kg-1 s-2)
                 G = 6.67300E-11
@@ -1993,7 +2204,90 @@ class LabelledList(LabelledIntEnum):
         self.assertEqual(LabelledList.unprocessed, 1)
         self.assertEqual(LabelledList(1), LabelledList.unprocessed)
 
-    def test_default_missing_no_chained_exception(self):
+    def test_auto_number(self):
+        class Color(Enum):
+            red = auto()
+            blue = auto()
+            green = auto()
+
+        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+        self.assertEqual(Color.red.value, 1)
+        self.assertEqual(Color.blue.value, 2)
+        self.assertEqual(Color.green.value, 3)
+
+    def test_auto_name(self):
+        class Color(Enum):
+            def _generate_next_value_(name, start, count, last):
+                return name
+            red = auto()
+            blue = auto()
+            green = auto()
+
+        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+        self.assertEqual(Color.red.value, 'red')
+        self.assertEqual(Color.blue.value, 'blue')
+        self.assertEqual(Color.green.value, 'green')
+
+    def test_auto_name_inherit(self):
+        class AutoNameEnum(Enum):
+            def _generate_next_value_(name, start, count, last):
+                return name
+        class Color(AutoNameEnum):
+            red = auto()
+            blue = auto()
+            green = auto()
+
+        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+        self.assertEqual(Color.red.value, 'red')
+        self.assertEqual(Color.blue.value, 'blue')
+        self.assertEqual(Color.green.value, 'green')
+
+    def test_auto_garbage(self):
+        class Color(Enum):
+            red = 'red'
+            blue = auto()
+        self.assertEqual(Color.blue.value, 1)
+
+    def test_auto_garbage_corrected(self):
+        class Color(Enum):
+            red = 'red'
+            blue = 2
+            green = auto()
+
+        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+        self.assertEqual(Color.red.value, 'red')
+        self.assertEqual(Color.blue.value, 2)
+        self.assertEqual(Color.green.value, 3)
+
+    def test_auto_order(self):
+        with self.assertRaises(TypeError):
+            class Color(Enum):
+                red = auto()
+                green = auto()
+                blue = auto()
+                def _generate_next_value_(name, start, count, last):
+                    return name
+
+    def test_auto_order_wierd(self):
+        weird_auto = auto()
+        weird_auto.value = 'pathological case'
+        class Color(Enum):
+            red = weird_auto
+            def _generate_next_value_(name, start, count, last):
+                return name
+            blue = auto()
+        self.assertEqual(list(Color), [Color.red, Color.blue])
+        self.assertEqual(Color.red.value, 'pathological case')
+        self.assertEqual(Color.blue.value, 'blue')
+
+    def test_duplicate_auto(self):
+        class Dupes(Enum):
+            first = primero = auto()
+            second = auto()
+            third = auto()
+        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
+
+    def test_default_missing(self):
         class Color(Enum):
             RED = 1
             GREEN = 2
@@ -2005,7 +2299,7 @@ class Color(Enum):
         else:
             raise Exception('Exception not raised.')
 
-    def test_missing_override(self):
+    def test_missing(self):
         class Color(Enum):
             red = 1
             green = 2
@@ -2069,9 +2363,9 @@ def __init__(self):
         class_1_ref = weakref.ref(Class1())
         class_2_ref = weakref.ref(Class2())
         #
-        # The exception raised by Enum used to create a reference loop and thus
-        # Class2 instances would stick around until the next garbage collection
-        # cycle, unlike Class1.  Verify Class2 no longer does this.
+        # The exception raised by Enum creates a reference loop and thus
+        # Class2 instances will stick around until the next garbage collection
+        # cycle, unlike Class1.
         gc.collect()  # For PyPy or other GCs.
         self.assertIs(class_1_ref(), None)
         self.assertIs(class_2_ref(), None)
@@ -2102,12 +2396,11 @@ class Color(MaxMixin, Enum):
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 3)
         self.assertEqual(Color.MAX, 3)
-        self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+        self.assertEqual(str(Color.BLUE), 'BLUE')
         class Color(MaxMixin, StrMixin, Enum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 3)
@@ -2117,7 +2410,6 @@ class Color(StrMixin, MaxMixin, Enum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 3)
@@ -2127,7 +2419,6 @@ class CoolColor(StrMixin, SomeEnum, Enum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(CoolColor.RED.value, 1)
         self.assertEqual(CoolColor.GREEN.value, 2)
         self.assertEqual(CoolColor.BLUE.value, 3)
@@ -2137,7 +2428,6 @@ class CoolerColor(StrMixin, AnotherEnum, Enum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(CoolerColor.RED.value, 1)
         self.assertEqual(CoolerColor.GREEN.value, 2)
         self.assertEqual(CoolerColor.BLUE.value, 3)
@@ -2148,7 +2438,6 @@ class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(CoolestColor.RED.value, 1)
         self.assertEqual(CoolestColor.GREEN.value, 2)
         self.assertEqual(CoolestColor.BLUE.value, 3)
@@ -2159,7 +2448,6 @@ class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(ConfusedColor.RED.value, 1)
         self.assertEqual(ConfusedColor.GREEN.value, 2)
         self.assertEqual(ConfusedColor.BLUE.value, 3)
@@ -2170,7 +2458,6 @@ class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__          # needed as of 3.11
         self.assertEqual(ReformedColor.RED.value, 1)
         self.assertEqual(ReformedColor.GREEN.value, 2)
         self.assertEqual(ReformedColor.BLUE.value, 3)
@@ -2203,12 +2490,11 @@ def __repr__(self):
                 return hex(self)
 
         class MyIntEnum(HexMixin, MyInt, enum.Enum):
-            __repr__ = HexMixin.__repr__
+            pass
 
         class Foo(MyIntEnum):
             TEST = 1
         self.assertTrue(isinstance(Foo.TEST, MyInt))
-        self.assertEqual(Foo._member_type_, MyInt)
         self.assertEqual(repr(Foo.TEST), "0x1")
 
         class Fee(MyIntEnum):
@@ -2220,7 +2506,7 @@ def __new__(cls, value):
                 return member
         self.assertEqual(Fee.TEST, 2)
 
-    def test_multiple_mixin_with_common_data_type(self):
+    def test_miltuple_mixin_with_common_data_type(self):
         class CaseInsensitiveStrEnum(str, Enum):
             @classmethod
             def _missing_(cls, value):
@@ -2240,7 +2526,7 @@ def _missing_(cls, value):
                 unknown._value_ = value
                 cls._member_map_[value] = unknown
                 return unknown
-            @enum.property
+            @property
             def valid(self):
                 return self._valid
         #
@@ -2284,7 +2570,7 @@ class GoodStrEnum(StrEnum):
         self.assertEqual('{}'.format(GoodStrEnum.one), '1')
         self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
         self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
-        self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
+        self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one')
         #
         class DumbMixin:
             def __str__(self):
@@ -2293,7 +2579,6 @@ class DumbStrEnum(DumbMixin, StrEnum):
             five = '5'
             six = '6'
             seven = '7'
-            __str__ = DumbMixin.__str__             # needed as of 3.11
         self.assertEqual(DumbStrEnum.seven, '7')
         self.assertEqual(str(DumbStrEnum.seven), "don't do this")
         #
@@ -2335,6 +2620,74 @@ class ThirdFailedStrEnum(StrEnum):
                 one = '1'
                 two = b'2', 'ascii', 9
 
+    @unittest.skipIf(
+            python_version >= (3, 12),
+            'mixin-format now uses member instead of member.value',
+            )
+    def test_custom_strenum_with_warning(self):
+        class CustomStrEnum(str, Enum):
+            pass
+        class OkayEnum(CustomStrEnum):
+            one = '1'
+            two = '2'
+            three = b'3', 'ascii'
+            four = b'4', 'latin1', 'strict'
+        self.assertEqual(OkayEnum.one, '1')
+        self.assertEqual(str(OkayEnum.one), 'one')
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual('{}'.format(OkayEnum.one), '1')
+            self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one))
+        self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
+        #
+        class DumbMixin:
+            def __str__(self):
+                return "don't do this"
+        class DumbStrEnum(DumbMixin, CustomStrEnum):
+            five = '5'
+            six = '6'
+            seven = '7'
+        self.assertEqual(DumbStrEnum.seven, '7')
+        self.assertEqual(str(DumbStrEnum.seven), "don't do this")
+        #
+        class EnumMixin(Enum):
+            def hello(self):
+                print('hello from %s' % (self, ))
+        class HelloEnum(EnumMixin, CustomStrEnum):
+            eight = '8'
+        self.assertEqual(HelloEnum.eight, '8')
+        self.assertEqual(str(HelloEnum.eight), 'eight')
+        #
+        class GoodbyeMixin:
+            def goodbye(self):
+                print('%s wishes you a fond farewell')
+        class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
+            nine = '9'
+        self.assertEqual(GoodbyeEnum.nine, '9')
+        self.assertEqual(str(GoodbyeEnum.nine), 'nine')
+        #
+        class FirstFailedStrEnum(CustomStrEnum):
+            one = 1   # this will become '1'
+            two = '2'
+        class SecondFailedStrEnum(CustomStrEnum):
+            one = '1'
+            two = 2,  # this will become '2'
+            three = '3'
+        class ThirdFailedStrEnum(CustomStrEnum):
+            one = '1'
+            two = 2  # this will become '2'
+        with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
+            class ThirdFailedStrEnum(CustomStrEnum):
+                one = '1'
+                two = b'2', sys.getdefaultencoding
+        with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
+            class ThirdFailedStrEnum(CustomStrEnum):
+                one = '1'
+                two = b'2', 'ascii', 9
+
+    @unittest.skipIf(
+            python_version < (3, 12),
+            'mixin-format currently uses member.value',
+            )
     def test_custom_strenum(self):
         class CustomStrEnum(str, Enum):
             pass
@@ -2344,9 +2697,9 @@ class OkayEnum(CustomStrEnum):
             three = b'3', 'ascii'
             four = b'4', 'latin1', 'strict'
         self.assertEqual(OkayEnum.one, '1')
-        self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
-        self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
-        self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
+        self.assertEqual(str(OkayEnum.one), 'one')
+        self.assertEqual('{}'.format(OkayEnum.one), 'one')
+        self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
         #
         class DumbMixin:
             def __str__(self):
@@ -2355,7 +2708,6 @@ class DumbStrEnum(DumbMixin, CustomStrEnum):
             five = '5'
             six = '6'
             seven = '7'
-            __str__ = DumbMixin.__str__         # needed as of 3.11
         self.assertEqual(DumbStrEnum.seven, '7')
         self.assertEqual(str(DumbStrEnum.seven), "don't do this")
         #
@@ -2365,7 +2717,7 @@ def hello(self):
         class HelloEnum(EnumMixin, CustomStrEnum):
             eight = '8'
         self.assertEqual(HelloEnum.eight, '8')
-        self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
+        self.assertEqual(str(HelloEnum.eight), 'eight')
         #
         class GoodbyeMixin:
             def goodbye(self):
@@ -2373,7 +2725,7 @@ def goodbye(self):
         class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
             nine = '9'
         self.assertEqual(GoodbyeEnum.nine, '9')
-        self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
+        self.assertEqual(str(GoodbyeEnum.nine), 'nine')
         #
         class FirstFailedStrEnum(CustomStrEnum):
             one = 1   # this will become '1'
@@ -2419,6 +2771,21 @@ def __repr__(self):
                 code          = 'An$(5,1)', 2
                 description   = 'Bn$',      3
 
+    @unittest.skipUnless(
+            python_version == (3, 9),
+            'private variables are now normal attributes',
+            )
+    def test_warning_for_private_variables(self):
+        with self.assertWarns(DeprecationWarning):
+            class Private(Enum):
+                __corporal = 'Radar'
+        self.assertEqual(Private._Private__corporal.value, 'Radar')
+        try:
+            with self.assertWarns(DeprecationWarning):
+                class Private(Enum):
+                    __major_ = 'Hoolihan'
+        except ValueError:
+            pass
 
     def test_private_variable_is_normal_attribute(self):
         class Private(Enum):
@@ -2427,13 +2794,35 @@ class Private(Enum):
         self.assertEqual(Private._Private__corporal, 'Radar')
         self.assertEqual(Private._Private__major_, 'Hoolihan')
 
+    @unittest.skipUnless(
+            python_version < (3, 12),
+            'member-member access now raises an exception',
+            )
+    def test_warning_for_member_from_member_access(self):
+        with self.assertWarns(DeprecationWarning):
+            class Di(Enum):
+                YES = 1
+                NO = 0
+            nope = Di.YES.NO
+        self.assertIs(Di.NO, nope)
+
+    @unittest.skipUnless(
+            python_version >= (3, 12),
+            'member-member access currently issues a warning',
+            )
     def test_exception_for_member_from_member_access(self):
-        with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
+        with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
             class Di(Enum):
                 YES = 1
                 NO = 0
             nope = Di.YES.NO
 
+    def test_strenum_auto(self):
+        class Strings(StrEnum):
+            ONE = auto()
+            TWO = auto()
+        self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
+
 
     def test_dynamic_members_with_static_methods(self):
         #
@@ -2450,7 +2839,7 @@ def upper(self):
         self.assertEqual(Foo.FOO_CAT.value, 'aloof')
         self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
         #
-        with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as 'aloof'"):
+        with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
             class FooBar(Enum):
                 vars().update({
                         k: v
@@ -2462,42 +2851,8 @@ class FooBar(Enum):
                 def upper(self):
                     return self.value.upper()
 
-    def test_repr_with_dataclass(self):
-        "ensure dataclass-mixin has correct repr()"
-        from dataclasses import dataclass
-        @dataclass
-        class Foo:
-            __qualname__ = 'Foo'
-            a: int = 0
-        class Entries(Foo, Enum):
-            ENTRY1 = Foo(1)
-        self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
-    def test_repr_with_non_data_type_mixin(self):
-        # non-data_type is a mixin that doesn't define __new__
-        class Foo:
-            def __init__(self, a):
-                self.a = a
-            def __repr__(self):
-                return f'Foo(a={self.a!r})'
-        class Entries(Foo, Enum):
-            ENTRY1 = Foo(1)
-
-        self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
-    def test_value_backup_assign(self):
-        # check that enum will add missing values when custom __new__ does not
-        class Some(Enum):
-            def __new__(cls, val):
-                return object.__new__(cls)
-            x = 1
-            y = 2
-        self.assertEqual(Some.x.value, 1)
-        self.assertEqual(Some.y.value, 2)
-
 
 class TestOrder(unittest.TestCase):
-    "test usage of the `_order_` attribute"
 
     def test_same_members(self):
         class Color(Enum):
@@ -2559,7 +2914,7 @@ class Color(Enum):
                 verde = green
 
 
-class OldTestFlag(unittest.TestCase):
+class TestFlag(unittest.TestCase):
     """Tests of the Flags."""
 
     class Perm(Flag):
@@ -2582,6 +2937,65 @@ class Color(Flag):
         WHITE = RED|GREEN|BLUE
         BLANCO = RED|GREEN|BLUE
 
+    def test_str(self):
+        Perm = self.Perm
+        self.assertEqual(str(Perm.R), 'R')
+        self.assertEqual(str(Perm.W), 'W')
+        self.assertEqual(str(Perm.X), 'X')
+        self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+        self.assertEqual(str(Perm(0)), 'Perm(0)')
+        self.assertEqual(str(~Perm.R), 'W|X')
+        self.assertEqual(str(~Perm.W), 'R|X')
+        self.assertEqual(str(~Perm.X), 'R|W')
+        self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+        self.assertEqual(str(Perm(~0)), 'R|W|X')
+
+        Open = self.Open
+        self.assertEqual(str(Open.RO), 'RO')
+        self.assertEqual(str(Open.WO), 'WO')
+        self.assertEqual(str(Open.AC), 'AC')
+        self.assertEqual(str(Open.RO | Open.CE), 'CE')
+        self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+        self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+        self.assertEqual(str(~Open.WO), 'RW|CE')
+        self.assertEqual(str(~Open.AC), 'CE')
+        self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+        self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+
+    def test_repr(self):
+        Perm = self.Perm
+        self.assertEqual(repr(Perm.R), 'Perm.R')
+        self.assertEqual(repr(Perm.W), 'Perm.W')
+        self.assertEqual(repr(Perm.X), 'Perm.X')
+        self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+        self.assertEqual(repr(Perm(0)), '0x0')
+        self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+        self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+        self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+        self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+        self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+
+        Open = self.Open
+        self.assertEqual(repr(Open.RO), 'Open.RO')
+        self.assertEqual(repr(Open.WO), 'Open.WO')
+        self.assertEqual(repr(Open.AC), 'Open.AC')
+        self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+        self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+        self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+        self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+        self.assertEqual(repr(~Open.AC), 'Open.CE')
+        self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+        self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+
+    def test_format(self):
+        Perm = self.Perm
+        self.assertEqual(format(Perm.R, ''), 'R')
+        self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
+
     def test_or(self):
         Perm = self.Perm
         for i in Perm:
@@ -2674,7 +3088,7 @@ class Bizarre(Flag, boundary=KEEP):
             c = 4
             d = 6
         #
-        self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7)
+        self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
         #
         self.assertIs(Water(7), Water.ONE|Water.TWO)
         self.assertIs(Water(~9), Water.TWO)
@@ -2883,7 +3297,7 @@ class Color(Flag):
         self.assertEqual(Color.green.value, 4)
 
     def test_auto_number_garbage(self):
-        with self.assertRaisesRegex(TypeError, 'invalid flag value .not an int.'):
+        with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
             class Color(Flag):
                 red = 'not an int'
                 blue = auto()
@@ -2918,12 +3332,11 @@ class Color(AllMixin, Flag):
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
         self.assertEqual(Color.ALL.value, 7)
-        self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+        self.assertEqual(str(Color.BLUE), 'BLUE')
         class Color(AllMixin, StrMixin, Flag):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
@@ -2933,7 +3346,6 @@ class Color(StrMixin, AllMixin, Flag):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
@@ -3014,8 +3426,21 @@ class NeverEnum(WhereEnum):
         self.assertFalse(NeverEnum.__dict__.get('_test1', False))
         self.assertFalse(NeverEnum.__dict__.get('_test2', False))
 
+    def test_default_missing(self):
+        with self.assertRaisesRegex(
+            ValueError,
+            "'RED' is not a valid TestFlag.Color",
+        ) as ctx:
+            self.Color('RED')
+        self.assertIs(ctx.exception.__context__, None)
+
+        P = Flag('P', 'X Y')
+        with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+            P('X')
+        self.assertIs(ctx.exception.__context__, None)
+
 
-class OldTestIntFlag(unittest.TestCase):
+class TestIntFlag(unittest.TestCase):
     """Tests of the IntFlags."""
 
     class Perm(IntFlag):
@@ -3060,6 +3485,73 @@ def test_type(self):
         self.assertTrue(isinstance(Open.WO | Open.RW, Open))
         self.assertEqual(Open.WO | Open.RW, 3)
 
+
+    def test_str(self):
+        Perm = self.Perm
+        self.assertEqual(str(Perm.R), 'R')
+        self.assertEqual(str(Perm.W), 'W')
+        self.assertEqual(str(Perm.X), 'X')
+        self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+        self.assertEqual(str(Perm.R | 8), '12')
+        self.assertEqual(str(Perm(0)), 'Perm(0)')
+        self.assertEqual(str(Perm(8)), '8')
+        self.assertEqual(str(~Perm.R), 'W|X')
+        self.assertEqual(str(~Perm.W), 'R|X')
+        self.assertEqual(str(~Perm.X), 'R|W')
+        self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+        self.assertEqual(str(~(Perm.R | 8)), '-13')
+        self.assertEqual(str(Perm(~0)), 'R|W|X')
+        self.assertEqual(str(Perm(~8)), '-9')
+
+        Open = self.Open
+        self.assertEqual(str(Open.RO), 'RO')
+        self.assertEqual(str(Open.WO), 'WO')
+        self.assertEqual(str(Open.AC), 'AC')
+        self.assertEqual(str(Open.RO | Open.CE), 'CE')
+        self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+        self.assertEqual(str(Open(4)), '4')
+        self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+        self.assertEqual(str(~Open.WO), 'RW|CE')
+        self.assertEqual(str(~Open.AC), 'CE')
+        self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+        self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+        self.assertEqual(str(Open(~4)), '-5')
+
+    def test_repr(self):
+        Perm = self.Perm
+        self.assertEqual(repr(Perm.R), 'Perm.R')
+        self.assertEqual(repr(Perm.W), 'Perm.W')
+        self.assertEqual(repr(Perm.X), 'Perm.X')
+        self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+        self.assertEqual(repr(Perm.R | 8), '12')
+        self.assertEqual(repr(Perm(0)), '0x0')
+        self.assertEqual(repr(Perm(8)), '8')
+        self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+        self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+        self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+        self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+        self.assertEqual(repr(~(Perm.R | 8)), '-13')
+        self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+        self.assertEqual(repr(Perm(~8)), '-9')
+
+        Open = self.Open
+        self.assertEqual(repr(Open.RO), 'Open.RO')
+        self.assertEqual(repr(Open.WO), 'Open.WO')
+        self.assertEqual(repr(Open.AC), 'Open.AC')
+        self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+        self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+        self.assertEqual(repr(Open(4)), '4')
+        self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+        self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+        self.assertEqual(repr(~Open.AC), 'Open.CE')
+        self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+        self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+        self.assertEqual(repr(Open(~4)), '-5')
+
     def test_global_repr_keep(self):
         self.assertEqual(
                 repr(HeadlightsK(0)),
@@ -3067,11 +3559,11 @@ def test_global_repr_keep(self):
                 )
         self.assertEqual(
                 repr(HeadlightsK(2**0 + 2**2 + 2**3)),
-                '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
+                '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
                 )
         self.assertEqual(
                 repr(HeadlightsK(2**3)),
-                '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
+                '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
                 )
 
     def test_global_repr_conform1(self):
@@ -3213,7 +3705,7 @@ class Bizarre(IntFlag, boundary=KEEP):
             c = 4
             d = 6
         #
-        self.assertRaisesRegex(ValueError, 'invalid value 5', Iron, 5)
+        self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
         #
         self.assertIs(Water(7), Water.ONE|Water.TWO)
         self.assertIs(Water(~9), Water.TWO)
@@ -3450,12 +3942,11 @@ class Color(AllMixin, IntFlag):
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
         self.assertEqual(Color.ALL.value, 7)
-        self.assertEqual(str(Color.BLUE), '4')
+        self.assertEqual(str(Color.BLUE), 'BLUE')
         class Color(AllMixin, StrMixin, IntFlag):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
@@ -3465,7 +3956,6 @@ class Color(StrMixin, AllMixin, IntFlag):
             RED = auto()
             GREEN = auto()
             BLUE = auto()
-            __str__ = StrMixin.__str__
         self.assertEqual(Color.RED.value, 1)
         self.assertEqual(Color.GREEN.value, 2)
         self.assertEqual(Color.BLUE.value, 4)
@@ -3510,6 +4000,19 @@ def cycle_enum():
                 'at least one thread failed while creating composite members')
         self.assertEqual(256, len(seen), 'too many composite members created')
 
+    def test_default_missing(self):
+        with self.assertRaisesRegex(
+            ValueError,
+            "'RED' is not a valid TestIntFlag.Color",
+        ) as ctx:
+            self.Color('RED')
+        self.assertIs(ctx.exception.__context__, None)
+
+        P = IntFlag('P', 'X Y')
+        with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+            P('X')
+        self.assertIs(ctx.exception.__context__, None)
+
 
 class TestEmptyAndNonLatinStrings(unittest.TestCase):
 
@@ -3726,89 +4229,6 @@ def test_is_private(self):
         for name in self.sunder_names + self.dunder_names + self.random_names:
             self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
 
-    def test_auto_number(self):
-        class Color(Enum):
-            red = auto()
-            blue = auto()
-            green = auto()
-
-        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
-        self.assertEqual(Color.red.value, 1)
-        self.assertEqual(Color.blue.value, 2)
-        self.assertEqual(Color.green.value, 3)
-
-    def test_auto_name(self):
-        class Color(Enum):
-            def _generate_next_value_(name, start, count, last):
-                return name
-            red = auto()
-            blue = auto()
-            green = auto()
-
-        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
-        self.assertEqual(Color.red.value, 'red')
-        self.assertEqual(Color.blue.value, 'blue')
-        self.assertEqual(Color.green.value, 'green')
-
-    def test_auto_name_inherit(self):
-        class AutoNameEnum(Enum):
-            def _generate_next_value_(name, start, count, last):
-                return name
-        class Color(AutoNameEnum):
-            red = auto()
-            blue = auto()
-            green = auto()
-
-        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
-        self.assertEqual(Color.red.value, 'red')
-        self.assertEqual(Color.blue.value, 'blue')
-        self.assertEqual(Color.green.value, 'green')
-
-    def test_auto_garbage(self):
-        class Color(Enum):
-            red = 'red'
-            blue = auto()
-        self.assertEqual(Color.blue.value, 1)
-
-    def test_auto_garbage_corrected(self):
-        class Color(Enum):
-            red = 'red'
-            blue = 2
-            green = auto()
-
-        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
-        self.assertEqual(Color.red.value, 'red')
-        self.assertEqual(Color.blue.value, 2)
-        self.assertEqual(Color.green.value, 3)
-
-    def test_auto_order(self):
-        with self.assertRaises(TypeError):
-            class Color(Enum):
-                red = auto()
-                green = auto()
-                blue = auto()
-                def _generate_next_value_(name, start, count, last):
-                    return name
-
-    def test_auto_order_wierd(self):
-        weird_auto = auto()
-        weird_auto.value = 'pathological case'
-        class Color(Enum):
-            red = weird_auto
-            def _generate_next_value_(name, start, count, last):
-                return name
-            blue = auto()
-        self.assertEqual(list(Color), [Color.red, Color.blue])
-        self.assertEqual(Color.red.value, 'pathological case')
-        self.assertEqual(Color.blue.value, 'blue')
-
-    def test_duplicate_auto(self):
-        class Dupes(Enum):
-            first = primero = auto()
-            second = auto()
-            third = auto()
-        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
-
 class TestEnumTypeSubclassing(unittest.TestCase):
     pass
 
@@ -3818,35 +4238,7 @@ class TestEnumTypeSubclassing(unittest.TestCase):
 class Color(enum.Enum)
  |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
  |\x20\x20
- |  A collection of name/value pairs.
- |\x20\x20
- |  Access them by:
- |\x20\x20
- |  - attribute access::
- |\x20\x20
- |  >>> Color.CYAN
- |  <Color.CYAN: 1>
- |\x20\x20
- |  - value lookup:
- |\x20\x20
- |  >>> Color(1)
- |  <Color.CYAN: 1>
- |\x20\x20
- |  - name lookup:
- |\x20\x20
- |  >>> Color['CYAN']
- |  <Color.CYAN: 1>
- |\x20\x20
- |  Enumerations can be iterated over, and know how many members they have:
- |\x20\x20
- |  >>> len(Color)
- |  3
- |\x20\x20
- |  >>> list(Color)
- |  [<Color.CYAN: 1>, <Color.MAGENTA: 2>, <Color.YELLOW: 3>]
- |\x20\x20
- |  Methods can be added to enumerations, and members can have their own
- |  attributes -- see the documentation for details.
+ |  An enumeration.
  |\x20\x20
  |  Method resolution order:
  |      Color
@@ -3855,11 +4247,11 @@ class Color(enum.Enum)
  |\x20\x20
  |  Data and other attributes defined here:
  |\x20\x20
- |  CYAN = <Color.CYAN: 1>
+ |  blue = Color.blue
  |\x20\x20
- |  MAGENTA = <Color.MAGENTA: 2>
+ |  green = Color.green
  |\x20\x20
- |  YELLOW = <Color.YELLOW: 3>
+ |  red = Color.red
  |\x20\x20
  |  ----------------------------------------------------------------------
  |  Data descriptors inherited from enum.Enum:
@@ -3871,25 +4263,6 @@ class Color(enum.Enum)
  |      The value of the Enum member.
  |\x20\x20
  |  ----------------------------------------------------------------------
- |  Methods inherited from enum.EnumType:
- |\x20\x20
- |  __contains__(member) from enum.EnumType
- |      Return True if member is a member of this enum
- |      raises TypeError if member is not an enum member
- |\x20\x20\x20\x20\x20\x20
- |      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
- |\x20\x20
- |  __getitem__(name) from enum.EnumType
- |      Return the member matching `name`.
- |\x20\x20
- |  __iter__() from enum.EnumType
- |      Return members in definition order.
- |\x20\x20
- |  __len__() from enum.EnumType
- |      Return the number of members (no aliases)
- |\x20\x20
- |  ----------------------------------------------------------------------
  |  Readonly properties inherited from enum.EnumType:
  |\x20\x20
  |  __members__
@@ -3911,11 +4284,11 @@ class Color(enum.Enum)
  |\x20\x20
  |  Data and other attributes defined here:
  |\x20\x20
- |  YELLOW = <Color.YELLOW: 3>
+ |  blue = Color.blue
  |\x20\x20
- |  MAGENTA = <Color.MAGENTA: 2>
+ |  green = Color.green
  |\x20\x20
- |  CYAN = <Color.CYAN: 1>
+ |  red = Color.red
  |\x20\x20
  |  ----------------------------------------------------------------------
  |  Data descriptors inherited from enum.Enum:
@@ -3934,9 +4307,9 @@ class TestStdLib(unittest.TestCase):
     maxDiff = None
 
     class Color(Enum):
-        CYAN = 1
-        MAGENTA = 2
-        YELLOW = 3
+        red = 1
+        green = 2
+        blue = 3
 
     def test_pydoc(self):
         # indirectly test __objclass__
@@ -3948,34 +4321,24 @@ def test_pydoc(self):
         helper = pydoc.Helper(output=output)
         helper(self.Color)
         result = output.getvalue().strip()
-        self.assertEqual(result, expected_text, result)
+        self.assertEqual(result, expected_text)
 
     def test_inspect_getmembers(self):
         values = dict((
                 ('__class__', EnumType),
-                ('__doc__', '...'),
+                ('__doc__', 'An enumeration.'),
                 ('__members__', self.Color.__members__),
                 ('__module__', __name__),
-                ('YELLOW', self.Color.YELLOW),
-                ('MAGENTA', self.Color.MAGENTA),
-                ('CYAN', self.Color.CYAN),
+                ('blue', self.Color.blue),
+                ('green', self.Color.green),
                 ('name', Enum.__dict__['name']),
+                ('red', self.Color.red),
                 ('value', Enum.__dict__['value']),
-                ('__len__', self.Color.__len__),
-                ('__contains__', self.Color.__contains__),
-                ('__name__', 'Color'),
-                ('__getitem__', self.Color.__getitem__),
-                ('__qualname__', 'TestStdLib.Color'),
-                ('__init_subclass__', getattr(self.Color, '__init_subclass__')),
-                ('__iter__', self.Color.__iter__),
                 ))
         result = dict(inspect.getmembers(self.Color))
         self.assertEqual(set(values.keys()), set(result.keys()))
         failed = False
         for k in values.keys():
-            if k == '__doc__':
-                # __doc__ is huge, not comparing
-                continue
             if result[k] != values[k]:
                 print()
                 print('\n%s\n     key: %s\n  result: %s\nexpected: %s\n%s\n' %
@@ -3990,42 +4353,23 @@ def test_inspect_classify_class_attrs(self):
         values = [
                 Attribute(name='__class__', kind='data',
                     defining_class=object, object=EnumType),
-                Attribute(name='__contains__', kind='method',
-                    defining_class=EnumType, object=self.Color.__contains__),
                 Attribute(name='__doc__', kind='data',
-                    defining_class=self.Color, object='...'),
-                Attribute(name='__getitem__', kind='method',
-                    defining_class=EnumType, object=self.Color.__getitem__),
-                Attribute(name='__iter__', kind='method',
-                    defining_class=EnumType, object=self.Color.__iter__),
-                Attribute(name='__init_subclass__', kind='class method',
-                    defining_class=object, object=getattr(self.Color, '__init_subclass__')),
-                Attribute(name='__len__', kind='method',
-                    defining_class=EnumType, object=self.Color.__len__),
+                    defining_class=self.Color, object='An enumeration.'),
                 Attribute(name='__members__', kind='property',
                     defining_class=EnumType, object=EnumType.__members__),
                 Attribute(name='__module__', kind='data',
                     defining_class=self.Color, object=__name__),
-                Attribute(name='__name__', kind='data',
-                    defining_class=self.Color, object='Color'),
-                Attribute(name='__qualname__', kind='data',
-                    defining_class=self.Color, object='TestStdLib.Color'),
-                Attribute(name='YELLOW', kind='data',
-                    defining_class=self.Color, object=self.Color.YELLOW),
-                Attribute(name='MAGENTA', kind='data',
-                    defining_class=self.Color, object=self.Color.MAGENTA),
-                Attribute(name='CYAN', kind='data',
-                    defining_class=self.Color, object=self.Color.CYAN),
+                Attribute(name='blue', kind='data',
+                    defining_class=self.Color, object=self.Color.blue),
+                Attribute(name='green', kind='data',
+                    defining_class=self.Color, object=self.Color.green),
+                Attribute(name='red', kind='data',
+                    defining_class=self.Color, object=self.Color.red),
                 Attribute(name='name', kind='data',
                     defining_class=Enum, object=Enum.__dict__['name']),
                 Attribute(name='value', kind='data',
                     defining_class=Enum, object=Enum.__dict__['value']),
                 ]
-        for v in values:
-            try:
-                v.name
-            except AttributeError:
-                print(v)
         values.sort(key=lambda item: item.name)
         result = list(inspect.classify_class_attrs(self.Color))
         result.sort(key=lambda item: item.name)
@@ -4035,15 +4379,7 @@ def test_inspect_classify_class_attrs(self):
                 )
         failed = False
         for v, r in zip(values, result):
-            if r.name in ('__init_subclass__', '__doc__'):
-                # not sure how to make the __init_subclass_ Attributes match
-                # so as long as there is one, call it good
-                # __doc__ is too big to check exactly, so treat the same as __init_subclass__
-                for name in ('name','kind','defining_class'):
-                    if getattr(v, name) != getattr(r, name):
-                        print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
-                        failed = True
-            elif r != v:
+            if r != v:
                 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
                 failed = True
         if failed:
@@ -4052,15 +4388,15 @@ def test_inspect_classify_class_attrs(self):
     def test_test_simple_enum(self):
         @_simple_enum(Enum)
         class SimpleColor:
-            CYAN = 1
-            MAGENTA = 2
-            YELLOW = 3
+            RED = 1
+            GREEN = 2
+            BLUE = 3
         class CheckedColor(Enum):
-            CYAN = 1
-            MAGENTA = 2
-            YELLOW = 3
+            RED = 1
+            GREEN = 2
+            BLUE = 3
         self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
-        SimpleColor.MAGENTA._value_ = 9
+        SimpleColor.GREEN._value_ = 9
         self.assertRaisesRegex(
                 TypeError, "enum mismatch",
                 _test_simple_enum, CheckedColor, SimpleColor,
@@ -4086,165 +4422,9 @@ class Missing:
 
 
 class MiscTestCase(unittest.TestCase):
-
     def test__all__(self):
         support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
 
-    def test_doc_1(self):
-        class Single(Enum):
-            ONE = 1
-        self.assertEqual(
-                Single.__doc__,
-                dedent("""\
-                    A collection of name/value pairs.
-
-                    Access them by:
-
-                    - attribute access::
-
-                    >>> Single.ONE
-                    <Single.ONE: 1>
-
-                    - value lookup:
-
-                    >>> Single(1)
-                    <Single.ONE: 1>
-
-                    - name lookup:
-
-                    >>> Single['ONE']
-                    <Single.ONE: 1>
-
-                    Enumerations can be iterated over, and know how many members they have:
-
-                    >>> len(Single)
-                    1
-
-                    >>> list(Single)
-                    [<Single.ONE: 1>]
-
-                    Methods can be added to enumerations, and members can have their own
-                    attributes -- see the documentation for details.
-                    """))
-
-    def test_doc_2(self):
-        class Double(Enum):
-            ONE = 1
-            TWO = 2
-        self.assertEqual(
-                Double.__doc__,
-                dedent("""\
-                    A collection of name/value pairs.
-
-                    Access them by:
-
-                    - attribute access::
-
-                    >>> Double.ONE
-                    <Double.ONE: 1>
-
-                    - value lookup:
-
-                    >>> Double(1)
-                    <Double.ONE: 1>
-
-                    - name lookup:
-
-                    >>> Double['ONE']
-                    <Double.ONE: 1>
-
-                    Enumerations can be iterated over, and know how many members they have:
-
-                    >>> len(Double)
-                    2
-
-                    >>> list(Double)
-                    [<Double.ONE: 1>, <Double.TWO: 2>]
-
-                    Methods can be added to enumerations, and members can have their own
-                    attributes -- see the documentation for details.
-                    """))
-
-
-    def test_doc_1(self):
-        class Triple(Enum):
-            ONE = 1
-            TWO = 2
-            THREE = 3
-        self.assertEqual(
-                Triple.__doc__,
-                dedent("""\
-                    A collection of name/value pairs.
-
-                    Access them by:
-
-                    - attribute access::
-
-                    >>> Triple.ONE
-                    <Triple.ONE: 1>
-
-                    - value lookup:
-
-                    >>> Triple(1)
-                    <Triple.ONE: 1>
-
-                    - name lookup:
-
-                    >>> Triple['ONE']
-                    <Triple.ONE: 1>
-
-                    Enumerations can be iterated over, and know how many members they have:
-
-                    >>> len(Triple)
-                    3
-
-                    >>> list(Triple)
-                    [<Triple.ONE: 1>, <Triple.TWO: 2>, <Triple.THREE: 3>]
-
-                    Methods can be added to enumerations, and members can have their own
-                    attributes -- see the documentation for details.
-                    """))
-
-    def test_doc_1(self):
-        class Quadruple(Enum):
-            ONE = 1
-            TWO = 2
-            THREE = 3
-            FOUR = 4
-        self.assertEqual(
-                Quadruple.__doc__,
-                dedent("""\
-                    A collection of name/value pairs.
-
-                    Access them by:
-
-                    - attribute access::
-
-                    >>> Quadruple.ONE
-                    <Quadruple.ONE: 1>
-
-                    - value lookup:
-
-                    >>> Quadruple(1)
-                    <Quadruple.ONE: 1>
-
-                    - name lookup:
-
-                    >>> Quadruple['ONE']
-                    <Quadruple.ONE: 1>
-
-                    Enumerations can be iterated over, and know how many members they have:
-
-                    >>> len(Quadruple)
-                    4
-
-                    >>> list(Quadruple)[:3]
-                    [<Quadruple.ONE: 1>, <Quadruple.TWO: 2>, <Quadruple.THREE: 3>]
-
-                    Methods can be added to enumerations, and members can have their own
-                    attributes -- see the documentation for details.
-                    """))
-
 
 # These are unordered here on purpose to ensure that declaration order
 # makes no difference.
@@ -4262,10 +4442,6 @@ class Quadruple(Enum):
 CONVERT_STRING_TEST_NAME_E = 5
 CONVERT_STRING_TEST_NAME_F = 5
 
-# global names for StrEnum._convert_ test
-CONVERT_STR_TEST_2 = 'goodbye'
-CONVERT_STR_TEST_1 = 'hello'
-
 # We also need values that cannot be compared:
 UNCOMPARABLE_A = 5
 UNCOMPARABLE_C = (9, 1)  # naming order is broken on purpose
@@ -4277,40 +4453,32 @@ class Quadruple(Enum):
 
 class _ModuleWrapper:
     """We use this class as a namespace for swapping modules."""
+
     def __init__(self, module):
         self.__dict__.update(module.__dict__)
 
-class TestConvert(unittest.TestCase):
-    def tearDown(self):
-        # Reset the module-level test variables to their original integer
-        # values, otherwise the already created enum values get converted
-        # instead.
-        g = globals()
-        for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
-            g['CONVERT_TEST_NAME_%s' % suffix] = 5
-            g['CONVERT_STRING_TEST_NAME_%s' % suffix] = 5
-        for suffix, value in (('A', 5), ('B', (9, 1)), ('C', 'value')):
-            g['UNCOMPARABLE_%s' % suffix] = value
-        for suffix, value in (('A', 2j), ('B', 3j), ('C', 1j)):
-            g['COMPLEX_%s' % suffix] = value
-        for suffix, value in (('1', 'hello'), ('2', 'goodbye')):
-            g['CONVERT_STR_TEST_%s' % suffix] = value
-
+class TestIntEnumConvert(unittest.TestCase):
     def test_convert_value_lookup_priority(self):
-        test_type = enum.IntEnum._convert_(
-                'UnittestConvert',
-                MODULE,
-                filter=lambda x: x.startswith('CONVERT_TEST_'))
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            test_type = enum.IntEnum._convert_(
+                    'UnittestConvert',
+                    MODULE,
+                    filter=lambda x: x.startswith('CONVERT_TEST_'))
         # We don't want the reverse lookup value to vary when there are
         # multiple possible names for a given value.  It should always
         # report the first lexigraphical name in that case.
         self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
 
-    def test_convert_int(self):
-        test_type = enum.IntEnum._convert_(
-                'UnittestConvert',
-                MODULE,
-                filter=lambda x: x.startswith('CONVERT_TEST_'))
+    def test_convert(self):
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            test_type = enum.IntEnum._convert_(
+                    'UnittestConvert',
+                    MODULE,
+                    filter=lambda x: x.startswith('CONVERT_TEST_'))
         # Ensure that test_type has all of the desired names and values.
         self.assertEqual(test_type.CONVERT_TEST_NAME_F,
                          test_type.CONVERT_TEST_NAME_A)
@@ -4319,57 +4487,43 @@ def test_convert_int(self):
         self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
         self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
         # Ensure that test_type only picked up names matching the filter.
-        int_dir = dir(int) + [
-                'CONVERT_TEST_NAME_A', 'CONVERT_TEST_NAME_B', 'CONVERT_TEST_NAME_C',
-                'CONVERT_TEST_NAME_D', 'CONVERT_TEST_NAME_E', 'CONVERT_TEST_NAME_F',
-                ]
-        self.assertEqual(
-                [name for name in dir(test_type) if name not in int_dir],
-                [],
-                msg='Names other than CONVERT_TEST_* found.',
-                )
+        self.assertEqual([name for name in dir(test_type)
+                          if name[0:2] not in ('CO', '__')
+                          and name not in dir(IntEnum)],
+                         [], msg='Names other than CONVERT_TEST_* found.')
 
     def test_convert_uncomparable(self):
-        uncomp = enum.Enum._convert_(
-                'Uncomparable',
-                MODULE,
-                filter=lambda x: x.startswith('UNCOMPARABLE_'))
+        # We swap a module to some other object with `__dict__`
+        # because otherwise refleak is created.
+        # `_convert_` uses a module side effect that does this. See 30472
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            uncomp = enum.Enum._convert_(
+                    'Uncomparable',
+                    MODULE,
+                    filter=lambda x: x.startswith('UNCOMPARABLE_'))
+
         # Should be ordered by `name` only:
         self.assertEqual(
             list(uncomp),
             [uncomp.UNCOMPARABLE_A, uncomp.UNCOMPARABLE_B, uncomp.UNCOMPARABLE_C],
-            )
+        )
 
     def test_convert_complex(self):
-        uncomp = enum.Enum._convert_(
-            'Uncomparable',
-            MODULE,
-            filter=lambda x: x.startswith('COMPLEX_'))
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            uncomp = enum.Enum._convert_(
+                'Uncomparable',
+                MODULE,
+                filter=lambda x: x.startswith('COMPLEX_'))
+
         # Should be ordered by `name` only:
         self.assertEqual(
             list(uncomp),
             [uncomp.COMPLEX_A, uncomp.COMPLEX_B, uncomp.COMPLEX_C],
-            )
-
-    def test_convert_str(self):
-        test_type = enum.StrEnum._convert_(
-                'UnittestConvert',
-                MODULE,
-                filter=lambda x: x.startswith('CONVERT_STR_'),
-                as_global=True)
-        # Ensure that test_type has all of the desired names and values.
-        self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
-        self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
-        # Ensure that test_type only picked up names matching the filter.
-        str_dir = dir(str) + ['CONVERT_STR_TEST_1', 'CONVERT_STR_TEST_2']
-        self.assertEqual(
-                [name for name in dir(test_type) if name not in str_dir],
-                [],
-                msg='Names other than CONVERT_STR_* found.',
-                )
-        self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
-        self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
-        self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
+        )
 
     def test_convert_raise(self):
         with self.assertRaises(AttributeError):
@@ -4379,58 +4533,50 @@ def test_convert_raise(self):
                 filter=lambda x: x.startswith('CONVERT_TEST_'))
 
     def test_convert_repr_and_str(self):
-        test_type = enum.IntEnum._convert_(
-                'UnittestConvert',
-                MODULE,
-                filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
-                as_global=True)
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            test_type = enum.IntEnum._convert_(
+                    'UnittestConvert',
+                    MODULE,
+                    filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
         self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
-        self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5')
+        self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
         self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
 
+# global names for StrEnum._convert_ test
+CONVERT_STR_TEST_2 = 'goodbye'
+CONVERT_STR_TEST_1 = 'hello'
 
-# helpers
-
-def enum_dir(cls):
-    # TODO: check for custom __init__, __new__, __format__, __repr__, __str__, __init_subclass__
-    if cls._member_type_ is object:
-        interesting = set()
-        if cls.__init_subclass__ is not object.__init_subclass__:
-            interesting.add('__init_subclass__')
-        return sorted(set([
-                '__class__', '__contains__', '__doc__', '__getitem__',
-                '__iter__', '__len__', '__members__', '__module__',
-                '__name__', '__qualname__',
-                ]
-                + cls._member_names_
-                ) | interesting
-                )
-    else:
-        # return whatever mixed-in data type has
-        return sorted(set(
-                dir(cls._member_type_)
-                + cls._member_names_
-                ))
-
-def member_dir(member):
-    if member.__class__._member_type_ is object:
-        allowed = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value'])
-    else:
-        allowed = set(dir(member))
-    for cls in member.__class__.mro():
-        for name, obj in cls.__dict__.items():
-            if name[0] == '_':
-                continue
-            if isinstance(obj, enum.property):
-                if obj.fget is not None or name not in member._member_map_:
-                    allowed.add(name)
-                else:
-                    allowed.discard(name)
-            else:
-                allowed.add(name)
-    return sorted(allowed)
+class TestStrEnumConvert(unittest.TestCase):
+    def test_convert(self):
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            test_type = enum.StrEnum._convert_(
+                    'UnittestConvert',
+                    MODULE,
+                    filter=lambda x: x.startswith('CONVERT_STR_'))
+        # Ensure that test_type has all of the desired names and values.
+        self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
+        self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
+        # Ensure that test_type only picked up names matching the filter.
+        self.assertEqual([name for name in dir(test_type)
+                          if name[0:2] not in ('CO', '__')
+                          and name not in dir(StrEnum)],
+                         [], msg='Names other than CONVERT_STR_* found.')
 
-missing = object()
+    def test_convert_repr_and_str(self):
+        with support.swap_item(
+                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+            ):
+            test_type = enum.StrEnum._convert_(
+                    'UnittestConvert',
+                    MODULE,
+                    filter=lambda x: x.startswith('CONVERT_STR_'))
+        self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
+        self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
+        self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
 
 
 if __name__ == '__main__':
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index ac4626d0c456e..3f0e7270eb26f 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -908,7 +908,7 @@ def handler(signum, frame):
 
         %s
 
-        blocked = %s
+        blocked = %r
         signum = signal.SIGALRM
 
         # child: block and wait the signal
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 56cc23dbbbf4e..394d2942483fb 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -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)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 64f4bce7f7781..f99a3e8da95f8 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -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)
                 )
 
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 8e4e64808b688..d5e2c5266aae7 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -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},
diff --git a/Misc/NEWS.d/next/Library/2022-01-13-11-41-24.bpo-40066.1QuVli.rst b/Misc/NEWS.d/next/Library/2022-01-13-11-41-24.bpo-40066.1QuVli.rst
deleted file mode 100644
index 2df487855785e..0000000000000
--- a/Misc/NEWS.d/next/Library/2022-01-13-11-41-24.bpo-40066.1QuVli.rst
+++ /dev/null
@@ -1,2 +0,0 @@
-``IntEnum``, ``IntFlag``, and ``StrEnum`` use the mixed-in type for their
-``str()`` and ``format()`` output.



More information about the Python-checkins mailing list