[Python-checkins] bpo-40066: [Enum] skip failing doc test (GH-30637)

ethanfurman webhook-mailer at python.org
Mon Jan 17 10:18:35 EST 2022


https://github.com/python/cpython/commit/83d544b9292870eb44f6fca37df0aa351c4ef83a
commit: 83d544b9292870eb44f6fca37df0aa351c4ef83a
branch: main
author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com>
committer: ethanfurman <ethan at stoneleaf.us>
date: 2022-01-17T07:18:13-08:00
summary:

bpo-40066: [Enum] skip failing doc test (GH-30637)

files:
A 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 6c09b9925c1de..fa0e2283ebc10 100644
--- a/Doc/howto/enum.rst
+++ b/Doc/howto/enum.rst
@@ -2,15 +2,10 @@
 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.
@@ -28,6 +23,14 @@ 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.
 
@@ -41,13 +44,14 @@ important, but either way that value can be used to get the corresponding
 member::
 
     >>> Weekday(3)
-    Weekday.WEDNESDAY
+    <Weekday.WEDNESDAY: 3>
 
-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::
+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::
 
     >>> print(Weekday.THURSDAY)
-    THURSDAY
+    Weekday.THURSDAY
 
 The *type* of an enumeration member is the enum it belongs to::
 
@@ -97,8 +101,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())
-    Weekday.TUESDAY
+    >>> Weekday.from_date(date.today())     # doctest: +SKIP
+    <Weekday.TUESDAY: 2>
 
 Of course, if you're reading this on some other day, you'll see that day instead.
 
@@ -124,21 +128,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
+    <Weekday.MONDAY: 1>
 
 But :class:`Flag` also allows us to combine several members into a single
 variable::
 
     >>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
     >>> weekend
-    Weekday.SATURDAY|Weekday.SUNDAY
+    <Weekday.SATURDAY|SUNDAY: 96>
 
 You can even iterate over a :class:`Flag` variable::
 
     >>> for day in weekend:
     ...     print(day)
-    SATURDAY
-    SUNDAY
+    Weekday.SATURDAY
+    Weekday.SUNDAY
 
 Okay, let's get some chores set up::
 
@@ -173,6 +177,7 @@ yourself some work and use :func:`auto()` for the values::
 
 .. _enum-advanced-tutorial:
 
+
 Programmatic access to enumeration members and their attributes
 ---------------------------------------------------------------
 
@@ -181,16 +186,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
+    <Color.RED: 1>
     >>> Color(3)
-    Color.BLUE
+    <Color.BLUE: 3>
 
 If you want to access enum members by *name*, use item access::
 
     >>> Color['RED']
-    Color.RED
+    <Color.RED: 1>
     >>> Color['GREEN']
-    Color.GREEN
+    <Color.GREEN: 2>
 
 If you have an enum member and need its :attr:`name` or :attr:`value`::
 
@@ -212,7 +217,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``
@@ -227,11 +232,11 @@ By-name lookup of ``B`` will also return the member ``A``::
     ...     ALIAS_FOR_SQUARE = 2
     ...
     >>> Shape.SQUARE
-    Shape.SQUARE
+    <Shape.SQUARE: 2>
     >>> Shape.ALIAS_FOR_SQUARE
-    Shape.SQUARE
+    <Shape.SQUARE: 2>
     >>> Shape(2)
-    Shape.SQUARE
+    <Shape.SQUARE: 2>
 
 .. note::
 
@@ -299,7 +304,7 @@ Iteration
 Iterating over the members of an enum does not provide the aliases::
 
     >>> list(Shape)
-    [Shape.SQUARE, Shape.DIAMOND, Shape.CIRCLE]
+    [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
 
 The special attribute ``__members__`` is a read-only ordered mapping of names
 to members.  It includes all names defined in the enumeration, including the
@@ -308,10 +313,10 @@ aliases::
     >>> for name, member in Shape.__members__.items():
     ...     name, member
     ...
-    ('SQUARE', Shape.SQUARE)
-    ('DIAMOND', Shape.DIAMOND)
-    ('CIRCLE', Shape.CIRCLE)
-    ('ALIAS_FOR_SQUARE', Shape.SQUARE)
+    ('SQUARE', <Shape.SQUARE: 2>)
+    ('DIAMOND', <Shape.DIAMOND: 1>)
+    ('CIRCLE', <Shape.CIRCLE: 3>)
+    ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
 
 The ``__members__`` attribute can be used for detailed programmatic access to
 the enumeration members.  For example, finding all the aliases::
@@ -360,8 +365,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.
@@ -389,7 +394,7 @@ usual.  If we have this enumeration::
 Then::
 
     >>> Mood.favorite_mood()
-    Mood.HAPPY
+    <Mood.HAPPY: 3>
     >>> Mood.HAPPY.describe()
     ('HAPPY', 3)
     >>> str(Mood.FUNKY)
@@ -425,7 +430,7 @@ any members.  So this is forbidden::
     ...
     Traceback (most recent call last):
     ...
-    TypeError: MoreColor: cannot extend enumeration 'Color'
+    TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
 
 But this is allowed::
 
@@ -476,11 +481,9 @@ The :class:`Enum` class is callable, providing the following functional API::
     >>> Animal
     <enum 'Animal'>
     >>> Animal.ANT
-    Animal.ANT
-    >>> Animal.ANT.value
-    1
+    <Animal.ANT: 1>
     >>> list(Animal)
-    [Animal.ANT, Animal.BEE, Animal.CAT, Animal.DOG]
+    [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
 
 The semantics of this API resemble :class:`~collections.namedtuple`. The first
 argument of the call to :class:`Enum` is the name of the enumeration.
@@ -625,16 +628,7 @@ 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.  :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',)``.
+to each other.
 
 .. versionadded:: 3.11
 
@@ -645,9 +639,8 @@ 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.  However, as the name implies, :class:`IntFlag`
-members also subclass :class:`int` and can be used wherever an :class:`int` is
-used.
+:class:`IntFlag` member, if possible.  Like :class:`IntEnum`, :class:`IntFlag`
+members are also integers and can be used wherever an :class:`int` is used.
 
 .. note::
 
@@ -670,7 +663,7 @@ Sample :class:`IntFlag` class::
     ...     X = 1
     ...
     >>> Perm.R | Perm.W
-    Perm.R|Perm.W
+    <Perm.R|W: 6>
     >>> Perm.R + Perm.W
     6
     >>> RW = Perm.R | Perm.W
@@ -685,11 +678,11 @@ It is also possible to name the combinations::
     ...     X = 1
     ...     RWX = 7
     >>> Perm.RWX
-    Perm.RWX
+    <Perm.RWX: 7>
     >>> ~Perm.RWX
-    Perm(0)
+    <Perm: 0>
     >>> Perm(7)
-    Perm.RWX
+    <Perm.RWX: 7>
 
 .. note::
 
@@ -702,7 +695,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
 
@@ -710,7 +703,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|Perm.X
+    <Perm.R|X: 5>
 
     >>> Perm.X | 8
     9
@@ -726,7 +719,7 @@ be combined with them (but may lose :class:`IntFlag` membership::
 :class:`IntFlag` members can also be iterated over::
 
     >>> list(RW)
-    [Perm.R, Perm.W]
+    [<Perm.R: 4>, <Perm.W: 2>]
 
 .. versionadded:: 3.11
 
@@ -753,7 +746,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
 
@@ -767,7 +760,7 @@ while combinations of flags won't::
     ...     WHITE = RED | BLUE | GREEN
     ...
     >>> Color.WHITE
-    Color.WHITE
+    <Color.WHITE: 7>
 
 Giving a name to the "no flags set" condition does not change its boolean
 value::
@@ -779,7 +772,7 @@ value::
     ...     GREEN = auto()
     ...
     >>> Color.BLACK
-    Color.BLACK
+    <Color.BLACK: 0>
     >>> bool(Color.BLACK)
     False
 
@@ -787,7 +780,7 @@ value::
 
     >>> purple = Color.RED | Color.BLUE
     >>> list(purple)
-    [Color.RED, Color.BLUE]
+    [<Color.RED: 1>, <Color.BLUE: 2>]
 
 .. versionadded:: 3.11
 
@@ -812,16 +805,16 @@ simple to implement independently::
         pass
 
 This demonstrates how similar derived enumerations can be defined; for example
-a :class:`StrEnum` that mixes in :class:`str` instead of :class:`int`.
+a :class:`FloatEnum` that mixes in :class:`float` 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
@@ -829,15 +822,18 @@ 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 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.
+   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.
 
 When to use :meth:`__new__` vs. :meth:`__init__`
 ------------------------------------------------
@@ -866,10 +862,10 @@ want one of them to be the value::
     ...
 
     >>> print(Coordinate['PY'])
-    PY
+    Coordinate.PY
 
     >>> print(Coordinate(3))
-    VY
+    Coordinate.VY
 
 
 Finer Points
@@ -927,8 +923,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::
 
@@ -949,35 +945,36 @@ 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.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`::
+``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::
 
     >>> class FieldTypes(Enum):
     ...     name = 0
     ...     value = 1
     ...     size = 2
     ...
-    >>> FieldTypes.value.size       # doctest: +SKIP
-    DeprecationWarning: accessing one member from another is not supported,
-      and will be disabled in 3.12
-    <FieldTypes.size: 2>
+    >>> FieldTypes.value.size
+    Traceback (most recent call last):
+    ...
+    AttributeError: <enum 'FieldTypes'> member has no attribute 'size'
+
 
 .. 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):
-    ...     example = '11', 16      # '11' will be interpreted as a hexadecimal
-    ...                             # number
-    >>> MyEnum.example.value
+    >>> 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...
     17
 
 
@@ -1000,13 +997,12 @@ 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 and the
-class. Attributes defined in an :func:`__init__` method will only show up in a
-:func:`dir` of the member::
+class below, those methods will show up in a :func:`dir` of the member,
+but not of the class::
 
-    >>> dir(Planet)
-    ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__init__', '__members__', '__module__', 'surface_gravity']
-    >>> dir(Planet.EARTH)
+    >>> dir(Planet)                         # doctest: +SKIP
+    ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
+    >>> dir(Planet.EARTH)                   # doctest: +SKIP
     ['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
 
 
@@ -1025,19 +1021,10 @@ are comprised of a single bit::
     ...     CYAN = GREEN | BLUE
     ...
     >>> Color(3)  # named combination
-    Color.YELLOW
+    <Color.YELLOW: 3>
     >>> Color(7)      # not named combination
-    Color.RED|Color.GREEN|Color.BLUE
+    <Color.RED|GREEN|BLUE: 7>
 
-``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
 """"""""""""""""""""""""""""""""
@@ -1060,16 +1047,16 @@ the following are true:
 - only canonical flags are returned during iteration::
 
     >>> list(Color.WHITE)
-    [Color.RED, Color.GREEN, Color.BLUE]
+    [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
 
 - negating a flag or flag set returns a new flag/flag set with the
   corresponding positive integer value::
 
     >>> Color.BLUE
-    Color.BLUE
+    <Color.BLUE: 4>
 
     >>> ~Color.BLUE
-    Color.RED|Color.GREEN
+    <Color.RED|GREEN: 3>
 
 - names of pseudo-flags are constructed from their members' names::
 
@@ -1079,25 +1066,29 @@ the following are true:
 - multi-bit flags, aka aliases, can be returned from operations::
 
     >>> Color.RED | Color.BLUE
-    Color.PURPLE
+    <Color.PURPLE: 5>
 
     >>> Color(7)  # or Color(-1)
-    Color.WHITE
+    <Color.WHITE: 7>
 
     >>> Color(0)
-    Color.BLACK
+    <Color.BLACK: 0>
 
-- membership / containment checking has changed slightly -- zero-valued flags
-  are never considered to be contained::
+- membership / containment checking: zero-valued flags are always considered
+  to be contained::
 
     >>> Color.BLACK in Color.WHITE
-    False
+    True
 
-  otherwise, if all bits of one flag are in the other flag, True is returned::
+  otherwise, only if all bits of one flag are in the other flag will True
+  be 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``:
 
@@ -1181,7 +1172,7 @@ Using :class:`auto` would look like::
     ...     GREEN = auto()
     ...
     >>> Color.GREEN
-    <Color.GREEN>
+    <Color.GREEN: 3>
 
 
 Using :class:`object`
@@ -1194,10 +1185,24 @@ 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
 """"""""""""""""""""""""""
 
@@ -1209,9 +1214,7 @@ Using a string as the value would look like::
     ...     BLUE = 'too fast!'
     ...
     >>> Color.GREEN
-    <Color.GREEN>
-    >>> Color.GREEN.value
-    'go'
+    <Color.GREEN: 'go'>
 
 
 Using a custom :meth:`__new__`
@@ -1232,9 +1235,7 @@ Using an auto-numbering :meth:`__new__` would look like::
     ...     BLUE = ()
     ...
     >>> Color.GREEN
-    <Color.GREEN>
-    >>> Color.GREEN.value
-    2
+    <Color.GREEN: 2>
 
 To make a more general purpose ``AutoNumber``, add ``*args`` to the signature::
 
@@ -1257,7 +1258,7 @@ to handle any extra arguments::
     ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
     ...
     >>> Swatch.SEA_GREEN
-    <Swatch.SEA_GREEN>
+    <Swatch.SEA_GREEN: 2>
     >>> Swatch.SEA_GREEN.pantone
     '1246'
     >>> Swatch.BLEACHED_CORAL.pantone
@@ -1384,30 +1385,9 @@ An example to show the :attr:`_ignore_` attribute in use::
     ...         Period['day_%d' % i] = i
     ...
     >>> list(Period)[:2]
-    [Period.day_0, Period.day_1]
+    [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
     >>> list(Period)[-2:]
-    [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
+    [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
 
 
 .. _enumtype-examples:
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
index 8bb19dcdf2b61..a37c9d4506241 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 the :keyword:`class` syntax, or by
+Enumerations are created either by using :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 the :keyword:`class` syntax to create Enums, Enums
+Even though we can use :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 *enum members*) and are functionally constants.
+     *enumeration members* (or *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,15 +110,10 @@ 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:`global_enum`
-
-      :class:`Enum` class decorator to apply the appropriate global `__repr__`,
-      and export its members into the global name space.
-
-   :func:`.property`
+   :func:`property`
 
       Allows :class:`Enum` members to have attributes without conflicting with
-      other members' names.
+      member names.
 
    :func:`unique`
 
@@ -131,7 +126,7 @@ Module Contents
 
 
 .. versionadded:: 3.6  ``Flag``, ``IntFlag``, ``auto``
-.. versionadded:: 3.11  ``StrEnum``, ``EnumCheck``, ``FlagBoundary``
+.. versionadded:: 3.11  ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property``
 
 ---------------
 
@@ -145,6 +140,11 @@ 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,32 +162,31 @@ Data Types
    .. method:: EnumType.__dir__(cls)
 
       Returns ``['__class__', '__doc__', '__members__', '__module__']`` and the
-      names of the members in ``cls``. User-defined methods and methods from
-      mixin classes will also be included::
+      names of the members in *cls*::
 
         >>> dir(Color)
-        ['BLUE', 'GREEN', 'RED', '__class__', '__doc__', '__members__', '__module__']
+        ['BLUE', 'GREEN', 'RED', '__class__', '__contains__', '__doc__', '__getitem__', '__init_subclass__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__']
 
    .. method:: EnumType.__getattr__(cls, name)
 
       Returns the Enum member in *cls* matching *name*, or raises an :exc:`AttributeError`::
 
         >>> Color.GREEN
-        Color.GREEN
+        <Color.GREEN: 2>
 
    .. method:: EnumType.__getitem__(cls, name)
 
-      Returns the Enum member in *cls* matching *name*, or raises a :exc:`KeyError`::
+      Returns the Enum member in *cls* matching *name*, or raises an :exc:`KeyError`::
 
         >>> Color['BLUE']
-        Color.BLUE
+        <Color.BLUE: 3>
 
    .. method:: EnumType.__iter__(cls)
 
       Returns each member in *cls* in definition order::
 
         >>> list(Color)
-        [Color.RED, Color.GREEN, Color.BLUE]
+        [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
 
    .. method:: EnumType.__len__(cls)
 
@@ -201,7 +200,7 @@ Data Types
       Returns each member in *cls* in reverse definition order::
 
         >>> list(reversed(Color))
-        [Color.BLUE, Color.GREEN, Color.RED]
+        [<Color.BLUE: 3>, <Color.GREEN: 2>, <Color.RED: 1>]
 
 
 .. class:: Enum
@@ -232,7 +231,7 @@ Data Types
    .. attribute:: Enum._ignore_
 
       ``_ignore_`` is only used during creation and is removed from the
-      enumeration once that is complete.
+      enumeration once creation 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
@@ -261,7 +260,7 @@ Data Types
    .. method:: Enum.__dir__(self)
 
       Returns ``['__class__', '__doc__', '__module__', 'name', 'value']`` and
-      any public methods defined on ``self.__class__`` or a mixin class::
+      any public methods defined on *self.__class__*::
 
          >>> from datetime import date
          >>> class Weekday(Enum):
@@ -276,7 +275,7 @@ Data Types
          ...     def today(cls):
          ...         print('today is %s' % cls(date.today().isoweekday()).name)
          >>> dir(Weekday.SATURDAY)
-         ['__class__', '__doc__', '__module__', 'name', 'today', 'value']
+         ['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'today', 'value']
 
    .. method:: Enum._generate_next_value_(name, start, count, last_values)
 
@@ -298,6 +297,11 @@ 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
@@ -317,42 +321,55 @@ Data Types
          >>> Build.DEBUG.value
          'debug'
          >>> Build('deBUG')
-         Build.DEBUG
+         <Build.DEBUG: 'debug'>
 
    .. method:: Enum.__repr__(self)
 
       Returns the string used for *repr()* calls.  By default, returns the
-      *Enum* name and the member name, but can be overridden::
+      *Enum* name, member name, and value, but can be overridden::
 
-         >>> class OldStyle(Enum):
-         ...     RETRO = auto()
-         ...     OLD_SCHOOl = auto()
-         ...     YESTERYEAR = auto()
+         >>> class OtherStyle(Enum):
+         ...     ALTERNATE = auto()
+         ...     OTHER = auto()
+         ...     SOMETHING_ELSE = auto()
          ...     def __repr__(self):
          ...         cls_name = self.__class__.__name__
-         ...         return f'<{cls_name}.{self.name}: {self.value}>'
-         >>> OldStyle.RETRO
-         <OldStyle.RETRO: 1>
+         ...         return f'{cls_name}.{self.name}'
+         >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}"
+         (OtherStyle.ALTERNATE, 'OtherStyle.ALTERNATE', 'OtherStyle.ALTERNATE')
 
    .. method:: Enum.__str__(self)
 
       Returns the string used for *str()* calls.  By default, returns the
-      member name, but can be overridden::
+      *Enum* name and member name, but can be overridden::
 
-         >>> class OldStyle(Enum):
-         ...     RETRO = auto()
-         ...     OLD_SCHOOl = auto()
-         ...     YESTERYEAR = auto()
+         >>> class OtherStyle(Enum):
+         ...     ALTERNATE = auto()
+         ...     OTHER = auto()
+         ...     SOMETHING_ELSE = auto()
          ...     def __str__(self):
-         ...         cls_name = self.__class__.__name__
-         ...         return f'{cls_name}.{self.name}'
-         >>> OldStyle.RETRO
-         OldStyle.RETRO
+         ...         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')
 
-.. 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
@@ -367,7 +384,7 @@ Data Types
       ...     TWO = 2
       ...     THREE = 3
       >>> Numbers.THREE
-      Numbers.THREE
+      <Numbers.THREE: 3>
       >>> Numbers.ONE + Numbers.TWO
       3
       >>> Numbers.THREE + 5
@@ -375,10 +392,14 @@ Data Types
       >>> Numbers.THREE == 3
       True
 
-.. note::
+   .. note::
 
-   Using :class:`auto` with :class:`IntEnum` results in integers of increasing value,
-   starting with ``1``.
+      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.
 
 
 .. class:: StrEnum
@@ -392,13 +413,16 @@ Data Types
              instead of ``isinstance(str, unknown)``), and in those locations you
              will need to use ``str(StrEnum.member)``.
 
+   .. note::
 
-.. note::
+      Using :class:`auto` with :class:`StrEnum` results in the lower-cased member
+      name as the value.
 
-   Using :class:`auto` with :class:`StrEnum` results in values of the member name,
-   lower-cased.
+   .. 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.
 
-.. versionadded:: 3.11
+   .. versionadded:: 3.11
 
 .. class:: Flag
 
@@ -431,9 +455,9 @@ Data Types
       Returns all contained members::
 
          >>> list(Color.RED)
-         [Color.RED]
+         [<Color.RED: 1>]
          >>> list(purple)
-         [Color.RED, Color.BLUE]
+         [<Color.RED: 1>, <Color.BLUE: 4>]
 
    .. method:: __len__(self):
 
@@ -461,42 +485,52 @@ Data Types
       Returns current flag binary or'ed with other::
 
          >>> Color.RED | Color.GREEN
-         Color.RED|Color.GREEN
+         <Color.RED|GREEN: 3>
 
    .. method:: __and__(self, other)
 
       Returns current flag binary and'ed with other::
 
          >>> purple & white
-         Color.RED|Color.BLUE
+         <Color.RED|BLUE: 5>
          >>> purple & Color.GREEN
-         0x0
+         <Color: 0>
 
    .. method:: __xor__(self, other)
 
       Returns current flag binary xor'ed with other::
 
          >>> purple ^ white
-         Color.GREEN
+         <Color.GREEN: 2>
          >>> purple ^ Color.GREEN
-         Color.RED|Color.GREEN|Color.BLUE
+         <Color.RED|GREEN|BLUE: 7>
 
    .. method:: __invert__(self):
 
       Returns all the flags in *type(self)* that are not in self::
 
          >>> ~white
-         0x0
+         <Color: 0>
          >>> ~purple
-         Color.GREEN
+         <Color.GREEN: 2>
          >>> ~Color.RED
-         Color.GREEN|Color.BLUE
+         <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::
 
-.. note::
+      Using :class:`auto` with :class:`Flag` results in integers that are powers
+      of two, starting with ``1``.
 
-   Using :class:`auto` with :class:`Flag` results in integers that are powers
-   of two, starting with ``1``.
+   .. versionchanged:: 3.11  The *repr()* of zero-valued flags has changed.  It
+      is now::
 
+          >>> Color(0) # doctest: +SKIP
+          <Color: 0>
 
 .. class:: IntFlag
 
@@ -509,9 +543,9 @@ Data Types
       ...     GREEN = auto()
       ...     BLUE = auto()
       >>> Color.RED & 2
-      0x0
+      <Color: 0>
       >>> Color.RED | 2
-      Color.RED|Color.GREEN
+      <Color.RED|GREEN: 3>
 
    If any integer operation is performed with an *IntFlag* member, the result is
    not an *IntFlag*::
@@ -524,15 +558,25 @@ 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
 
-.. note::
+   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.
 
-   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:`TypeError`.
+   various constraints; failed constraints result in a :exc:`ValueError`.
 
    .. attribute:: UNIQUE
 
@@ -582,11 +626,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
 
@@ -606,7 +650,7 @@ Data Types
          >>> StrictFlag(2**2 + 2**4)
          Traceback (most recent call last):
          ...
-         ValueError: StrictFlag: invalid value: 20
+         ValueError: <flag 'StrictFlag'> invalid value 20
              given 0b0 10100
            allowed 0b0 00111
 
@@ -621,7 +665,7 @@ Data Types
          ...     GREEN = auto()
          ...     BLUE = auto()
          >>> ConformFlag(2**2 + 2**4)
-         ConformFlag.BLUE
+         <ConformFlag.BLUE: 4>
 
    .. attribute:: EJECT
 
@@ -647,12 +691,52 @@ Data Types
          ...     GREEN = auto()
          ...     BLUE = auto()
          >>> KeepFlag(2**2 + 2**4)
-         KeepFlag.BLUE|0x10
+         <KeepFlag.BLUE|16: 20>
 
 .. 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
 ------------------------
 
@@ -668,15 +752,6 @@ 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
@@ -688,7 +763,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
 
@@ -714,7 +789,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
 
 ---------------
 
@@ -726,14 +801,20 @@ 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:
 
-    - ``format()`` will use the value of the enum member, unless ``__str__``
-      has been overridden
+    - ``__str__`` uses the value and not the name of the enum member
 
-    - ``StrEnum.__str__`` uses the value and not the name of the enum member
+    - ``__format__``, because it uses ``__str__``, will also use the value of
+      the enum member instead of its name
 
-    If you do not need/want those limitations, you can create your own base
-    class by mixing in the ``int`` or ``str`` type yourself::
+    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::
 
         >>> 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 eb33d7e1778a7..4d8488a4a28de 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
-         ssl.VERIFY_X509_TRUSTED_FIRST
+         <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
 
 .. 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
-         ssl.CERT_REQUIRED
+         <VerifyMode.CERT_REQUIRED: 2>
 
 .. index:: single: certificates
 
diff --git a/Lib/enum.py b/Lib/enum.py
index 93ea1bea36db7..772e1eac0e1e6 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',
+        'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag', 'ReprEnum',
         'auto', 'unique', 'property', 'verify',
         'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
-        'global_flag_repr', 'global_enum_repr', 'global_enum',
+        'global_flag_repr', 'global_enum_repr', 'global_str', '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 = None
+Enum = Flag = EJECT = _stdlib_enums = ReprEnum = None
 
 def _is_descriptor(obj):
     """
@@ -116,9 +116,9 @@ def bin(num, max_bits=None):
 
     ceiling = 2 ** (num).bit_length()
     if num >= 0:
-        s = _bltin_bin(num + ceiling).replace('1', '0', 1)
+        s = bltns.bin(num + ceiling).replace('1', '0', 1)
     else:
-        s = _bltin_bin(~num ^ (ceiling - 1) + ceiling)
+        s = bltns.bin(~num ^ (ceiling - 1) + ceiling)
     sign = s[:3]
     digits = s[3:]
     if max_bits is not None:
@@ -126,6 +126,19 @@ 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:
@@ -149,22 +162,12 @@ def __get__(self, instance, ownerclass=None):
                 return ownerclass._member_map_[self.name]
             except KeyError:
                 raise AttributeError(
-                        '%s: no class attribute %r' % (ownerclass.__name__, self.name)
+                        '%r has no attribute %r' % (ownerclass, 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(
-                        '%s: no instance attribute %r' % (ownerclass.__name__, self.name)
+                        '%r member has no attribute %r' % (ownerclass, self.name)
                         )
             else:
                 return self.fget(instance)
@@ -172,7 +175,7 @@ def __get__(self, instance, ownerclass=None):
     def __set__(self, instance, value):
         if self.fset is None:
             raise AttributeError(
-                    "%s: cannot set instance attribute %r" % (self.clsname, self.name)
+                    "<enum %r> cannot set attribute %r" % (self.clsname, self.name)
                     )
         else:
             return self.fset(instance, value)
@@ -180,7 +183,7 @@ def __set__(self, instance, value):
     def __delete__(self, instance):
         if self.fdel is None:
             raise AttributeError(
-                    "%s: cannot delete instance attribute %r" % (self.clsname, self.name)
+                    "<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
                     )
         else:
             return self.fdel(instance)
@@ -328,7 +331,7 @@ def __setitem__(self, key, value):
         elif _is_sunder(key):
             if key not in (
                     '_order_',
-                    '_generate_next_value_', '_missing_', '_ignore_',
+                    '_generate_next_value_', '_numeric_repr_', '_missing_', '_ignore_',
                     '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_',
                     ):
                 raise ValueError(
@@ -358,13 +361,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(
@@ -395,7 +398,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
@@ -413,9 +416,10 @@ 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:
@@ -427,8 +431,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: {0}'.format(
-                ','.join(invalid_names)))
+            raise ValueError('invalid enum member name(s) '.format(
+                ','.join(repr(n) for n in invalid_names)))
         #
         # adjust the sunders
         _order_ = classdict.pop('_order_', None)
@@ -458,6 +462,8 @@ 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_'] = (
@@ -467,10 +473,6 @@ 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)
@@ -481,18 +483,140 @@ 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 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)
+            if name not in classdict:
+                setattr(enum_class, name, getattr(first_enum, name))
         #
         # replace any other __new__ with our own (as long as Enum is not None,
         # anyway) -- again, this is to support pickle
@@ -563,13 +687,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__(self):
+    def __bool__(cls):
         """
         classes/types should always be True.
         """
@@ -614,6 +738,13 @@ 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(
@@ -631,60 +762,33 @@ def __delattr__(cls, attr):
         # nicer error message when someone tries to delete an attribute
         # (see issue19025).
         if attr in cls._member_map_:
-            raise AttributeError("%s: cannot delete Enum member %r." % (cls.__name__, attr))
+            raise AttributeError("%r cannot delete member %r." % (cls.__name__, attr))
         super().__delattr__(attr)
 
-    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 __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 __getattr__(cls, name):
         """
@@ -703,18 +807,24 @@ 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):
         """
-        Returns members in definition order.
+        Return 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_)
 
-    @_bltin_property
+    @bltns.property
     def __members__(cls):
         """
         Returns a mapping of member name->value.
@@ -732,7 +842,7 @@ def __repr__(cls):
 
     def __reversed__(cls):
         """
-        Returns members in reverse definition order.
+        Return members in reverse definition order.
         """
         return (cls._member_map_[name] for name in reversed(cls._member_names_))
 
@@ -746,7 +856,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):
@@ -801,8 +911,7 @@ 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):
-
+    def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_global=False):
         """
         Create a new Enum subclass that replaces a collection of global constants
         """
@@ -834,22 +943,25 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None):
         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
-        global_enum(cls)
+        if as_global:
+            global_enum(cls)
+        else:
+            sys.modules[cls.__module__].__dict__.update(cls.__members__)
         module_globals[name] = cls
         return cls
 
-    @staticmethod
-    def _check_for_existing_members(class_name, bases):
+    @classmethod
+    def _check_for_existing_members_(mcls, class_name, bases):
         for chain in bases:
             for base in chain.__mro__:
                 if issubclass(base, Enum) and base._member_names_:
                     raise TypeError(
-                            "%s: cannot extend enumeration %r"
-                            % (class_name, base.__name__)
+                            "<enum %r> cannot extend %r"
+                            % (class_name, base)
                             )
 
     @classmethod
-    def _get_mixins_(cls, class_name, bases):
+    def _get_mixins_(mcls, class_name, bases):
         """
         Returns the type for creating enum members, and the first inherited
         enum class.
@@ -859,30 +971,7 @@ def _get_mixins_(cls, class_name, bases):
         if not bases:
             return object, Enum
 
-        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
+        mcls._check_for_existing_members_(class_name, bases)
 
         # ensure final parent class is an Enum derivative, find any concrete
         # data type, and check that Enum has no members
@@ -890,12 +979,51 @@ def _find_data_type(bases):
         if not issubclass(first_enum, Enum):
             raise TypeError("new enumerations should be created as "
                     "`EnumName([mixin_type, ...] [data_type,] enum_type)`")
-        cls._check_for_existing_members(class_name, bases)
-        member_type = _find_data_type(bases) or object
+        member_type = mcls._find_data_type_(class_name, bases) or object
         return member_type, first_enum
 
-    @staticmethod
-    def _find_new_(classdict, 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):
         """
         Returns the __new__ to be used for creating the enum members.
 
@@ -943,9 +1071,42 @@ def _find_new_(classdict, member_type, first_enum):
 
 class Enum(metaclass=EnumType):
     """
-    Generic enumeration.
+    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>
 
-    Derive from this class to define new enumerations.
+    - 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.
     """
 
     def __new__(cls, value):
@@ -999,6 +1160,9 @@ 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.
@@ -1021,47 +1185,44 @@ def _missing_(cls, value):
         return None
 
     def __repr__(self):
-        return "%s.%s" % ( self.__class__.__name__, self._name_)
+        v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__
+        return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_))
 
     def __str__(self):
-        return "%s" % (self._name_, )
+        return "%s.%s" % (self.__class__.__name__, self._name_, )
 
     def __dir__(self):
         """
         Returns all members and all public methods
         """
-        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)
+        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
 
     def __format__(self, format_spec):
-        """
-        Returns format using actual value type unless __str__ has been overridden.
-        """
-        # mixed-in Enums should use the mixed-in type's __format__, otherwise
-        # we can get strange results with the Enum name showing up instead of
-        # the value
-        #
-        # 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)
+        return str.__format__(str(self), format_spec)
 
     def __hash__(self):
         return hash(self._name_)
@@ -1088,34 +1249,25 @@ def value(self):
         return self._value_
 
 
-class IntEnum(int, Enum):
+class ReprEnum(Enum):
     """
-    Enum where members are also (and must be) ints
+    Only changes the repr(), leaving str() and format() to the mixed-in type.
     """
 
-    def __str__(self):
-        return "%s" % (self._name_, )
 
-    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 IntEnum(int, ReprEnum):
+    """
+    Enum where members are also (and must be) ints
+    """
 
 
-class StrEnum(str, Enum):
+class StrEnum(str, ReprEnum):
     """
     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:
@@ -1135,10 +1287,6 @@ 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.
@@ -1169,6 +1317,8 @@ 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.
@@ -1184,7 +1334,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
@@ -1232,8 +1382,8 @@ def _missing_(cls, value):
             if cls._boundary_ is STRICT:
                 max_bits = max(value.bit_length(), flag_mask.bit_length())
                 raise ValueError(
-                        "%s: invalid value: %r\n    given %s\n  allowed %s" % (
-                            cls.__name__, value, bin(value, max_bits), bin(flag_mask, max_bits),
+                        "%r invalid value %r\n    given %s\n  allowed %s" % (
+                            cls, value, bin(value, max_bits), bin(flag_mask, max_bits),
                             ))
             elif cls._boundary_ is CONFORM:
                 value = value & flag_mask
@@ -1247,7 +1397,7 @@ def _missing_(cls, value):
                             )
             else:
                 raise ValueError(
-                        'unknown flag boundary: %r' % (cls._boundary_, )
+                        '%r unknown flag boundary %r' % (cls, cls._boundary_, )
                         )
         if value < 0:
             neg_value = value
@@ -1274,7 +1424,7 @@ def _missing_(cls, value):
                 m._name_ for m in cls._iter_member_(member_value)
                 ])
             if unknown:
-                pseudo_member._name_ += '|0x%x' % unknown
+                pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown)
         else:
             pseudo_member._name_ = None
         # use setdefault in case another thread already created a composite
@@ -1292,10 +1442,8 @@ def __contains__(self, other):
         """
         if not isinstance(other, self.__class__):
             raise TypeError(
-                "unsupported operand type(s) for 'in': '%s' and '%s'" % (
+                "unsupported operand type(s) for 'in': %r and %r" % (
                     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):
@@ -1309,27 +1457,18 @@ 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 "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('|'))
+            return "<%s: %s>" % (cls_name, v_repr(self._value_))
         else:
-            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)
+            return "<%s.%s: %s>" % (cls_name, self._name_, v_repr(self._value_))
 
     def __str__(self):
-        cls = self.__class__
+        cls_name = self.__class__.__name__
         if self._name_ is None:
-            return '%s(%x)' % (cls.__name__, self._value_)
+            return '%s(%r)' % (cls_name, self._value_)
         else:
-            return self._name_
+            return "%s.%s" % (cls_name, self._name_)
 
     def __bool__(self):
         return bool(self._value_)
@@ -1362,20 +1501,11 @@ def __invert__(self):
         return self._inverted_
 
 
-class IntFlag(int, Flag, boundary=EJECT):
+class IntFlag(int, ReprEnum, 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__):
@@ -1412,6 +1542,7 @@ 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
@@ -1456,7 +1587,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(0x%x)" % (module, cls_name, self._value_)
+        return "%s.%s(%r)" % (module, cls_name, self._value_)
     if _is_single_bit(self):
         return '%s.%s' % (module, self._name_)
     if self._boundary_ is not FlagBoundary.KEEP:
@@ -1464,14 +1595,22 @@ def global_flag_repr(self):
     else:
         name = []
         for n in self._name_.split('|'):
-            if n.startswith('0'):
+            if n[0].isdigit():
                 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):
+def global_enum(cls, update_str=False):
     """
     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
@@ -1481,6 +1620,8 @@ def global_enum(cls):
         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
 
@@ -1522,6 +1663,7 @@ 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
@@ -1543,13 +1685,8 @@ 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 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)
+            if name not in body:
+                setattr(enum_class, name, getattr(etype, name))
         gnv_last_values = []
         if issubclass(enum_class, Flag):
             # Flag / IntFlag
@@ -1760,8 +1897,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_'):
-                # keys known to be different
+            if key in ('__module__', '_member_map_', '_value2member_map_', '__doc__'):
+                # keys known to be different, or very long
                 continue
             elif key in member_names:
                 # members are checked below
@@ -1882,3 +2019,5 @@ 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 5d33f0d445fb9..8236698b8de0f 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2567,15 +2567,21 @@ class _empty:
 
 
 class _ParameterKind(enum.IntEnum):
-    POSITIONAL_ONLY = 0
-    POSITIONAL_OR_KEYWORD = 1
-    VAR_POSITIONAL = 2
-    KEYWORD_ONLY = 3
-    VAR_KEYWORD = 4
+    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
 
-    @property
-    def description(self):
-        return _PARAM_NAME_MAPPING[self]
+    def __str__(self):
+        return self.name
 
 _POSITIONAL_ONLY         = _ParameterKind.POSITIONAL_ONLY
 _POSITIONAL_OR_KEYWORD   = _ParameterKind.POSITIONAL_OR_KEYWORD
@@ -2583,14 +2589,6 @@ def description(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 3ab71edc320af..4862355b2252c 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -61,7 +61,8 @@
 from xml.parsers.expat import ParserCreate
 
 
-PlistFormat = enum.global_enum(enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__))
+PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
+globals().update(PlistFormat.__members__)
 
 
 class UID:
diff --git a/Lib/re.py b/Lib/re.py
index ea41217ce08c2..a7ab9b3706748 100644
--- a/Lib/re.py
+++ b/Lib/re.py
@@ -155,6 +155,8 @@ 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 207925166efa3..dafb70a67864c 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -119,7 +119,6 @@
 )
 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 43f98c1c1efb6..a0953fb960f33 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,15 +6,18 @@
 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
+from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
 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]
@@ -107,6 +110,12 @@ 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
@@ -116,21 +125,36 @@ class foo:
             setattr(obj, attr, 1)
             self.assertTrue(enum._is_descriptor(obj))
 
-    def test_is_sunder(self):
+    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)
         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_is_dunder(self):
+    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)
         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:
@@ -166,473 +190,658 @@ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
 
 # tests
 
-class TestEnum(unittest.TestCase):
+class _EnumTests:
+    """
+    Test for behavior that is the same across the different types of enumerations.
+    """
+
+    values = None
 
     def setUp(self):
-        class Season(Enum):
-            SPRING = 1
-            SUMMER = 2
-            AUTUMN = 3
-            WINTER = 4
-        self.Season = Season
+        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
 
-        class Konstants(float, Enum):
-            E = 2.7182818
-            PI = 3.1415926
-            TAU = 2 * PI
-        self.Konstants = Konstants
+    def assertFormatIsValue(self, spec, member):
+        self.assertEqual(spec.format(member), spec.format(member.value))
 
-        class Grades(IntEnum):
-            A = 5
-            B = 4
-            C = 3
-            D = 2
-            F = 0
-        self.Grades = Grades
+    def assertFormatIsStr(self, spec, member):
+        self.assertEqual(spec.format(member), spec.format(str(member)))
 
-        class Directional(str, Enum):
-            EAST = 'east'
-            WEST = 'west'
-            NORTH = 'north'
-            SOUTH = 'south'
-        self.Directional = Directional
+    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
 
-        from datetime import date
-        class Holiday(date, Enum):
-            NEW_YEAR = 2013, 1, 1
-            IDES_OF_MARCH = 2013, 3, 15
-        self.Holiday = Holiday
+    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 DateEnum(date, Enum): pass
-        self.DateEnum = DateEnum
+    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 FloatEnum(float, Enum): pass
-        self.FloatEnum = FloatEnum
+    def test_changing_member_fails(self):
+        MainEnum = self.MainEnum
+        with self.assertRaises(AttributeError):
+            self.MainEnum.second = 'really first'
 
-        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)
-            @classmethod
-            def classmethod_wowser(cls): pass
-            @staticmethod
-            def staticmethod_wowser(): pass
-        self.FloatWowser = FloatWowser
+    @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 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
+    @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)
 
-        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_class(self):
+        TE = self.MainEnum
+        self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
+
+    def test_dir_on_item(self):
+        TE = self.MainEnum
+        self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
+
+    def test_dir_with_added_behavior(self):
+        class Test(self.enum_type):
+            this = auto()
+            these = auto()
+            def wowser(self):
+                return ("Wowser! I'm %s!" % self.name)
+        self.assertTrue('wowser' not in dir(Test))
+        self.assertTrue('wowser' in dir(Test.this))
 
+    def test_dir_on_sub_with_behavior_on_super(self):
         # see issue22506
-        class SuperEnum1(Enum):
+        class SuperEnum(self.enum_type):
             def invisible(self):
                 return "did you see me?"
-        class SubEnum1(SuperEnum1):
-            sample = 5
-        self.SubEnum1 = SubEnum1
+        class SubEnum(SuperEnum):
+            sample = auto()
+        self.assertTrue('invisible' not in dir(SubEnum))
+        self.assertTrue('invisible' in dir(SubEnum.sample))
 
-        class SuperEnum2(IntEnum):
-            def __new__(cls, value, description=""):
-                obj = int.__new__(cls, value)
-                obj._value_ = value
-                obj.description = description
+    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'
                 return obj
-        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
-                ))
+        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))
 
-        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_enum_in_enum_out(self):
+        Main = self.MainEnum
+        self.assertIs(Main(Main.first), Main.first)
 
-        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_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())
 
-                first_enum_base = next(
-                    base for base in enum_cls.__mro__
-                    if is_from_enum_module(base)
+    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)))
+
+    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)))
+
+    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,
                 )
+        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))
 
-                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_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))
 
-    def test_dir_on_sub_with_behavior_on_super(self):
-        # see issue22506
+    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)
         self.assertEqual(
-                set(dir(self.SubEnum1.sample)),
-                set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
+                [MinorEnum.june, MinorEnum.july, MinorEnum.august],
+                lst,
                 )
+        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_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
-        # see issue40084
-        self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
+    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_enum_in_enum_out(self):
-        Season = self.Season
-        self.assertIs(Season(Season.WINTER), Season.WINTER)
+    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_value(self):
-        Season = self.Season
-        self.assertEqual(Season.SPRING.value, 1)
+    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_intenum_value(self):
-        self.assertEqual(IntStooges.CURLY.value, 2)
+    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_enum(self):
-        Season = self.Season
-        lst = list(Season)
-        self.assertEqual(len(lst), len(Season))
-        self.assertEqual(len(Season), 4, Season)
+    def test_reversed_iteration_order(self):
         self.assertEqual(
-            [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
+                list(reversed(self.MainEnum)),
+                [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
+                )
 
-        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 _PlainOutputTests:
 
-    def test_changing_member(self):
-        Season = self.Season
-        with self.assertRaises(AttributeError):
-            Season.WINTER = 'really cold'
+    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_attribute_deletion(self):
-        class Season(Enum):
-            SPRING = 1
-            SUMMER = 2
-            AUTUMN = 3
-            WINTER = 4
+    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 spam(cls):
-                pass
+    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")
 
-        self.assertTrue(hasattr(Season, 'spam'))
-        del Season.spam
-        self.assertFalse(hasattr(Season, 'spam'))
+    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)
 
-        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 _MixedOutputTests:
 
-    def test_bool_of_member(self):
-        class Count(Enum):
-            zero = 0
-            one = 1
-            two = 2
-        for member in Count:
-            self.assertTrue(bool(member))
+    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]
 
-    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
+
+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]
+
+
+class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
+
+    values = [4.4, 5.5, 6.6]
+
+    class enum_type(float, ReprEnum):
+        def _generate_next_value_(name, start, count, last_values):
+            values = [4.4, 5.5, 6.6]
+            return values[count]
+
+
+class TestSpecial(unittest.TestCase):
+    """
+    various operations that are not attributable to every possible enum
+    """
+
+    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_bool(self):
         # plain Enum members are always True
@@ -656,92 +865,56 @@ 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_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_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_duplicate_name(self):
+    def test_duplicate_name_error(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
@@ -749,232 +922,45 @@ class Color(Enum):
                 blue = 3
                 def red(self):
                     return 'red'
-
+        #
         with self.assertRaises(TypeError):
             class Color(Enum):
-                @property
+                @enum.property
                 def red(self):
                     return 'redder'
-                red = 1
-                green = 2
-                blue = 3
-
-    def test_reserved__sunder_(self):
-        with self.assertRaisesRegex(
-                ValueError,
-                '_sunder_ names, such as ._bad_., are reserved',
-            ):
-            class Bad(Enum):
-                _bad_ = 1
+                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_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'
@@ -990,7 +976,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.9, but does now with pickling by name
+        # This did not work in 3.10, but does now with pickling by name
         class UnBrokenInt(int):
             __qualname__ = 'UnBrokenInt'
             def __new__(cls, value):
@@ -1007,6 +993,124 @@ 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):
@@ -1022,122 +1126,6 @@ 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):
@@ -1169,12 +1157,7 @@ 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_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):
+    def test_pickle_nested_class(self):
         # would normally just have this directly in the class namespace
         class NestedEnum(Enum):
             twigs = 'common'
@@ -1192,225 +1175,46 @@ class ReplaceGlobalInt(IntEnum):
         for proto in range(HIGHEST_PROTOCOL):
             self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
 
-    def test_exploding_pickle(self):
+    def test_pickle_explodes(self):
         BadPickle = Enum(
                 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
         globals()['BadPickle'] = BadPickle
         # now break BadPickle to test exception raising
         enum._make_class_unpicklable(BadPickle)
-        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_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)
+        test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
+        test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
 
-    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_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_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_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_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_getattr_dunder(self):
+        Season = self.Season
+        self.assertTrue(getattr(Season, '__eq__'))
 
-    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)
+    def test_iteration_order(self):
+        class Season(Enum):
+            SUMMER = 2
+            WINTER = 4
+            AUTUMN = 3
+            SPRING = 1
         self.assertEqual(
-                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
-                lst,
+                list(Season),
+                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
                 )
-        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):
@@ -1425,15 +1229,18 @@ 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, "EvenMoreColor: cannot extend enumeration 'Color'"):
+        #
+        with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
             class EvenMoreColor(Color, IntEnum):
                 chartruese = 7
-        with self.assertRaisesRegex(TypeError, "Foo: cannot extend enumeration 'Color'"):
+        #
+        with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
             Color('Foo', ('pink', 'black'))
 
     def test_exclude_methods(self):
@@ -1537,27 +1344,7 @@ class Color(Enum):
         with self.assertRaises(KeyError):
             Color['chartreuse']
 
-    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.")
+    # tests that need to be evalualted for moving
 
     def test_multiple_mixin_mro(self):
         class auto_enum(type(Enum)):
@@ -1610,7 +1397,7 @@ def __new__(cls, *args):
                 return self
             def __getnewargs__(self):
                 return self._args
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1670,7 +1457,7 @@ def __new__(cls, *args):
                 return self
             def __getnewargs_ex__(self):
                 return self._args, {}
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1730,7 +1517,7 @@ def __new__(cls, *args):
                 return self
             def __reduce__(self):
                 return self.__class__, self._args
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1790,7 +1577,7 @@ def __new__(cls, *args):
                 return self
             def __reduce_ex__(self, proto):
                 return self.__class__, self._args
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1847,7 +1634,7 @@ def __new__(cls, *args):
                 self._intname = name
                 self._args = _args
                 return self
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -1902,7 +1689,7 @@ def __new__(cls, *args):
                 self._intname = name
                 self._args = _args
                 return self
-            @property
+            @bltns.property
             def __name__(self):
                 return self._intname
             def __repr__(self):
@@ -2091,6 +1878,7 @@ 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):
@@ -2098,6 +1886,7 @@ 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):
@@ -2134,7 +1923,7 @@ class Planet(Enum):
             def __init__(self, mass, radius):
                 self.mass = mass       # in kilograms
                 self.radius = radius   # in meters
-            @property
+            @enum.property
             def surface_gravity(self):
                 # universal gravitational constant  (m3 kg-1 s-2)
                 G = 6.67300E-11
@@ -2204,90 +1993,7 @@ class LabelledList(LabelledIntEnum):
         self.assertEqual(LabelledList.unprocessed, 1)
         self.assertEqual(LabelledList(1), LabelledList.unprocessed)
 
-    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):
+    def test_default_missing_no_chained_exception(self):
         class Color(Enum):
             RED = 1
             GREEN = 2
@@ -2299,7 +2005,7 @@ class Color(Enum):
         else:
             raise Exception('Exception not raised.')
 
-    def test_missing(self):
+    def test_missing_override(self):
         class Color(Enum):
             red = 1
             green = 2
@@ -2363,9 +2069,9 @@ def __init__(self):
         class_1_ref = weakref.ref(Class1())
         class_2_ref = weakref.ref(Class2())
         #
-        # The exception raised by Enum creates a reference loop and thus
-        # Class2 instances will stick around until the next garbage collection
-        # cycle, unlike Class1.
+        # 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.
         gc.collect()  # For PyPy or other GCs.
         self.assertIs(class_1_ref(), None)
         self.assertIs(class_2_ref(), None)
@@ -2396,11 +2102,12 @@ 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), 'BLUE')
+        self.assertEqual(str(Color.BLUE), 'Color.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)
@@ -2410,6 +2117,7 @@ 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)
@@ -2419,6 +2127,7 @@ 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)
@@ -2428,6 +2137,7 @@ 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)
@@ -2438,6 +2148,7 @@ 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)
@@ -2448,6 +2159,7 @@ 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)
@@ -2458,6 +2170,7 @@ 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)
@@ -2490,11 +2203,12 @@ def __repr__(self):
                 return hex(self)
 
         class MyIntEnum(HexMixin, MyInt, enum.Enum):
-            pass
+            __repr__ = HexMixin.__repr__
 
         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):
@@ -2506,7 +2220,7 @@ def __new__(cls, value):
                 return member
         self.assertEqual(Fee.TEST, 2)
 
-    def test_miltuple_mixin_with_common_data_type(self):
+    def test_multiple_mixin_with_common_data_type(self):
         class CaseInsensitiveStrEnum(str, Enum):
             @classmethod
             def _missing_(cls, value):
@@ -2526,7 +2240,7 @@ def _missing_(cls, value):
                 unknown._value_ = value
                 cls._member_map_[value] = unknown
                 return unknown
-            @property
+            @enum.property
             def valid(self):
                 return self._valid
         #
@@ -2570,7 +2284,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')
+        self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
         #
         class DumbMixin:
             def __str__(self):
@@ -2579,6 +2293,7 @@ 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")
         #
@@ -2620,74 +2335,6 @@ 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
@@ -2697,9 +2344,9 @@ class OkayEnum(CustomStrEnum):
             three = b'3', 'ascii'
             four = b'4', 'latin1', 'strict'
         self.assertEqual(OkayEnum.one, '1')
-        self.assertEqual(str(OkayEnum.one), 'one')
-        self.assertEqual('{}'.format(OkayEnum.one), 'one')
-        self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
+        self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
+        self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
+        self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
         #
         class DumbMixin:
             def __str__(self):
@@ -2708,6 +2355,7 @@ 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")
         #
@@ -2717,7 +2365,7 @@ def hello(self):
         class HelloEnum(EnumMixin, CustomStrEnum):
             eight = '8'
         self.assertEqual(HelloEnum.eight, '8')
-        self.assertEqual(str(HelloEnum.eight), 'eight')
+        self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
         #
         class GoodbyeMixin:
             def goodbye(self):
@@ -2725,7 +2373,7 @@ def goodbye(self):
         class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
             nine = '9'
         self.assertEqual(GoodbyeEnum.nine, '9')
-        self.assertEqual(str(GoodbyeEnum.nine), 'nine')
+        self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
         #
         class FirstFailedStrEnum(CustomStrEnum):
             one = 1   # this will become '1'
@@ -2771,21 +2419,6 @@ 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):
@@ -2794,35 +2427,13 @@ 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, "Di: no instance attribute .NO."):
+        with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no 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):
         #
@@ -2839,7 +2450,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
@@ -2851,8 +2462,42 @@ 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):
@@ -2914,7 +2559,7 @@ class Color(Enum):
                 verde = green
 
 
-class TestFlag(unittest.TestCase):
+class OldTestFlag(unittest.TestCase):
     """Tests of the Flags."""
 
     class Perm(Flag):
@@ -2934,67 +2579,8 @@ class Color(Flag):
         GREEN = 2
         BLUE = 4
         PURPLE = RED|BLUE
-        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')
+        WHITE = RED|GREEN|BLUE
+        BLANCO = RED|GREEN|BLUE
 
     def test_or(self):
         Perm = self.Perm
@@ -3088,7 +2674,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)
@@ -3297,7 +2883,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()
@@ -3332,11 +2918,12 @@ 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), 'BLUE')
+        self.assertEqual(str(Color.BLUE), 'Color.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)
@@ -3346,6 +2933,7 @@ 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)
@@ -3426,21 +3014,8 @@ 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 TestIntFlag(unittest.TestCase):
+class OldTestIntFlag(unittest.TestCase):
     """Tests of the IntFlags."""
 
     class Perm(IntFlag):
@@ -3485,73 +3060,6 @@ 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)),
@@ -3559,11 +3067,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|0x8' % {'m': SHORT_MODULE},
+                '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
                 )
         self.assertEqual(
                 repr(HeadlightsK(2**3)),
-                '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
+                '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
                 )
 
     def test_global_repr_conform1(self):
@@ -3705,7 +3213,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)
@@ -3942,11 +3450,12 @@ 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), 'BLUE')
+        self.assertEqual(str(Color.BLUE), '4')
         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)
@@ -3956,6 +3465,7 @@ 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)
@@ -4000,19 +3510,6 @@ 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):
 
@@ -4229,6 +3726,89 @@ 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
 
@@ -4238,7 +3818,35 @@ class TestEnumTypeSubclassing(unittest.TestCase):
 class Color(enum.Enum)
  |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
  |\x20\x20
- |  An enumeration.
+ |  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.
  |\x20\x20
  |  Method resolution order:
  |      Color
@@ -4247,11 +3855,11 @@ class Color(enum.Enum)
  |\x20\x20
  |  Data and other attributes defined here:
  |\x20\x20
- |  blue = Color.blue
+ |  CYAN = <Color.CYAN: 1>
  |\x20\x20
- |  green = Color.green
+ |  MAGENTA = <Color.MAGENTA: 2>
  |\x20\x20
- |  red = Color.red
+ |  YELLOW = <Color.YELLOW: 3>
  |\x20\x20
  |  ----------------------------------------------------------------------
  |  Data descriptors inherited from enum.Enum:
@@ -4263,6 +3871,25 @@ 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__
@@ -4284,11 +3911,11 @@ class Color(enum.Enum)
  |\x20\x20
  |  Data and other attributes defined here:
  |\x20\x20
- |  blue = Color.blue
+ |  YELLOW = <Color.YELLOW: 3>
  |\x20\x20
- |  green = Color.green
+ |  MAGENTA = <Color.MAGENTA: 2>
  |\x20\x20
- |  red = Color.red
+ |  CYAN = <Color.CYAN: 1>
  |\x20\x20
  |  ----------------------------------------------------------------------
  |  Data descriptors inherited from enum.Enum:
@@ -4307,9 +3934,9 @@ class TestStdLib(unittest.TestCase):
     maxDiff = None
 
     class Color(Enum):
-        red = 1
-        green = 2
-        blue = 3
+        CYAN = 1
+        MAGENTA = 2
+        YELLOW = 3
 
     def test_pydoc(self):
         # indirectly test __objclass__
@@ -4321,24 +3948,34 @@ def test_pydoc(self):
         helper = pydoc.Helper(output=output)
         helper(self.Color)
         result = output.getvalue().strip()
-        self.assertEqual(result, expected_text)
+        self.assertEqual(result, expected_text, result)
 
     def test_inspect_getmembers(self):
         values = dict((
                 ('__class__', EnumType),
-                ('__doc__', 'An enumeration.'),
+                ('__doc__', '...'),
                 ('__members__', self.Color.__members__),
                 ('__module__', __name__),
-                ('blue', self.Color.blue),
-                ('green', self.Color.green),
+                ('YELLOW', self.Color.YELLOW),
+                ('MAGENTA', self.Color.MAGENTA),
+                ('CYAN', self.Color.CYAN),
                 ('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' %
@@ -4353,23 +3990,42 @@ 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='An enumeration.'),
+                    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__),
                 Attribute(name='__members__', kind='property',
                     defining_class=EnumType, object=EnumType.__members__),
                 Attribute(name='__module__', kind='data',
                     defining_class=self.Color, object=__name__),
-                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=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='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)
@@ -4379,7 +4035,15 @@ def test_inspect_classify_class_attrs(self):
                 )
         failed = False
         for v, r in zip(values, result):
-            if r != v:
+            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:
                 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
                 failed = True
         if failed:
@@ -4388,15 +4052,15 @@ def test_inspect_classify_class_attrs(self):
     def test_test_simple_enum(self):
         @_simple_enum(Enum)
         class SimpleColor:
-            RED = 1
-            GREEN = 2
-            BLUE = 3
+            CYAN = 1
+            MAGENTA = 2
+            YELLOW = 3
         class CheckedColor(Enum):
-            RED = 1
-            GREEN = 2
-            BLUE = 3
+            CYAN = 1
+            MAGENTA = 2
+            YELLOW = 3
         self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
-        SimpleColor.GREEN._value_ = 9
+        SimpleColor.MAGENTA._value_ = 9
         self.assertRaisesRegex(
                 TypeError, "enum mismatch",
                 _test_simple_enum, CheckedColor, SimpleColor,
@@ -4422,9 +4086,165 @@ 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.
@@ -4442,6 +4262,10 @@ def test__all__(self):
 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
@@ -4453,32 +4277,40 @@ def test__all__(self):
 
 class _ModuleWrapper:
     """We use this class as a namespace for swapping modules."""
-
     def __init__(self, module):
         self.__dict__.update(module.__dict__)
 
-class TestIntEnumConvert(unittest.TestCase):
+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
+
     def test_convert_value_lookup_priority(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_'))
+        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(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_'))
+    def test_convert_int(self):
+        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)
@@ -4487,43 +4319,57 @@ def test_convert(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.
-        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.')
+        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.',
+                )
 
     def test_convert_uncomparable(self):
-        # 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_'))
-
+        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):
-        with support.swap_item(
-                sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
-            ):
-            uncomp = enum.Enum._convert_(
-                'Uncomparable',
-                MODULE,
-                filter=lambda x: x.startswith('COMPLEX_'))
-
+        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):
@@ -4533,50 +4379,58 @@ def test_convert_raise(self):
                 filter=lambda x: x.startswith('CONVERT_TEST_'))
 
     def test_convert_repr_and_str(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_STRING_TEST_'))
+        test_type = enum.IntEnum._convert_(
+                'UnittestConvert',
+                MODULE,
+                filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
+                as_global=True)
         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), 'CONVERT_STRING_TEST_NAME_A')
+        self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5')
         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'
 
-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.')
+# helpers
 
-    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')
+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)
+
+missing = object()
 
 
 if __name__ == '__main__':
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 3f0e7270eb26f..ac4626d0c456e 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -908,7 +908,7 @@ def handler(signum, frame):
 
         %s
 
-        blocked = %r
+        blocked = %s
         signum = signal.SIGALRM
 
         # child: block and wait the signal
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 394d2942483fb..56cc23dbbbf4e 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1517,9 +1517,11 @@ 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(str(family), 'AF_INET')
+            self.assertEqual(repr(family), '<AddressFamily.AF_INET: 2>')
+            self.assertEqual(str(family), '2')
             self.assertEqual(type, socket.SOCK_STREAM)
-            self.assertEqual(str(type), 'SOCK_STREAM')
+            self.assertEqual(repr(type), '<SocketKind.SOCK_STREAM: 1>')
+            self.assertEqual(str(type), '1')
         infos = socket.getaddrinfo(HOST, None, 0, socket.SOCK_STREAM)
         for _, socktype, _, _, _ in infos:
             self.assertEqual(socktype, socket.SOCK_STREAM)
@@ -1793,8 +1795,10 @@ 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(str(s.family), 'AF_INET')
-            self.assertEqual(str(s.type), 'SOCK_STREAM')
+            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')
 
     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 f99a3e8da95f8..64f4bce7f7781 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -373,7 +373,8 @@ def test_str_for_enums(self):
         # Make sure that the PROTOCOL_* constants have enum-like string
         # reprs.
         proto = ssl.PROTOCOL_TLS_CLIENT
-        self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT')
+        self.assertEqual(repr(proto), '<_SSLMethod.PROTOCOL_TLS_CLIENT: 16>')
+        self.assertEqual(str(proto), '16')
         ctx = ssl.SSLContext(proto)
         self.assertIs(ctx.protocol, proto)
 
@@ -622,7 +623,7 @@ def test_openssl111_deprecations(self):
                 with self.assertWarns(DeprecationWarning) as cm:
                     ssl.SSLContext(protocol)
                 self.assertEqual(
-                    f'{protocol!r} is deprecated',
+                    f'ssl.{protocol.name} is deprecated',
                     str(cm.warning)
                 )
 
@@ -631,8 +632,9 @@ 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!r} is deprecated',
+                    f'ssl.{version_text} is deprecated',
                     str(cm.warning)
                 )
 
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index d5e2c5266aae7..8e4e64808b688 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -1490,8 +1490,10 @@ 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.
@@ -1508,8 +1510,10 @@ 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},
-                         '...IDES...')
+                         '...15...')
         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
new file mode 100644
index 0000000000000..2df487855785e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-01-13-11-41-24.bpo-40066.1QuVli.rst
@@ -0,0 +1,2 @@
+``IntEnum``, ``IntFlag``, and ``StrEnum`` use the mixed-in type for their
+``str()`` and ``format()`` output.



More information about the Python-checkins mailing list