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