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