1import enum
2import doctest
3import inspect
4import os
5import pydoc
6import sys
7import unittest
8import threading
9from collections import OrderedDict
10from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
11from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
12from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS
13from io import StringIO
14from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
15from test import support
16from test.support import ALWAYS_EQ
17from test.support import threading_helper
18from datetime import timedelta
19
20python_version = sys.version_info[:2]
21
22def load_tests(loader, tests, ignore):
23    tests.addTests(doctest.DocTestSuite(enum))
24    if os.path.exists('Doc/library/enum.rst'):
25        tests.addTests(doctest.DocFileSuite(
26                '../../Doc/library/enum.rst',
27                optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
28                ))
29    return tests
30
31MODULE = ('test.test_enum', '__main__')[__name__=='__main__']
32SHORT_MODULE = MODULE.split('.')[-1]
33
34# for pickle tests
35try:
36    class Stooges(Enum):
37        LARRY = 1
38        CURLY = 2
39        MOE = 3
40except Exception as exc:
41    Stooges = exc
42
43try:
44    class IntStooges(int, Enum):
45        LARRY = 1
46        CURLY = 2
47        MOE = 3
48except Exception as exc:
49    IntStooges = exc
50
51try:
52    class FloatStooges(float, Enum):
53        LARRY = 1.39
54        CURLY = 2.72
55        MOE = 3.142596
56except Exception as exc:
57    FloatStooges = exc
58
59try:
60    class FlagStooges(Flag):
61        LARRY = 1
62        CURLY = 2
63        MOE = 3
64except Exception as exc:
65    FlagStooges = exc
66
67# for pickle test and subclass tests
68class Name(StrEnum):
69    BDFL = 'Guido van Rossum'
70    FLUFL = 'Barry Warsaw'
71
72try:
73    Question = Enum('Question', 'who what when where why', module=__name__)
74except Exception as exc:
75    Question = exc
76
77try:
78    Answer = Enum('Answer', 'him this then there because')
79except Exception as exc:
80    Answer = exc
81
82try:
83    Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
84except Exception as exc:
85    Theory = exc
86
87# for doctests
88try:
89    class Fruit(Enum):
90        TOMATO = 1
91        BANANA = 2
92        CHERRY = 3
93except Exception:
94    pass
95
96def test_pickle_dump_load(assertion, source, target=None):
97    if target is None:
98        target = source
99    for protocol in range(HIGHEST_PROTOCOL + 1):
100        assertion(loads(dumps(source, protocol=protocol)), target)
101
102def test_pickle_exception(assertion, exception, obj):
103    for protocol in range(HIGHEST_PROTOCOL + 1):
104        with assertion(exception):
105            dumps(obj, protocol=protocol)
106
107class TestHelpers(unittest.TestCase):
108    # _is_descriptor, _is_sunder, _is_dunder
109
110    def test_is_descriptor(self):
111        class foo:
112            pass
113        for attr in ('__get__','__set__','__delete__'):
114            obj = foo()
115            self.assertFalse(enum._is_descriptor(obj))
116            setattr(obj, attr, 1)
117            self.assertTrue(enum._is_descriptor(obj))
118
119    def test_is_sunder(self):
120        for s in ('_a_', '_aa_'):
121            self.assertTrue(enum._is_sunder(s))
122
123        for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
124                '__', '___', '____', '_____',):
125            self.assertFalse(enum._is_sunder(s))
126
127    def test_is_dunder(self):
128        for s in ('__a__', '__aa__'):
129            self.assertTrue(enum._is_dunder(s))
130        for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
131                '__', '___', '____', '_____',):
132            self.assertFalse(enum._is_dunder(s))
133
134# for subclassing tests
135
136class classproperty:
137
138    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
139        self.fget = fget
140        self.fset = fset
141        self.fdel = fdel
142        if doc is None and fget is not None:
143            doc = fget.__doc__
144        self.__doc__ = doc
145
146    def __get__(self, instance, ownerclass):
147        return self.fget(ownerclass)
148
149# for global repr tests
150
151@enum.global_enum
152class HeadlightsK(IntFlag, boundary=enum.KEEP):
153    OFF_K = 0
154    LOW_BEAM_K = auto()
155    HIGH_BEAM_K = auto()
156    FOG_K = auto()
157
158
159@enum.global_enum
160class HeadlightsC(IntFlag, boundary=enum.CONFORM):
161    OFF_C = 0
162    LOW_BEAM_C = auto()
163    HIGH_BEAM_C = auto()
164    FOG_C = auto()
165
166
167# tests
168
169class TestEnum(unittest.TestCase):
170
171    def setUp(self):
172        class Season(Enum):
173            SPRING = 1
174            SUMMER = 2
175            AUTUMN = 3
176            WINTER = 4
177        self.Season = Season
178
179        class Konstants(float, Enum):
180            E = 2.7182818
181            PI = 3.1415926
182            TAU = 2 * PI
183        self.Konstants = Konstants
184
185        class Grades(IntEnum):
186            A = 5
187            B = 4
188            C = 3
189            D = 2
190            F = 0
191        self.Grades = Grades
192
193        class Directional(str, Enum):
194            EAST = 'east'
195            WEST = 'west'
196            NORTH = 'north'
197            SOUTH = 'south'
198        self.Directional = Directional
199
200        from datetime import date
201        class Holiday(date, Enum):
202            NEW_YEAR = 2013, 1, 1
203            IDES_OF_MARCH = 2013, 3, 15
204        self.Holiday = Holiday
205
206        class DateEnum(date, Enum): pass
207        self.DateEnum = DateEnum
208
209        class FloatEnum(float, Enum): pass
210        self.FloatEnum = FloatEnum
211
212        class Wowser(Enum):
213            this = 'that'
214            these = 'those'
215            def wowser(self):
216                """Wowser docstring"""
217                return ("Wowser! I'm %s!" % self.name)
218            @classmethod
219            def classmethod_wowser(cls): pass
220            @staticmethod
221            def staticmethod_wowser(): pass
222        self.Wowser = Wowser
223
224        class IntWowser(IntEnum):
225            this = 1
226            these = 2
227            def wowser(self):
228                """Wowser docstring"""
229                return ("Wowser! I'm %s!" % self.name)
230            @classmethod
231            def classmethod_wowser(cls): pass
232            @staticmethod
233            def staticmethod_wowser(): pass
234        self.IntWowser = IntWowser
235
236        class FloatWowser(float, Enum):
237            this = 3.14
238            these = 4.2
239            def wowser(self):
240                """Wowser docstring"""
241                return ("Wowser! I'm %s!" % self.name)
242            @classmethod
243            def classmethod_wowser(cls): pass
244            @staticmethod
245            def staticmethod_wowser(): pass
246        self.FloatWowser = FloatWowser
247
248        class WowserNoMembers(Enum):
249            def wowser(self): pass
250            @classmethod
251            def classmethod_wowser(cls): pass
252            @staticmethod
253            def staticmethod_wowser(): pass
254        class SubclassOfWowserNoMembers(WowserNoMembers): pass
255        self.WowserNoMembers = WowserNoMembers
256        self.SubclassOfWowserNoMembers = SubclassOfWowserNoMembers
257
258        class IntWowserNoMembers(IntEnum):
259            def wowser(self): pass
260            @classmethod
261            def classmethod_wowser(cls): pass
262            @staticmethod
263            def staticmethod_wowser(): pass
264        self.IntWowserNoMembers = IntWowserNoMembers
265
266        class FloatWowserNoMembers(float, Enum):
267            def wowser(self): pass
268            @classmethod
269            def classmethod_wowser(cls): pass
270            @staticmethod
271            def staticmethod_wowser(): pass
272        self.FloatWowserNoMembers = FloatWowserNoMembers
273
274        class EnumWithInit(Enum):
275            def __init__(self, greeting, farewell):
276                self.greeting = greeting
277                self.farewell = farewell
278            ENGLISH = 'hello', 'goodbye'
279            GERMAN = 'Guten Morgen', 'Auf Wiedersehen'
280            def some_method(self): pass
281        self.EnumWithInit = EnumWithInit
282
283        # see issue22506
284        class SuperEnum1(Enum):
285            def invisible(self):
286                return "did you see me?"
287        class SubEnum1(SuperEnum1):
288            sample = 5
289        self.SubEnum1 = SubEnum1
290
291        class SuperEnum2(IntEnum):
292            def __new__(cls, value, description=""):
293                obj = int.__new__(cls, value)
294                obj._value_ = value
295                obj.description = description
296                return obj
297        class SubEnum2(SuperEnum2):
298            sample = 5
299        self.SubEnum2 = SubEnum2
300
301    def test_dir_basics_for_all_enums(self):
302        enums_for_tests = (
303            # Generic enums in enum.py
304            Enum,
305            IntEnum,
306            StrEnum,
307            # Generic enums defined outside of enum.py
308            self.DateEnum,
309            self.FloatEnum,
310            # Concrete enums derived from enum.py generics
311            self.Grades,
312            self.Season,
313            # Concrete enums derived from generics defined outside of enum.py
314            self.Konstants,
315            self.Holiday,
316            # Standard enum with added behaviour & members
317            self.Wowser,
318            # Mixin-enum-from-enum.py with added behaviour & members
319            self.IntWowser,
320            # Mixin-enum-from-oustide-enum.py with added behaviour & members
321            self.FloatWowser,
322            # Equivalents of the three immediately above, but with no members
323            self.WowserNoMembers,
324            self.IntWowserNoMembers,
325            self.FloatWowserNoMembers,
326            # Enum with members and an __init__ method
327            self.EnumWithInit,
328            # Special cases to test
329            self.SubEnum1,
330            self.SubEnum2
331        )
332
333        for cls in enums_for_tests:
334            with self.subTest(cls=cls):
335                cls_dir = dir(cls)
336                # test that dir is deterministic
337                self.assertEqual(cls_dir, dir(cls))
338                # test that dir is sorted
339                self.assertEqual(list(cls_dir), sorted(cls_dir))
340                # test that there are no dupes in dir
341                self.assertEqual(len(cls_dir), len(set(cls_dir)))
342                # test that there are no sunders in dir
343                self.assertFalse(any(enum._is_sunder(attr) for attr in cls_dir))
344                self.assertNotIn('__new__', cls_dir)
345
346                for attr in ('__class__', '__doc__', '__members__', '__module__'):
347                    with self.subTest(attr=attr):
348                        self.assertIn(attr, cls_dir)
349
350    def test_dir_for_enum_with_members(self):
351        enums_for_test = (
352            # Enum with members
353            self.Season,
354            # IntEnum with members
355            self.Grades,
356            # Two custom-mixin enums with members
357            self.Konstants,
358            self.Holiday,
359            # several enums-with-added-behaviour and members
360            self.Wowser,
361            self.IntWowser,
362            self.FloatWowser,
363            # An enum with an __init__ method and members
364            self.EnumWithInit,
365            # Special cases to test
366            self.SubEnum1,
367            self.SubEnum2
368        )
369
370        for cls in enums_for_test:
371            cls_dir = dir(cls)
372            member_names = cls._member_names_
373            with self.subTest(cls=cls):
374                self.assertTrue(all(member_name in cls_dir for member_name in member_names))
375                for member in cls:
376                    member_dir = dir(member)
377                    # test that dir is deterministic
378                    self.assertEqual(member_dir, dir(member))
379                    # test that dir is sorted
380                    self.assertEqual(list(member_dir), sorted(member_dir))
381                    # test that there are no dupes in dir
382                    self.assertEqual(len(member_dir), len(set(member_dir)))
383
384                    for attr_name in cls_dir:
385                        with self.subTest(attr_name=attr_name):
386                            if attr_name in {'__members__', '__init__', '__new__', *member_names}:
387                                self.assertNotIn(attr_name, member_dir)
388                            else:
389                                self.assertIn(attr_name, member_dir)
390
391                    self.assertFalse(any(enum._is_sunder(attr) for attr in member_dir))
392
393    def test_dir_for_enums_with_added_behaviour(self):
394        enums_for_test = (
395            self.Wowser,
396            self.IntWowser,
397            self.FloatWowser,
398            self.WowserNoMembers,
399            self.SubclassOfWowserNoMembers,
400            self.IntWowserNoMembers,
401            self.FloatWowserNoMembers
402        )
403
404        for cls in enums_for_test:
405            with self.subTest(cls=cls):
406                self.assertIn('wowser', dir(cls))
407                self.assertIn('classmethod_wowser', dir(cls))
408                self.assertIn('staticmethod_wowser', dir(cls))
409                self.assertTrue(all(
410                    all(attr in dir(member) for attr in ('wowser', 'classmethod_wowser', 'staticmethod_wowser'))
411                    for member in cls
412                ))
413
414        self.assertEqual(dir(self.WowserNoMembers), dir(self.SubclassOfWowserNoMembers))
415        # Check classmethods are present
416        self.assertIn('from_bytes', dir(self.IntWowser))
417        self.assertIn('from_bytes', dir(self.IntWowserNoMembers))
418
419    def test_help_output_on_enum_members(self):
420        added_behaviour_enums = (
421            self.Wowser,
422            self.IntWowser,
423            self.FloatWowser
424        )
425
426        for cls in added_behaviour_enums:
427            with self.subTest(cls=cls):
428                rendered_doc = pydoc.render_doc(cls.this)
429                self.assertIn('Wowser docstring', rendered_doc)
430                if cls in {self.IntWowser, self.FloatWowser}:
431                    self.assertIn('float(self)', rendered_doc)
432
433    def test_dir_for_enum_with_init(self):
434        EnumWithInit = self.EnumWithInit
435
436        cls_dir = dir(EnumWithInit)
437        self.assertIn('__init__', cls_dir)
438        self.assertIn('some_method', cls_dir)
439        self.assertNotIn('greeting', cls_dir)
440        self.assertNotIn('farewell', cls_dir)
441
442        member_dir = dir(EnumWithInit.ENGLISH)
443        self.assertNotIn('__init__', member_dir)
444        self.assertIn('some_method', member_dir)
445        self.assertIn('greeting', member_dir)
446        self.assertIn('farewell', member_dir)
447
448    def test_mixin_dirs(self):
449        from datetime import date
450
451        enums_for_test = (
452            # generic mixins from enum.py
453            (IntEnum, int),
454            (StrEnum, str),
455            # generic mixins from outside enum.py
456            (self.FloatEnum, float),
457            (self.DateEnum, date),
458            # concrete mixin from enum.py
459            (self.Grades, int),
460            # concrete mixin from outside enum.py
461            (self.Holiday, date),
462            # concrete mixin from enum.py with added behaviour
463            (self.IntWowser, int),
464            # concrete mixin from outside enum.py with added behaviour
465            (self.FloatWowser, float)
466        )
467
468        enum_dict = Enum.__dict__
469        enum_dir = dir(Enum)
470        enum_module_names = enum.__all__
471        is_from_enum_module = lambda cls: cls.__name__ in enum_module_names
472        is_enum_dunder = lambda attr: enum._is_dunder(attr) and attr in enum_dict
473
474        def attr_is_inherited_from_object(cls, attr_name):
475            for base in cls.__mro__:
476                if attr_name in base.__dict__:
477                    return base is object
478            return False
479
480        # General tests
481        for enum_cls, mixin_cls in enums_for_test:
482            with self.subTest(enum_cls=enum_cls):
483                cls_dir = dir(enum_cls)
484                cls_dict = enum_cls.__dict__
485
486                mixin_attrs = [
487                    x for x in dir(mixin_cls)
488                    if not attr_is_inherited_from_object(cls=mixin_cls, attr_name=x)
489                ]
490
491                first_enum_base = next(
492                    base for base in enum_cls.__mro__
493                    if is_from_enum_module(base)
494                )
495
496                for attr in mixin_attrs:
497                    with self.subTest(attr=attr):
498                        if enum._is_sunder(attr):
499                            # Unlikely, but no harm in testing
500                            self.assertNotIn(attr, cls_dir)
501                        elif attr in {'__class__', '__doc__', '__members__', '__module__'}:
502                            self.assertIn(attr, cls_dir)
503                        elif is_enum_dunder(attr):
504                            if is_from_enum_module(enum_cls):
505                                self.assertNotIn(attr, cls_dir)
506                            elif getattr(enum_cls, attr) is getattr(first_enum_base, attr):
507                                self.assertNotIn(attr, cls_dir)
508                            else:
509                                self.assertIn(attr, cls_dir)
510                        else:
511                            self.assertIn(attr, cls_dir)
512
513        # Some specific examples
514        int_enum_dir = dir(IntEnum)
515        self.assertIn('imag', int_enum_dir)
516        self.assertIn('__rfloordiv__', int_enum_dir)
517        self.assertNotIn('__format__', int_enum_dir)
518        self.assertNotIn('__hash__', int_enum_dir)
519        self.assertNotIn('__init_subclass__', int_enum_dir)
520        self.assertNotIn('__subclasshook__', int_enum_dir)
521
522        class OverridesFormatOutsideEnumModule(Enum):
523            def __format__(self, *args, **kwargs):
524                return super().__format__(*args, **kwargs)
525            SOME_MEMBER = 1
526
527        self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule))
528        self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule.SOME_MEMBER))
529
530    def test_dir_on_sub_with_behavior_on_super(self):
531        # see issue22506
532        self.assertEqual(
533                set(dir(self.SubEnum1.sample)),
534                set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
535                )
536
537    def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
538        # see issue40084
539        self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
540
541    def test_enum_in_enum_out(self):
542        Season = self.Season
543        self.assertIs(Season(Season.WINTER), Season.WINTER)
544
545    def test_enum_value(self):
546        Season = self.Season
547        self.assertEqual(Season.SPRING.value, 1)
548
549    def test_intenum_value(self):
550        self.assertEqual(IntStooges.CURLY.value, 2)
551
552    def test_enum(self):
553        Season = self.Season
554        lst = list(Season)
555        self.assertEqual(len(lst), len(Season))
556        self.assertEqual(len(Season), 4, Season)
557        self.assertEqual(
558            [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
559
560        for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
561            e = Season(i)
562            self.assertEqual(e, getattr(Season, season))
563            self.assertEqual(e.value, i)
564            self.assertNotEqual(e, i)
565            self.assertEqual(e.name, season)
566            self.assertIn(e, Season)
567            self.assertIs(type(e), Season)
568            self.assertIsInstance(e, Season)
569            self.assertEqual(str(e), season)
570            self.assertEqual(repr(e), 'Season.{0}'.format(season))
571
572    def test_value_name(self):
573        Season = self.Season
574        self.assertEqual(Season.SPRING.name, 'SPRING')
575        self.assertEqual(Season.SPRING.value, 1)
576        with self.assertRaises(AttributeError):
577            Season.SPRING.name = 'invierno'
578        with self.assertRaises(AttributeError):
579            Season.SPRING.value = 2
580
581    def test_changing_member(self):
582        Season = self.Season
583        with self.assertRaises(AttributeError):
584            Season.WINTER = 'really cold'
585
586    def test_attribute_deletion(self):
587        class Season(Enum):
588            SPRING = 1
589            SUMMER = 2
590            AUTUMN = 3
591            WINTER = 4
592
593            def spam(cls):
594                pass
595
596        self.assertTrue(hasattr(Season, 'spam'))
597        del Season.spam
598        self.assertFalse(hasattr(Season, 'spam'))
599
600        with self.assertRaises(AttributeError):
601            del Season.SPRING
602        with self.assertRaises(AttributeError):
603            del Season.DRY
604        with self.assertRaises(AttributeError):
605            del Season.SPRING.name
606
607    def test_bool_of_class(self):
608        class Empty(Enum):
609            pass
610        self.assertTrue(bool(Empty))
611
612    def test_bool_of_member(self):
613        class Count(Enum):
614            zero = 0
615            one = 1
616            two = 2
617        for member in Count:
618            self.assertTrue(bool(member))
619
620    def test_invalid_names(self):
621        with self.assertRaises(ValueError):
622            class Wrong(Enum):
623                mro = 9
624        with self.assertRaises(ValueError):
625            class Wrong(Enum):
626                _create_= 11
627        with self.assertRaises(ValueError):
628            class Wrong(Enum):
629                _get_mixins_ = 9
630        with self.assertRaises(ValueError):
631            class Wrong(Enum):
632                _find_new_ = 1
633        with self.assertRaises(ValueError):
634            class Wrong(Enum):
635                _any_name_ = 9
636
637    def test_bool(self):
638        # plain Enum members are always True
639        class Logic(Enum):
640            true = True
641            false = False
642        self.assertTrue(Logic.true)
643        self.assertTrue(Logic.false)
644        # unless overridden
645        class RealLogic(Enum):
646            true = True
647            false = False
648            def __bool__(self):
649                return bool(self._value_)
650        self.assertTrue(RealLogic.true)
651        self.assertFalse(RealLogic.false)
652        # mixed Enums depend on mixed-in type
653        class IntLogic(int, Enum):
654            true = 1
655            false = 0
656        self.assertTrue(IntLogic.true)
657        self.assertFalse(IntLogic.false)
658
659    @unittest.skipIf(
660            python_version >= (3, 12),
661            '__contains__ now returns True/False for all inputs',
662            )
663    def test_contains_er(self):
664        Season = self.Season
665        self.assertIn(Season.AUTUMN, Season)
666        with self.assertRaises(TypeError):
667            with self.assertWarns(DeprecationWarning):
668                3 in Season
669        with self.assertRaises(TypeError):
670            with self.assertWarns(DeprecationWarning):
671                'AUTUMN' in Season
672        val = Season(3)
673        self.assertIn(val, Season)
674        #
675        class OtherEnum(Enum):
676            one = 1; two = 2
677        self.assertNotIn(OtherEnum.two, Season)
678
679    @unittest.skipIf(
680            python_version < (3, 12),
681            '__contains__ only works with enum memmbers before 3.12',
682            )
683    def test_contains_tf(self):
684        Season = self.Season
685        self.assertIn(Season.AUTUMN, Season)
686        self.assertTrue(3 in Season)
687        self.assertFalse('AUTUMN' in Season)
688        val = Season(3)
689        self.assertIn(val, Season)
690        #
691        class OtherEnum(Enum):
692            one = 1; two = 2
693        self.assertNotIn(OtherEnum.two, Season)
694
695    def test_comparisons(self):
696        Season = self.Season
697        with self.assertRaises(TypeError):
698            Season.SPRING < Season.WINTER
699        with self.assertRaises(TypeError):
700            Season.SPRING > 4
701
702        self.assertNotEqual(Season.SPRING, 1)
703
704        class Part(Enum):
705            SPRING = 1
706            CLIP = 2
707            BARREL = 3
708
709        self.assertNotEqual(Season.SPRING, Part.SPRING)
710        with self.assertRaises(TypeError):
711            Season.SPRING < Part.CLIP
712
713    def test_enum_duplicates(self):
714        class Season(Enum):
715            SPRING = 1
716            SUMMER = 2
717            AUTUMN = FALL = 3
718            WINTER = 4
719            ANOTHER_SPRING = 1
720        lst = list(Season)
721        self.assertEqual(
722            lst,
723            [Season.SPRING, Season.SUMMER,
724             Season.AUTUMN, Season.WINTER,
725            ])
726        self.assertIs(Season.FALL, Season.AUTUMN)
727        self.assertEqual(Season.FALL.value, 3)
728        self.assertEqual(Season.AUTUMN.value, 3)
729        self.assertIs(Season(3), Season.AUTUMN)
730        self.assertIs(Season(1), Season.SPRING)
731        self.assertEqual(Season.FALL.name, 'AUTUMN')
732        self.assertEqual(
733                [k for k,v in Season.__members__.items() if v.name != k],
734                ['FALL', 'ANOTHER_SPRING'],
735                )
736
737    def test_duplicate_name(self):
738        with self.assertRaises(TypeError):
739            class Color(Enum):
740                red = 1
741                green = 2
742                blue = 3
743                red = 4
744
745        with self.assertRaises(TypeError):
746            class Color(Enum):
747                red = 1
748                green = 2
749                blue = 3
750                def red(self):
751                    return 'red'
752
753        with self.assertRaises(TypeError):
754            class Color(Enum):
755                @property
756                def red(self):
757                    return 'redder'
758                red = 1
759                green = 2
760                blue = 3
761
762    def test_reserved__sunder_(self):
763        with self.assertRaisesRegex(
764                ValueError,
765                '_sunder_ names, such as ._bad_., are reserved',
766            ):
767            class Bad(Enum):
768                _bad_ = 1
769
770    def test_enum_with_value_name(self):
771        class Huh(Enum):
772            name = 1
773            value = 2
774        self.assertEqual(
775            list(Huh),
776            [Huh.name, Huh.value],
777            )
778        self.assertIs(type(Huh.name), Huh)
779        self.assertEqual(Huh.name.name, 'name')
780        self.assertEqual(Huh.name.value, 1)
781
782    def test_format_enum(self):
783        Season = self.Season
784        self.assertEqual('{}'.format(Season.SPRING),
785                         '{}'.format(str(Season.SPRING)))
786        self.assertEqual( '{:}'.format(Season.SPRING),
787                          '{:}'.format(str(Season.SPRING)))
788        self.assertEqual('{:20}'.format(Season.SPRING),
789                         '{:20}'.format(str(Season.SPRING)))
790        self.assertEqual('{:^20}'.format(Season.SPRING),
791                         '{:^20}'.format(str(Season.SPRING)))
792        self.assertEqual('{:>20}'.format(Season.SPRING),
793                         '{:>20}'.format(str(Season.SPRING)))
794        self.assertEqual('{:<20}'.format(Season.SPRING),
795                         '{:<20}'.format(str(Season.SPRING)))
796
797    def test_str_override_enum(self):
798        class EnumWithStrOverrides(Enum):
799            one = auto()
800            two = auto()
801
802            def __str__(self):
803                return 'Str!'
804        self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
805        self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
806
807    def test_format_override_enum(self):
808        class EnumWithFormatOverride(Enum):
809            one = 1.0
810            two = 2.0
811            def __format__(self, spec):
812                return 'Format!!'
813        self.assertEqual(str(EnumWithFormatOverride.one), 'one')
814        self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
815
816    def test_str_and_format_override_enum(self):
817        class EnumWithStrFormatOverrides(Enum):
818            one = auto()
819            two = auto()
820            def __str__(self):
821                return 'Str!'
822            def __format__(self, spec):
823                return 'Format!'
824        self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
825        self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
826
827    def test_str_override_mixin(self):
828        class MixinEnumWithStrOverride(float, Enum):
829            one = 1.0
830            two = 2.0
831            def __str__(self):
832                return 'Overridden!'
833        self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
834        self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
835
836    def test_str_and_format_override_mixin(self):
837        class MixinWithStrFormatOverrides(float, Enum):
838            one = 1.0
839            two = 2.0
840            def __str__(self):
841                return 'Str!'
842            def __format__(self, spec):
843                return 'Format!'
844        self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
845        self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
846
847    def test_format_override_mixin(self):
848        class TestFloat(float, Enum):
849            one = 1.0
850            two = 2.0
851            def __format__(self, spec):
852                return 'TestFloat success!'
853        self.assertEqual(str(TestFloat.one), 'one')
854        self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
855
856    @unittest.skipIf(
857            python_version < (3, 12),
858            'mixin-format is still using member.value',
859            )
860    def test_mixin_format_warning(self):
861        class Grades(int, Enum):
862            A = 5
863            B = 4
864            C = 3
865            D = 2
866            F = 0
867        self.assertEqual(f'{self.Grades.B}', 'B')
868
869    @unittest.skipIf(
870            python_version >= (3, 12),
871            'mixin-format now uses member instead of member.value',
872            )
873    def test_mixin_format_warning(self):
874        class Grades(int, Enum):
875            A = 5
876            B = 4
877            C = 3
878            D = 2
879            F = 0
880        with self.assertWarns(DeprecationWarning):
881            self.assertEqual(f'{Grades.B}', '4')
882
883    def assertFormatIsValue(self, spec, member):
884        if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
885            with self.assertWarns(DeprecationWarning):
886                self.assertEqual(spec.format(member), spec.format(member.value))
887        else:
888            self.assertEqual(spec.format(member), spec.format(member.value))
889
890    def test_format_enum_date(self):
891        Holiday = self.Holiday
892        self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
893        self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
894        self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
895        self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
896        self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
897        self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
898        self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
899        self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
900
901    def test_format_enum_float(self):
902        Konstants = self.Konstants
903        self.assertFormatIsValue('{}', Konstants.TAU)
904        self.assertFormatIsValue('{:}', Konstants.TAU)
905        self.assertFormatIsValue('{:20}', Konstants.TAU)
906        self.assertFormatIsValue('{:^20}', Konstants.TAU)
907        self.assertFormatIsValue('{:>20}', Konstants.TAU)
908        self.assertFormatIsValue('{:<20}', Konstants.TAU)
909        self.assertFormatIsValue('{:n}', Konstants.TAU)
910        self.assertFormatIsValue('{:5.2}', Konstants.TAU)
911        self.assertFormatIsValue('{:f}', Konstants.TAU)
912
913    def test_format_enum_int(self):
914        class Grades(int, Enum):
915            A = 5
916            B = 4
917            C = 3
918            D = 2
919            F = 0
920        self.assertFormatIsValue('{}', Grades.C)
921        self.assertFormatIsValue('{:}', Grades.C)
922        self.assertFormatIsValue('{:20}', Grades.C)
923        self.assertFormatIsValue('{:^20}', Grades.C)
924        self.assertFormatIsValue('{:>20}', Grades.C)
925        self.assertFormatIsValue('{:<20}', Grades.C)
926        self.assertFormatIsValue('{:+}', Grades.C)
927        self.assertFormatIsValue('{:08X}', Grades.C)
928        self.assertFormatIsValue('{:b}', Grades.C)
929
930    def test_format_enum_str(self):
931        Directional = self.Directional
932        self.assertFormatIsValue('{}', Directional.WEST)
933        self.assertFormatIsValue('{:}', Directional.WEST)
934        self.assertFormatIsValue('{:20}', Directional.WEST)
935        self.assertFormatIsValue('{:^20}', Directional.WEST)
936        self.assertFormatIsValue('{:>20}', Directional.WEST)
937        self.assertFormatIsValue('{:<20}', Directional.WEST)
938
939    def test_object_str_override(self):
940        class Colors(Enum):
941            RED, GREEN, BLUE = 1, 2, 3
942            def __repr__(self):
943                return "test.%s" % (self._name_, )
944            __str__ = object.__str__
945        self.assertEqual(str(Colors.RED), 'test.RED')
946
947    def test_enum_str_override(self):
948        class MyStrEnum(Enum):
949            def __str__(self):
950                return 'MyStr'
951        class MyMethodEnum(Enum):
952            def hello(self):
953                return 'Hello!  My name is %s' % self.name
954        class Test1Enum(MyMethodEnum, int, MyStrEnum):
955            One = 1
956            Two = 2
957        self.assertTrue(Test1Enum._member_type_ is int)
958        self.assertEqual(str(Test1Enum.One), 'MyStr')
959        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
960        #
961        class Test2Enum(MyStrEnum, MyMethodEnum):
962            One = 1
963            Two = 2
964        self.assertEqual(str(Test2Enum.One), 'MyStr')
965        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
966
967    def test_inherited_data_type(self):
968        class HexInt(int):
969            def __repr__(self):
970                return hex(self)
971        class MyEnum(HexInt, enum.Enum):
972            A = 1
973            B = 2
974            C = 3
975            def __repr__(self):
976                return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
977        self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
978        #
979        class SillyInt(HexInt):
980            __qualname__ = 'SillyInt'
981            pass
982        class MyOtherEnum(SillyInt, enum.Enum):
983            __qualname__ = 'MyOtherEnum'
984            D = 4
985            E = 5
986            F = 6
987        self.assertIs(MyOtherEnum._member_type_, SillyInt)
988        globals()['SillyInt'] = SillyInt
989        globals()['MyOtherEnum'] = MyOtherEnum
990        test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
991        test_pickle_dump_load(self.assertIs, MyOtherEnum)
992        #
993        # This did not work in 3.9, but does now with pickling by name
994        class UnBrokenInt(int):
995            __qualname__ = 'UnBrokenInt'
996            def __new__(cls, value):
997                return int.__new__(cls, value)
998        class MyUnBrokenEnum(UnBrokenInt, Enum):
999            __qualname__ = 'MyUnBrokenEnum'
1000            G = 7
1001            H = 8
1002            I = 9
1003        self.assertIs(MyUnBrokenEnum._member_type_, UnBrokenInt)
1004        self.assertIs(MyUnBrokenEnum(7), MyUnBrokenEnum.G)
1005        globals()['UnBrokenInt'] = UnBrokenInt
1006        globals()['MyUnBrokenEnum'] = MyUnBrokenEnum
1007        test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
1008        test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
1009
1010    def test_too_many_data_types(self):
1011        with self.assertRaisesRegex(TypeError, 'too many data types'):
1012            class Huh(str, int, Enum):
1013                One = 1
1014
1015        class MyStr(str):
1016            def hello(self):
1017                return 'hello, %s' % self
1018        class MyInt(int):
1019            def repr(self):
1020                return hex(self)
1021        with self.assertRaisesRegex(TypeError, 'too many data types'):
1022            class Huh(MyStr, MyInt, Enum):
1023                One = 1
1024
1025    def test_hash(self):
1026        Season = self.Season
1027        dates = {}
1028        dates[Season.WINTER] = '1225'
1029        dates[Season.SPRING] = '0315'
1030        dates[Season.SUMMER] = '0704'
1031        dates[Season.AUTUMN] = '1031'
1032        self.assertEqual(dates[Season.AUTUMN], '1031')
1033
1034    def test_intenum_from_scratch(self):
1035        class phy(int, Enum):
1036            pi = 3
1037            tau = 2 * pi
1038        self.assertTrue(phy.pi < phy.tau)
1039
1040    def test_intenum_inherited(self):
1041        class IntEnum(int, Enum):
1042            pass
1043        class phy(IntEnum):
1044            pi = 3
1045            tau = 2 * pi
1046        self.assertTrue(phy.pi < phy.tau)
1047
1048    def test_floatenum_from_scratch(self):
1049        class phy(float, Enum):
1050            pi = 3.1415926
1051            tau = 2 * pi
1052        self.assertTrue(phy.pi < phy.tau)
1053
1054    def test_floatenum_inherited(self):
1055        class FloatEnum(float, Enum):
1056            pass
1057        class phy(FloatEnum):
1058            pi = 3.1415926
1059            tau = 2 * pi
1060        self.assertTrue(phy.pi < phy.tau)
1061
1062    def test_strenum_from_scratch(self):
1063        class phy(str, Enum):
1064            pi = 'Pi'
1065            tau = 'Tau'
1066        self.assertTrue(phy.pi < phy.tau)
1067
1068    def test_strenum_inherited_methods(self):
1069        class phy(StrEnum):
1070            pi = 'Pi'
1071            tau = 'Tau'
1072        self.assertTrue(phy.pi < phy.tau)
1073        self.assertEqual(phy.pi.upper(), 'PI')
1074        self.assertEqual(phy.tau.count('a'), 1)
1075
1076    def test_intenum(self):
1077        class WeekDay(IntEnum):
1078            SUNDAY = 1
1079            MONDAY = 2
1080            TUESDAY = 3
1081            WEDNESDAY = 4
1082            THURSDAY = 5
1083            FRIDAY = 6
1084            SATURDAY = 7
1085
1086        self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
1087        self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
1088
1089        lst = list(WeekDay)
1090        self.assertEqual(len(lst), len(WeekDay))
1091        self.assertEqual(len(WeekDay), 7)
1092        target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
1093        target = target.split()
1094        for i, weekday in enumerate(target, 1):
1095            e = WeekDay(i)
1096            self.assertEqual(e, i)
1097            self.assertEqual(int(e), i)
1098            self.assertEqual(e.name, weekday)
1099            self.assertIn(e, WeekDay)
1100            self.assertEqual(lst.index(e)+1, i)
1101            self.assertTrue(0 < e < 8)
1102            self.assertIs(type(e), WeekDay)
1103            self.assertIsInstance(e, int)
1104            self.assertIsInstance(e, Enum)
1105
1106    def test_intenum_duplicates(self):
1107        class WeekDay(IntEnum):
1108            SUNDAY = 1
1109            MONDAY = 2
1110            TUESDAY = TEUSDAY = 3
1111            WEDNESDAY = 4
1112            THURSDAY = 5
1113            FRIDAY = 6
1114            SATURDAY = 7
1115        self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
1116        self.assertEqual(WeekDay(3).name, 'TUESDAY')
1117        self.assertEqual([k for k,v in WeekDay.__members__.items()
1118                if v.name != k], ['TEUSDAY', ])
1119
1120    def test_intenum_from_bytes(self):
1121        self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
1122        with self.assertRaises(ValueError):
1123            IntStooges.from_bytes(b'\x00\x05', 'big')
1124
1125    def test_floatenum_fromhex(self):
1126        h = float.hex(FloatStooges.MOE.value)
1127        self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
1128        h = float.hex(FloatStooges.MOE.value + 0.01)
1129        with self.assertRaises(ValueError):
1130            FloatStooges.fromhex(h)
1131
1132    def test_pickle_enum(self):
1133        if isinstance(Stooges, Exception):
1134            raise Stooges
1135        test_pickle_dump_load(self.assertIs, Stooges.CURLY)
1136        test_pickle_dump_load(self.assertIs, Stooges)
1137
1138    def test_pickle_int(self):
1139        if isinstance(IntStooges, Exception):
1140            raise IntStooges
1141        test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
1142        test_pickle_dump_load(self.assertIs, IntStooges)
1143
1144    def test_pickle_float(self):
1145        if isinstance(FloatStooges, Exception):
1146            raise FloatStooges
1147        test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
1148        test_pickle_dump_load(self.assertIs, FloatStooges)
1149
1150    def test_pickle_enum_function(self):
1151        if isinstance(Answer, Exception):
1152            raise Answer
1153        test_pickle_dump_load(self.assertIs, Answer.him)
1154        test_pickle_dump_load(self.assertIs, Answer)
1155
1156    def test_pickle_enum_function_with_module(self):
1157        if isinstance(Question, Exception):
1158            raise Question
1159        test_pickle_dump_load(self.assertIs, Question.who)
1160        test_pickle_dump_load(self.assertIs, Question)
1161
1162    def test_enum_function_with_qualname(self):
1163        if isinstance(Theory, Exception):
1164            raise Theory
1165        self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
1166
1167    def test_class_nested_enum_and_pickle_protocol_four(self):
1168        # would normally just have this directly in the class namespace
1169        class NestedEnum(Enum):
1170            twigs = 'common'
1171            shiny = 'rare'
1172
1173        self.__class__.NestedEnum = NestedEnum
1174        self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
1175        test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
1176
1177    def test_pickle_by_name(self):
1178        class ReplaceGlobalInt(IntEnum):
1179            ONE = 1
1180            TWO = 2
1181        ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
1182        for proto in range(HIGHEST_PROTOCOL):
1183            self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
1184
1185    def test_exploding_pickle(self):
1186        BadPickle = Enum(
1187                'BadPickle', 'dill sweet bread-n-butter', module=__name__)
1188        globals()['BadPickle'] = BadPickle
1189        # now break BadPickle to test exception raising
1190        enum._make_class_unpicklable(BadPickle)
1191        test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
1192        test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
1193
1194    def test_string_enum(self):
1195        class SkillLevel(str, Enum):
1196            master = 'what is the sound of one hand clapping?'
1197            journeyman = 'why did the chicken cross the road?'
1198            apprentice = 'knock, knock!'
1199        self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
1200
1201    def test_getattr_getitem(self):
1202        class Period(Enum):
1203            morning = 1
1204            noon = 2
1205            evening = 3
1206            night = 4
1207        self.assertIs(Period(2), Period.noon)
1208        self.assertIs(getattr(Period, 'night'), Period.night)
1209        self.assertIs(Period['morning'], Period.morning)
1210
1211    def test_getattr_dunder(self):
1212        Season = self.Season
1213        self.assertTrue(getattr(Season, '__eq__'))
1214
1215    def test_iteration_order(self):
1216        class Season(Enum):
1217            SUMMER = 2
1218            WINTER = 4
1219            AUTUMN = 3
1220            SPRING = 1
1221        self.assertEqual(
1222                list(Season),
1223                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
1224                )
1225
1226    def test_reversed_iteration_order(self):
1227        self.assertEqual(
1228                list(reversed(self.Season)),
1229                [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
1230                 self.Season.SPRING]
1231                )
1232
1233    def test_programmatic_function_string(self):
1234        SummerMonth = Enum('SummerMonth', 'june july august')
1235        lst = list(SummerMonth)
1236        self.assertEqual(len(lst), len(SummerMonth))
1237        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1238        self.assertEqual(
1239                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1240                lst,
1241                )
1242        for i, month in enumerate('june july august'.split(), 1):
1243            e = SummerMonth(i)
1244            self.assertEqual(int(e.value), i)
1245            self.assertNotEqual(e, i)
1246            self.assertEqual(e.name, month)
1247            self.assertIn(e, SummerMonth)
1248            self.assertIs(type(e), SummerMonth)
1249
1250    def test_programmatic_function_string_with_start(self):
1251        SummerMonth = Enum('SummerMonth', 'june july august', start=10)
1252        lst = list(SummerMonth)
1253        self.assertEqual(len(lst), len(SummerMonth))
1254        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1255        self.assertEqual(
1256                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1257                lst,
1258                )
1259        for i, month in enumerate('june july august'.split(), 10):
1260            e = SummerMonth(i)
1261            self.assertEqual(int(e.value), i)
1262            self.assertNotEqual(e, i)
1263            self.assertEqual(e.name, month)
1264            self.assertIn(e, SummerMonth)
1265            self.assertIs(type(e), SummerMonth)
1266
1267    def test_programmatic_function_string_list(self):
1268        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
1269        lst = list(SummerMonth)
1270        self.assertEqual(len(lst), len(SummerMonth))
1271        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1272        self.assertEqual(
1273                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1274                lst,
1275                )
1276        for i, month in enumerate('june july august'.split(), 1):
1277            e = SummerMonth(i)
1278            self.assertEqual(int(e.value), i)
1279            self.assertNotEqual(e, i)
1280            self.assertEqual(e.name, month)
1281            self.assertIn(e, SummerMonth)
1282            self.assertIs(type(e), SummerMonth)
1283
1284    def test_programmatic_function_string_list_with_start(self):
1285        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
1286        lst = list(SummerMonth)
1287        self.assertEqual(len(lst), len(SummerMonth))
1288        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1289        self.assertEqual(
1290                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1291                lst,
1292                )
1293        for i, month in enumerate('june july august'.split(), 20):
1294            e = SummerMonth(i)
1295            self.assertEqual(int(e.value), i)
1296            self.assertNotEqual(e, i)
1297            self.assertEqual(e.name, month)
1298            self.assertIn(e, SummerMonth)
1299            self.assertIs(type(e), SummerMonth)
1300
1301    def test_programmatic_function_iterable(self):
1302        SummerMonth = Enum(
1303                'SummerMonth',
1304                (('june', 1), ('july', 2), ('august', 3))
1305                )
1306        lst = list(SummerMonth)
1307        self.assertEqual(len(lst), len(SummerMonth))
1308        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1309        self.assertEqual(
1310                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1311                lst,
1312                )
1313        for i, month in enumerate('june july august'.split(), 1):
1314            e = SummerMonth(i)
1315            self.assertEqual(int(e.value), i)
1316            self.assertNotEqual(e, i)
1317            self.assertEqual(e.name, month)
1318            self.assertIn(e, SummerMonth)
1319            self.assertIs(type(e), SummerMonth)
1320
1321    def test_programmatic_function_from_dict(self):
1322        SummerMonth = Enum(
1323                'SummerMonth',
1324                OrderedDict((('june', 1), ('july', 2), ('august', 3)))
1325                )
1326        lst = list(SummerMonth)
1327        self.assertEqual(len(lst), len(SummerMonth))
1328        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1329        self.assertEqual(
1330                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1331                lst,
1332                )
1333        for i, month in enumerate('june july august'.split(), 1):
1334            e = SummerMonth(i)
1335            self.assertEqual(int(e.value), i)
1336            self.assertNotEqual(e, i)
1337            self.assertEqual(e.name, month)
1338            self.assertIn(e, SummerMonth)
1339            self.assertIs(type(e), SummerMonth)
1340
1341    def test_programmatic_function_type(self):
1342        SummerMonth = Enum('SummerMonth', 'june july august', type=int)
1343        lst = list(SummerMonth)
1344        self.assertEqual(len(lst), len(SummerMonth))
1345        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1346        self.assertEqual(
1347                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1348                lst,
1349                )
1350        for i, month in enumerate('june july august'.split(), 1):
1351            e = SummerMonth(i)
1352            self.assertEqual(e, i)
1353            self.assertEqual(e.name, month)
1354            self.assertIn(e, SummerMonth)
1355            self.assertIs(type(e), SummerMonth)
1356
1357    def test_programmatic_function_type_with_start(self):
1358        SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1359        lst = list(SummerMonth)
1360        self.assertEqual(len(lst), len(SummerMonth))
1361        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1362        self.assertEqual(
1363                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1364                lst,
1365                )
1366        for i, month in enumerate('june july august'.split(), 30):
1367            e = SummerMonth(i)
1368            self.assertEqual(e, i)
1369            self.assertEqual(e.name, month)
1370            self.assertIn(e, SummerMonth)
1371            self.assertIs(type(e), SummerMonth)
1372
1373    def test_programmatic_function_type_from_subclass(self):
1374        SummerMonth = IntEnum('SummerMonth', 'june july august')
1375        lst = list(SummerMonth)
1376        self.assertEqual(len(lst), len(SummerMonth))
1377        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1378        self.assertEqual(
1379                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1380                lst,
1381                )
1382        for i, month in enumerate('june july august'.split(), 1):
1383            e = SummerMonth(i)
1384            self.assertEqual(e, i)
1385            self.assertEqual(e.name, month)
1386            self.assertIn(e, SummerMonth)
1387            self.assertIs(type(e), SummerMonth)
1388
1389    def test_programmatic_function_type_from_subclass_with_start(self):
1390        SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1391        lst = list(SummerMonth)
1392        self.assertEqual(len(lst), len(SummerMonth))
1393        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1394        self.assertEqual(
1395                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1396                lst,
1397                )
1398        for i, month in enumerate('june july august'.split(), 40):
1399            e = SummerMonth(i)
1400            self.assertEqual(e, i)
1401            self.assertEqual(e.name, month)
1402            self.assertIn(e, SummerMonth)
1403            self.assertIs(type(e), SummerMonth)
1404
1405    def test_subclassing(self):
1406        if isinstance(Name, Exception):
1407            raise Name
1408        self.assertEqual(Name.BDFL, 'Guido van Rossum')
1409        self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1410        self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
1411        test_pickle_dump_load(self.assertIs, Name.BDFL)
1412
1413    def test_extending(self):
1414        class Color(Enum):
1415            red = 1
1416            green = 2
1417            blue = 3
1418        with self.assertRaises(TypeError):
1419            class MoreColor(Color):
1420                cyan = 4
1421                magenta = 5
1422                yellow = 6
1423        with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1424            class EvenMoreColor(Color, IntEnum):
1425                chartruese = 7
1426
1427    def test_exclude_methods(self):
1428        class whatever(Enum):
1429            this = 'that'
1430            these = 'those'
1431            def really(self):
1432                return 'no, not %s' % self.value
1433        self.assertIsNot(type(whatever.really), whatever)
1434        self.assertEqual(whatever.this.really(), 'no, not that')
1435
1436    def test_wrong_inheritance_order(self):
1437        with self.assertRaises(TypeError):
1438            class Wrong(Enum, str):
1439                NotHere = 'error before this point'
1440
1441    def test_intenum_transitivity(self):
1442        class number(IntEnum):
1443            one = 1
1444            two = 2
1445            three = 3
1446        class numero(IntEnum):
1447            uno = 1
1448            dos = 2
1449            tres = 3
1450        self.assertEqual(number.one, numero.uno)
1451        self.assertEqual(number.two, numero.dos)
1452        self.assertEqual(number.three, numero.tres)
1453
1454    def test_wrong_enum_in_call(self):
1455        class Monochrome(Enum):
1456            black = 0
1457            white = 1
1458        class Gender(Enum):
1459            male = 0
1460            female = 1
1461        self.assertRaises(ValueError, Monochrome, Gender.male)
1462
1463    def test_wrong_enum_in_mixed_call(self):
1464        class Monochrome(IntEnum):
1465            black = 0
1466            white = 1
1467        class Gender(Enum):
1468            male = 0
1469            female = 1
1470        self.assertRaises(ValueError, Monochrome, Gender.male)
1471
1472    def test_mixed_enum_in_call_1(self):
1473        class Monochrome(IntEnum):
1474            black = 0
1475            white = 1
1476        class Gender(IntEnum):
1477            male = 0
1478            female = 1
1479        self.assertIs(Monochrome(Gender.female), Monochrome.white)
1480
1481    def test_mixed_enum_in_call_2(self):
1482        class Monochrome(Enum):
1483            black = 0
1484            white = 1
1485        class Gender(IntEnum):
1486            male = 0
1487            female = 1
1488        self.assertIs(Monochrome(Gender.male), Monochrome.black)
1489
1490    def test_flufl_enum(self):
1491        class Fluflnum(Enum):
1492            def __int__(self):
1493                return int(self.value)
1494        class MailManOptions(Fluflnum):
1495            option1 = 1
1496            option2 = 2
1497            option3 = 3
1498        self.assertEqual(int(MailManOptions.option1), 1)
1499
1500    def test_introspection(self):
1501        class Number(IntEnum):
1502            one = 100
1503            two = 200
1504        self.assertIs(Number.one._member_type_, int)
1505        self.assertIs(Number._member_type_, int)
1506        class String(str, Enum):
1507            yarn = 'soft'
1508            rope = 'rough'
1509            wire = 'hard'
1510        self.assertIs(String.yarn._member_type_, str)
1511        self.assertIs(String._member_type_, str)
1512        class Plain(Enum):
1513            vanilla = 'white'
1514            one = 1
1515        self.assertIs(Plain.vanilla._member_type_, object)
1516        self.assertIs(Plain._member_type_, object)
1517
1518    def test_no_such_enum_member(self):
1519        class Color(Enum):
1520            red = 1
1521            green = 2
1522            blue = 3
1523        with self.assertRaises(ValueError):
1524            Color(4)
1525        with self.assertRaises(KeyError):
1526            Color['chartreuse']
1527
1528    def test_new_repr(self):
1529        class Color(Enum):
1530            red = 1
1531            green = 2
1532            blue = 3
1533            def __repr__(self):
1534                return "don't you just love shades of %s?" % self.name
1535        self.assertEqual(
1536                repr(Color.blue),
1537                "don't you just love shades of blue?",
1538                )
1539
1540    def test_inherited_repr(self):
1541        class MyEnum(Enum):
1542            def __repr__(self):
1543                return "My name is %s." % self.name
1544        class MyIntEnum(int, MyEnum):
1545            this = 1
1546            that = 2
1547            theother = 3
1548        self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1549
1550    def test_multiple_mixin_mro(self):
1551        class auto_enum(type(Enum)):
1552            def __new__(metacls, cls, bases, classdict):
1553                temp = type(classdict)()
1554                temp._cls_name = cls
1555                names = set(classdict._member_names)
1556                i = 0
1557                for k in classdict._member_names:
1558                    v = classdict[k]
1559                    if v is Ellipsis:
1560                        v = i
1561                    else:
1562                        i = v
1563                    i += 1
1564                    temp[k] = v
1565                for k, v in classdict.items():
1566                    if k not in names:
1567                        temp[k] = v
1568                return super(auto_enum, metacls).__new__(
1569                        metacls, cls, bases, temp)
1570
1571        class AutoNumberedEnum(Enum, metaclass=auto_enum):
1572            pass
1573
1574        class AutoIntEnum(IntEnum, metaclass=auto_enum):
1575            pass
1576
1577        class TestAutoNumber(AutoNumberedEnum):
1578            a = ...
1579            b = 3
1580            c = ...
1581
1582        class TestAutoInt(AutoIntEnum):
1583            a = ...
1584            b = 3
1585            c = ...
1586
1587    def test_subclasses_with_getnewargs(self):
1588        class NamedInt(int):
1589            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1590            def __new__(cls, *args):
1591                _args = args
1592                name, *args = args
1593                if len(args) == 0:
1594                    raise TypeError("name and value must be specified")
1595                self = int.__new__(cls, *args)
1596                self._intname = name
1597                self._args = _args
1598                return self
1599            def __getnewargs__(self):
1600                return self._args
1601            @property
1602            def __name__(self):
1603                return self._intname
1604            def __repr__(self):
1605                # repr() is updated to include the name and type info
1606                return "{}({!r}, {})".format(
1607                        type(self).__name__,
1608                        self.__name__,
1609                        int.__repr__(self),
1610                        )
1611            def __str__(self):
1612                # str() is unchanged, even if it relies on the repr() fallback
1613                base = int
1614                base_str = base.__str__
1615                if base_str.__objclass__ is object:
1616                    return base.__repr__(self)
1617                return base_str(self)
1618            # for simplicity, we only define one operator that
1619            # propagates expressions
1620            def __add__(self, other):
1621                temp = int(self) + int( other)
1622                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1623                    return NamedInt(
1624                        '({0} + {1})'.format(self.__name__, other.__name__),
1625                        temp,
1626                        )
1627                else:
1628                    return temp
1629
1630        class NEI(NamedInt, Enum):
1631            __qualname__ = 'NEI'      # needed for pickle protocol 4
1632            x = ('the-x', 1)
1633            y = ('the-y', 2)
1634
1635
1636        self.assertIs(NEI.__new__, Enum.__new__)
1637        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1638        globals()['NamedInt'] = NamedInt
1639        globals()['NEI'] = NEI
1640        NI5 = NamedInt('test', 5)
1641        self.assertEqual(NI5, 5)
1642        test_pickle_dump_load(self.assertEqual, NI5, 5)
1643        self.assertEqual(NEI.y.value, 2)
1644        test_pickle_dump_load(self.assertIs, NEI.y)
1645        test_pickle_dump_load(self.assertIs, NEI)
1646
1647    def test_subclasses_with_getnewargs_ex(self):
1648        class NamedInt(int):
1649            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1650            def __new__(cls, *args):
1651                _args = args
1652                name, *args = args
1653                if len(args) == 0:
1654                    raise TypeError("name and value must be specified")
1655                self = int.__new__(cls, *args)
1656                self._intname = name
1657                self._args = _args
1658                return self
1659            def __getnewargs_ex__(self):
1660                return self._args, {}
1661            @property
1662            def __name__(self):
1663                return self._intname
1664            def __repr__(self):
1665                # repr() is updated to include the name and type info
1666                return "{}({!r}, {})".format(
1667                        type(self).__name__,
1668                        self.__name__,
1669                        int.__repr__(self),
1670                        )
1671            def __str__(self):
1672                # str() is unchanged, even if it relies on the repr() fallback
1673                base = int
1674                base_str = base.__str__
1675                if base_str.__objclass__ is object:
1676                    return base.__repr__(self)
1677                return base_str(self)
1678            # for simplicity, we only define one operator that
1679            # propagates expressions
1680            def __add__(self, other):
1681                temp = int(self) + int( other)
1682                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1683                    return NamedInt(
1684                        '({0} + {1})'.format(self.__name__, other.__name__),
1685                        temp,
1686                        )
1687                else:
1688                    return temp
1689
1690        class NEI(NamedInt, Enum):
1691            __qualname__ = 'NEI'      # needed for pickle protocol 4
1692            x = ('the-x', 1)
1693            y = ('the-y', 2)
1694
1695
1696        self.assertIs(NEI.__new__, Enum.__new__)
1697        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1698        globals()['NamedInt'] = NamedInt
1699        globals()['NEI'] = NEI
1700        NI5 = NamedInt('test', 5)
1701        self.assertEqual(NI5, 5)
1702        test_pickle_dump_load(self.assertEqual, NI5, 5)
1703        self.assertEqual(NEI.y.value, 2)
1704        test_pickle_dump_load(self.assertIs, NEI.y)
1705        test_pickle_dump_load(self.assertIs, NEI)
1706
1707    def test_subclasses_with_reduce(self):
1708        class NamedInt(int):
1709            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1710            def __new__(cls, *args):
1711                _args = args
1712                name, *args = args
1713                if len(args) == 0:
1714                    raise TypeError("name and value must be specified")
1715                self = int.__new__(cls, *args)
1716                self._intname = name
1717                self._args = _args
1718                return self
1719            def __reduce__(self):
1720                return self.__class__, self._args
1721            @property
1722            def __name__(self):
1723                return self._intname
1724            def __repr__(self):
1725                # repr() is updated to include the name and type info
1726                return "{}({!r}, {})".format(
1727                        type(self).__name__,
1728                        self.__name__,
1729                        int.__repr__(self),
1730                        )
1731            def __str__(self):
1732                # str() is unchanged, even if it relies on the repr() fallback
1733                base = int
1734                base_str = base.__str__
1735                if base_str.__objclass__ is object:
1736                    return base.__repr__(self)
1737                return base_str(self)
1738            # for simplicity, we only define one operator that
1739            # propagates expressions
1740            def __add__(self, other):
1741                temp = int(self) + int( other)
1742                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1743                    return NamedInt(
1744                        '({0} + {1})'.format(self.__name__, other.__name__),
1745                        temp,
1746                        )
1747                else:
1748                    return temp
1749
1750        class NEI(NamedInt, Enum):
1751            __qualname__ = 'NEI'      # needed for pickle protocol 4
1752            x = ('the-x', 1)
1753            y = ('the-y', 2)
1754
1755
1756        self.assertIs(NEI.__new__, Enum.__new__)
1757        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1758        globals()['NamedInt'] = NamedInt
1759        globals()['NEI'] = NEI
1760        NI5 = NamedInt('test', 5)
1761        self.assertEqual(NI5, 5)
1762        test_pickle_dump_load(self.assertEqual, NI5, 5)
1763        self.assertEqual(NEI.y.value, 2)
1764        test_pickle_dump_load(self.assertIs, NEI.y)
1765        test_pickle_dump_load(self.assertIs, NEI)
1766
1767    def test_subclasses_with_reduce_ex(self):
1768        class NamedInt(int):
1769            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1770            def __new__(cls, *args):
1771                _args = args
1772                name, *args = args
1773                if len(args) == 0:
1774                    raise TypeError("name and value must be specified")
1775                self = int.__new__(cls, *args)
1776                self._intname = name
1777                self._args = _args
1778                return self
1779            def __reduce_ex__(self, proto):
1780                return self.__class__, self._args
1781            @property
1782            def __name__(self):
1783                return self._intname
1784            def __repr__(self):
1785                # repr() is updated to include the name and type info
1786                return "{}({!r}, {})".format(
1787                        type(self).__name__,
1788                        self.__name__,
1789                        int.__repr__(self),
1790                        )
1791            def __str__(self):
1792                # str() is unchanged, even if it relies on the repr() fallback
1793                base = int
1794                base_str = base.__str__
1795                if base_str.__objclass__ is object:
1796                    return base.__repr__(self)
1797                return base_str(self)
1798            # for simplicity, we only define one operator that
1799            # propagates expressions
1800            def __add__(self, other):
1801                temp = int(self) + int( other)
1802                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1803                    return NamedInt(
1804                        '({0} + {1})'.format(self.__name__, other.__name__),
1805                        temp,
1806                        )
1807                else:
1808                    return temp
1809
1810        class NEI(NamedInt, Enum):
1811            __qualname__ = 'NEI'      # needed for pickle protocol 4
1812            x = ('the-x', 1)
1813            y = ('the-y', 2)
1814
1815        self.assertIs(NEI.__new__, Enum.__new__)
1816        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1817        globals()['NamedInt'] = NamedInt
1818        globals()['NEI'] = NEI
1819        NI5 = NamedInt('test', 5)
1820        self.assertEqual(NI5, 5)
1821        test_pickle_dump_load(self.assertEqual, NI5, 5)
1822        self.assertEqual(NEI.y.value, 2)
1823        test_pickle_dump_load(self.assertIs, NEI.y)
1824        test_pickle_dump_load(self.assertIs, NEI)
1825
1826    def test_subclasses_without_direct_pickle_support(self):
1827        class NamedInt(int):
1828            __qualname__ = 'NamedInt'
1829            def __new__(cls, *args):
1830                _args = args
1831                name, *args = args
1832                if len(args) == 0:
1833                    raise TypeError("name and value must be specified")
1834                self = int.__new__(cls, *args)
1835                self._intname = name
1836                self._args = _args
1837                return self
1838            @property
1839            def __name__(self):
1840                return self._intname
1841            def __repr__(self):
1842                # repr() is updated to include the name and type info
1843                return "{}({!r}, {})".format(
1844                        type(self).__name__,
1845                        self.__name__,
1846                        int.__repr__(self),
1847                        )
1848            def __str__(self):
1849                # str() is unchanged, even if it relies on the repr() fallback
1850                base = int
1851                base_str = base.__str__
1852                if base_str.__objclass__ is object:
1853                    return base.__repr__(self)
1854                return base_str(self)
1855            # for simplicity, we only define one operator that
1856            # propagates expressions
1857            def __add__(self, other):
1858                temp = int(self) + int( other)
1859                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1860                    return NamedInt(
1861                        '({0} + {1})'.format(self.__name__, other.__name__),
1862                        temp )
1863                else:
1864                    return temp
1865
1866        class NEI(NamedInt, Enum):
1867            __qualname__ = 'NEI'
1868            x = ('the-x', 1)
1869            y = ('the-y', 2)
1870
1871        self.assertIs(NEI.__new__, Enum.__new__)
1872        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1873        globals()['NamedInt'] = NamedInt
1874        globals()['NEI'] = NEI
1875        NI5 = NamedInt('test', 5)
1876        self.assertEqual(NI5, 5)
1877        self.assertEqual(NEI.y.value, 2)
1878        test_pickle_dump_load(self.assertIs, NEI.y)
1879        test_pickle_dump_load(self.assertIs, NEI)
1880
1881    def test_subclasses_with_direct_pickle_support(self):
1882        class NamedInt(int):
1883            __qualname__ = 'NamedInt'
1884            def __new__(cls, *args):
1885                _args = args
1886                name, *args = args
1887                if len(args) == 0:
1888                    raise TypeError("name and value must be specified")
1889                self = int.__new__(cls, *args)
1890                self._intname = name
1891                self._args = _args
1892                return self
1893            @property
1894            def __name__(self):
1895                return self._intname
1896            def __repr__(self):
1897                # repr() is updated to include the name and type info
1898                return "{}({!r}, {})".format(
1899                        type(self).__name__,
1900                        self.__name__,
1901                        int.__repr__(self),
1902                        )
1903            def __str__(self):
1904                # str() is unchanged, even if it relies on the repr() fallback
1905                base = int
1906                base_str = base.__str__
1907                if base_str.__objclass__ is object:
1908                    return base.__repr__(self)
1909                return base_str(self)
1910            # for simplicity, we only define one operator that
1911            # propagates expressions
1912            def __add__(self, other):
1913                temp = int(self) + int( other)
1914                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1915                    return NamedInt(
1916                        '({0} + {1})'.format(self.__name__, other.__name__),
1917                        temp,
1918                        )
1919                else:
1920                    return temp
1921
1922        class NEI(NamedInt, Enum):
1923            __qualname__ = 'NEI'
1924            x = ('the-x', 1)
1925            y = ('the-y', 2)
1926            def __reduce_ex__(self, proto):
1927                return getattr, (self.__class__, self._name_)
1928
1929        self.assertIs(NEI.__new__, Enum.__new__)
1930        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1931        globals()['NamedInt'] = NamedInt
1932        globals()['NEI'] = NEI
1933        NI5 = NamedInt('test', 5)
1934        self.assertEqual(NI5, 5)
1935        self.assertEqual(NEI.y.value, 2)
1936        test_pickle_dump_load(self.assertIs, NEI.y)
1937        test_pickle_dump_load(self.assertIs, NEI)
1938
1939    def test_tuple_subclass(self):
1940        class SomeTuple(tuple, Enum):
1941            __qualname__ = 'SomeTuple'      # needed for pickle protocol 4
1942            first = (1, 'for the money')
1943            second = (2, 'for the show')
1944            third = (3, 'for the music')
1945        self.assertIs(type(SomeTuple.first), SomeTuple)
1946        self.assertIsInstance(SomeTuple.second, tuple)
1947        self.assertEqual(SomeTuple.third, (3, 'for the music'))
1948        globals()['SomeTuple'] = SomeTuple
1949        test_pickle_dump_load(self.assertIs, SomeTuple.first)
1950
1951    def test_duplicate_values_give_unique_enum_items(self):
1952        class AutoNumber(Enum):
1953            first = ()
1954            second = ()
1955            third = ()
1956            def __new__(cls):
1957                value = len(cls.__members__) + 1
1958                obj = object.__new__(cls)
1959                obj._value_ = value
1960                return obj
1961            def __int__(self):
1962                return int(self._value_)
1963        self.assertEqual(
1964                list(AutoNumber),
1965                [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1966                )
1967        self.assertEqual(int(AutoNumber.second), 2)
1968        self.assertEqual(AutoNumber.third.value, 3)
1969        self.assertIs(AutoNumber(1), AutoNumber.first)
1970
1971    def test_inherited_new_from_enhanced_enum(self):
1972        class AutoNumber(Enum):
1973            def __new__(cls):
1974                value = len(cls.__members__) + 1
1975                obj = object.__new__(cls)
1976                obj._value_ = value
1977                return obj
1978            def __int__(self):
1979                return int(self._value_)
1980        class Color(AutoNumber):
1981            red = ()
1982            green = ()
1983            blue = ()
1984        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1985        self.assertEqual(list(map(int, Color)), [1, 2, 3])
1986
1987    def test_inherited_new_from_mixed_enum(self):
1988        class AutoNumber(IntEnum):
1989            def __new__(cls):
1990                value = len(cls.__members__) + 1
1991                obj = int.__new__(cls, value)
1992                obj._value_ = value
1993                return obj
1994        class Color(AutoNumber):
1995            red = ()
1996            green = ()
1997            blue = ()
1998        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1999        self.assertEqual(list(map(int, Color)), [1, 2, 3])
2000
2001    def test_equality(self):
2002        class OrdinaryEnum(Enum):
2003            a = 1
2004        self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
2005        self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
2006
2007    def test_ordered_mixin(self):
2008        class OrderedEnum(Enum):
2009            def __ge__(self, other):
2010                if self.__class__ is other.__class__:
2011                    return self._value_ >= other._value_
2012                return NotImplemented
2013            def __gt__(self, other):
2014                if self.__class__ is other.__class__:
2015                    return self._value_ > other._value_
2016                return NotImplemented
2017            def __le__(self, other):
2018                if self.__class__ is other.__class__:
2019                    return self._value_ <= other._value_
2020                return NotImplemented
2021            def __lt__(self, other):
2022                if self.__class__ is other.__class__:
2023                    return self._value_ < other._value_
2024                return NotImplemented
2025        class Grade(OrderedEnum):
2026            A = 5
2027            B = 4
2028            C = 3
2029            D = 2
2030            F = 1
2031        self.assertGreater(Grade.A, Grade.B)
2032        self.assertLessEqual(Grade.F, Grade.C)
2033        self.assertLess(Grade.D, Grade.A)
2034        self.assertGreaterEqual(Grade.B, Grade.B)
2035        self.assertEqual(Grade.B, Grade.B)
2036        self.assertNotEqual(Grade.C, Grade.D)
2037
2038    def test_extending2(self):
2039        class Shade(Enum):
2040            def shade(self):
2041                print(self.name)
2042        class Color(Shade):
2043            red = 1
2044            green = 2
2045            blue = 3
2046        with self.assertRaises(TypeError):
2047            class MoreColor(Color):
2048                cyan = 4
2049                magenta = 5
2050                yellow = 6
2051
2052    def test_extending3(self):
2053        class Shade(Enum):
2054            def shade(self):
2055                return self.name
2056        class Color(Shade):
2057            def hex(self):
2058                return '%s hexlified!' % self.value
2059        class MoreColor(Color):
2060            cyan = 4
2061            magenta = 5
2062            yellow = 6
2063        self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
2064
2065    def test_subclass_duplicate_name(self):
2066        class Base(Enum):
2067            def test(self):
2068                pass
2069        class Test(Base):
2070            test = 1
2071        self.assertIs(type(Test.test), Test)
2072
2073    def test_subclass_duplicate_name_dynamic(self):
2074        from types import DynamicClassAttribute
2075        class Base(Enum):
2076            @DynamicClassAttribute
2077            def test(self):
2078                return 'dynamic'
2079        class Test(Base):
2080            test = 1
2081        self.assertEqual(Test.test.test, 'dynamic')
2082        class Base2(Enum):
2083            @enum.property
2084            def flash(self):
2085                return 'flashy dynamic'
2086        class Test(Base2):
2087            flash = 1
2088        self.assertEqual(Test.flash.flash, 'flashy dynamic')
2089
2090    def test_no_duplicates(self):
2091        class UniqueEnum(Enum):
2092            def __init__(self, *args):
2093                cls = self.__class__
2094                if any(self.value == e.value for e in cls):
2095                    a = self.name
2096                    e = cls(self.value).name
2097                    raise ValueError(
2098                            "aliases not allowed in UniqueEnum:  %r --> %r"
2099                            % (a, e)
2100                            )
2101        class Color(UniqueEnum):
2102            red = 1
2103            green = 2
2104            blue = 3
2105        with self.assertRaises(ValueError):
2106            class Color(UniqueEnum):
2107                red = 1
2108                green = 2
2109                blue = 3
2110                grene = 2
2111
2112    def test_init(self):
2113        class Planet(Enum):
2114            MERCURY = (3.303e+23, 2.4397e6)
2115            VENUS   = (4.869e+24, 6.0518e6)
2116            EARTH   = (5.976e+24, 6.37814e6)
2117            MARS    = (6.421e+23, 3.3972e6)
2118            JUPITER = (1.9e+27,   7.1492e7)
2119            SATURN  = (5.688e+26, 6.0268e7)
2120            URANUS  = (8.686e+25, 2.5559e7)
2121            NEPTUNE = (1.024e+26, 2.4746e7)
2122            def __init__(self, mass, radius):
2123                self.mass = mass       # in kilograms
2124                self.radius = radius   # in meters
2125            @property
2126            def surface_gravity(self):
2127                # universal gravitational constant  (m3 kg-1 s-2)
2128                G = 6.67300E-11
2129                return G * self.mass / (self.radius * self.radius)
2130        self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
2131        self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
2132
2133    def test_ignore(self):
2134        class Period(timedelta, Enum):
2135            '''
2136            different lengths of time
2137            '''
2138            def __new__(cls, value, period):
2139                obj = timedelta.__new__(cls, value)
2140                obj._value_ = value
2141                obj.period = period
2142                return obj
2143            _ignore_ = 'Period i'
2144            Period = vars()
2145            for i in range(13):
2146                Period['month_%d' % i] = i*30, 'month'
2147            for i in range(53):
2148                Period['week_%d' % i] = i*7, 'week'
2149            for i in range(32):
2150                Period['day_%d' % i] = i, 'day'
2151            OneDay = day_1
2152            OneWeek = week_1
2153            OneMonth = month_1
2154        self.assertFalse(hasattr(Period, '_ignore_'))
2155        self.assertFalse(hasattr(Period, 'Period'))
2156        self.assertFalse(hasattr(Period, 'i'))
2157        self.assertTrue(isinstance(Period.day_1, timedelta))
2158        self.assertTrue(Period.month_1 is Period.day_30)
2159        self.assertTrue(Period.week_4 is Period.day_28)
2160
2161    def test_nonhash_value(self):
2162        class AutoNumberInAList(Enum):
2163            def __new__(cls):
2164                value = [len(cls.__members__) + 1]
2165                obj = object.__new__(cls)
2166                obj._value_ = value
2167                return obj
2168        class ColorInAList(AutoNumberInAList):
2169            red = ()
2170            green = ()
2171            blue = ()
2172        self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
2173        for enum, value in zip(ColorInAList, range(3)):
2174            value += 1
2175            self.assertEqual(enum.value, [value])
2176            self.assertIs(ColorInAList([value]), enum)
2177
2178    def test_conflicting_types_resolved_in_new(self):
2179        class LabelledIntEnum(int, Enum):
2180            def __new__(cls, *args):
2181                value, label = args
2182                obj = int.__new__(cls, value)
2183                obj.label = label
2184                obj._value_ = value
2185                return obj
2186
2187        class LabelledList(LabelledIntEnum):
2188            unprocessed = (1, "Unprocessed")
2189            payment_complete = (2, "Payment Complete")
2190
2191        self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
2192        self.assertEqual(LabelledList.unprocessed, 1)
2193        self.assertEqual(LabelledList(1), LabelledList.unprocessed)
2194
2195    def test_auto_number(self):
2196        class Color(Enum):
2197            red = auto()
2198            blue = auto()
2199            green = auto()
2200
2201        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2202        self.assertEqual(Color.red.value, 1)
2203        self.assertEqual(Color.blue.value, 2)
2204        self.assertEqual(Color.green.value, 3)
2205
2206    def test_auto_name(self):
2207        class Color(Enum):
2208            def _generate_next_value_(name, start, count, last):
2209                return name
2210            red = auto()
2211            blue = auto()
2212            green = auto()
2213
2214        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2215        self.assertEqual(Color.red.value, 'red')
2216        self.assertEqual(Color.blue.value, 'blue')
2217        self.assertEqual(Color.green.value, 'green')
2218
2219    def test_auto_name_inherit(self):
2220        class AutoNameEnum(Enum):
2221            def _generate_next_value_(name, start, count, last):
2222                return name
2223        class Color(AutoNameEnum):
2224            red = auto()
2225            blue = auto()
2226            green = auto()
2227
2228        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2229        self.assertEqual(Color.red.value, 'red')
2230        self.assertEqual(Color.blue.value, 'blue')
2231        self.assertEqual(Color.green.value, 'green')
2232
2233    def test_auto_garbage(self):
2234        class Color(Enum):
2235            red = 'red'
2236            blue = auto()
2237        self.assertEqual(Color.blue.value, 1)
2238
2239    def test_auto_garbage_corrected(self):
2240        class Color(Enum):
2241            red = 'red'
2242            blue = 2
2243            green = auto()
2244
2245        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2246        self.assertEqual(Color.red.value, 'red')
2247        self.assertEqual(Color.blue.value, 2)
2248        self.assertEqual(Color.green.value, 3)
2249
2250    def test_auto_order(self):
2251        with self.assertRaises(TypeError):
2252            class Color(Enum):
2253                red = auto()
2254                green = auto()
2255                blue = auto()
2256                def _generate_next_value_(name, start, count, last):
2257                    return name
2258
2259    def test_auto_order_wierd(self):
2260        weird_auto = auto()
2261        weird_auto.value = 'pathological case'
2262        class Color(Enum):
2263            red = weird_auto
2264            def _generate_next_value_(name, start, count, last):
2265                return name
2266            blue = auto()
2267        self.assertEqual(list(Color), [Color.red, Color.blue])
2268        self.assertEqual(Color.red.value, 'pathological case')
2269        self.assertEqual(Color.blue.value, 'blue')
2270
2271    def test_duplicate_auto(self):
2272        class Dupes(Enum):
2273            first = primero = auto()
2274            second = auto()
2275            third = auto()
2276        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2277
2278    def test_default_missing(self):
2279        class Color(Enum):
2280            RED = 1
2281            GREEN = 2
2282            BLUE = 3
2283        try:
2284            Color(7)
2285        except ValueError as exc:
2286            self.assertTrue(exc.__context__ is None)
2287        else:
2288            raise Exception('Exception not raised.')
2289
2290    def test_missing(self):
2291        class Color(Enum):
2292            red = 1
2293            green = 2
2294            blue = 3
2295            @classmethod
2296            def _missing_(cls, item):
2297                if item == 'three':
2298                    return cls.blue
2299                elif item == 'bad return':
2300                    # trigger internal error
2301                    return 5
2302                elif item == 'error out':
2303                    raise ZeroDivisionError
2304                else:
2305                    # trigger not found
2306                    return None
2307        self.assertIs(Color('three'), Color.blue)
2308        try:
2309            Color(7)
2310        except ValueError as exc:
2311            self.assertTrue(exc.__context__ is None)
2312        else:
2313            raise Exception('Exception not raised.')
2314        try:
2315            Color('bad return')
2316        except TypeError as exc:
2317            self.assertTrue(isinstance(exc.__context__, ValueError))
2318        else:
2319            raise Exception('Exception not raised.')
2320        try:
2321            Color('error out')
2322        except ZeroDivisionError as exc:
2323            self.assertTrue(isinstance(exc.__context__, ValueError))
2324        else:
2325            raise Exception('Exception not raised.')
2326
2327    def test_missing_exceptions_reset(self):
2328        import gc
2329        import weakref
2330        #
2331        class TestEnum(enum.Enum):
2332            VAL1 = 'val1'
2333            VAL2 = 'val2'
2334        #
2335        class Class1:
2336            def __init__(self):
2337                # Gracefully handle an exception of our own making
2338                try:
2339                    raise ValueError()
2340                except ValueError:
2341                    pass
2342        #
2343        class Class2:
2344            def __init__(self):
2345                # Gracefully handle an exception of Enum's making
2346                try:
2347                    TestEnum('invalid_value')
2348                except ValueError:
2349                    pass
2350        # No strong refs here so these are free to die.
2351        class_1_ref = weakref.ref(Class1())
2352        class_2_ref = weakref.ref(Class2())
2353        #
2354        # The exception raised by Enum creates a reference loop and thus
2355        # Class2 instances will stick around until the next garbage collection
2356        # cycle, unlike Class1.
2357        gc.collect()  # For PyPy or other GCs.
2358        self.assertIs(class_1_ref(), None)
2359        self.assertIs(class_2_ref(), None)
2360
2361    def test_multiple_mixin(self):
2362        class MaxMixin:
2363            @classproperty
2364            def MAX(cls):
2365                max = len(cls)
2366                cls.MAX = max
2367                return max
2368        class StrMixin:
2369            def __str__(self):
2370                return self._name_.lower()
2371        class SomeEnum(Enum):
2372            def behavior(self):
2373                return 'booyah'
2374        class AnotherEnum(Enum):
2375            def behavior(self):
2376                return 'nuhuh!'
2377            def social(self):
2378                return "what's up?"
2379        class Color(MaxMixin, Enum):
2380            RED = auto()
2381            GREEN = auto()
2382            BLUE = auto()
2383        self.assertEqual(Color.RED.value, 1)
2384        self.assertEqual(Color.GREEN.value, 2)
2385        self.assertEqual(Color.BLUE.value, 3)
2386        self.assertEqual(Color.MAX, 3)
2387        self.assertEqual(str(Color.BLUE), 'BLUE')
2388        class Color(MaxMixin, StrMixin, Enum):
2389            RED = auto()
2390            GREEN = auto()
2391            BLUE = auto()
2392        self.assertEqual(Color.RED.value, 1)
2393        self.assertEqual(Color.GREEN.value, 2)
2394        self.assertEqual(Color.BLUE.value, 3)
2395        self.assertEqual(Color.MAX, 3)
2396        self.assertEqual(str(Color.BLUE), 'blue')
2397        class Color(StrMixin, MaxMixin, Enum):
2398            RED = auto()
2399            GREEN = auto()
2400            BLUE = auto()
2401        self.assertEqual(Color.RED.value, 1)
2402        self.assertEqual(Color.GREEN.value, 2)
2403        self.assertEqual(Color.BLUE.value, 3)
2404        self.assertEqual(Color.MAX, 3)
2405        self.assertEqual(str(Color.BLUE), 'blue')
2406        class CoolColor(StrMixin, SomeEnum, Enum):
2407            RED = auto()
2408            GREEN = auto()
2409            BLUE = auto()
2410        self.assertEqual(CoolColor.RED.value, 1)
2411        self.assertEqual(CoolColor.GREEN.value, 2)
2412        self.assertEqual(CoolColor.BLUE.value, 3)
2413        self.assertEqual(str(CoolColor.BLUE), 'blue')
2414        self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2415        class CoolerColor(StrMixin, AnotherEnum, Enum):
2416            RED = auto()
2417            GREEN = auto()
2418            BLUE = auto()
2419        self.assertEqual(CoolerColor.RED.value, 1)
2420        self.assertEqual(CoolerColor.GREEN.value, 2)
2421        self.assertEqual(CoolerColor.BLUE.value, 3)
2422        self.assertEqual(str(CoolerColor.BLUE), 'blue')
2423        self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2424        self.assertEqual(CoolerColor.RED.social(), "what's up?")
2425        class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2426            RED = auto()
2427            GREEN = auto()
2428            BLUE = auto()
2429        self.assertEqual(CoolestColor.RED.value, 1)
2430        self.assertEqual(CoolestColor.GREEN.value, 2)
2431        self.assertEqual(CoolestColor.BLUE.value, 3)
2432        self.assertEqual(str(CoolestColor.BLUE), 'blue')
2433        self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2434        self.assertEqual(CoolestColor.RED.social(), "what's up?")
2435        class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2436            RED = auto()
2437            GREEN = auto()
2438            BLUE = auto()
2439        self.assertEqual(ConfusedColor.RED.value, 1)
2440        self.assertEqual(ConfusedColor.GREEN.value, 2)
2441        self.assertEqual(ConfusedColor.BLUE.value, 3)
2442        self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2443        self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2444        self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2445        class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2446            RED = auto()
2447            GREEN = auto()
2448            BLUE = auto()
2449        self.assertEqual(ReformedColor.RED.value, 1)
2450        self.assertEqual(ReformedColor.GREEN.value, 2)
2451        self.assertEqual(ReformedColor.BLUE.value, 3)
2452        self.assertEqual(str(ReformedColor.BLUE), 'blue')
2453        self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2454        self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2455        self.assertTrue(issubclass(ReformedColor, int))
2456
2457    def test_multiple_inherited_mixin(self):
2458        @unique
2459        class Decision1(StrEnum):
2460            REVERT = "REVERT"
2461            REVERT_ALL = "REVERT_ALL"
2462            RETRY = "RETRY"
2463        class MyEnum(StrEnum):
2464            pass
2465        @unique
2466        class Decision2(MyEnum):
2467            REVERT = "REVERT"
2468            REVERT_ALL = "REVERT_ALL"
2469            RETRY = "RETRY"
2470
2471    def test_multiple_mixin_inherited(self):
2472        class MyInt(int):
2473            def __new__(cls, value):
2474                return super().__new__(cls, value)
2475
2476        class HexMixin:
2477            def __repr__(self):
2478                return hex(self)
2479
2480        class MyIntEnum(HexMixin, MyInt, enum.Enum):
2481            pass
2482
2483        class Foo(MyIntEnum):
2484            TEST = 1
2485        self.assertTrue(isinstance(Foo.TEST, MyInt))
2486        self.assertEqual(repr(Foo.TEST), "0x1")
2487
2488        class Fee(MyIntEnum):
2489            TEST = 1
2490            def __new__(cls, value):
2491                value += 1
2492                member = int.__new__(cls, value)
2493                member._value_ = value
2494                return member
2495        self.assertEqual(Fee.TEST, 2)
2496
2497    def test_miltuple_mixin_with_common_data_type(self):
2498        class CaseInsensitiveStrEnum(str, Enum):
2499            @classmethod
2500            def _missing_(cls, value):
2501                for member in cls._member_map_.values():
2502                    if member._value_.lower() == value.lower():
2503                        return member
2504                return super()._missing_(value)
2505        #
2506        class LenientStrEnum(str, Enum):
2507            def __init__(self, *args):
2508                self._valid = True
2509            @classmethod
2510            def _missing_(cls, value):
2511                unknown = cls._member_type_.__new__(cls, value)
2512                unknown._valid = False
2513                unknown._name_ = value.upper()
2514                unknown._value_ = value
2515                cls._member_map_[value] = unknown
2516                return unknown
2517            @property
2518            def valid(self):
2519                return self._valid
2520        #
2521        class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2522            ACTIVE = "active"
2523            PENDING = "pending"
2524            TERMINATED = "terminated"
2525        #
2526        JS = JobStatus
2527        self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2528        self.assertEqual(JS.ACTIVE, 'active')
2529        self.assertEqual(JS.ACTIVE.value, 'active')
2530        self.assertIs(JS('Active'), JS.ACTIVE)
2531        self.assertTrue(JS.ACTIVE.valid)
2532        missing = JS('missing')
2533        self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2534        self.assertEqual(JS.ACTIVE, 'active')
2535        self.assertEqual(JS.ACTIVE.value, 'active')
2536        self.assertIs(JS('Active'), JS.ACTIVE)
2537        self.assertTrue(JS.ACTIVE.valid)
2538        self.assertTrue(isinstance(missing, JS))
2539        self.assertFalse(missing.valid)
2540
2541    def test_empty_globals(self):
2542        # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2543        # when using compile and exec because f_globals is empty
2544        code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2545        code = compile(code, "<string>", "exec")
2546        global_ns = {}
2547        local_ls = {}
2548        exec(code, global_ns, local_ls)
2549
2550    def test_strenum(self):
2551        class GoodStrEnum(StrEnum):
2552            one = '1'
2553            two = '2'
2554            three = b'3', 'ascii'
2555            four = b'4', 'latin1', 'strict'
2556        self.assertEqual(GoodStrEnum.one, '1')
2557        self.assertEqual(str(GoodStrEnum.one), '1')
2558        self.assertEqual('{}'.format(GoodStrEnum.one), '1')
2559        self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2560        self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2561        self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one')
2562        #
2563        class DumbMixin:
2564            def __str__(self):
2565                return "don't do this"
2566        class DumbStrEnum(DumbMixin, StrEnum):
2567            five = '5'
2568            six = '6'
2569            seven = '7'
2570        self.assertEqual(DumbStrEnum.seven, '7')
2571        self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2572        #
2573        class EnumMixin(Enum):
2574            def hello(self):
2575                print('hello from %s' % (self, ))
2576        class HelloEnum(EnumMixin, StrEnum):
2577            eight = '8'
2578        self.assertEqual(HelloEnum.eight, '8')
2579        self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2580        #
2581        class GoodbyeMixin:
2582            def goodbye(self):
2583                print('%s wishes you a fond farewell')
2584        class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2585            nine = '9'
2586        self.assertEqual(GoodbyeEnum.nine, '9')
2587        self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2588        #
2589        with self.assertRaisesRegex(TypeError, '1 is not a string'):
2590            class FirstFailedStrEnum(StrEnum):
2591                one = 1
2592                two = '2'
2593        with self.assertRaisesRegex(TypeError, "2 is not a string"):
2594            class SecondFailedStrEnum(StrEnum):
2595                one = '1'
2596                two = 2,
2597                three = '3'
2598        with self.assertRaisesRegex(TypeError, '2 is not a string'):
2599            class ThirdFailedStrEnum(StrEnum):
2600                one = '1'
2601                two = 2
2602        with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2603            class ThirdFailedStrEnum(StrEnum):
2604                one = '1'
2605                two = b'2', sys.getdefaultencoding
2606        with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2607            class ThirdFailedStrEnum(StrEnum):
2608                one = '1'
2609                two = b'2', 'ascii', 9
2610
2611    @unittest.skipIf(
2612            python_version >= (3, 12),
2613            'mixin-format now uses member instead of member.value',
2614            )
2615    def test_custom_strenum_with_warning(self):
2616        class CustomStrEnum(str, Enum):
2617            pass
2618        class OkayEnum(CustomStrEnum):
2619            one = '1'
2620            two = '2'
2621            three = b'3', 'ascii'
2622            four = b'4', 'latin1', 'strict'
2623        self.assertEqual(OkayEnum.one, '1')
2624        self.assertEqual(str(OkayEnum.one), 'one')
2625        with self.assertWarns(DeprecationWarning):
2626            self.assertEqual('{}'.format(OkayEnum.one), '1')
2627            self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one))
2628        self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
2629        #
2630        class DumbMixin:
2631            def __str__(self):
2632                return "don't do this"
2633        class DumbStrEnum(DumbMixin, CustomStrEnum):
2634            five = '5'
2635            six = '6'
2636            seven = '7'
2637        self.assertEqual(DumbStrEnum.seven, '7')
2638        self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2639        #
2640        class EnumMixin(Enum):
2641            def hello(self):
2642                print('hello from %s' % (self, ))
2643        class HelloEnum(EnumMixin, CustomStrEnum):
2644            eight = '8'
2645        self.assertEqual(HelloEnum.eight, '8')
2646        self.assertEqual(str(HelloEnum.eight), 'eight')
2647        #
2648        class GoodbyeMixin:
2649            def goodbye(self):
2650                print('%s wishes you a fond farewell')
2651        class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
2652            nine = '9'
2653        self.assertEqual(GoodbyeEnum.nine, '9')
2654        self.assertEqual(str(GoodbyeEnum.nine), 'nine')
2655        #
2656        class FirstFailedStrEnum(CustomStrEnum):
2657            one = 1   # this will become '1'
2658            two = '2'
2659        class SecondFailedStrEnum(CustomStrEnum):
2660            one = '1'
2661            two = 2,  # this will become '2'
2662            three = '3'
2663        class ThirdFailedStrEnum(CustomStrEnum):
2664            one = '1'
2665            two = 2  # this will become '2'
2666        with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
2667            class ThirdFailedStrEnum(CustomStrEnum):
2668                one = '1'
2669                two = b'2', sys.getdefaultencoding
2670        with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
2671            class ThirdFailedStrEnum(CustomStrEnum):
2672                one = '1'
2673                two = b'2', 'ascii', 9
2674
2675    @unittest.skipIf(
2676            python_version < (3, 12),
2677            'mixin-format currently uses member.value',
2678            )
2679    def test_custom_strenum(self):
2680        class CustomStrEnum(str, Enum):
2681            pass
2682        class OkayEnum(CustomStrEnum):
2683            one = '1'
2684            two = '2'
2685            three = b'3', 'ascii'
2686            four = b'4', 'latin1', 'strict'
2687        self.assertEqual(OkayEnum.one, '1')
2688        self.assertEqual(str(OkayEnum.one), 'one')
2689        self.assertEqual('{}'.format(OkayEnum.one), 'one')
2690        self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
2691        #
2692        class DumbMixin:
2693            def __str__(self):
2694                return "don't do this"
2695        class DumbStrEnum(DumbMixin, CustomStrEnum):
2696            five = '5'
2697            six = '6'
2698            seven = '7'
2699        self.assertEqual(DumbStrEnum.seven, '7')
2700        self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2701        #
2702        class EnumMixin(Enum):
2703            def hello(self):
2704                print('hello from %s' % (self, ))
2705        class HelloEnum(EnumMixin, CustomStrEnum):
2706            eight = '8'
2707        self.assertEqual(HelloEnum.eight, '8')
2708        self.assertEqual(str(HelloEnum.eight), 'eight')
2709        #
2710        class GoodbyeMixin:
2711            def goodbye(self):
2712                print('%s wishes you a fond farewell')
2713        class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
2714            nine = '9'
2715        self.assertEqual(GoodbyeEnum.nine, '9')
2716        self.assertEqual(str(GoodbyeEnum.nine), 'nine')
2717        #
2718        class FirstFailedStrEnum(CustomStrEnum):
2719            one = 1   # this will become '1'
2720            two = '2'
2721        class SecondFailedStrEnum(CustomStrEnum):
2722            one = '1'
2723            two = 2,  # this will become '2'
2724            three = '3'
2725        class ThirdFailedStrEnum(CustomStrEnum):
2726            one = '1'
2727            two = 2  # this will become '2'
2728        with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
2729            class ThirdFailedStrEnum(CustomStrEnum):
2730                one = '1'
2731                two = b'2', sys.getdefaultencoding
2732        with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
2733            class ThirdFailedStrEnum(CustomStrEnum):
2734                one = '1'
2735                two = b'2', 'ascii', 9
2736
2737    def test_missing_value_error(self):
2738        with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2739            class Combined(str, Enum):
2740                #
2741                def __new__(cls, value, sequence):
2742                    enum = str.__new__(cls, value)
2743                    if '(' in value:
2744                        fis_name, segment = value.split('(', 1)
2745                        segment = segment.strip(' )')
2746                    else:
2747                        fis_name = value
2748                        segment = None
2749                    enum.fis_name = fis_name
2750                    enum.segment = segment
2751                    enum.sequence = sequence
2752                    return enum
2753                #
2754                def __repr__(self):
2755                    return "<%s.%s>" % (self.__class__.__name__, self._name_)
2756                #
2757                key_type      = 'An$(1,2)', 0
2758                company_id    = 'An$(3,2)', 1
2759                code          = 'An$(5,1)', 2
2760                description   = 'Bn$',      3
2761
2762    @unittest.skipUnless(
2763            python_version == (3, 9),
2764            'private variables are now normal attributes',
2765            )
2766    def test_warning_for_private_variables(self):
2767        with self.assertWarns(DeprecationWarning):
2768            class Private(Enum):
2769                __corporal = 'Radar'
2770        self.assertEqual(Private._Private__corporal.value, 'Radar')
2771        try:
2772            with self.assertWarns(DeprecationWarning):
2773                class Private(Enum):
2774                    __major_ = 'Hoolihan'
2775        except ValueError:
2776            pass
2777
2778    def test_private_variable_is_normal_attribute(self):
2779        class Private(Enum):
2780            __corporal = 'Radar'
2781            __major_ = 'Hoolihan'
2782        self.assertEqual(Private._Private__corporal, 'Radar')
2783        self.assertEqual(Private._Private__major_, 'Hoolihan')
2784
2785    @unittest.skipUnless(
2786            python_version < (3, 12),
2787            'member-member access now raises an exception',
2788            )
2789    def test_warning_for_member_from_member_access(self):
2790        with self.assertWarns(DeprecationWarning):
2791            class Di(Enum):
2792                YES = 1
2793                NO = 0
2794            nope = Di.YES.NO
2795        self.assertIs(Di.NO, nope)
2796
2797    @unittest.skipUnless(
2798            python_version >= (3, 12),
2799            'member-member access currently issues a warning',
2800            )
2801    def test_exception_for_member_from_member_access(self):
2802        with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2803            class Di(Enum):
2804                YES = 1
2805                NO = 0
2806            nope = Di.YES.NO
2807
2808    def test_strenum_auto(self):
2809        class Strings(StrEnum):
2810            ONE = auto()
2811            TWO = auto()
2812        self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2813
2814
2815    def test_dynamic_members_with_static_methods(self):
2816        #
2817        foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2818        class Foo(Enum):
2819            vars().update({
2820                    k: v
2821                    for k, v in foo_defines.items()
2822                    if k.startswith('FOO_')
2823                    })
2824            def upper(self):
2825                return self.value.upper()
2826        self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2827        self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2828        self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2829        #
2830        with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2831            class FooBar(Enum):
2832                vars().update({
2833                        k: v
2834                        for k, v in foo_defines.items()
2835                        if k.startswith('FOO_')
2836                        },
2837                        **{'FOO_CAT': 'small'},
2838                        )
2839                def upper(self):
2840                    return self.value.upper()
2841
2842
2843class TestOrder(unittest.TestCase):
2844
2845    def test_same_members(self):
2846        class Color(Enum):
2847            _order_ = 'red green blue'
2848            red = 1
2849            green = 2
2850            blue = 3
2851
2852    def test_same_members_with_aliases(self):
2853        class Color(Enum):
2854            _order_ = 'red green blue'
2855            red = 1
2856            green = 2
2857            blue = 3
2858            verde = green
2859
2860    def test_same_members_wrong_order(self):
2861        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2862            class Color(Enum):
2863                _order_ = 'red green blue'
2864                red = 1
2865                blue = 3
2866                green = 2
2867
2868    def test_order_has_extra_members(self):
2869        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2870            class Color(Enum):
2871                _order_ = 'red green blue purple'
2872                red = 1
2873                green = 2
2874                blue = 3
2875
2876    def test_order_has_extra_members_with_aliases(self):
2877        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2878            class Color(Enum):
2879                _order_ = 'red green blue purple'
2880                red = 1
2881                green = 2
2882                blue = 3
2883                verde = green
2884
2885    def test_enum_has_extra_members(self):
2886        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2887            class Color(Enum):
2888                _order_ = 'red green blue'
2889                red = 1
2890                green = 2
2891                blue = 3
2892                purple = 4
2893
2894    def test_enum_has_extra_members_with_aliases(self):
2895        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2896            class Color(Enum):
2897                _order_ = 'red green blue'
2898                red = 1
2899                green = 2
2900                blue = 3
2901                purple = 4
2902                verde = green
2903
2904
2905class TestFlag(unittest.TestCase):
2906    """Tests of the Flags."""
2907
2908    class Perm(Flag):
2909        R, W, X = 4, 2, 1
2910
2911    class Open(Flag):
2912        RO = 0
2913        WO = 1
2914        RW = 2
2915        AC = 3
2916        CE = 1<<19
2917
2918    class Color(Flag):
2919        BLACK = 0
2920        RED = 1
2921        ROJO = 1
2922        GREEN = 2
2923        BLUE = 4
2924        PURPLE = RED|BLUE
2925        WHITE = RED|GREEN|BLUE
2926        BLANCO = RED|GREEN|BLUE
2927
2928    def test_str(self):
2929        Perm = self.Perm
2930        self.assertEqual(str(Perm.R), 'R')
2931        self.assertEqual(str(Perm.W), 'W')
2932        self.assertEqual(str(Perm.X), 'X')
2933        self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2934        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
2935        self.assertEqual(str(Perm(0)), 'Perm(0)')
2936        self.assertEqual(str(~Perm.R), 'W|X')
2937        self.assertEqual(str(~Perm.W), 'R|X')
2938        self.assertEqual(str(~Perm.X), 'R|W')
2939        self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
2940        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2941        self.assertEqual(str(Perm(~0)), 'R|W|X')
2942
2943        Open = self.Open
2944        self.assertEqual(str(Open.RO), 'RO')
2945        self.assertEqual(str(Open.WO), 'WO')
2946        self.assertEqual(str(Open.AC), 'AC')
2947        self.assertEqual(str(Open.RO | Open.CE), 'CE')
2948        self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2949        self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2950        self.assertEqual(str(~Open.WO), 'RW|CE')
2951        self.assertEqual(str(~Open.AC), 'CE')
2952        self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2953        self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
2954
2955    def test_repr(self):
2956        Perm = self.Perm
2957        self.assertEqual(repr(Perm.R), 'Perm.R')
2958        self.assertEqual(repr(Perm.W), 'Perm.W')
2959        self.assertEqual(repr(Perm.X), 'Perm.X')
2960        self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2961        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2962        self.assertEqual(repr(Perm(0)), '0x0')
2963        self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2964        self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2965        self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2966        self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2967        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2968        self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
2969
2970        Open = self.Open
2971        self.assertEqual(repr(Open.RO), 'Open.RO')
2972        self.assertEqual(repr(Open.WO), 'Open.WO')
2973        self.assertEqual(repr(Open.AC), 'Open.AC')
2974        self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2975        self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2976        self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2977        self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2978        self.assertEqual(repr(~Open.AC), 'Open.CE')
2979        self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2980        self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
2981
2982    def test_format(self):
2983        Perm = self.Perm
2984        self.assertEqual(format(Perm.R, ''), 'R')
2985        self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
2986
2987    def test_or(self):
2988        Perm = self.Perm
2989        for i in Perm:
2990            for j in Perm:
2991                self.assertEqual((i | j), Perm(i.value | j.value))
2992                self.assertEqual((i | j).value, i.value | j.value)
2993                self.assertIs(type(i | j), Perm)
2994        for i in Perm:
2995            self.assertIs(i | i, i)
2996        Open = self.Open
2997        self.assertIs(Open.RO | Open.CE, Open.CE)
2998
2999    def test_and(self):
3000        Perm = self.Perm
3001        RW = Perm.R | Perm.W
3002        RX = Perm.R | Perm.X
3003        WX = Perm.W | Perm.X
3004        RWX = Perm.R | Perm.W | Perm.X
3005        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3006        for i in values:
3007            for j in values:
3008                self.assertEqual((i & j).value, i.value & j.value)
3009                self.assertIs(type(i & j), Perm)
3010        for i in Perm:
3011            self.assertIs(i & i, i)
3012            self.assertIs(i & RWX, i)
3013            self.assertIs(RWX & i, i)
3014        Open = self.Open
3015        self.assertIs(Open.RO & Open.CE, Open.RO)
3016
3017    def test_xor(self):
3018        Perm = self.Perm
3019        for i in Perm:
3020            for j in Perm:
3021                self.assertEqual((i ^ j).value, i.value ^ j.value)
3022                self.assertIs(type(i ^ j), Perm)
3023        for i in Perm:
3024            self.assertIs(i ^ Perm(0), i)
3025            self.assertIs(Perm(0) ^ i, i)
3026        Open = self.Open
3027        self.assertIs(Open.RO ^ Open.CE, Open.CE)
3028        self.assertIs(Open.CE ^ Open.CE, Open.RO)
3029
3030    def test_invert(self):
3031        Perm = self.Perm
3032        RW = Perm.R | Perm.W
3033        RX = Perm.R | Perm.X
3034        WX = Perm.W | Perm.X
3035        RWX = Perm.R | Perm.W | Perm.X
3036        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3037        for i in values:
3038            self.assertIs(type(~i), Perm)
3039            self.assertEqual(~~i, i)
3040        for i in Perm:
3041            self.assertIs(~~i, i)
3042        Open = self.Open
3043        self.assertIs(Open.WO & ~Open.WO, Open.RO)
3044        self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3045
3046    def test_bool(self):
3047        Perm = self.Perm
3048        for f in Perm:
3049            self.assertTrue(f)
3050        Open = self.Open
3051        for f in Open:
3052            self.assertEqual(bool(f.value), bool(f))
3053
3054    def test_boundary(self):
3055        self.assertIs(enum.Flag._boundary_, STRICT)
3056        class Iron(Flag, boundary=STRICT):
3057            ONE = 1
3058            TWO = 2
3059            EIGHT = 8
3060        self.assertIs(Iron._boundary_, STRICT)
3061        #
3062        class Water(Flag, boundary=CONFORM):
3063            ONE = 1
3064            TWO = 2
3065            EIGHT = 8
3066        self.assertIs(Water._boundary_, CONFORM)
3067        #
3068        class Space(Flag, boundary=EJECT):
3069            ONE = 1
3070            TWO = 2
3071            EIGHT = 8
3072        self.assertIs(Space._boundary_, EJECT)
3073        #
3074        class Bizarre(Flag, boundary=KEEP):
3075            b = 3
3076            c = 4
3077            d = 6
3078        #
3079        self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
3080        #
3081        self.assertIs(Water(7), Water.ONE|Water.TWO)
3082        self.assertIs(Water(~9), Water.TWO)
3083        #
3084        self.assertEqual(Space(7), 7)
3085        self.assertTrue(type(Space(7)) is int)
3086        #
3087        self.assertEqual(list(Bizarre), [Bizarre.c])
3088        self.assertIs(Bizarre(3), Bizarre.b)
3089        self.assertIs(Bizarre(6), Bizarre.d)
3090
3091    def test_iter(self):
3092        Color = self.Color
3093        Open = self.Open
3094        self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3095        self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3096
3097    def test_programatic_function_string(self):
3098        Perm = Flag('Perm', 'R W X')
3099        lst = list(Perm)
3100        self.assertEqual(len(lst), len(Perm))
3101        self.assertEqual(len(Perm), 3, Perm)
3102        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3103        for i, n in enumerate('R W X'.split()):
3104            v = 1<<i
3105            e = Perm(v)
3106            self.assertEqual(e.value, v)
3107            self.assertEqual(type(e.value), int)
3108            self.assertEqual(e.name, n)
3109            self.assertIn(e, Perm)
3110            self.assertIs(type(e), Perm)
3111
3112    def test_programatic_function_string_with_start(self):
3113        Perm = Flag('Perm', 'R W X', start=8)
3114        lst = list(Perm)
3115        self.assertEqual(len(lst), len(Perm))
3116        self.assertEqual(len(Perm), 3, Perm)
3117        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3118        for i, n in enumerate('R W X'.split()):
3119            v = 8<<i
3120            e = Perm(v)
3121            self.assertEqual(e.value, v)
3122            self.assertEqual(type(e.value), int)
3123            self.assertEqual(e.name, n)
3124            self.assertIn(e, Perm)
3125            self.assertIs(type(e), Perm)
3126
3127    def test_programatic_function_string_list(self):
3128        Perm = Flag('Perm', ['R', 'W', 'X'])
3129        lst = list(Perm)
3130        self.assertEqual(len(lst), len(Perm))
3131        self.assertEqual(len(Perm), 3, Perm)
3132        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3133        for i, n in enumerate('R W X'.split()):
3134            v = 1<<i
3135            e = Perm(v)
3136            self.assertEqual(e.value, v)
3137            self.assertEqual(type(e.value), int)
3138            self.assertEqual(e.name, n)
3139            self.assertIn(e, Perm)
3140            self.assertIs(type(e), Perm)
3141
3142    def test_programatic_function_iterable(self):
3143        Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
3144        lst = list(Perm)
3145        self.assertEqual(len(lst), len(Perm))
3146        self.assertEqual(len(Perm), 3, Perm)
3147        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3148        for i, n in enumerate('R W X'.split()):
3149            v = 1<<(2*i+1)
3150            e = Perm(v)
3151            self.assertEqual(e.value, v)
3152            self.assertEqual(type(e.value), int)
3153            self.assertEqual(e.name, n)
3154            self.assertIn(e, Perm)
3155            self.assertIs(type(e), Perm)
3156
3157    def test_programatic_function_from_dict(self):
3158        Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
3159        lst = list(Perm)
3160        self.assertEqual(len(lst), len(Perm))
3161        self.assertEqual(len(Perm), 3, Perm)
3162        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3163        for i, n in enumerate('R W X'.split()):
3164            v = 1<<(2*i+1)
3165            e = Perm(v)
3166            self.assertEqual(e.value, v)
3167            self.assertEqual(type(e.value), int)
3168            self.assertEqual(e.name, n)
3169            self.assertIn(e, Perm)
3170            self.assertIs(type(e), Perm)
3171
3172    def test_pickle(self):
3173        if isinstance(FlagStooges, Exception):
3174            raise FlagStooges
3175        test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
3176        test_pickle_dump_load(self.assertIs, FlagStooges)
3177
3178    @unittest.skipIf(
3179            python_version >= (3, 12),
3180            '__contains__ now returns True/False for all inputs',
3181            )
3182    def test_contains_er(self):
3183        Open = self.Open
3184        Color = self.Color
3185        self.assertFalse(Color.BLACK in Open)
3186        self.assertFalse(Open.RO in Color)
3187        with self.assertRaises(TypeError):
3188            with self.assertWarns(DeprecationWarning):
3189                'BLACK' in Color
3190        with self.assertRaises(TypeError):
3191            with self.assertWarns(DeprecationWarning):
3192                'RO' in Open
3193        with self.assertRaises(TypeError):
3194            with self.assertWarns(DeprecationWarning):
3195                1 in Color
3196        with self.assertRaises(TypeError):
3197            with self.assertWarns(DeprecationWarning):
3198                1 in Open
3199
3200    @unittest.skipIf(
3201            python_version < (3, 12),
3202            '__contains__ only works with enum memmbers before 3.12',
3203            )
3204    def test_contains_tf(self):
3205        Open = self.Open
3206        Color = self.Color
3207        self.assertFalse(Color.BLACK in Open)
3208        self.assertFalse(Open.RO in Color)
3209        self.assertFalse('BLACK' in Color)
3210        self.assertFalse('RO' in Open)
3211        self.assertTrue(1 in Color)
3212        self.assertTrue(1 in Open)
3213
3214    def test_member_contains(self):
3215        Perm = self.Perm
3216        R, W, X = Perm
3217        RW = R | W
3218        RX = R | X
3219        WX = W | X
3220        RWX = R | W | X
3221        self.assertTrue(R in RW)
3222        self.assertTrue(R in RX)
3223        self.assertTrue(R in RWX)
3224        self.assertTrue(W in RW)
3225        self.assertTrue(W in WX)
3226        self.assertTrue(W in RWX)
3227        self.assertTrue(X in RX)
3228        self.assertTrue(X in WX)
3229        self.assertTrue(X in RWX)
3230        self.assertFalse(R in WX)
3231        self.assertFalse(W in RX)
3232        self.assertFalse(X in RW)
3233
3234    def test_member_iter(self):
3235        Color = self.Color
3236        self.assertEqual(list(Color.BLACK), [])
3237        self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
3238        self.assertEqual(list(Color.BLUE), [Color.BLUE])
3239        self.assertEqual(list(Color.GREEN), [Color.GREEN])
3240        self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3241        self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3242
3243    def test_member_length(self):
3244        self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3245        self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3246        self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3247        self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3248
3249    def test_number_reset_and_order_cleanup(self):
3250        class Confused(Flag):
3251            _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
3252            ONE = auto()
3253            TWO = auto()
3254            FOUR = auto()
3255            DOS = 2
3256            EIGHT = auto()
3257            SIXTEEN = auto()
3258        self.assertEqual(
3259                list(Confused),
3260                [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
3261        self.assertIs(Confused.TWO, Confused.DOS)
3262        self.assertEqual(Confused.DOS._value_, 2)
3263        self.assertEqual(Confused.EIGHT._value_, 8)
3264        self.assertEqual(Confused.SIXTEEN._value_, 16)
3265
3266    def test_aliases(self):
3267        Color = self.Color
3268        self.assertEqual(Color(1).name, 'RED')
3269        self.assertEqual(Color['ROJO'].name, 'RED')
3270        self.assertEqual(Color(7).name, 'WHITE')
3271        self.assertEqual(Color['BLANCO'].name, 'WHITE')
3272        self.assertIs(Color.BLANCO, Color.WHITE)
3273        Open = self.Open
3274        self.assertIs(Open['AC'], Open.AC)
3275
3276    def test_auto_number(self):
3277        class Color(Flag):
3278            red = auto()
3279            blue = auto()
3280            green = auto()
3281
3282        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
3283        self.assertEqual(Color.red.value, 1)
3284        self.assertEqual(Color.blue.value, 2)
3285        self.assertEqual(Color.green.value, 4)
3286
3287    def test_auto_number_garbage(self):
3288        with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
3289            class Color(Flag):
3290                red = 'not an int'
3291                blue = auto()
3292
3293    def test_duplicate_auto(self):
3294        class Dupes(Enum):
3295            first = primero = auto()
3296            second = auto()
3297            third = auto()
3298        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
3299
3300    def test_multiple_mixin(self):
3301        class AllMixin:
3302            @classproperty
3303            def ALL(cls):
3304                members = list(cls)
3305                all_value = None
3306                if members:
3307                    all_value = members[0]
3308                    for member in members[1:]:
3309                        all_value |= member
3310                cls.ALL = all_value
3311                return all_value
3312        class StrMixin:
3313            def __str__(self):
3314                return self._name_.lower()
3315        class Color(AllMixin, Flag):
3316            RED = auto()
3317            GREEN = auto()
3318            BLUE = auto()
3319        self.assertEqual(Color.RED.value, 1)
3320        self.assertEqual(Color.GREEN.value, 2)
3321        self.assertEqual(Color.BLUE.value, 4)
3322        self.assertEqual(Color.ALL.value, 7)
3323        self.assertEqual(str(Color.BLUE), 'BLUE')
3324        class Color(AllMixin, StrMixin, Flag):
3325            RED = auto()
3326            GREEN = auto()
3327            BLUE = auto()
3328        self.assertEqual(Color.RED.value, 1)
3329        self.assertEqual(Color.GREEN.value, 2)
3330        self.assertEqual(Color.BLUE.value, 4)
3331        self.assertEqual(Color.ALL.value, 7)
3332        self.assertEqual(str(Color.BLUE), 'blue')
3333        class Color(StrMixin, AllMixin, Flag):
3334            RED = auto()
3335            GREEN = auto()
3336            BLUE = auto()
3337        self.assertEqual(Color.RED.value, 1)
3338        self.assertEqual(Color.GREEN.value, 2)
3339        self.assertEqual(Color.BLUE.value, 4)
3340        self.assertEqual(Color.ALL.value, 7)
3341        self.assertEqual(str(Color.BLUE), 'blue')
3342
3343    @threading_helper.reap_threads
3344    def test_unique_composite(self):
3345        # override __eq__ to be identity only
3346        class TestFlag(Flag):
3347            one = auto()
3348            two = auto()
3349            three = auto()
3350            four = auto()
3351            five = auto()
3352            six = auto()
3353            seven = auto()
3354            eight = auto()
3355            def __eq__(self, other):
3356                return self is other
3357            def __hash__(self):
3358                return hash(self._value_)
3359        # have multiple threads competing to complete the composite members
3360        seen = set()
3361        failed = False
3362        def cycle_enum():
3363            nonlocal failed
3364            try:
3365                for i in range(256):
3366                    seen.add(TestFlag(i))
3367            except Exception:
3368                failed = True
3369        threads = [
3370                threading.Thread(target=cycle_enum)
3371                for _ in range(8)
3372                ]
3373        with threading_helper.start_threads(threads):
3374            pass
3375        # check that only 248 members were created
3376        self.assertFalse(
3377                failed,
3378                'at least one thread failed while creating composite members')
3379        self.assertEqual(256, len(seen), 'too many composite members created')
3380
3381    def test_init_subclass(self):
3382        class MyEnum(Flag):
3383            def __init_subclass__(cls, **kwds):
3384                super().__init_subclass__(**kwds)
3385                self.assertFalse(cls.__dict__.get('_test', False))
3386                cls._test1 = 'MyEnum'
3387        #
3388        class TheirEnum(MyEnum):
3389            def __init_subclass__(cls, **kwds):
3390                super(TheirEnum, cls).__init_subclass__(**kwds)
3391                cls._test2 = 'TheirEnum'
3392        class WhoseEnum(TheirEnum):
3393            def __init_subclass__(cls, **kwds):
3394                pass
3395        class NoEnum(WhoseEnum):
3396            ONE = 1
3397        self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
3398        self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
3399        self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
3400        self.assertFalse(NoEnum.__dict__.get('_test1', False))
3401        self.assertFalse(NoEnum.__dict__.get('_test2', False))
3402        #
3403        class OurEnum(MyEnum):
3404            def __init_subclass__(cls, **kwds):
3405                cls._test2 = 'OurEnum'
3406        class WhereEnum(OurEnum):
3407            def __init_subclass__(cls, **kwds):
3408                pass
3409        class NeverEnum(WhereEnum):
3410            ONE = 1
3411        self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
3412        self.assertFalse(WhereEnum.__dict__.get('_test1', False))
3413        self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
3414        self.assertFalse(NeverEnum.__dict__.get('_test1', False))
3415        self.assertFalse(NeverEnum.__dict__.get('_test2', False))
3416
3417
3418class TestIntFlag(unittest.TestCase):
3419    """Tests of the IntFlags."""
3420
3421    class Perm(IntFlag):
3422        R = 1 << 2
3423        W = 1 << 1
3424        X = 1 << 0
3425
3426    class Open(IntFlag):
3427        RO = 0
3428        WO = 1
3429        RW = 2
3430        AC = 3
3431        CE = 1<<19
3432
3433    class Color(IntFlag):
3434        BLACK = 0
3435        RED = 1
3436        ROJO = 1
3437        GREEN = 2
3438        BLUE = 4
3439        PURPLE = RED|BLUE
3440        WHITE = RED|GREEN|BLUE
3441        BLANCO = RED|GREEN|BLUE
3442
3443    class Skip(IntFlag):
3444        FIRST = 1
3445        SECOND = 2
3446        EIGHTH = 8
3447
3448    def test_type(self):
3449        Perm = self.Perm
3450        self.assertTrue(Perm._member_type_ is int)
3451        Open = self.Open
3452        for f in Perm:
3453            self.assertTrue(isinstance(f, Perm))
3454            self.assertEqual(f, f.value)
3455        self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
3456        self.assertEqual(Perm.W | Perm.X, 3)
3457        for f in Open:
3458            self.assertTrue(isinstance(f, Open))
3459            self.assertEqual(f, f.value)
3460        self.assertTrue(isinstance(Open.WO | Open.RW, Open))
3461        self.assertEqual(Open.WO | Open.RW, 3)
3462
3463
3464    def test_str(self):
3465        Perm = self.Perm
3466        self.assertEqual(str(Perm.R), 'R')
3467        self.assertEqual(str(Perm.W), 'W')
3468        self.assertEqual(str(Perm.X), 'X')
3469        self.assertEqual(str(Perm.R | Perm.W), 'R|W')
3470        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
3471        self.assertEqual(str(Perm.R | 8), '12')
3472        self.assertEqual(str(Perm(0)), 'Perm(0)')
3473        self.assertEqual(str(Perm(8)), '8')
3474        self.assertEqual(str(~Perm.R), 'W|X')
3475        self.assertEqual(str(~Perm.W), 'R|X')
3476        self.assertEqual(str(~Perm.X), 'R|W')
3477        self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
3478        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3479        self.assertEqual(str(~(Perm.R | 8)), '-13')
3480        self.assertEqual(str(Perm(~0)), 'R|W|X')
3481        self.assertEqual(str(Perm(~8)), '-9')
3482
3483        Open = self.Open
3484        self.assertEqual(str(Open.RO), 'RO')
3485        self.assertEqual(str(Open.WO), 'WO')
3486        self.assertEqual(str(Open.AC), 'AC')
3487        self.assertEqual(str(Open.RO | Open.CE), 'CE')
3488        self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
3489        self.assertEqual(str(Open(4)), '4')
3490        self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3491        self.assertEqual(str(~Open.WO), 'RW|CE')
3492        self.assertEqual(str(~Open.AC), 'CE')
3493        self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3494        self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
3495        self.assertEqual(str(Open(~4)), '-5')
3496
3497    def test_repr(self):
3498        Perm = self.Perm
3499        self.assertEqual(repr(Perm.R), 'Perm.R')
3500        self.assertEqual(repr(Perm.W), 'Perm.W')
3501        self.assertEqual(repr(Perm.X), 'Perm.X')
3502        self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3503        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
3504        self.assertEqual(repr(Perm.R | 8), '12')
3505        self.assertEqual(repr(Perm(0)), '0x0')
3506        self.assertEqual(repr(Perm(8)), '8')
3507        self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3508        self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3509        self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3510        self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3511        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
3512        self.assertEqual(repr(~(Perm.R | 8)), '-13')
3513        self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
3514        self.assertEqual(repr(Perm(~8)), '-9')
3515
3516        Open = self.Open
3517        self.assertEqual(repr(Open.RO), 'Open.RO')
3518        self.assertEqual(repr(Open.WO), 'Open.WO')
3519        self.assertEqual(repr(Open.AC), 'Open.AC')
3520        self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3521        self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
3522        self.assertEqual(repr(Open(4)), '4')
3523        self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3524        self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3525        self.assertEqual(repr(~Open.AC), 'Open.CE')
3526        self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3527        self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
3528        self.assertEqual(repr(Open(~4)), '-5')
3529
3530    def test_global_repr_keep(self):
3531        self.assertEqual(
3532                repr(HeadlightsK(0)),
3533                '%s.OFF_K' % SHORT_MODULE,
3534                )
3535        self.assertEqual(
3536                repr(HeadlightsK(2**0 + 2**2 + 2**3)),
3537                '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
3538                )
3539        self.assertEqual(
3540                repr(HeadlightsK(2**3)),
3541                '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
3542                )
3543
3544    def test_global_repr_conform1(self):
3545        self.assertEqual(
3546                repr(HeadlightsC(0)),
3547                '%s.OFF_C' % SHORT_MODULE,
3548                )
3549        self.assertEqual(
3550                repr(HeadlightsC(2**0 + 2**2 + 2**3)),
3551                '%(m)s.LOW_BEAM_C|%(m)s.FOG_C' % {'m': SHORT_MODULE},
3552                )
3553        self.assertEqual(
3554                repr(HeadlightsC(2**3)),
3555                '%(m)s.OFF_C' % {'m': SHORT_MODULE},
3556                )
3557
3558    def test_format(self):
3559        Perm = self.Perm
3560        self.assertEqual(format(Perm.R, ''), '4')
3561        self.assertEqual(format(Perm.R | Perm.X, ''), '5')
3562        #
3563        class NewPerm(IntFlag):
3564            R = 1 << 2
3565            W = 1 << 1
3566            X = 1 << 0
3567            def __str__(self):
3568                return self._name_
3569        self.assertEqual(format(NewPerm.R, ''), 'R')
3570        self.assertEqual(format(NewPerm.R | Perm.X, ''), 'R|X')
3571
3572    def test_or(self):
3573        Perm = self.Perm
3574        for i in Perm:
3575            for j in Perm:
3576                self.assertEqual(i | j, i.value | j.value)
3577                self.assertEqual((i | j).value, i.value | j.value)
3578                self.assertIs(type(i | j), Perm)
3579            for j in range(8):
3580                self.assertEqual(i | j, i.value | j)
3581                self.assertEqual((i | j).value, i.value | j)
3582                self.assertIs(type(i | j), Perm)
3583                self.assertEqual(j | i, j | i.value)
3584                self.assertEqual((j | i).value, j | i.value)
3585                self.assertIs(type(j | i), Perm)
3586        for i in Perm:
3587            self.assertIs(i | i, i)
3588            self.assertIs(i | 0, i)
3589            self.assertIs(0 | i, i)
3590        Open = self.Open
3591        self.assertIs(Open.RO | Open.CE, Open.CE)
3592
3593    def test_and(self):
3594        Perm = self.Perm
3595        RW = Perm.R | Perm.W
3596        RX = Perm.R | Perm.X
3597        WX = Perm.W | Perm.X
3598        RWX = Perm.R | Perm.W | Perm.X
3599        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3600        for i in values:
3601            for j in values:
3602                self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3603                self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3604                self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3605            for j in range(8):
3606                self.assertEqual(i & j, i.value & j)
3607                self.assertEqual((i & j).value, i.value & j)
3608                self.assertIs(type(i & j), Perm)
3609                self.assertEqual(j & i, j & i.value)
3610                self.assertEqual((j & i).value, j & i.value)
3611                self.assertIs(type(j & i), Perm)
3612        for i in Perm:
3613            self.assertIs(i & i, i)
3614            self.assertIs(i & 7, i)
3615            self.assertIs(7 & i, i)
3616        Open = self.Open
3617        self.assertIs(Open.RO & Open.CE, Open.RO)
3618
3619    def test_xor(self):
3620        Perm = self.Perm
3621        for i in Perm:
3622            for j in Perm:
3623                self.assertEqual(i ^ j, i.value ^ j.value)
3624                self.assertEqual((i ^ j).value, i.value ^ j.value)
3625                self.assertIs(type(i ^ j), Perm)
3626            for j in range(8):
3627                self.assertEqual(i ^ j, i.value ^ j)
3628                self.assertEqual((i ^ j).value, i.value ^ j)
3629                self.assertIs(type(i ^ j), Perm)
3630                self.assertEqual(j ^ i, j ^ i.value)
3631                self.assertEqual((j ^ i).value, j ^ i.value)
3632                self.assertIs(type(j ^ i), Perm)
3633        for i in Perm:
3634            self.assertIs(i ^ 0, i)
3635            self.assertIs(0 ^ i, i)
3636        Open = self.Open
3637        self.assertIs(Open.RO ^ Open.CE, Open.CE)
3638        self.assertIs(Open.CE ^ Open.CE, Open.RO)
3639
3640    def test_invert(self):
3641        Perm = self.Perm
3642        RW = Perm.R | Perm.W
3643        RX = Perm.R | Perm.X
3644        WX = Perm.W | Perm.X
3645        RWX = Perm.R | Perm.W | Perm.X
3646        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3647        for i in values:
3648            self.assertEqual(~i, (~i).value)
3649            self.assertIs(type(~i), Perm)
3650            self.assertEqual(~~i, i)
3651        for i in Perm:
3652            self.assertIs(~~i, i)
3653        Open = self.Open
3654        self.assertIs(Open.WO & ~Open.WO, Open.RO)
3655        self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3656
3657    def test_boundary(self):
3658        self.assertIs(enum.IntFlag._boundary_, EJECT)
3659        class Iron(IntFlag, boundary=STRICT):
3660            ONE = 1
3661            TWO = 2
3662            EIGHT = 8
3663        self.assertIs(Iron._boundary_, STRICT)
3664        #
3665        class Water(IntFlag, boundary=CONFORM):
3666            ONE = 1
3667            TWO = 2
3668            EIGHT = 8
3669        self.assertIs(Water._boundary_, CONFORM)
3670        #
3671        class Space(IntFlag, boundary=EJECT):
3672            ONE = 1
3673            TWO = 2
3674            EIGHT = 8
3675        self.assertIs(Space._boundary_, EJECT)
3676        #
3677        #
3678        class Bizarre(IntFlag, boundary=KEEP):
3679            b = 3
3680            c = 4
3681            d = 6
3682        #
3683        self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
3684        #
3685        self.assertIs(Water(7), Water.ONE|Water.TWO)
3686        self.assertIs(Water(~9), Water.TWO)
3687        #
3688        self.assertEqual(Space(7), 7)
3689        self.assertTrue(type(Space(7)) is int)
3690        #
3691        self.assertEqual(list(Bizarre), [Bizarre.c])
3692        self.assertIs(Bizarre(3), Bizarre.b)
3693        self.assertIs(Bizarre(6), Bizarre.d)
3694
3695    def test_iter(self):
3696        Color = self.Color
3697        Open = self.Open
3698        self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3699        self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3700
3701    def test_programatic_function_string(self):
3702        Perm = IntFlag('Perm', 'R W X')
3703        lst = list(Perm)
3704        self.assertEqual(len(lst), len(Perm))
3705        self.assertEqual(len(Perm), 3, Perm)
3706        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3707        for i, n in enumerate('R W X'.split()):
3708            v = 1<<i
3709            e = Perm(v)
3710            self.assertEqual(e.value, v)
3711            self.assertEqual(type(e.value), int)
3712            self.assertEqual(e, v)
3713            self.assertEqual(e.name, n)
3714            self.assertIn(e, Perm)
3715            self.assertIs(type(e), Perm)
3716
3717    def test_programatic_function_string_with_start(self):
3718        Perm = IntFlag('Perm', 'R W X', start=8)
3719        lst = list(Perm)
3720        self.assertEqual(len(lst), len(Perm))
3721        self.assertEqual(len(Perm), 3, Perm)
3722        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3723        for i, n in enumerate('R W X'.split()):
3724            v = 8<<i
3725            e = Perm(v)
3726            self.assertEqual(e.value, v)
3727            self.assertEqual(type(e.value), int)
3728            self.assertEqual(e, v)
3729            self.assertEqual(e.name, n)
3730            self.assertIn(e, Perm)
3731            self.assertIs(type(e), Perm)
3732
3733    def test_programatic_function_string_list(self):
3734        Perm = IntFlag('Perm', ['R', 'W', 'X'])
3735        lst = list(Perm)
3736        self.assertEqual(len(lst), len(Perm))
3737        self.assertEqual(len(Perm), 3, Perm)
3738        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3739        for i, n in enumerate('R W X'.split()):
3740            v = 1<<i
3741            e = Perm(v)
3742            self.assertEqual(e.value, v)
3743            self.assertEqual(type(e.value), int)
3744            self.assertEqual(e, v)
3745            self.assertEqual(e.name, n)
3746            self.assertIn(e, Perm)
3747            self.assertIs(type(e), Perm)
3748
3749    def test_programatic_function_iterable(self):
3750        Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
3751        lst = list(Perm)
3752        self.assertEqual(len(lst), len(Perm))
3753        self.assertEqual(len(Perm), 3, Perm)
3754        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3755        for i, n in enumerate('R W X'.split()):
3756            v = 1<<(2*i+1)
3757            e = Perm(v)
3758            self.assertEqual(e.value, v)
3759            self.assertEqual(type(e.value), int)
3760            self.assertEqual(e, v)
3761            self.assertEqual(e.name, n)
3762            self.assertIn(e, Perm)
3763            self.assertIs(type(e), Perm)
3764
3765    def test_programatic_function_from_dict(self):
3766        Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
3767        lst = list(Perm)
3768        self.assertEqual(len(lst), len(Perm))
3769        self.assertEqual(len(Perm), 3, Perm)
3770        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3771        for i, n in enumerate('R W X'.split()):
3772            v = 1<<(2*i+1)
3773            e = Perm(v)
3774            self.assertEqual(e.value, v)
3775            self.assertEqual(type(e.value), int)
3776            self.assertEqual(e, v)
3777            self.assertEqual(e.name, n)
3778            self.assertIn(e, Perm)
3779            self.assertIs(type(e), Perm)
3780
3781
3782    def test_programatic_function_from_empty_list(self):
3783        Perm = enum.IntFlag('Perm', [])
3784        lst = list(Perm)
3785        self.assertEqual(len(lst), len(Perm))
3786        self.assertEqual(len(Perm), 0, Perm)
3787        Thing = enum.Enum('Thing', [])
3788        lst = list(Thing)
3789        self.assertEqual(len(lst), len(Thing))
3790        self.assertEqual(len(Thing), 0, Thing)
3791
3792
3793    def test_programatic_function_from_empty_tuple(self):
3794        Perm = enum.IntFlag('Perm', ())
3795        lst = list(Perm)
3796        self.assertEqual(len(lst), len(Perm))
3797        self.assertEqual(len(Perm), 0, Perm)
3798        Thing = enum.Enum('Thing', ())
3799        self.assertEqual(len(lst), len(Thing))
3800        self.assertEqual(len(Thing), 0, Thing)
3801
3802    @unittest.skipIf(
3803            python_version >= (3, 12),
3804            '__contains__ now returns True/False for all inputs',
3805            )
3806    def test_contains_er(self):
3807        Open = self.Open
3808        Color = self.Color
3809        self.assertTrue(Color.GREEN in Color)
3810        self.assertTrue(Open.RW in Open)
3811        self.assertFalse(Color.GREEN in Open)
3812        self.assertFalse(Open.RW in Color)
3813        with self.assertRaises(TypeError):
3814            with self.assertWarns(DeprecationWarning):
3815                'GREEN' in Color
3816        with self.assertRaises(TypeError):
3817            with self.assertWarns(DeprecationWarning):
3818                'RW' in Open
3819        with self.assertRaises(TypeError):
3820            with self.assertWarns(DeprecationWarning):
3821                2 in Color
3822        with self.assertRaises(TypeError):
3823            with self.assertWarns(DeprecationWarning):
3824                2 in Open
3825
3826    @unittest.skipIf(
3827            python_version < (3, 12),
3828            '__contains__ only works with enum memmbers before 3.12',
3829            )
3830    def test_contains_tf(self):
3831        Open = self.Open
3832        Color = self.Color
3833        self.assertTrue(Color.GREEN in Color)
3834        self.assertTrue(Open.RW in Open)
3835        self.assertTrue(Color.GREEN in Open)
3836        self.assertTrue(Open.RW in Color)
3837        self.assertFalse('GREEN' in Color)
3838        self.assertFalse('RW' in Open)
3839        self.assertTrue(2 in Color)
3840        self.assertTrue(2 in Open)
3841
3842    def test_member_contains(self):
3843        Perm = self.Perm
3844        R, W, X = Perm
3845        RW = R | W
3846        RX = R | X
3847        WX = W | X
3848        RWX = R | W | X
3849        self.assertTrue(R in RW)
3850        self.assertTrue(R in RX)
3851        self.assertTrue(R in RWX)
3852        self.assertTrue(W in RW)
3853        self.assertTrue(W in WX)
3854        self.assertTrue(W in RWX)
3855        self.assertTrue(X in RX)
3856        self.assertTrue(X in WX)
3857        self.assertTrue(X in RWX)
3858        self.assertFalse(R in WX)
3859        self.assertFalse(W in RX)
3860        self.assertFalse(X in RW)
3861        with self.assertRaises(TypeError):
3862            self.assertFalse('test' in RW)
3863
3864    def test_member_iter(self):
3865        Color = self.Color
3866        self.assertEqual(list(Color.BLACK), [])
3867        self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
3868        self.assertEqual(list(Color.BLUE), [Color.BLUE])
3869        self.assertEqual(list(Color.GREEN), [Color.GREEN])
3870        self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3871
3872    def test_member_length(self):
3873        self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3874        self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3875        self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3876        self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3877
3878    def test_aliases(self):
3879        Color = self.Color
3880        self.assertEqual(Color(1).name, 'RED')
3881        self.assertEqual(Color['ROJO'].name, 'RED')
3882        self.assertEqual(Color(7).name, 'WHITE')
3883        self.assertEqual(Color['BLANCO'].name, 'WHITE')
3884        self.assertIs(Color.BLANCO, Color.WHITE)
3885        Open = self.Open
3886        self.assertIs(Open['AC'], Open.AC)
3887
3888    def test_bool(self):
3889        Perm = self.Perm
3890        for f in Perm:
3891            self.assertTrue(f)
3892        Open = self.Open
3893        for f in Open:
3894            self.assertEqual(bool(f.value), bool(f))
3895
3896
3897    def test_multiple_mixin(self):
3898        class AllMixin:
3899            @classproperty
3900            def ALL(cls):
3901                members = list(cls)
3902                all_value = None
3903                if members:
3904                    all_value = members[0]
3905                    for member in members[1:]:
3906                        all_value |= member
3907                cls.ALL = all_value
3908                return all_value
3909        class StrMixin:
3910            def __str__(self):
3911                return self._name_.lower()
3912        class Color(AllMixin, IntFlag):
3913            RED = auto()
3914            GREEN = auto()
3915            BLUE = auto()
3916        self.assertEqual(Color.RED.value, 1)
3917        self.assertEqual(Color.GREEN.value, 2)
3918        self.assertEqual(Color.BLUE.value, 4)
3919        self.assertEqual(Color.ALL.value, 7)
3920        self.assertEqual(str(Color.BLUE), 'BLUE')
3921        class Color(AllMixin, StrMixin, IntFlag):
3922            RED = auto()
3923            GREEN = auto()
3924            BLUE = auto()
3925        self.assertEqual(Color.RED.value, 1)
3926        self.assertEqual(Color.GREEN.value, 2)
3927        self.assertEqual(Color.BLUE.value, 4)
3928        self.assertEqual(Color.ALL.value, 7)
3929        self.assertEqual(str(Color.BLUE), 'blue')
3930        class Color(StrMixin, AllMixin, IntFlag):
3931            RED = auto()
3932            GREEN = auto()
3933            BLUE = auto()
3934        self.assertEqual(Color.RED.value, 1)
3935        self.assertEqual(Color.GREEN.value, 2)
3936        self.assertEqual(Color.BLUE.value, 4)
3937        self.assertEqual(Color.ALL.value, 7)
3938        self.assertEqual(str(Color.BLUE), 'blue')
3939
3940    @threading_helper.reap_threads
3941    def test_unique_composite(self):
3942        # override __eq__ to be identity only
3943        class TestFlag(IntFlag):
3944            one = auto()
3945            two = auto()
3946            three = auto()
3947            four = auto()
3948            five = auto()
3949            six = auto()
3950            seven = auto()
3951            eight = auto()
3952            def __eq__(self, other):
3953                return self is other
3954            def __hash__(self):
3955                return hash(self._value_)
3956        # have multiple threads competing to complete the composite members
3957        seen = set()
3958        failed = False
3959        def cycle_enum():
3960            nonlocal failed
3961            try:
3962                for i in range(256):
3963                    seen.add(TestFlag(i))
3964            except Exception:
3965                failed = True
3966        threads = [
3967                threading.Thread(target=cycle_enum)
3968                for _ in range(8)
3969                ]
3970        with threading_helper.start_threads(threads):
3971            pass
3972        # check that only 248 members were created
3973        self.assertFalse(
3974                failed,
3975                'at least one thread failed while creating composite members')
3976        self.assertEqual(256, len(seen), 'too many composite members created')
3977
3978
3979class TestEmptyAndNonLatinStrings(unittest.TestCase):
3980
3981    def test_empty_string(self):
3982        with self.assertRaises(ValueError):
3983            empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3984
3985    def test_non_latin_character_string(self):
3986        greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3987        item = getattr(greek_abc, '\u03B1')
3988        self.assertEqual(item.value, 1)
3989
3990    def test_non_latin_number_string(self):
3991        hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3992        item = getattr(hebrew_123, '\u05D0')
3993        self.assertEqual(item.value, 1)
3994
3995
3996class TestUnique(unittest.TestCase):
3997
3998    def test_unique_clean(self):
3999        @unique
4000        class Clean(Enum):
4001            one = 1
4002            two = 'dos'
4003            tres = 4.0
4004        #
4005        @unique
4006        class Cleaner(IntEnum):
4007            single = 1
4008            double = 2
4009            triple = 3
4010
4011    def test_unique_dirty(self):
4012        with self.assertRaisesRegex(ValueError, 'tres.*one'):
4013            @unique
4014            class Dirty(Enum):
4015                one = 1
4016                two = 'dos'
4017                tres = 1
4018        with self.assertRaisesRegex(
4019                ValueError,
4020                'double.*single.*turkey.*triple',
4021                ):
4022            @unique
4023            class Dirtier(IntEnum):
4024                single = 1
4025                double = 1
4026                triple = 3
4027                turkey = 3
4028
4029    def test_unique_with_name(self):
4030        @verify(UNIQUE)
4031        class Silly(Enum):
4032            one = 1
4033            two = 'dos'
4034            name = 3
4035        #
4036        @verify(UNIQUE)
4037        class Sillier(IntEnum):
4038            single = 1
4039            name = 2
4040            triple = 3
4041            value = 4
4042
4043class TestVerify(unittest.TestCase):
4044
4045    def test_continuous(self):
4046        @verify(CONTINUOUS)
4047        class Auto(Enum):
4048            FIRST = auto()
4049            SECOND = auto()
4050            THIRD = auto()
4051            FORTH = auto()
4052        #
4053        @verify(CONTINUOUS)
4054        class Manual(Enum):
4055            FIRST = 3
4056            SECOND = 4
4057            THIRD = 5
4058            FORTH = 6
4059        #
4060        with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
4061            @verify(CONTINUOUS)
4062            class Missing(Enum):
4063                FIRST = 3
4064                SECOND = 4
4065                THIRD = 11
4066                FORTH = 13
4067        #
4068        with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
4069            @verify(CONTINUOUS)
4070            class Incomplete(Flag):
4071                FIRST = 4
4072                SECOND = 8
4073                THIRD = 16
4074                FORTH = 64
4075        #
4076        with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
4077            @verify(CONTINUOUS)
4078            class StillIncomplete(Flag):
4079                FIRST = 4
4080                SECOND = 8
4081                THIRD = 11
4082                FORTH = 32
4083
4084
4085    def test_composite(self):
4086        class Bizarre(Flag):
4087            b = 3
4088            c = 4
4089            d = 6
4090        self.assertEqual(list(Bizarre), [Bizarre.c])
4091        self.assertEqual(Bizarre.b.value, 3)
4092        self.assertEqual(Bizarre.c.value, 4)
4093        self.assertEqual(Bizarre.d.value, 6)
4094        with self.assertRaisesRegex(
4095                ValueError,
4096                "invalid Flag 'Bizarre': aliases b and d are missing combined values of 0x3 .use enum.show_flag_values.value. for details.",
4097            ):
4098            @verify(NAMED_FLAGS)
4099            class Bizarre(Flag):
4100                b = 3
4101                c = 4
4102                d = 6
4103        #
4104        self.assertEqual(enum.show_flag_values(3), [1, 2])
4105        class Bizarre(IntFlag):
4106            b = 3
4107            c = 4
4108            d = 6
4109        self.assertEqual(list(Bizarre), [Bizarre.c])
4110        self.assertEqual(Bizarre.b.value, 3)
4111        self.assertEqual(Bizarre.c.value, 4)
4112        self.assertEqual(Bizarre.d.value, 6)
4113        with self.assertRaisesRegex(
4114                ValueError,
4115                "invalid Flag 'Bizarre': alias d is missing value 0x2 .use enum.show_flag_values.value. for details.",
4116            ):
4117            @verify(NAMED_FLAGS)
4118            class Bizarre(IntFlag):
4119                c = 4
4120                d = 6
4121        self.assertEqual(enum.show_flag_values(2), [2])
4122
4123    def test_unique_clean(self):
4124        @verify(UNIQUE)
4125        class Clean(Enum):
4126            one = 1
4127            two = 'dos'
4128            tres = 4.0
4129        #
4130        @verify(UNIQUE)
4131        class Cleaner(IntEnum):
4132            single = 1
4133            double = 2
4134            triple = 3
4135
4136    def test_unique_dirty(self):
4137        with self.assertRaisesRegex(ValueError, 'tres.*one'):
4138            @verify(UNIQUE)
4139            class Dirty(Enum):
4140                one = 1
4141                two = 'dos'
4142                tres = 1
4143        with self.assertRaisesRegex(
4144                ValueError,
4145                'double.*single.*turkey.*triple',
4146                ):
4147            @verify(UNIQUE)
4148            class Dirtier(IntEnum):
4149                single = 1
4150                double = 1
4151                triple = 3
4152                turkey = 3
4153
4154    def test_unique_with_name(self):
4155        @verify(UNIQUE)
4156        class Silly(Enum):
4157            one = 1
4158            two = 'dos'
4159            name = 3
4160        #
4161        @verify(UNIQUE)
4162        class Sillier(IntEnum):
4163            single = 1
4164            name = 2
4165            triple = 3
4166            value = 4
4167
4168class TestHelpers(unittest.TestCase):
4169
4170    sunder_names = '_bad_', '_good_', '_what_ho_'
4171    dunder_names = '__mal__', '__bien__', '__que_que__'
4172    private_names = '_MyEnum__private', '_MyEnum__still_private'
4173    private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
4174    random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
4175
4176    def test_sunder(self):
4177        for name in self.sunder_names + self.private_and_sunder_names:
4178            self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
4179        for name in self.dunder_names + self.private_names + self.random_names:
4180            self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
4181
4182    def test_dunder(self):
4183        for name in self.dunder_names:
4184            self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
4185        for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
4186            self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
4187
4188    def test_is_private(self):
4189        for name in self.private_names + self.private_and_sunder_names:
4190            self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
4191        for name in self.sunder_names + self.dunder_names + self.random_names:
4192            self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
4193
4194class TestEnumTypeSubclassing(unittest.TestCase):
4195    pass
4196
4197expected_help_output_with_docs = """\
4198Help on class Color in module %s:
4199
4200class Color(enum.Enum)
4201 |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
4202 |\x20\x20
4203 |  An enumeration.
4204 |\x20\x20
4205 |  Method resolution order:
4206 |      Color
4207 |      enum.Enum
4208 |      builtins.object
4209 |\x20\x20
4210 |  Data and other attributes defined here:
4211 |\x20\x20
4212 |  blue = Color.blue
4213 |\x20\x20
4214 |  green = Color.green
4215 |\x20\x20
4216 |  red = Color.red
4217 |\x20\x20
4218 |  ----------------------------------------------------------------------
4219 |  Data descriptors inherited from enum.Enum:
4220 |\x20\x20
4221 |  name
4222 |      The name of the Enum member.
4223 |\x20\x20
4224 |  value
4225 |      The value of the Enum member.
4226 |\x20\x20
4227 |  ----------------------------------------------------------------------
4228 |  Readonly properties inherited from enum.EnumType:
4229 |\x20\x20
4230 |  __members__
4231 |      Returns a mapping of member name->value.
4232 |\x20\x20\x20\x20\x20\x20
4233 |      This mapping lists all enum members, including aliases. Note that this
4234 |      is a read-only view of the internal mapping."""
4235
4236expected_help_output_without_docs = """\
4237Help on class Color in module %s:
4238
4239class Color(enum.Enum)
4240 |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
4241 |\x20\x20
4242 |  Method resolution order:
4243 |      Color
4244 |      enum.Enum
4245 |      builtins.object
4246 |\x20\x20
4247 |  Data and other attributes defined here:
4248 |\x20\x20
4249 |  blue = Color.blue
4250 |\x20\x20
4251 |  green = Color.green
4252 |\x20\x20
4253 |  red = Color.red
4254 |\x20\x20
4255 |  ----------------------------------------------------------------------
4256 |  Data descriptors inherited from enum.Enum:
4257 |\x20\x20
4258 |  name
4259 |\x20\x20
4260 |  value
4261 |\x20\x20
4262 |  ----------------------------------------------------------------------
4263 |  Data descriptors inherited from enum.EnumType:
4264 |\x20\x20
4265 |  __members__"""
4266
4267class TestStdLib(unittest.TestCase):
4268
4269    maxDiff = None
4270
4271    class Color(Enum):
4272        red = 1
4273        green = 2
4274        blue = 3
4275
4276    def test_pydoc(self):
4277        # indirectly test __objclass__
4278        if StrEnum.__doc__ is None:
4279            expected_text = expected_help_output_without_docs % __name__
4280        else:
4281            expected_text = expected_help_output_with_docs % __name__
4282        output = StringIO()
4283        helper = pydoc.Helper(output=output)
4284        helper(self.Color)
4285        result = output.getvalue().strip()
4286        self.assertEqual(result, expected_text)
4287
4288    def test_inspect_getmembers(self):
4289        values = dict((
4290                ('__class__', EnumType),
4291                ('__doc__', 'An enumeration.'),
4292                ('__members__', self.Color.__members__),
4293                ('__module__', __name__),
4294                ('blue', self.Color.blue),
4295                ('green', self.Color.green),
4296                ('name', Enum.__dict__['name']),
4297                ('red', self.Color.red),
4298                ('value', Enum.__dict__['value']),
4299                ))
4300        result = dict(inspect.getmembers(self.Color))
4301        self.assertEqual(set(values.keys()), set(result.keys()))
4302        failed = False
4303        for k in values.keys():
4304            if result[k] != values[k]:
4305                print()
4306                print('\n%s\n     key: %s\n  result: %s\nexpected: %s\n%s\n' %
4307                        ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
4308                failed = True
4309        if failed:
4310            self.fail("result does not equal expected, see print above")
4311
4312    def test_inspect_classify_class_attrs(self):
4313        # indirectly test __objclass__
4314        from inspect import Attribute
4315        values = [
4316                Attribute(name='__class__', kind='data',
4317                    defining_class=object, object=EnumType),
4318                Attribute(name='__doc__', kind='data',
4319                    defining_class=self.Color, object='An enumeration.'),
4320                Attribute(name='__members__', kind='property',
4321                    defining_class=EnumType, object=EnumType.__members__),
4322                Attribute(name='__module__', kind='data',
4323                    defining_class=self.Color, object=__name__),
4324                Attribute(name='blue', kind='data',
4325                    defining_class=self.Color, object=self.Color.blue),
4326                Attribute(name='green', kind='data',
4327                    defining_class=self.Color, object=self.Color.green),
4328                Attribute(name='red', kind='data',
4329                    defining_class=self.Color, object=self.Color.red),
4330                Attribute(name='name', kind='data',
4331                    defining_class=Enum, object=Enum.__dict__['name']),
4332                Attribute(name='value', kind='data',
4333                    defining_class=Enum, object=Enum.__dict__['value']),
4334                ]
4335        values.sort(key=lambda item: item.name)
4336        result = list(inspect.classify_class_attrs(self.Color))
4337        result.sort(key=lambda item: item.name)
4338        self.assertEqual(
4339                len(values), len(result),
4340                "%s != %s" % ([a.name for a in values], [a.name for a in result])
4341                )
4342        failed = False
4343        for v, r in zip(values, result):
4344            if r != v:
4345                print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
4346                failed = True
4347        if failed:
4348            self.fail("result does not equal expected, see print above")
4349
4350    def test_test_simple_enum(self):
4351        @_simple_enum(Enum)
4352        class SimpleColor:
4353            RED = 1
4354            GREEN = 2
4355            BLUE = 3
4356        class CheckedColor(Enum):
4357            RED = 1
4358            GREEN = 2
4359            BLUE = 3
4360        self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
4361        SimpleColor.GREEN._value_ = 9
4362        self.assertRaisesRegex(
4363                TypeError, "enum mismatch",
4364                _test_simple_enum, CheckedColor, SimpleColor,
4365                )
4366        class CheckedMissing(IntFlag, boundary=KEEP):
4367            SIXTY_FOUR = 64
4368            ONE_TWENTY_EIGHT = 128
4369            TWENTY_FORTY_EIGHT = 2048
4370            ALL = 2048 + 128 + 64 + 12
4371        CM = CheckedMissing
4372        self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
4373        #
4374        @_simple_enum(IntFlag, boundary=KEEP)
4375        class Missing:
4376            SIXTY_FOUR = 64
4377            ONE_TWENTY_EIGHT = 128
4378            TWENTY_FORTY_EIGHT = 2048
4379            ALL = 2048 + 128 + 64 + 12
4380        M = Missing
4381        self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
4382        #
4383        _test_simple_enum(CheckedMissing, Missing)
4384
4385
4386class MiscTestCase(unittest.TestCase):
4387    def test__all__(self):
4388        support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
4389
4390
4391# These are unordered here on purpose to ensure that declaration order
4392# makes no difference.
4393CONVERT_TEST_NAME_D = 5
4394CONVERT_TEST_NAME_C = 5
4395CONVERT_TEST_NAME_B = 5
4396CONVERT_TEST_NAME_A = 5  # This one should sort first.
4397CONVERT_TEST_NAME_E = 5
4398CONVERT_TEST_NAME_F = 5
4399
4400CONVERT_STRING_TEST_NAME_D = 5
4401CONVERT_STRING_TEST_NAME_C = 5
4402CONVERT_STRING_TEST_NAME_B = 5
4403CONVERT_STRING_TEST_NAME_A = 5  # This one should sort first.
4404CONVERT_STRING_TEST_NAME_E = 5
4405CONVERT_STRING_TEST_NAME_F = 5
4406
4407class TestIntEnumConvert(unittest.TestCase):
4408    def setUp(self):
4409        # Reset the module-level test variables to their original integer
4410        # values, otherwise the already created enum values get converted
4411        # instead.
4412        for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
4413            globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
4414            globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
4415
4416    def test_convert_value_lookup_priority(self):
4417        test_type = enum.IntEnum._convert_(
4418                'UnittestConvert',
4419                MODULE,
4420                filter=lambda x: x.startswith('CONVERT_TEST_'))
4421        # We don't want the reverse lookup value to vary when there are
4422        # multiple possible names for a given value.  It should always
4423        # report the first lexigraphical name in that case.
4424        self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
4425
4426    def test_convert(self):
4427        test_type = enum.IntEnum._convert_(
4428                'UnittestConvert',
4429                MODULE,
4430                filter=lambda x: x.startswith('CONVERT_TEST_'))
4431        # Ensure that test_type has all of the desired names and values.
4432        self.assertEqual(test_type.CONVERT_TEST_NAME_F,
4433                         test_type.CONVERT_TEST_NAME_A)
4434        self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
4435        self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
4436        self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
4437        self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
4438        # Ensure that test_type only picked up names matching the filter.
4439        self.assertEqual([name for name in dir(test_type)
4440                          if name[0:2] not in ('CO', '__')
4441                          and name not in dir(IntEnum)],
4442                         [], msg='Names other than CONVERT_TEST_* found.')
4443
4444    @unittest.skipUnless(python_version == (3, 8),
4445                         '_convert was deprecated in 3.8')
4446    def test_convert_warn(self):
4447        with self.assertWarns(DeprecationWarning):
4448            enum.IntEnum._convert(
4449                'UnittestConvert',
4450                MODULE,
4451                filter=lambda x: x.startswith('CONVERT_TEST_'))
4452
4453    @unittest.skipUnless(python_version >= (3, 9),
4454                         '_convert was removed in 3.9')
4455    def test_convert_raise(self):
4456        with self.assertRaises(AttributeError):
4457            enum.IntEnum._convert(
4458                'UnittestConvert',
4459                MODULE,
4460                filter=lambda x: x.startswith('CONVERT_TEST_'))
4461
4462    def test_convert_repr_and_str(self):
4463        test_type = enum.IntEnum._convert_(
4464                'UnittestConvert',
4465                MODULE,
4466                filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
4467        self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
4468        self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
4469        self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
4470
4471# global names for StrEnum._convert_ test
4472CONVERT_STR_TEST_2 = 'goodbye'
4473CONVERT_STR_TEST_1 = 'hello'
4474
4475class TestStrEnumConvert(unittest.TestCase):
4476    def setUp(self):
4477        global CONVERT_STR_TEST_1
4478        global CONVERT_STR_TEST_2
4479        CONVERT_STR_TEST_2 = 'goodbye'
4480        CONVERT_STR_TEST_1 = 'hello'
4481
4482    def test_convert(self):
4483        test_type = enum.StrEnum._convert_(
4484                'UnittestConvert',
4485                MODULE,
4486                filter=lambda x: x.startswith('CONVERT_STR_'))
4487        # Ensure that test_type has all of the desired names and values.
4488        self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
4489        self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
4490        # Ensure that test_type only picked up names matching the filter.
4491        self.assertEqual([name for name in dir(test_type)
4492                          if name[0:2] not in ('CO', '__')
4493                          and name not in dir(StrEnum)],
4494                         [], msg='Names other than CONVERT_STR_* found.')
4495
4496    def test_convert_repr_and_str(self):
4497        test_type = enum.StrEnum._convert_(
4498                'UnittestConvert',
4499                MODULE,
4500                filter=lambda x: x.startswith('CONVERT_STR_'))
4501        self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
4502        self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
4503        self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
4504
4505
4506if __name__ == '__main__':
4507    unittest.main()
4508