• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import enum
2import inspect
3import pydoc
4import sys
5import unittest
6import threading
7from collections import OrderedDict
8from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
9from io import StringIO
10from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
11from test.support import ALWAYS_EQ, check__all__, threading_helper
12from datetime import timedelta
13
14python_version = sys.version_info[:2]
15
16# for pickle tests
17try:
18    class Stooges(Enum):
19        LARRY = 1
20        CURLY = 2
21        MOE = 3
22except Exception as exc:
23    Stooges = exc
24
25try:
26    class IntStooges(int, Enum):
27        LARRY = 1
28        CURLY = 2
29        MOE = 3
30except Exception as exc:
31    IntStooges = exc
32
33try:
34    class FloatStooges(float, Enum):
35        LARRY = 1.39
36        CURLY = 2.72
37        MOE = 3.142596
38except Exception as exc:
39    FloatStooges = exc
40
41try:
42    class FlagStooges(Flag):
43        LARRY = 1
44        CURLY = 2
45        MOE = 3
46except Exception as exc:
47    FlagStooges = exc
48
49# for pickle test and subclass tests
50try:
51    class StrEnum(str, Enum):
52        'accepts only string values'
53    class Name(StrEnum):
54        BDFL = 'Guido van Rossum'
55        FLUFL = 'Barry Warsaw'
56except Exception as exc:
57    Name = exc
58
59try:
60    Question = Enum('Question', 'who what when where why', module=__name__)
61except Exception as exc:
62    Question = exc
63
64try:
65    Answer = Enum('Answer', 'him this then there because')
66except Exception as exc:
67    Answer = exc
68
69try:
70    Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
71except Exception as exc:
72    Theory = exc
73
74# for doctests
75try:
76    class Fruit(Enum):
77        TOMATO = 1
78        BANANA = 2
79        CHERRY = 3
80except Exception:
81    pass
82
83def test_pickle_dump_load(assertion, source, target=None):
84    if target is None:
85        target = source
86    for protocol in range(HIGHEST_PROTOCOL + 1):
87        assertion(loads(dumps(source, protocol=protocol)), target)
88
89def test_pickle_exception(assertion, exception, obj):
90    for protocol in range(HIGHEST_PROTOCOL + 1):
91        with assertion(exception):
92            dumps(obj, protocol=protocol)
93
94class TestHelpers(unittest.TestCase):
95    # _is_descriptor, _is_sunder, _is_dunder
96
97    def test_is_descriptor(self):
98        class foo:
99            pass
100        for attr in ('__get__','__set__','__delete__'):
101            obj = foo()
102            self.assertFalse(enum._is_descriptor(obj))
103            setattr(obj, attr, 1)
104            self.assertTrue(enum._is_descriptor(obj))
105
106    def test_is_sunder(self):
107        for s in ('_a_', '_aa_'):
108            self.assertTrue(enum._is_sunder(s))
109
110        for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
111                '__', '___', '____', '_____',):
112            self.assertFalse(enum._is_sunder(s))
113
114    def test_is_dunder(self):
115        for s in ('__a__', '__aa__'):
116            self.assertTrue(enum._is_dunder(s))
117        for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
118                '__', '___', '____', '_____',):
119            self.assertFalse(enum._is_dunder(s))
120
121# for subclassing tests
122
123class classproperty:
124
125    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
126        self.fget = fget
127        self.fset = fset
128        self.fdel = fdel
129        if doc is None and fget is not None:
130            doc = fget.__doc__
131        self.__doc__ = doc
132
133    def __get__(self, instance, ownerclass):
134        return self.fget(ownerclass)
135
136
137# tests
138
139class TestEnum(unittest.TestCase):
140
141    def setUp(self):
142        class Season(Enum):
143            SPRING = 1
144            SUMMER = 2
145            AUTUMN = 3
146            WINTER = 4
147        self.Season = Season
148
149        class Konstants(float, Enum):
150            E = 2.7182818
151            PI = 3.1415926
152            TAU = 2 * PI
153        self.Konstants = Konstants
154
155        class Grades(IntEnum):
156            A = 5
157            B = 4
158            C = 3
159            D = 2
160            F = 0
161        self.Grades = Grades
162
163        class Directional(str, Enum):
164            EAST = 'east'
165            WEST = 'west'
166            NORTH = 'north'
167            SOUTH = 'south'
168        self.Directional = Directional
169
170        from datetime import date
171        class Holiday(date, Enum):
172            NEW_YEAR = 2013, 1, 1
173            IDES_OF_MARCH = 2013, 3, 15
174        self.Holiday = Holiday
175
176    def test_dir_on_class(self):
177        Season = self.Season
178        self.assertEqual(
179            set(dir(Season)),
180            set(['__class__', '__doc__', '__members__', '__module__',
181                'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
182            )
183
184    def test_dir_on_item(self):
185        Season = self.Season
186        self.assertEqual(
187            set(dir(Season.WINTER)),
188            set(['__class__', '__doc__', '__module__', 'name', 'value']),
189            )
190
191    def test_dir_with_added_behavior(self):
192        class Test(Enum):
193            this = 'that'
194            these = 'those'
195            def wowser(self):
196                return ("Wowser! I'm %s!" % self.name)
197        self.assertEqual(
198                set(dir(Test)),
199                set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
200                )
201        self.assertEqual(
202                set(dir(Test.this)),
203                set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
204                )
205
206    def test_dir_on_sub_with_behavior_on_super(self):
207        # see issue22506
208        class SuperEnum(Enum):
209            def invisible(self):
210                return "did you see me?"
211        class SubEnum(SuperEnum):
212            sample = 5
213        self.assertEqual(
214                set(dir(SubEnum.sample)),
215                set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
216                )
217
218    def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
219        # see issue40084
220        class SuperEnum(IntEnum):
221            def __new__(cls, value, description=""):
222                obj = int.__new__(cls, value)
223                obj._value_ = value
224                obj.description = description
225                return obj
226        class SubEnum(SuperEnum):
227            sample = 5
228        self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
229
230    def test_enum_in_enum_out(self):
231        Season = self.Season
232        self.assertIs(Season(Season.WINTER), Season.WINTER)
233
234    def test_enum_value(self):
235        Season = self.Season
236        self.assertEqual(Season.SPRING.value, 1)
237
238    def test_intenum_value(self):
239        self.assertEqual(IntStooges.CURLY.value, 2)
240
241    def test_enum(self):
242        Season = self.Season
243        lst = list(Season)
244        self.assertEqual(len(lst), len(Season))
245        self.assertEqual(len(Season), 4, Season)
246        self.assertEqual(
247            [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
248
249        for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
250            e = Season(i)
251            self.assertEqual(e, getattr(Season, season))
252            self.assertEqual(e.value, i)
253            self.assertNotEqual(e, i)
254            self.assertEqual(e.name, season)
255            self.assertIn(e, Season)
256            self.assertIs(type(e), Season)
257            self.assertIsInstance(e, Season)
258            self.assertEqual(str(e), 'Season.' + season)
259            self.assertEqual(
260                    repr(e),
261                    '<Season.{0}: {1}>'.format(season, i),
262                    )
263
264    def test_value_name(self):
265        Season = self.Season
266        self.assertEqual(Season.SPRING.name, 'SPRING')
267        self.assertEqual(Season.SPRING.value, 1)
268        with self.assertRaises(AttributeError):
269            Season.SPRING.name = 'invierno'
270        with self.assertRaises(AttributeError):
271            Season.SPRING.value = 2
272
273    def test_changing_member(self):
274        Season = self.Season
275        with self.assertRaises(AttributeError):
276            Season.WINTER = 'really cold'
277
278    def test_attribute_deletion(self):
279        class Season(Enum):
280            SPRING = 1
281            SUMMER = 2
282            AUTUMN = 3
283            WINTER = 4
284
285            def spam(cls):
286                pass
287
288        self.assertTrue(hasattr(Season, 'spam'))
289        del Season.spam
290        self.assertFalse(hasattr(Season, 'spam'))
291
292        with self.assertRaises(AttributeError):
293            del Season.SPRING
294        with self.assertRaises(AttributeError):
295            del Season.DRY
296        with self.assertRaises(AttributeError):
297            del Season.SPRING.name
298
299    def test_bool_of_class(self):
300        class Empty(Enum):
301            pass
302        self.assertTrue(bool(Empty))
303
304    def test_bool_of_member(self):
305        class Count(Enum):
306            zero = 0
307            one = 1
308            two = 2
309        for member in Count:
310            self.assertTrue(bool(member))
311
312    def test_invalid_names(self):
313        with self.assertRaises(ValueError):
314            class Wrong(Enum):
315                mro = 9
316        with self.assertRaises(ValueError):
317            class Wrong(Enum):
318                _create_= 11
319        with self.assertRaises(ValueError):
320            class Wrong(Enum):
321                _get_mixins_ = 9
322        with self.assertRaises(ValueError):
323            class Wrong(Enum):
324                _find_new_ = 1
325        with self.assertRaises(ValueError):
326            class Wrong(Enum):
327                _any_name_ = 9
328
329    def test_bool(self):
330        # plain Enum members are always True
331        class Logic(Enum):
332            true = True
333            false = False
334        self.assertTrue(Logic.true)
335        self.assertTrue(Logic.false)
336        # unless overridden
337        class RealLogic(Enum):
338            true = True
339            false = False
340            def __bool__(self):
341                return bool(self._value_)
342        self.assertTrue(RealLogic.true)
343        self.assertFalse(RealLogic.false)
344        # mixed Enums depend on mixed-in type
345        class IntLogic(int, Enum):
346            true = 1
347            false = 0
348        self.assertTrue(IntLogic.true)
349        self.assertFalse(IntLogic.false)
350
351    @unittest.skipIf(
352            python_version >= (3, 12),
353            '__contains__ now returns True/False for all inputs',
354            )
355    def test_contains_er(self):
356        Season = self.Season
357        self.assertIn(Season.AUTUMN, Season)
358        with self.assertRaises(TypeError):
359            with self.assertWarns(DeprecationWarning):
360                3 in Season
361        with self.assertRaises(TypeError):
362            with self.assertWarns(DeprecationWarning):
363                'AUTUMN' in Season
364        val = Season(3)
365        self.assertIn(val, Season)
366        #
367        class OtherEnum(Enum):
368            one = 1; two = 2
369        self.assertNotIn(OtherEnum.two, Season)
370
371    @unittest.skipIf(
372            python_version < (3, 12),
373            '__contains__ only works with enum memmbers before 3.12',
374            )
375    def test_contains_tf(self):
376        Season = self.Season
377        self.assertIn(Season.AUTUMN, Season)
378        self.assertTrue(3 in Season)
379        self.assertFalse('AUTUMN' in Season)
380        val = Season(3)
381        self.assertIn(val, Season)
382        #
383        class OtherEnum(Enum):
384            one = 1; two = 2
385        self.assertNotIn(OtherEnum.two, Season)
386
387    def test_comparisons(self):
388        Season = self.Season
389        with self.assertRaises(TypeError):
390            Season.SPRING < Season.WINTER
391        with self.assertRaises(TypeError):
392            Season.SPRING > 4
393
394        self.assertNotEqual(Season.SPRING, 1)
395
396        class Part(Enum):
397            SPRING = 1
398            CLIP = 2
399            BARREL = 3
400
401        self.assertNotEqual(Season.SPRING, Part.SPRING)
402        with self.assertRaises(TypeError):
403            Season.SPRING < Part.CLIP
404
405    def test_enum_duplicates(self):
406        class Season(Enum):
407            SPRING = 1
408            SUMMER = 2
409            AUTUMN = FALL = 3
410            WINTER = 4
411            ANOTHER_SPRING = 1
412        lst = list(Season)
413        self.assertEqual(
414            lst,
415            [Season.SPRING, Season.SUMMER,
416             Season.AUTUMN, Season.WINTER,
417            ])
418        self.assertIs(Season.FALL, Season.AUTUMN)
419        self.assertEqual(Season.FALL.value, 3)
420        self.assertEqual(Season.AUTUMN.value, 3)
421        self.assertIs(Season(3), Season.AUTUMN)
422        self.assertIs(Season(1), Season.SPRING)
423        self.assertEqual(Season.FALL.name, 'AUTUMN')
424        self.assertEqual(
425                [k for k,v in Season.__members__.items() if v.name != k],
426                ['FALL', 'ANOTHER_SPRING'],
427                )
428
429    def test_duplicate_name(self):
430        with self.assertRaises(TypeError):
431            class Color(Enum):
432                red = 1
433                green = 2
434                blue = 3
435                red = 4
436
437        with self.assertRaises(TypeError):
438            class Color(Enum):
439                red = 1
440                green = 2
441                blue = 3
442                def red(self):
443                    return 'red'
444
445        with self.assertRaises(TypeError):
446            class Color(Enum):
447                @property
448                def red(self):
449                    return 'redder'
450                red = 1
451                green = 2
452                blue = 3
453
454
455    def test_enum_with_value_name(self):
456        class Huh(Enum):
457            name = 1
458            value = 2
459        self.assertEqual(
460            list(Huh),
461            [Huh.name, Huh.value],
462            )
463        self.assertIs(type(Huh.name), Huh)
464        self.assertEqual(Huh.name.name, 'name')
465        self.assertEqual(Huh.name.value, 1)
466
467    def test_format_enum(self):
468        Season = self.Season
469        self.assertEqual('{}'.format(Season.SPRING),
470                         '{}'.format(str(Season.SPRING)))
471        self.assertEqual( '{:}'.format(Season.SPRING),
472                          '{:}'.format(str(Season.SPRING)))
473        self.assertEqual('{:20}'.format(Season.SPRING),
474                         '{:20}'.format(str(Season.SPRING)))
475        self.assertEqual('{:^20}'.format(Season.SPRING),
476                         '{:^20}'.format(str(Season.SPRING)))
477        self.assertEqual('{:>20}'.format(Season.SPRING),
478                         '{:>20}'.format(str(Season.SPRING)))
479        self.assertEqual('{:<20}'.format(Season.SPRING),
480                         '{:<20}'.format(str(Season.SPRING)))
481
482    def test_str_override_enum(self):
483        class EnumWithStrOverrides(Enum):
484            one = auto()
485            two = auto()
486
487            def __str__(self):
488                return 'Str!'
489        self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
490        self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
491
492    def test_format_override_enum(self):
493        class EnumWithFormatOverride(Enum):
494            one = 1.0
495            two = 2.0
496            def __format__(self, spec):
497                return 'Format!!'
498        self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
499        self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
500
501    def test_str_and_format_override_enum(self):
502        class EnumWithStrFormatOverrides(Enum):
503            one = auto()
504            two = auto()
505            def __str__(self):
506                return 'Str!'
507            def __format__(self, spec):
508                return 'Format!'
509        self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
510        self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
511
512    def test_str_override_mixin(self):
513        class MixinEnumWithStrOverride(float, Enum):
514            one = 1.0
515            two = 2.0
516            def __str__(self):
517                return 'Overridden!'
518        self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
519        self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
520
521    def test_str_and_format_override_mixin(self):
522        class MixinWithStrFormatOverrides(float, Enum):
523            one = 1.0
524            two = 2.0
525            def __str__(self):
526                return 'Str!'
527            def __format__(self, spec):
528                return 'Format!'
529        self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
530        self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
531
532    def test_format_override_mixin(self):
533        class TestFloat(float, Enum):
534            one = 1.0
535            two = 2.0
536            def __format__(self, spec):
537                return 'TestFloat success!'
538        self.assertEqual(str(TestFloat.one), 'TestFloat.one')
539        self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
540
541    def assertFormatIsValue(self, spec, member):
542        self.assertEqual(spec.format(member), spec.format(member.value))
543
544    def test_format_enum_date(self):
545        Holiday = self.Holiday
546        self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
547        self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
548        self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
549        self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
550        self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
551        self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
552        self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
553        self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
554
555    def test_format_enum_float(self):
556        Konstants = self.Konstants
557        self.assertFormatIsValue('{}', Konstants.TAU)
558        self.assertFormatIsValue('{:}', Konstants.TAU)
559        self.assertFormatIsValue('{:20}', Konstants.TAU)
560        self.assertFormatIsValue('{:^20}', Konstants.TAU)
561        self.assertFormatIsValue('{:>20}', Konstants.TAU)
562        self.assertFormatIsValue('{:<20}', Konstants.TAU)
563        self.assertFormatIsValue('{:n}', Konstants.TAU)
564        self.assertFormatIsValue('{:5.2}', Konstants.TAU)
565        self.assertFormatIsValue('{:f}', Konstants.TAU)
566
567    def test_format_enum_int(self):
568        Grades = self.Grades
569        self.assertFormatIsValue('{}', Grades.C)
570        self.assertFormatIsValue('{:}', Grades.C)
571        self.assertFormatIsValue('{:20}', Grades.C)
572        self.assertFormatIsValue('{:^20}', Grades.C)
573        self.assertFormatIsValue('{:>20}', Grades.C)
574        self.assertFormatIsValue('{:<20}', Grades.C)
575        self.assertFormatIsValue('{:+}', Grades.C)
576        self.assertFormatIsValue('{:08X}', Grades.C)
577        self.assertFormatIsValue('{:b}', Grades.C)
578
579    def test_format_enum_str(self):
580        Directional = self.Directional
581        self.assertFormatIsValue('{}', Directional.WEST)
582        self.assertFormatIsValue('{:}', Directional.WEST)
583        self.assertFormatIsValue('{:20}', Directional.WEST)
584        self.assertFormatIsValue('{:^20}', Directional.WEST)
585        self.assertFormatIsValue('{:>20}', Directional.WEST)
586        self.assertFormatIsValue('{:<20}', Directional.WEST)
587
588    def test_object_str_override(self):
589        class Colors(Enum):
590            RED, GREEN, BLUE = 1, 2, 3
591            def __repr__(self):
592                return "test.%s" % (self._name_, )
593            __str__ = object.__str__
594        self.assertEqual(str(Colors.RED), 'test.RED')
595
596    def test_enum_str_override(self):
597        class MyStrEnum(Enum):
598            def __str__(self):
599                return 'MyStr'
600        class MyMethodEnum(Enum):
601            def hello(self):
602                return 'Hello!  My name is %s' % self.name
603        class Test1Enum(MyMethodEnum, int, MyStrEnum):
604            One = 1
605            Two = 2
606        self.assertTrue(Test1Enum._member_type_ is int)
607        self.assertEqual(str(Test1Enum.One), 'MyStr')
608        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
609        #
610        class Test2Enum(MyStrEnum, MyMethodEnum):
611            One = 1
612            Two = 2
613        self.assertEqual(str(Test2Enum.One), 'MyStr')
614        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
615
616    def test_inherited_data_type(self):
617        class HexInt(int):
618            __qualname__ = 'HexInt'
619            def __repr__(self):
620                return hex(self)
621        class MyEnum(HexInt, enum.Enum):
622            __qualname__ = 'MyEnum'
623            A = 1
624            B = 2
625            C = 3
626        self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
627        globals()['HexInt'] = HexInt
628        globals()['MyEnum'] = MyEnum
629        test_pickle_dump_load(self.assertIs, MyEnum.A)
630        test_pickle_dump_load(self.assertIs, MyEnum)
631        #
632        class SillyInt(HexInt):
633            __qualname__ = 'SillyInt'
634            pass
635        class MyOtherEnum(SillyInt, enum.Enum):
636            __qualname__ = 'MyOtherEnum'
637            D = 4
638            E = 5
639            F = 6
640        self.assertIs(MyOtherEnum._member_type_, SillyInt)
641        globals()['SillyInt'] = SillyInt
642        globals()['MyOtherEnum'] = MyOtherEnum
643        test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
644        test_pickle_dump_load(self.assertIs, MyOtherEnum)
645        #
646        class BrokenInt(int):
647            __qualname__ = 'BrokenInt'
648            def __new__(cls, value):
649                return int.__new__(cls, value)
650        class MyBrokenEnum(BrokenInt, Enum):
651            __qualname__ = 'MyBrokenEnum'
652            G = 7
653            H = 8
654            I = 9
655        self.assertIs(MyBrokenEnum._member_type_, BrokenInt)
656        self.assertIs(MyBrokenEnum(7), MyBrokenEnum.G)
657        globals()['BrokenInt'] = BrokenInt
658        globals()['MyBrokenEnum'] = MyBrokenEnum
659        test_pickle_exception(self.assertRaises, TypeError, MyBrokenEnum.G)
660        test_pickle_exception(self.assertRaises, PicklingError, MyBrokenEnum)
661
662    def test_too_many_data_types(self):
663        with self.assertRaisesRegex(TypeError, 'too many data types'):
664            class Huh(str, int, Enum):
665                One = 1
666
667        class MyStr(str):
668            def hello(self):
669                return 'hello, %s' % self
670        class MyInt(int):
671            def repr(self):
672                return hex(self)
673        with self.assertRaisesRegex(TypeError, 'too many data types'):
674            class Huh(MyStr, MyInt, Enum):
675                One = 1
676
677    def test_hash(self):
678        Season = self.Season
679        dates = {}
680        dates[Season.WINTER] = '1225'
681        dates[Season.SPRING] = '0315'
682        dates[Season.SUMMER] = '0704'
683        dates[Season.AUTUMN] = '1031'
684        self.assertEqual(dates[Season.AUTUMN], '1031')
685
686    def test_intenum_from_scratch(self):
687        class phy(int, Enum):
688            pi = 3
689            tau = 2 * pi
690        self.assertTrue(phy.pi < phy.tau)
691
692    def test_intenum_inherited(self):
693        class IntEnum(int, Enum):
694            pass
695        class phy(IntEnum):
696            pi = 3
697            tau = 2 * pi
698        self.assertTrue(phy.pi < phy.tau)
699
700    def test_floatenum_from_scratch(self):
701        class phy(float, Enum):
702            pi = 3.1415926
703            tau = 2 * pi
704        self.assertTrue(phy.pi < phy.tau)
705
706    def test_floatenum_inherited(self):
707        class FloatEnum(float, Enum):
708            pass
709        class phy(FloatEnum):
710            pi = 3.1415926
711            tau = 2 * pi
712        self.assertTrue(phy.pi < phy.tau)
713
714    def test_strenum_from_scratch(self):
715        class phy(str, Enum):
716            pi = 'Pi'
717            tau = 'Tau'
718        self.assertTrue(phy.pi < phy.tau)
719
720    def test_strenum_inherited(self):
721        class StrEnum(str, Enum):
722            pass
723        class phy(StrEnum):
724            pi = 'Pi'
725            tau = 'Tau'
726        self.assertTrue(phy.pi < phy.tau)
727
728
729    def test_intenum(self):
730        class WeekDay(IntEnum):
731            SUNDAY = 1
732            MONDAY = 2
733            TUESDAY = 3
734            WEDNESDAY = 4
735            THURSDAY = 5
736            FRIDAY = 6
737            SATURDAY = 7
738
739        self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
740        self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
741
742        lst = list(WeekDay)
743        self.assertEqual(len(lst), len(WeekDay))
744        self.assertEqual(len(WeekDay), 7)
745        target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
746        target = target.split()
747        for i, weekday in enumerate(target, 1):
748            e = WeekDay(i)
749            self.assertEqual(e, i)
750            self.assertEqual(int(e), i)
751            self.assertEqual(e.name, weekday)
752            self.assertIn(e, WeekDay)
753            self.assertEqual(lst.index(e)+1, i)
754            self.assertTrue(0 < e < 8)
755            self.assertIs(type(e), WeekDay)
756            self.assertIsInstance(e, int)
757            self.assertIsInstance(e, Enum)
758
759    def test_intenum_duplicates(self):
760        class WeekDay(IntEnum):
761            SUNDAY = 1
762            MONDAY = 2
763            TUESDAY = TEUSDAY = 3
764            WEDNESDAY = 4
765            THURSDAY = 5
766            FRIDAY = 6
767            SATURDAY = 7
768        self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
769        self.assertEqual(WeekDay(3).name, 'TUESDAY')
770        self.assertEqual([k for k,v in WeekDay.__members__.items()
771                if v.name != k], ['TEUSDAY', ])
772
773    def test_intenum_from_bytes(self):
774        self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
775        with self.assertRaises(ValueError):
776            IntStooges.from_bytes(b'\x00\x05', 'big')
777
778    def test_floatenum_fromhex(self):
779        h = float.hex(FloatStooges.MOE.value)
780        self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
781        h = float.hex(FloatStooges.MOE.value + 0.01)
782        with self.assertRaises(ValueError):
783            FloatStooges.fromhex(h)
784
785    def test_pickle_enum(self):
786        if isinstance(Stooges, Exception):
787            raise Stooges
788        test_pickle_dump_load(self.assertIs, Stooges.CURLY)
789        test_pickle_dump_load(self.assertIs, Stooges)
790
791    def test_pickle_int(self):
792        if isinstance(IntStooges, Exception):
793            raise IntStooges
794        test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
795        test_pickle_dump_load(self.assertIs, IntStooges)
796
797    def test_pickle_float(self):
798        if isinstance(FloatStooges, Exception):
799            raise FloatStooges
800        test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
801        test_pickle_dump_load(self.assertIs, FloatStooges)
802
803    def test_pickle_enum_function(self):
804        if isinstance(Answer, Exception):
805            raise Answer
806        test_pickle_dump_load(self.assertIs, Answer.him)
807        test_pickle_dump_load(self.assertIs, Answer)
808
809    def test_pickle_enum_function_with_module(self):
810        if isinstance(Question, Exception):
811            raise Question
812        test_pickle_dump_load(self.assertIs, Question.who)
813        test_pickle_dump_load(self.assertIs, Question)
814
815    def test_enum_function_with_qualname(self):
816        if isinstance(Theory, Exception):
817            raise Theory
818        self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
819
820    def test_class_nested_enum_and_pickle_protocol_four(self):
821        # would normally just have this directly in the class namespace
822        class NestedEnum(Enum):
823            twigs = 'common'
824            shiny = 'rare'
825
826        self.__class__.NestedEnum = NestedEnum
827        self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
828        test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
829
830    def test_pickle_by_name(self):
831        class ReplaceGlobalInt(IntEnum):
832            ONE = 1
833            TWO = 2
834        ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
835        for proto in range(HIGHEST_PROTOCOL):
836            self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
837
838    def test_exploding_pickle(self):
839        BadPickle = Enum(
840                'BadPickle', 'dill sweet bread-n-butter', module=__name__)
841        globals()['BadPickle'] = BadPickle
842        # now break BadPickle to test exception raising
843        enum._make_class_unpicklable(BadPickle)
844        test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
845        test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
846
847    def test_string_enum(self):
848        class SkillLevel(str, Enum):
849            master = 'what is the sound of one hand clapping?'
850            journeyman = 'why did the chicken cross the road?'
851            apprentice = 'knock, knock!'
852        self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
853
854    def test_getattr_getitem(self):
855        class Period(Enum):
856            morning = 1
857            noon = 2
858            evening = 3
859            night = 4
860        self.assertIs(Period(2), Period.noon)
861        self.assertIs(getattr(Period, 'night'), Period.night)
862        self.assertIs(Period['morning'], Period.morning)
863
864    def test_getattr_dunder(self):
865        Season = self.Season
866        self.assertTrue(getattr(Season, '__eq__'))
867
868    def test_iteration_order(self):
869        class Season(Enum):
870            SUMMER = 2
871            WINTER = 4
872            AUTUMN = 3
873            SPRING = 1
874        self.assertEqual(
875                list(Season),
876                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
877                )
878
879    def test_reversed_iteration_order(self):
880        self.assertEqual(
881                list(reversed(self.Season)),
882                [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
883                 self.Season.SPRING]
884                )
885
886    def test_programmatic_function_string(self):
887        SummerMonth = Enum('SummerMonth', 'june july august')
888        lst = list(SummerMonth)
889        self.assertEqual(len(lst), len(SummerMonth))
890        self.assertEqual(len(SummerMonth), 3, SummerMonth)
891        self.assertEqual(
892                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
893                lst,
894                )
895        for i, month in enumerate('june july august'.split(), 1):
896            e = SummerMonth(i)
897            self.assertEqual(int(e.value), i)
898            self.assertNotEqual(e, i)
899            self.assertEqual(e.name, month)
900            self.assertIn(e, SummerMonth)
901            self.assertIs(type(e), SummerMonth)
902
903    def test_programmatic_function_string_with_start(self):
904        SummerMonth = Enum('SummerMonth', 'june july august', start=10)
905        lst = list(SummerMonth)
906        self.assertEqual(len(lst), len(SummerMonth))
907        self.assertEqual(len(SummerMonth), 3, SummerMonth)
908        self.assertEqual(
909                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
910                lst,
911                )
912        for i, month in enumerate('june july august'.split(), 10):
913            e = SummerMonth(i)
914            self.assertEqual(int(e.value), i)
915            self.assertNotEqual(e, i)
916            self.assertEqual(e.name, month)
917            self.assertIn(e, SummerMonth)
918            self.assertIs(type(e), SummerMonth)
919
920    def test_programmatic_function_string_list(self):
921        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
922        lst = list(SummerMonth)
923        self.assertEqual(len(lst), len(SummerMonth))
924        self.assertEqual(len(SummerMonth), 3, SummerMonth)
925        self.assertEqual(
926                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
927                lst,
928                )
929        for i, month in enumerate('june july august'.split(), 1):
930            e = SummerMonth(i)
931            self.assertEqual(int(e.value), i)
932            self.assertNotEqual(e, i)
933            self.assertEqual(e.name, month)
934            self.assertIn(e, SummerMonth)
935            self.assertIs(type(e), SummerMonth)
936
937    def test_programmatic_function_string_list_with_start(self):
938        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
939        lst = list(SummerMonth)
940        self.assertEqual(len(lst), len(SummerMonth))
941        self.assertEqual(len(SummerMonth), 3, SummerMonth)
942        self.assertEqual(
943                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
944                lst,
945                )
946        for i, month in enumerate('june july august'.split(), 20):
947            e = SummerMonth(i)
948            self.assertEqual(int(e.value), i)
949            self.assertNotEqual(e, i)
950            self.assertEqual(e.name, month)
951            self.assertIn(e, SummerMonth)
952            self.assertIs(type(e), SummerMonth)
953
954    def test_programmatic_function_iterable(self):
955        SummerMonth = Enum(
956                'SummerMonth',
957                (('june', 1), ('july', 2), ('august', 3))
958                )
959        lst = list(SummerMonth)
960        self.assertEqual(len(lst), len(SummerMonth))
961        self.assertEqual(len(SummerMonth), 3, SummerMonth)
962        self.assertEqual(
963                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
964                lst,
965                )
966        for i, month in enumerate('june july august'.split(), 1):
967            e = SummerMonth(i)
968            self.assertEqual(int(e.value), i)
969            self.assertNotEqual(e, i)
970            self.assertEqual(e.name, month)
971            self.assertIn(e, SummerMonth)
972            self.assertIs(type(e), SummerMonth)
973
974    def test_programmatic_function_from_dict(self):
975        SummerMonth = Enum(
976                'SummerMonth',
977                OrderedDict((('june', 1), ('july', 2), ('august', 3)))
978                )
979        lst = list(SummerMonth)
980        self.assertEqual(len(lst), len(SummerMonth))
981        self.assertEqual(len(SummerMonth), 3, SummerMonth)
982        self.assertEqual(
983                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
984                lst,
985                )
986        for i, month in enumerate('june july august'.split(), 1):
987            e = SummerMonth(i)
988            self.assertEqual(int(e.value), i)
989            self.assertNotEqual(e, i)
990            self.assertEqual(e.name, month)
991            self.assertIn(e, SummerMonth)
992            self.assertIs(type(e), SummerMonth)
993
994    def test_programmatic_function_type(self):
995        SummerMonth = Enum('SummerMonth', 'june july august', type=int)
996        lst = list(SummerMonth)
997        self.assertEqual(len(lst), len(SummerMonth))
998        self.assertEqual(len(SummerMonth), 3, SummerMonth)
999        self.assertEqual(
1000                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1001                lst,
1002                )
1003        for i, month in enumerate('june july august'.split(), 1):
1004            e = SummerMonth(i)
1005            self.assertEqual(e, i)
1006            self.assertEqual(e.name, month)
1007            self.assertIn(e, SummerMonth)
1008            self.assertIs(type(e), SummerMonth)
1009
1010    def test_programmatic_function_type_with_start(self):
1011        SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1012        lst = list(SummerMonth)
1013        self.assertEqual(len(lst), len(SummerMonth))
1014        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1015        self.assertEqual(
1016                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1017                lst,
1018                )
1019        for i, month in enumerate('june july august'.split(), 30):
1020            e = SummerMonth(i)
1021            self.assertEqual(e, i)
1022            self.assertEqual(e.name, month)
1023            self.assertIn(e, SummerMonth)
1024            self.assertIs(type(e), SummerMonth)
1025
1026    def test_programmatic_function_type_from_subclass(self):
1027        SummerMonth = IntEnum('SummerMonth', 'june july august')
1028        lst = list(SummerMonth)
1029        self.assertEqual(len(lst), len(SummerMonth))
1030        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1031        self.assertEqual(
1032                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1033                lst,
1034                )
1035        for i, month in enumerate('june july august'.split(), 1):
1036            e = SummerMonth(i)
1037            self.assertEqual(e, i)
1038            self.assertEqual(e.name, month)
1039            self.assertIn(e, SummerMonth)
1040            self.assertIs(type(e), SummerMonth)
1041
1042    def test_programmatic_function_type_from_subclass_with_start(self):
1043        SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1044        lst = list(SummerMonth)
1045        self.assertEqual(len(lst), len(SummerMonth))
1046        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1047        self.assertEqual(
1048                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1049                lst,
1050                )
1051        for i, month in enumerate('june july august'.split(), 40):
1052            e = SummerMonth(i)
1053            self.assertEqual(e, i)
1054            self.assertEqual(e.name, month)
1055            self.assertIn(e, SummerMonth)
1056            self.assertIs(type(e), SummerMonth)
1057
1058    def test_subclassing(self):
1059        if isinstance(Name, Exception):
1060            raise Name
1061        self.assertEqual(Name.BDFL, 'Guido van Rossum')
1062        self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1063        self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
1064        test_pickle_dump_load(self.assertIs, Name.BDFL)
1065
1066    def test_extending(self):
1067        class Color(Enum):
1068            red = 1
1069            green = 2
1070            blue = 3
1071        with self.assertRaises(TypeError):
1072            class MoreColor(Color):
1073                cyan = 4
1074                magenta = 5
1075                yellow = 6
1076        with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1077            class EvenMoreColor(Color, IntEnum):
1078                chartruese = 7
1079
1080    def test_exclude_methods(self):
1081        class whatever(Enum):
1082            this = 'that'
1083            these = 'those'
1084            def really(self):
1085                return 'no, not %s' % self.value
1086        self.assertIsNot(type(whatever.really), whatever)
1087        self.assertEqual(whatever.this.really(), 'no, not that')
1088
1089    def test_wrong_inheritance_order(self):
1090        with self.assertRaises(TypeError):
1091            class Wrong(Enum, str):
1092                NotHere = 'error before this point'
1093
1094    def test_intenum_transitivity(self):
1095        class number(IntEnum):
1096            one = 1
1097            two = 2
1098            three = 3
1099        class numero(IntEnum):
1100            uno = 1
1101            dos = 2
1102            tres = 3
1103        self.assertEqual(number.one, numero.uno)
1104        self.assertEqual(number.two, numero.dos)
1105        self.assertEqual(number.three, numero.tres)
1106
1107    def test_wrong_enum_in_call(self):
1108        class Monochrome(Enum):
1109            black = 0
1110            white = 1
1111        class Gender(Enum):
1112            male = 0
1113            female = 1
1114        self.assertRaises(ValueError, Monochrome, Gender.male)
1115
1116    def test_wrong_enum_in_mixed_call(self):
1117        class Monochrome(IntEnum):
1118            black = 0
1119            white = 1
1120        class Gender(Enum):
1121            male = 0
1122            female = 1
1123        self.assertRaises(ValueError, Monochrome, Gender.male)
1124
1125    def test_mixed_enum_in_call_1(self):
1126        class Monochrome(IntEnum):
1127            black = 0
1128            white = 1
1129        class Gender(IntEnum):
1130            male = 0
1131            female = 1
1132        self.assertIs(Monochrome(Gender.female), Monochrome.white)
1133
1134    def test_mixed_enum_in_call_2(self):
1135        class Monochrome(Enum):
1136            black = 0
1137            white = 1
1138        class Gender(IntEnum):
1139            male = 0
1140            female = 1
1141        self.assertIs(Monochrome(Gender.male), Monochrome.black)
1142
1143    def test_flufl_enum(self):
1144        class Fluflnum(Enum):
1145            def __int__(self):
1146                return int(self.value)
1147        class MailManOptions(Fluflnum):
1148            option1 = 1
1149            option2 = 2
1150            option3 = 3
1151        self.assertEqual(int(MailManOptions.option1), 1)
1152
1153    def test_introspection(self):
1154        class Number(IntEnum):
1155            one = 100
1156            two = 200
1157        self.assertIs(Number.one._member_type_, int)
1158        self.assertIs(Number._member_type_, int)
1159        class String(str, Enum):
1160            yarn = 'soft'
1161            rope = 'rough'
1162            wire = 'hard'
1163        self.assertIs(String.yarn._member_type_, str)
1164        self.assertIs(String._member_type_, str)
1165        class Plain(Enum):
1166            vanilla = 'white'
1167            one = 1
1168        self.assertIs(Plain.vanilla._member_type_, object)
1169        self.assertIs(Plain._member_type_, object)
1170
1171    def test_no_such_enum_member(self):
1172        class Color(Enum):
1173            red = 1
1174            green = 2
1175            blue = 3
1176        with self.assertRaises(ValueError):
1177            Color(4)
1178        with self.assertRaises(KeyError):
1179            Color['chartreuse']
1180
1181    def test_new_repr(self):
1182        class Color(Enum):
1183            red = 1
1184            green = 2
1185            blue = 3
1186            def __repr__(self):
1187                return "don't you just love shades of %s?" % self.name
1188        self.assertEqual(
1189                repr(Color.blue),
1190                "don't you just love shades of blue?",
1191                )
1192
1193    def test_inherited_repr(self):
1194        class MyEnum(Enum):
1195            def __repr__(self):
1196                return "My name is %s." % self.name
1197        class MyIntEnum(int, MyEnum):
1198            this = 1
1199            that = 2
1200            theother = 3
1201        self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1202
1203    def test_multiple_mixin_mro(self):
1204        class auto_enum(type(Enum)):
1205            def __new__(metacls, cls, bases, classdict):
1206                temp = type(classdict)()
1207                temp._cls_name = cls
1208                names = set(classdict._member_names)
1209                i = 0
1210                for k in classdict._member_names:
1211                    v = classdict[k]
1212                    if v is Ellipsis:
1213                        v = i
1214                    else:
1215                        i = v
1216                    i += 1
1217                    temp[k] = v
1218                for k, v in classdict.items():
1219                    if k not in names:
1220                        temp[k] = v
1221                return super(auto_enum, metacls).__new__(
1222                        metacls, cls, bases, temp)
1223
1224        class AutoNumberedEnum(Enum, metaclass=auto_enum):
1225            pass
1226
1227        class AutoIntEnum(IntEnum, metaclass=auto_enum):
1228            pass
1229
1230        class TestAutoNumber(AutoNumberedEnum):
1231            a = ...
1232            b = 3
1233            c = ...
1234
1235        class TestAutoInt(AutoIntEnum):
1236            a = ...
1237            b = 3
1238            c = ...
1239
1240    def test_subclasses_with_getnewargs(self):
1241        class NamedInt(int):
1242            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1243            def __new__(cls, *args):
1244                _args = args
1245                name, *args = args
1246                if len(args) == 0:
1247                    raise TypeError("name and value must be specified")
1248                self = int.__new__(cls, *args)
1249                self._intname = name
1250                self._args = _args
1251                return self
1252            def __getnewargs__(self):
1253                return self._args
1254            @property
1255            def __name__(self):
1256                return self._intname
1257            def __repr__(self):
1258                # repr() is updated to include the name and type info
1259                return "{}({!r}, {})".format(type(self).__name__,
1260                                             self.__name__,
1261                                             int.__repr__(self))
1262            def __str__(self):
1263                # str() is unchanged, even if it relies on the repr() fallback
1264                base = int
1265                base_str = base.__str__
1266                if base_str.__objclass__ is object:
1267                    return base.__repr__(self)
1268                return base_str(self)
1269            # for simplicity, we only define one operator that
1270            # propagates expressions
1271            def __add__(self, other):
1272                temp = int(self) + int( other)
1273                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1274                    return NamedInt(
1275                        '({0} + {1})'.format(self.__name__, other.__name__),
1276                        temp )
1277                else:
1278                    return temp
1279
1280        class NEI(NamedInt, Enum):
1281            __qualname__ = 'NEI'      # needed for pickle protocol 4
1282            x = ('the-x', 1)
1283            y = ('the-y', 2)
1284
1285
1286        self.assertIs(NEI.__new__, Enum.__new__)
1287        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1288        globals()['NamedInt'] = NamedInt
1289        globals()['NEI'] = NEI
1290        NI5 = NamedInt('test', 5)
1291        self.assertEqual(NI5, 5)
1292        test_pickle_dump_load(self.assertEqual, NI5, 5)
1293        self.assertEqual(NEI.y.value, 2)
1294        test_pickle_dump_load(self.assertIs, NEI.y)
1295        test_pickle_dump_load(self.assertIs, NEI)
1296
1297    def test_subclasses_with_getnewargs_ex(self):
1298        class NamedInt(int):
1299            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1300            def __new__(cls, *args):
1301                _args = args
1302                name, *args = args
1303                if len(args) == 0:
1304                    raise TypeError("name and value must be specified")
1305                self = int.__new__(cls, *args)
1306                self._intname = name
1307                self._args = _args
1308                return self
1309            def __getnewargs_ex__(self):
1310                return self._args, {}
1311            @property
1312            def __name__(self):
1313                return self._intname
1314            def __repr__(self):
1315                # repr() is updated to include the name and type info
1316                return "{}({!r}, {})".format(type(self).__name__,
1317                                             self.__name__,
1318                                             int.__repr__(self))
1319            def __str__(self):
1320                # str() is unchanged, even if it relies on the repr() fallback
1321                base = int
1322                base_str = base.__str__
1323                if base_str.__objclass__ is object:
1324                    return base.__repr__(self)
1325                return base_str(self)
1326            # for simplicity, we only define one operator that
1327            # propagates expressions
1328            def __add__(self, other):
1329                temp = int(self) + int( other)
1330                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1331                    return NamedInt(
1332                        '({0} + {1})'.format(self.__name__, other.__name__),
1333                        temp )
1334                else:
1335                    return temp
1336
1337        class NEI(NamedInt, Enum):
1338            __qualname__ = 'NEI'      # needed for pickle protocol 4
1339            x = ('the-x', 1)
1340            y = ('the-y', 2)
1341
1342
1343        self.assertIs(NEI.__new__, Enum.__new__)
1344        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1345        globals()['NamedInt'] = NamedInt
1346        globals()['NEI'] = NEI
1347        NI5 = NamedInt('test', 5)
1348        self.assertEqual(NI5, 5)
1349        test_pickle_dump_load(self.assertEqual, NI5, 5)
1350        self.assertEqual(NEI.y.value, 2)
1351        test_pickle_dump_load(self.assertIs, NEI.y)
1352        test_pickle_dump_load(self.assertIs, NEI)
1353
1354    def test_subclasses_with_reduce(self):
1355        class NamedInt(int):
1356            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1357            def __new__(cls, *args):
1358                _args = args
1359                name, *args = args
1360                if len(args) == 0:
1361                    raise TypeError("name and value must be specified")
1362                self = int.__new__(cls, *args)
1363                self._intname = name
1364                self._args = _args
1365                return self
1366            def __reduce__(self):
1367                return self.__class__, self._args
1368            @property
1369            def __name__(self):
1370                return self._intname
1371            def __repr__(self):
1372                # repr() is updated to include the name and type info
1373                return "{}({!r}, {})".format(type(self).__name__,
1374                                             self.__name__,
1375                                             int.__repr__(self))
1376            def __str__(self):
1377                # str() is unchanged, even if it relies on the repr() fallback
1378                base = int
1379                base_str = base.__str__
1380                if base_str.__objclass__ is object:
1381                    return base.__repr__(self)
1382                return base_str(self)
1383            # for simplicity, we only define one operator that
1384            # propagates expressions
1385            def __add__(self, other):
1386                temp = int(self) + int( other)
1387                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1388                    return NamedInt(
1389                        '({0} + {1})'.format(self.__name__, other.__name__),
1390                        temp )
1391                else:
1392                    return temp
1393
1394        class NEI(NamedInt, Enum):
1395            __qualname__ = 'NEI'      # needed for pickle protocol 4
1396            x = ('the-x', 1)
1397            y = ('the-y', 2)
1398
1399
1400        self.assertIs(NEI.__new__, Enum.__new__)
1401        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1402        globals()['NamedInt'] = NamedInt
1403        globals()['NEI'] = NEI
1404        NI5 = NamedInt('test', 5)
1405        self.assertEqual(NI5, 5)
1406        test_pickle_dump_load(self.assertEqual, NI5, 5)
1407        self.assertEqual(NEI.y.value, 2)
1408        test_pickle_dump_load(self.assertIs, NEI.y)
1409        test_pickle_dump_load(self.assertIs, NEI)
1410
1411    def test_subclasses_with_reduce_ex(self):
1412        class NamedInt(int):
1413            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1414            def __new__(cls, *args):
1415                _args = args
1416                name, *args = args
1417                if len(args) == 0:
1418                    raise TypeError("name and value must be specified")
1419                self = int.__new__(cls, *args)
1420                self._intname = name
1421                self._args = _args
1422                return self
1423            def __reduce_ex__(self, proto):
1424                return self.__class__, self._args
1425            @property
1426            def __name__(self):
1427                return self._intname
1428            def __repr__(self):
1429                # repr() is updated to include the name and type info
1430                return "{}({!r}, {})".format(type(self).__name__,
1431                                             self.__name__,
1432                                             int.__repr__(self))
1433            def __str__(self):
1434                # str() is unchanged, even if it relies on the repr() fallback
1435                base = int
1436                base_str = base.__str__
1437                if base_str.__objclass__ is object:
1438                    return base.__repr__(self)
1439                return base_str(self)
1440            # for simplicity, we only define one operator that
1441            # propagates expressions
1442            def __add__(self, other):
1443                temp = int(self) + int( other)
1444                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1445                    return NamedInt(
1446                        '({0} + {1})'.format(self.__name__, other.__name__),
1447                        temp )
1448                else:
1449                    return temp
1450
1451        class NEI(NamedInt, Enum):
1452            __qualname__ = 'NEI'      # needed for pickle protocol 4
1453            x = ('the-x', 1)
1454            y = ('the-y', 2)
1455
1456
1457        self.assertIs(NEI.__new__, Enum.__new__)
1458        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1459        globals()['NamedInt'] = NamedInt
1460        globals()['NEI'] = NEI
1461        NI5 = NamedInt('test', 5)
1462        self.assertEqual(NI5, 5)
1463        test_pickle_dump_load(self.assertEqual, NI5, 5)
1464        self.assertEqual(NEI.y.value, 2)
1465        test_pickle_dump_load(self.assertIs, NEI.y)
1466        test_pickle_dump_load(self.assertIs, NEI)
1467
1468    def test_subclasses_without_direct_pickle_support(self):
1469        class NamedInt(int):
1470            __qualname__ = 'NamedInt'
1471            def __new__(cls, *args):
1472                _args = args
1473                name, *args = args
1474                if len(args) == 0:
1475                    raise TypeError("name and value must be specified")
1476                self = int.__new__(cls, *args)
1477                self._intname = name
1478                self._args = _args
1479                return self
1480            @property
1481            def __name__(self):
1482                return self._intname
1483            def __repr__(self):
1484                # repr() is updated to include the name and type info
1485                return "{}({!r}, {})".format(type(self).__name__,
1486                                             self.__name__,
1487                                             int.__repr__(self))
1488            def __str__(self):
1489                # str() is unchanged, even if it relies on the repr() fallback
1490                base = int
1491                base_str = base.__str__
1492                if base_str.__objclass__ is object:
1493                    return base.__repr__(self)
1494                return base_str(self)
1495            # for simplicity, we only define one operator that
1496            # propagates expressions
1497            def __add__(self, other):
1498                temp = int(self) + int( other)
1499                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1500                    return NamedInt(
1501                        '({0} + {1})'.format(self.__name__, other.__name__),
1502                        temp )
1503                else:
1504                    return temp
1505
1506        class NEI(NamedInt, Enum):
1507            __qualname__ = 'NEI'
1508            x = ('the-x', 1)
1509            y = ('the-y', 2)
1510
1511        self.assertIs(NEI.__new__, Enum.__new__)
1512        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1513        globals()['NamedInt'] = NamedInt
1514        globals()['NEI'] = NEI
1515        NI5 = NamedInt('test', 5)
1516        self.assertEqual(NI5, 5)
1517        self.assertEqual(NEI.y.value, 2)
1518        test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1519        test_pickle_exception(self.assertRaises, PicklingError, NEI)
1520
1521    def test_subclasses_without_direct_pickle_support_using_name(self):
1522        class NamedInt(int):
1523            __qualname__ = 'NamedInt'
1524            def __new__(cls, *args):
1525                _args = args
1526                name, *args = args
1527                if len(args) == 0:
1528                    raise TypeError("name and value must be specified")
1529                self = int.__new__(cls, *args)
1530                self._intname = name
1531                self._args = _args
1532                return self
1533            @property
1534            def __name__(self):
1535                return self._intname
1536            def __repr__(self):
1537                # repr() is updated to include the name and type info
1538                return "{}({!r}, {})".format(type(self).__name__,
1539                                             self.__name__,
1540                                             int.__repr__(self))
1541            def __str__(self):
1542                # str() is unchanged, even if it relies on the repr() fallback
1543                base = int
1544                base_str = base.__str__
1545                if base_str.__objclass__ is object:
1546                    return base.__repr__(self)
1547                return base_str(self)
1548            # for simplicity, we only define one operator that
1549            # propagates expressions
1550            def __add__(self, other):
1551                temp = int(self) + int( other)
1552                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1553                    return NamedInt(
1554                        '({0} + {1})'.format(self.__name__, other.__name__),
1555                        temp )
1556                else:
1557                    return temp
1558
1559        class NEI(NamedInt, Enum):
1560            __qualname__ = 'NEI'
1561            x = ('the-x', 1)
1562            y = ('the-y', 2)
1563            def __reduce_ex__(self, proto):
1564                return getattr, (self.__class__, self._name_)
1565
1566        self.assertIs(NEI.__new__, Enum.__new__)
1567        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1568        globals()['NamedInt'] = NamedInt
1569        globals()['NEI'] = NEI
1570        NI5 = NamedInt('test', 5)
1571        self.assertEqual(NI5, 5)
1572        self.assertEqual(NEI.y.value, 2)
1573        test_pickle_dump_load(self.assertIs, NEI.y)
1574        test_pickle_dump_load(self.assertIs, NEI)
1575
1576    def test_tuple_subclass(self):
1577        class SomeTuple(tuple, Enum):
1578            __qualname__ = 'SomeTuple'      # needed for pickle protocol 4
1579            first = (1, 'for the money')
1580            second = (2, 'for the show')
1581            third = (3, 'for the music')
1582        self.assertIs(type(SomeTuple.first), SomeTuple)
1583        self.assertIsInstance(SomeTuple.second, tuple)
1584        self.assertEqual(SomeTuple.third, (3, 'for the music'))
1585        globals()['SomeTuple'] = SomeTuple
1586        test_pickle_dump_load(self.assertIs, SomeTuple.first)
1587
1588    def test_duplicate_values_give_unique_enum_items(self):
1589        class AutoNumber(Enum):
1590            first = ()
1591            second = ()
1592            third = ()
1593            def __new__(cls):
1594                value = len(cls.__members__) + 1
1595                obj = object.__new__(cls)
1596                obj._value_ = value
1597                return obj
1598            def __int__(self):
1599                return int(self._value_)
1600        self.assertEqual(
1601                list(AutoNumber),
1602                [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1603                )
1604        self.assertEqual(int(AutoNumber.second), 2)
1605        self.assertEqual(AutoNumber.third.value, 3)
1606        self.assertIs(AutoNumber(1), AutoNumber.first)
1607
1608    def test_inherited_new_from_enhanced_enum(self):
1609        class AutoNumber(Enum):
1610            def __new__(cls):
1611                value = len(cls.__members__) + 1
1612                obj = object.__new__(cls)
1613                obj._value_ = value
1614                return obj
1615            def __int__(self):
1616                return int(self._value_)
1617        class Color(AutoNumber):
1618            red = ()
1619            green = ()
1620            blue = ()
1621        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1622        self.assertEqual(list(map(int, Color)), [1, 2, 3])
1623
1624    def test_inherited_new_from_mixed_enum(self):
1625        class AutoNumber(IntEnum):
1626            def __new__(cls):
1627                value = len(cls.__members__) + 1
1628                obj = int.__new__(cls, value)
1629                obj._value_ = value
1630                return obj
1631        class Color(AutoNumber):
1632            red = ()
1633            green = ()
1634            blue = ()
1635        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1636        self.assertEqual(list(map(int, Color)), [1, 2, 3])
1637
1638    def test_equality(self):
1639        class OrdinaryEnum(Enum):
1640            a = 1
1641        self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1642        self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
1643
1644    def test_ordered_mixin(self):
1645        class OrderedEnum(Enum):
1646            def __ge__(self, other):
1647                if self.__class__ is other.__class__:
1648                    return self._value_ >= other._value_
1649                return NotImplemented
1650            def __gt__(self, other):
1651                if self.__class__ is other.__class__:
1652                    return self._value_ > other._value_
1653                return NotImplemented
1654            def __le__(self, other):
1655                if self.__class__ is other.__class__:
1656                    return self._value_ <= other._value_
1657                return NotImplemented
1658            def __lt__(self, other):
1659                if self.__class__ is other.__class__:
1660                    return self._value_ < other._value_
1661                return NotImplemented
1662        class Grade(OrderedEnum):
1663            A = 5
1664            B = 4
1665            C = 3
1666            D = 2
1667            F = 1
1668        self.assertGreater(Grade.A, Grade.B)
1669        self.assertLessEqual(Grade.F, Grade.C)
1670        self.assertLess(Grade.D, Grade.A)
1671        self.assertGreaterEqual(Grade.B, Grade.B)
1672        self.assertEqual(Grade.B, Grade.B)
1673        self.assertNotEqual(Grade.C, Grade.D)
1674
1675    def test_extending2(self):
1676        class Shade(Enum):
1677            def shade(self):
1678                print(self.name)
1679        class Color(Shade):
1680            red = 1
1681            green = 2
1682            blue = 3
1683        with self.assertRaises(TypeError):
1684            class MoreColor(Color):
1685                cyan = 4
1686                magenta = 5
1687                yellow = 6
1688
1689    def test_extending3(self):
1690        class Shade(Enum):
1691            def shade(self):
1692                return self.name
1693        class Color(Shade):
1694            def hex(self):
1695                return '%s hexlified!' % self.value
1696        class MoreColor(Color):
1697            cyan = 4
1698            magenta = 5
1699            yellow = 6
1700        self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1701
1702    def test_subclass_duplicate_name(self):
1703        class Base(Enum):
1704            def test(self):
1705                pass
1706        class Test(Base):
1707            test = 1
1708        self.assertIs(type(Test.test), Test)
1709
1710    def test_subclass_duplicate_name_dynamic(self):
1711        from types import DynamicClassAttribute
1712        class Base(Enum):
1713            @DynamicClassAttribute
1714            def test(self):
1715                return 'dynamic'
1716        class Test(Base):
1717            test = 1
1718        self.assertEqual(Test.test.test, 'dynamic')
1719
1720    def test_no_duplicates(self):
1721        class UniqueEnum(Enum):
1722            def __init__(self, *args):
1723                cls = self.__class__
1724                if any(self.value == e.value for e in cls):
1725                    a = self.name
1726                    e = cls(self.value).name
1727                    raise ValueError(
1728                            "aliases not allowed in UniqueEnum:  %r --> %r"
1729                            % (a, e)
1730                            )
1731        class Color(UniqueEnum):
1732            red = 1
1733            green = 2
1734            blue = 3
1735        with self.assertRaises(ValueError):
1736            class Color(UniqueEnum):
1737                red = 1
1738                green = 2
1739                blue = 3
1740                grene = 2
1741
1742    def test_init(self):
1743        class Planet(Enum):
1744            MERCURY = (3.303e+23, 2.4397e6)
1745            VENUS   = (4.869e+24, 6.0518e6)
1746            EARTH   = (5.976e+24, 6.37814e6)
1747            MARS    = (6.421e+23, 3.3972e6)
1748            JUPITER = (1.9e+27,   7.1492e7)
1749            SATURN  = (5.688e+26, 6.0268e7)
1750            URANUS  = (8.686e+25, 2.5559e7)
1751            NEPTUNE = (1.024e+26, 2.4746e7)
1752            def __init__(self, mass, radius):
1753                self.mass = mass       # in kilograms
1754                self.radius = radius   # in meters
1755            @property
1756            def surface_gravity(self):
1757                # universal gravitational constant  (m3 kg-1 s-2)
1758                G = 6.67300E-11
1759                return G * self.mass / (self.radius * self.radius)
1760        self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1761        self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1762
1763    def test_ignore(self):
1764        class Period(timedelta, Enum):
1765            '''
1766            different lengths of time
1767            '''
1768            def __new__(cls, value, period):
1769                obj = timedelta.__new__(cls, value)
1770                obj._value_ = value
1771                obj.period = period
1772                return obj
1773            _ignore_ = 'Period i'
1774            Period = vars()
1775            for i in range(13):
1776                Period['month_%d' % i] = i*30, 'month'
1777            for i in range(53):
1778                Period['week_%d' % i] = i*7, 'week'
1779            for i in range(32):
1780                Period['day_%d' % i] = i, 'day'
1781            OneDay = day_1
1782            OneWeek = week_1
1783            OneMonth = month_1
1784        self.assertFalse(hasattr(Period, '_ignore_'))
1785        self.assertFalse(hasattr(Period, 'Period'))
1786        self.assertFalse(hasattr(Period, 'i'))
1787        self.assertTrue(isinstance(Period.day_1, timedelta))
1788        self.assertTrue(Period.month_1 is Period.day_30)
1789        self.assertTrue(Period.week_4 is Period.day_28)
1790
1791    def test_nonhash_value(self):
1792        class AutoNumberInAList(Enum):
1793            def __new__(cls):
1794                value = [len(cls.__members__) + 1]
1795                obj = object.__new__(cls)
1796                obj._value_ = value
1797                return obj
1798        class ColorInAList(AutoNumberInAList):
1799            red = ()
1800            green = ()
1801            blue = ()
1802        self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
1803        for enum, value in zip(ColorInAList, range(3)):
1804            value += 1
1805            self.assertEqual(enum.value, [value])
1806            self.assertIs(ColorInAList([value]), enum)
1807
1808    def test_conflicting_types_resolved_in_new(self):
1809        class LabelledIntEnum(int, Enum):
1810            def __new__(cls, *args):
1811                value, label = args
1812                obj = int.__new__(cls, value)
1813                obj.label = label
1814                obj._value_ = value
1815                return obj
1816
1817        class LabelledList(LabelledIntEnum):
1818            unprocessed = (1, "Unprocessed")
1819            payment_complete = (2, "Payment Complete")
1820
1821        self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1822        self.assertEqual(LabelledList.unprocessed, 1)
1823        self.assertEqual(LabelledList(1), LabelledList.unprocessed)
1824
1825    def test_auto_number(self):
1826        class Color(Enum):
1827            red = auto()
1828            blue = auto()
1829            green = auto()
1830
1831        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1832        self.assertEqual(Color.red.value, 1)
1833        self.assertEqual(Color.blue.value, 2)
1834        self.assertEqual(Color.green.value, 3)
1835
1836    def test_auto_name(self):
1837        class Color(Enum):
1838            def _generate_next_value_(name, start, count, last):
1839                return name
1840            red = auto()
1841            blue = auto()
1842            green = auto()
1843
1844        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1845        self.assertEqual(Color.red.value, 'red')
1846        self.assertEqual(Color.blue.value, 'blue')
1847        self.assertEqual(Color.green.value, 'green')
1848
1849    def test_auto_name_inherit(self):
1850        class AutoNameEnum(Enum):
1851            def _generate_next_value_(name, start, count, last):
1852                return name
1853        class Color(AutoNameEnum):
1854            red = auto()
1855            blue = auto()
1856            green = auto()
1857
1858        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1859        self.assertEqual(Color.red.value, 'red')
1860        self.assertEqual(Color.blue.value, 'blue')
1861        self.assertEqual(Color.green.value, 'green')
1862
1863    def test_auto_garbage(self):
1864        class Color(Enum):
1865            red = 'red'
1866            blue = auto()
1867        self.assertEqual(Color.blue.value, 1)
1868
1869    def test_auto_garbage_corrected(self):
1870        class Color(Enum):
1871            red = 'red'
1872            blue = 2
1873            green = auto()
1874
1875        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1876        self.assertEqual(Color.red.value, 'red')
1877        self.assertEqual(Color.blue.value, 2)
1878        self.assertEqual(Color.green.value, 3)
1879
1880    def test_auto_order(self):
1881        with self.assertRaises(TypeError):
1882            class Color(Enum):
1883                red = auto()
1884                green = auto()
1885                blue = auto()
1886                def _generate_next_value_(name, start, count, last):
1887                    return name
1888
1889    def test_auto_order_wierd(self):
1890        weird_auto = auto()
1891        weird_auto.value = 'pathological case'
1892        class Color(Enum):
1893            red = weird_auto
1894            def _generate_next_value_(name, start, count, last):
1895                return name
1896            blue = auto()
1897        self.assertEqual(list(Color), [Color.red, Color.blue])
1898        self.assertEqual(Color.red.value, 'pathological case')
1899        self.assertEqual(Color.blue.value, 'blue')
1900
1901    def test_duplicate_auto(self):
1902        class Dupes(Enum):
1903            first = primero = auto()
1904            second = auto()
1905            third = auto()
1906        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1907
1908    def test_default_missing(self):
1909        class Color(Enum):
1910            RED = 1
1911            GREEN = 2
1912            BLUE = 3
1913        try:
1914            Color(7)
1915        except ValueError as exc:
1916            self.assertTrue(exc.__context__ is None)
1917        else:
1918            raise Exception('Exception not raised.')
1919
1920    def test_missing(self):
1921        class Color(Enum):
1922            red = 1
1923            green = 2
1924            blue = 3
1925            @classmethod
1926            def _missing_(cls, item):
1927                if item == 'three':
1928                    return cls.blue
1929                elif item == 'bad return':
1930                    # trigger internal error
1931                    return 5
1932                elif item == 'error out':
1933                    raise ZeroDivisionError
1934                else:
1935                    # trigger not found
1936                    return None
1937        self.assertIs(Color('three'), Color.blue)
1938        try:
1939            Color(7)
1940        except ValueError as exc:
1941            self.assertTrue(exc.__context__ is None)
1942        else:
1943            raise Exception('Exception not raised.')
1944        try:
1945            Color('bad return')
1946        except TypeError as exc:
1947            self.assertTrue(isinstance(exc.__context__, ValueError))
1948        else:
1949            raise Exception('Exception not raised.')
1950        try:
1951            Color('error out')
1952        except ZeroDivisionError as exc:
1953            self.assertTrue(isinstance(exc.__context__, ValueError))
1954        else:
1955            raise Exception('Exception not raised.')
1956
1957    def test_missing_exceptions_reset(self):
1958        import weakref
1959        #
1960        class TestEnum(enum.Enum):
1961            VAL1 = 'val1'
1962            VAL2 = 'val2'
1963        #
1964        class Class1:
1965            def __init__(self):
1966                # Gracefully handle an exception of our own making
1967                try:
1968                    raise ValueError()
1969                except ValueError:
1970                    pass
1971        #
1972        class Class2:
1973            def __init__(self):
1974                # Gracefully handle an exception of Enum's making
1975                try:
1976                    TestEnum('invalid_value')
1977                except ValueError:
1978                    pass
1979        # No strong refs here so these are free to die.
1980        class_1_ref = weakref.ref(Class1())
1981        class_2_ref = weakref.ref(Class2())
1982        #
1983        # The exception raised by Enum creates a reference loop and thus
1984        # Class2 instances will stick around until the next gargage collection
1985        # cycle, unlike Class1.
1986        self.assertIs(class_1_ref(), None)
1987        self.assertIs(class_2_ref(), None)
1988
1989    def test_multiple_mixin(self):
1990        class MaxMixin:
1991            @classproperty
1992            def MAX(cls):
1993                max = len(cls)
1994                cls.MAX = max
1995                return max
1996        class StrMixin:
1997            def __str__(self):
1998                return self._name_.lower()
1999        class SomeEnum(Enum):
2000            def behavior(self):
2001                return 'booyah'
2002        class AnotherEnum(Enum):
2003            def behavior(self):
2004                return 'nuhuh!'
2005            def social(self):
2006                return "what's up?"
2007        class Color(MaxMixin, Enum):
2008            RED = auto()
2009            GREEN = auto()
2010            BLUE = auto()
2011        self.assertEqual(Color.RED.value, 1)
2012        self.assertEqual(Color.GREEN.value, 2)
2013        self.assertEqual(Color.BLUE.value, 3)
2014        self.assertEqual(Color.MAX, 3)
2015        self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2016        class Color(MaxMixin, StrMixin, Enum):
2017            RED = auto()
2018            GREEN = auto()
2019            BLUE = auto()
2020        self.assertEqual(Color.RED.value, 1)
2021        self.assertEqual(Color.GREEN.value, 2)
2022        self.assertEqual(Color.BLUE.value, 3)
2023        self.assertEqual(Color.MAX, 3)
2024        self.assertEqual(str(Color.BLUE), 'blue')
2025        class Color(StrMixin, MaxMixin, Enum):
2026            RED = auto()
2027            GREEN = auto()
2028            BLUE = auto()
2029        self.assertEqual(Color.RED.value, 1)
2030        self.assertEqual(Color.GREEN.value, 2)
2031        self.assertEqual(Color.BLUE.value, 3)
2032        self.assertEqual(Color.MAX, 3)
2033        self.assertEqual(str(Color.BLUE), 'blue')
2034        class CoolColor(StrMixin, SomeEnum, Enum):
2035            RED = auto()
2036            GREEN = auto()
2037            BLUE = auto()
2038        self.assertEqual(CoolColor.RED.value, 1)
2039        self.assertEqual(CoolColor.GREEN.value, 2)
2040        self.assertEqual(CoolColor.BLUE.value, 3)
2041        self.assertEqual(str(CoolColor.BLUE), 'blue')
2042        self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2043        class CoolerColor(StrMixin, AnotherEnum, Enum):
2044            RED = auto()
2045            GREEN = auto()
2046            BLUE = auto()
2047        self.assertEqual(CoolerColor.RED.value, 1)
2048        self.assertEqual(CoolerColor.GREEN.value, 2)
2049        self.assertEqual(CoolerColor.BLUE.value, 3)
2050        self.assertEqual(str(CoolerColor.BLUE), 'blue')
2051        self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2052        self.assertEqual(CoolerColor.RED.social(), "what's up?")
2053        class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2054            RED = auto()
2055            GREEN = auto()
2056            BLUE = auto()
2057        self.assertEqual(CoolestColor.RED.value, 1)
2058        self.assertEqual(CoolestColor.GREEN.value, 2)
2059        self.assertEqual(CoolestColor.BLUE.value, 3)
2060        self.assertEqual(str(CoolestColor.BLUE), 'blue')
2061        self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2062        self.assertEqual(CoolestColor.RED.social(), "what's up?")
2063        class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2064            RED = auto()
2065            GREEN = auto()
2066            BLUE = auto()
2067        self.assertEqual(ConfusedColor.RED.value, 1)
2068        self.assertEqual(ConfusedColor.GREEN.value, 2)
2069        self.assertEqual(ConfusedColor.BLUE.value, 3)
2070        self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2071        self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2072        self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2073        class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2074            RED = auto()
2075            GREEN = auto()
2076            BLUE = auto()
2077        self.assertEqual(ReformedColor.RED.value, 1)
2078        self.assertEqual(ReformedColor.GREEN.value, 2)
2079        self.assertEqual(ReformedColor.BLUE.value, 3)
2080        self.assertEqual(str(ReformedColor.BLUE), 'blue')
2081        self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2082        self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2083        self.assertTrue(issubclass(ReformedColor, int))
2084
2085    def test_multiple_inherited_mixin(self):
2086        class StrEnum(str, Enum):
2087            def __new__(cls, *args, **kwargs):
2088                for a in args:
2089                    if not isinstance(a, str):
2090                        raise TypeError("Enumeration '%s' (%s) is not"
2091                                        " a string" % (a, type(a).__name__))
2092                return str.__new__(cls, *args, **kwargs)
2093        @unique
2094        class Decision1(StrEnum):
2095            REVERT = "REVERT"
2096            REVERT_ALL = "REVERT_ALL"
2097            RETRY = "RETRY"
2098        class MyEnum(StrEnum):
2099            pass
2100        @unique
2101        class Decision2(MyEnum):
2102            REVERT = "REVERT"
2103            REVERT_ALL = "REVERT_ALL"
2104            RETRY = "RETRY"
2105
2106    def test_multiple_mixin_inherited(self):
2107        class MyInt(int):
2108            def __new__(cls, value):
2109                return super().__new__(cls, value)
2110
2111        class HexMixin:
2112            def __repr__(self):
2113                return hex(self)
2114
2115        class MyIntEnum(HexMixin, MyInt, enum.Enum):
2116            pass
2117
2118        class Foo(MyIntEnum):
2119            TEST = 1
2120        self.assertTrue(isinstance(Foo.TEST, MyInt))
2121        self.assertEqual(repr(Foo.TEST), "0x1")
2122
2123        class Fee(MyIntEnum):
2124            TEST = 1
2125            def __new__(cls, value):
2126                value += 1
2127                member = int.__new__(cls, value)
2128                member._value_ = value
2129                return member
2130        self.assertEqual(Fee.TEST, 2)
2131
2132    def test_empty_globals(self):
2133        # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2134        # when using compile and exec because f_globals is empty
2135        code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2136        code = compile(code, "<string>", "exec")
2137        global_ns = {}
2138        local_ls = {}
2139        exec(code, global_ns, local_ls)
2140
2141    @unittest.skipUnless(
2142            python_version == (3, 9),
2143            'private variables are now normal attributes',
2144            )
2145    def test_warning_for_private_variables(self):
2146        with self.assertWarns(DeprecationWarning):
2147            class Private(Enum):
2148                __corporal = 'Radar'
2149        self.assertEqual(Private._Private__corporal.value, 'Radar')
2150        try:
2151            with self.assertWarns(DeprecationWarning):
2152                class Private(Enum):
2153                    __major_ = 'Hoolihan'
2154        except ValueError:
2155            pass
2156
2157
2158class TestOrder(unittest.TestCase):
2159
2160    def test_same_members(self):
2161        class Color(Enum):
2162            _order_ = 'red green blue'
2163            red = 1
2164            green = 2
2165            blue = 3
2166
2167    def test_same_members_with_aliases(self):
2168        class Color(Enum):
2169            _order_ = 'red green blue'
2170            red = 1
2171            green = 2
2172            blue = 3
2173            verde = green
2174
2175    def test_same_members_wrong_order(self):
2176        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2177            class Color(Enum):
2178                _order_ = 'red green blue'
2179                red = 1
2180                blue = 3
2181                green = 2
2182
2183    def test_order_has_extra_members(self):
2184        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2185            class Color(Enum):
2186                _order_ = 'red green blue purple'
2187                red = 1
2188                green = 2
2189                blue = 3
2190
2191    def test_order_has_extra_members_with_aliases(self):
2192        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2193            class Color(Enum):
2194                _order_ = 'red green blue purple'
2195                red = 1
2196                green = 2
2197                blue = 3
2198                verde = green
2199
2200    def test_enum_has_extra_members(self):
2201        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2202            class Color(Enum):
2203                _order_ = 'red green blue'
2204                red = 1
2205                green = 2
2206                blue = 3
2207                purple = 4
2208
2209    def test_enum_has_extra_members_with_aliases(self):
2210        with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2211            class Color(Enum):
2212                _order_ = 'red green blue'
2213                red = 1
2214                green = 2
2215                blue = 3
2216                purple = 4
2217                verde = green
2218
2219
2220class TestFlag(unittest.TestCase):
2221    """Tests of the Flags."""
2222
2223    class Perm(Flag):
2224        R, W, X = 4, 2, 1
2225
2226    class Open(Flag):
2227        RO = 0
2228        WO = 1
2229        RW = 2
2230        AC = 3
2231        CE = 1<<19
2232
2233    class Color(Flag):
2234        BLACK = 0
2235        RED = 1
2236        GREEN = 2
2237        BLUE = 4
2238        PURPLE = RED|BLUE
2239
2240    def test_str(self):
2241        Perm = self.Perm
2242        self.assertEqual(str(Perm.R), 'Perm.R')
2243        self.assertEqual(str(Perm.W), 'Perm.W')
2244        self.assertEqual(str(Perm.X), 'Perm.X')
2245        self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2246        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2247        self.assertEqual(str(Perm(0)), 'Perm.0')
2248        self.assertEqual(str(~Perm.R), 'Perm.W|X')
2249        self.assertEqual(str(~Perm.W), 'Perm.R|X')
2250        self.assertEqual(str(~Perm.X), 'Perm.R|W')
2251        self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2252        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2253        self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2254
2255        Open = self.Open
2256        self.assertEqual(str(Open.RO), 'Open.RO')
2257        self.assertEqual(str(Open.WO), 'Open.WO')
2258        self.assertEqual(str(Open.AC), 'Open.AC')
2259        self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2260        self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2261        self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2262        self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2263        self.assertEqual(str(~Open.AC), 'Open.CE')
2264        self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2265        self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2266
2267    def test_repr(self):
2268        Perm = self.Perm
2269        self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2270        self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2271        self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2272        self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2273        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2274        self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2275        self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2276        self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2277        self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2278        self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2279        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
2280        self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2281
2282        Open = self.Open
2283        self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2284        self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2285        self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2286        self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2287        self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2288        self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
2289        self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2290        self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2291        self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2292        self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2293
2294    def test_format(self):
2295        Perm = self.Perm
2296        self.assertEqual(format(Perm.R, ''), 'Perm.R')
2297        self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2298
2299    def test_or(self):
2300        Perm = self.Perm
2301        for i in Perm:
2302            for j in Perm:
2303                self.assertEqual((i | j), Perm(i.value | j.value))
2304                self.assertEqual((i | j).value, i.value | j.value)
2305                self.assertIs(type(i | j), Perm)
2306        for i in Perm:
2307            self.assertIs(i | i, i)
2308        Open = self.Open
2309        self.assertIs(Open.RO | Open.CE, Open.CE)
2310
2311    def test_and(self):
2312        Perm = self.Perm
2313        RW = Perm.R | Perm.W
2314        RX = Perm.R | Perm.X
2315        WX = Perm.W | Perm.X
2316        RWX = Perm.R | Perm.W | Perm.X
2317        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2318        for i in values:
2319            for j in values:
2320                self.assertEqual((i & j).value, i.value & j.value)
2321                self.assertIs(type(i & j), Perm)
2322        for i in Perm:
2323            self.assertIs(i & i, i)
2324            self.assertIs(i & RWX, i)
2325            self.assertIs(RWX & i, i)
2326        Open = self.Open
2327        self.assertIs(Open.RO & Open.CE, Open.RO)
2328
2329    def test_xor(self):
2330        Perm = self.Perm
2331        for i in Perm:
2332            for j in Perm:
2333                self.assertEqual((i ^ j).value, i.value ^ j.value)
2334                self.assertIs(type(i ^ j), Perm)
2335        for i in Perm:
2336            self.assertIs(i ^ Perm(0), i)
2337            self.assertIs(Perm(0) ^ i, i)
2338        Open = self.Open
2339        self.assertIs(Open.RO ^ Open.CE, Open.CE)
2340        self.assertIs(Open.CE ^ Open.CE, Open.RO)
2341
2342    def test_invert(self):
2343        Perm = self.Perm
2344        RW = Perm.R | Perm.W
2345        RX = Perm.R | Perm.X
2346        WX = Perm.W | Perm.X
2347        RWX = Perm.R | Perm.W | Perm.X
2348        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2349        for i in values:
2350            self.assertIs(type(~i), Perm)
2351            self.assertEqual(~~i, i)
2352        for i in Perm:
2353            self.assertIs(~~i, i)
2354        Open = self.Open
2355        self.assertIs(Open.WO & ~Open.WO, Open.RO)
2356        self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2357
2358    def test_bool(self):
2359        Perm = self.Perm
2360        for f in Perm:
2361            self.assertTrue(f)
2362        Open = self.Open
2363        for f in Open:
2364            self.assertEqual(bool(f.value), bool(f))
2365
2366    def test_programatic_function_string(self):
2367        Perm = Flag('Perm', 'R W X')
2368        lst = list(Perm)
2369        self.assertEqual(len(lst), len(Perm))
2370        self.assertEqual(len(Perm), 3, Perm)
2371        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2372        for i, n in enumerate('R W X'.split()):
2373            v = 1<<i
2374            e = Perm(v)
2375            self.assertEqual(e.value, v)
2376            self.assertEqual(type(e.value), int)
2377            self.assertEqual(e.name, n)
2378            self.assertIn(e, Perm)
2379            self.assertIs(type(e), Perm)
2380
2381    def test_programatic_function_string_with_start(self):
2382        Perm = Flag('Perm', 'R W X', start=8)
2383        lst = list(Perm)
2384        self.assertEqual(len(lst), len(Perm))
2385        self.assertEqual(len(Perm), 3, Perm)
2386        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2387        for i, n in enumerate('R W X'.split()):
2388            v = 8<<i
2389            e = Perm(v)
2390            self.assertEqual(e.value, v)
2391            self.assertEqual(type(e.value), int)
2392            self.assertEqual(e.name, n)
2393            self.assertIn(e, Perm)
2394            self.assertIs(type(e), Perm)
2395
2396    def test_programatic_function_string_list(self):
2397        Perm = Flag('Perm', ['R', 'W', 'X'])
2398        lst = list(Perm)
2399        self.assertEqual(len(lst), len(Perm))
2400        self.assertEqual(len(Perm), 3, Perm)
2401        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2402        for i, n in enumerate('R W X'.split()):
2403            v = 1<<i
2404            e = Perm(v)
2405            self.assertEqual(e.value, v)
2406            self.assertEqual(type(e.value), int)
2407            self.assertEqual(e.name, n)
2408            self.assertIn(e, Perm)
2409            self.assertIs(type(e), Perm)
2410
2411    def test_programatic_function_iterable(self):
2412        Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
2413        lst = list(Perm)
2414        self.assertEqual(len(lst), len(Perm))
2415        self.assertEqual(len(Perm), 3, Perm)
2416        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2417        for i, n in enumerate('R W X'.split()):
2418            v = 1<<(2*i+1)
2419            e = Perm(v)
2420            self.assertEqual(e.value, v)
2421            self.assertEqual(type(e.value), int)
2422            self.assertEqual(e.name, n)
2423            self.assertIn(e, Perm)
2424            self.assertIs(type(e), Perm)
2425
2426    def test_programatic_function_from_dict(self):
2427        Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
2428        lst = list(Perm)
2429        self.assertEqual(len(lst), len(Perm))
2430        self.assertEqual(len(Perm), 3, Perm)
2431        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2432        for i, n in enumerate('R W X'.split()):
2433            v = 1<<(2*i+1)
2434            e = Perm(v)
2435            self.assertEqual(e.value, v)
2436            self.assertEqual(type(e.value), int)
2437            self.assertEqual(e.name, n)
2438            self.assertIn(e, Perm)
2439            self.assertIs(type(e), Perm)
2440
2441    def test_pickle(self):
2442        if isinstance(FlagStooges, Exception):
2443            raise FlagStooges
2444        test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2445        test_pickle_dump_load(self.assertIs, FlagStooges)
2446
2447    @unittest.skipIf(
2448            python_version >= (3, 12),
2449            '__contains__ now returns True/False for all inputs',
2450            )
2451    def test_contains_er(self):
2452        Open = self.Open
2453        Color = self.Color
2454        self.assertFalse(Color.BLACK in Open)
2455        self.assertFalse(Open.RO in Color)
2456        with self.assertRaises(TypeError):
2457            with self.assertWarns(DeprecationWarning):
2458                'BLACK' in Color
2459        with self.assertRaises(TypeError):
2460            with self.assertWarns(DeprecationWarning):
2461                'RO' in Open
2462        with self.assertRaises(TypeError):
2463            with self.assertWarns(DeprecationWarning):
2464                1 in Color
2465        with self.assertRaises(TypeError):
2466            with self.assertWarns(DeprecationWarning):
2467                1 in Open
2468
2469    @unittest.skipIf(
2470            python_version < (3, 12),
2471            '__contains__ only works with enum memmbers before 3.12',
2472            )
2473    def test_contains_tf(self):
2474        Open = self.Open
2475        Color = self.Color
2476        self.assertFalse(Color.BLACK in Open)
2477        self.assertFalse(Open.RO in Color)
2478        self.assertFalse('BLACK' in Color)
2479        self.assertFalse('RO' in Open)
2480        self.assertTrue(1 in Color)
2481        self.assertTrue(1 in Open)
2482
2483
2484    def test_member_contains(self):
2485        Perm = self.Perm
2486        R, W, X = Perm
2487        RW = R | W
2488        RX = R | X
2489        WX = W | X
2490        RWX = R | W | X
2491        self.assertTrue(R in RW)
2492        self.assertTrue(R in RX)
2493        self.assertTrue(R in RWX)
2494        self.assertTrue(W in RW)
2495        self.assertTrue(W in WX)
2496        self.assertTrue(W in RWX)
2497        self.assertTrue(X in RX)
2498        self.assertTrue(X in WX)
2499        self.assertTrue(X in RWX)
2500        self.assertFalse(R in WX)
2501        self.assertFalse(W in RX)
2502        self.assertFalse(X in RW)
2503
2504    def test_auto_number(self):
2505        class Color(Flag):
2506            red = auto()
2507            blue = auto()
2508            green = auto()
2509
2510        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2511        self.assertEqual(Color.red.value, 1)
2512        self.assertEqual(Color.blue.value, 2)
2513        self.assertEqual(Color.green.value, 4)
2514
2515    def test_auto_number_garbage(self):
2516        with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2517            class Color(Flag):
2518                red = 'not an int'
2519                blue = auto()
2520
2521    def test_cascading_failure(self):
2522        class Bizarre(Flag):
2523            c = 3
2524            d = 4
2525            f = 6
2526        # Bizarre.c | Bizarre.d
2527        name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2528        self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2529        self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2530        self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2531        self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2532        self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2533        self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2534
2535    def test_duplicate_auto(self):
2536        class Dupes(Enum):
2537            first = primero = auto()
2538            second = auto()
2539            third = auto()
2540        self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2541
2542    def test_bizarre(self):
2543        class Bizarre(Flag):
2544            b = 3
2545            c = 4
2546            d = 6
2547        self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2548
2549    def test_multiple_mixin(self):
2550        class AllMixin:
2551            @classproperty
2552            def ALL(cls):
2553                members = list(cls)
2554                all_value = None
2555                if members:
2556                    all_value = members[0]
2557                    for member in members[1:]:
2558                        all_value |= member
2559                cls.ALL = all_value
2560                return all_value
2561        class StrMixin:
2562            def __str__(self):
2563                return self._name_.lower()
2564        class Color(AllMixin, Flag):
2565            RED = auto()
2566            GREEN = auto()
2567            BLUE = auto()
2568        self.assertEqual(Color.RED.value, 1)
2569        self.assertEqual(Color.GREEN.value, 2)
2570        self.assertEqual(Color.BLUE.value, 4)
2571        self.assertEqual(Color.ALL.value, 7)
2572        self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2573        class Color(AllMixin, StrMixin, Flag):
2574            RED = auto()
2575            GREEN = auto()
2576            BLUE = auto()
2577        self.assertEqual(Color.RED.value, 1)
2578        self.assertEqual(Color.GREEN.value, 2)
2579        self.assertEqual(Color.BLUE.value, 4)
2580        self.assertEqual(Color.ALL.value, 7)
2581        self.assertEqual(str(Color.BLUE), 'blue')
2582        class Color(StrMixin, AllMixin, Flag):
2583            RED = auto()
2584            GREEN = auto()
2585            BLUE = auto()
2586        self.assertEqual(Color.RED.value, 1)
2587        self.assertEqual(Color.GREEN.value, 2)
2588        self.assertEqual(Color.BLUE.value, 4)
2589        self.assertEqual(Color.ALL.value, 7)
2590        self.assertEqual(str(Color.BLUE), 'blue')
2591
2592    @threading_helper.reap_threads
2593    def test_unique_composite(self):
2594        # override __eq__ to be identity only
2595        class TestFlag(Flag):
2596            one = auto()
2597            two = auto()
2598            three = auto()
2599            four = auto()
2600            five = auto()
2601            six = auto()
2602            seven = auto()
2603            eight = auto()
2604            def __eq__(self, other):
2605                return self is other
2606            def __hash__(self):
2607                return hash(self._value_)
2608        # have multiple threads competing to complete the composite members
2609        seen = set()
2610        failed = False
2611        def cycle_enum():
2612            nonlocal failed
2613            try:
2614                for i in range(256):
2615                    seen.add(TestFlag(i))
2616            except Exception:
2617                failed = True
2618        threads = [
2619                threading.Thread(target=cycle_enum)
2620                for _ in range(8)
2621                ]
2622        with threading_helper.start_threads(threads):
2623            pass
2624        # check that only 248 members were created
2625        self.assertFalse(
2626                failed,
2627                'at least one thread failed while creating composite members')
2628        self.assertEqual(256, len(seen), 'too many composite members created')
2629
2630    def test_init_subclass(self):
2631        class MyEnum(Flag):
2632            def __init_subclass__(cls, **kwds):
2633                super().__init_subclass__(**kwds)
2634                self.assertFalse(cls.__dict__.get('_test', False))
2635                cls._test1 = 'MyEnum'
2636        #
2637        class TheirEnum(MyEnum):
2638            def __init_subclass__(cls, **kwds):
2639                super(TheirEnum, cls).__init_subclass__(**kwds)
2640                cls._test2 = 'TheirEnum'
2641        class WhoseEnum(TheirEnum):
2642            def __init_subclass__(cls, **kwds):
2643                pass
2644        class NoEnum(WhoseEnum):
2645            ONE = 1
2646        self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2647        self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2648        self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2649        self.assertFalse(NoEnum.__dict__.get('_test1', False))
2650        self.assertFalse(NoEnum.__dict__.get('_test2', False))
2651        #
2652        class OurEnum(MyEnum):
2653            def __init_subclass__(cls, **kwds):
2654                cls._test2 = 'OurEnum'
2655        class WhereEnum(OurEnum):
2656            def __init_subclass__(cls, **kwds):
2657                pass
2658        class NeverEnum(WhereEnum):
2659            ONE = 1
2660        self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2661        self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2662        self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2663        self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2664        self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2665
2666
2667class TestIntFlag(unittest.TestCase):
2668    """Tests of the IntFlags."""
2669
2670    class Perm(IntFlag):
2671        X = 1 << 0
2672        W = 1 << 1
2673        R = 1 << 2
2674
2675    class Open(IntFlag):
2676        RO = 0
2677        WO = 1
2678        RW = 2
2679        AC = 3
2680        CE = 1<<19
2681
2682    class Color(IntFlag):
2683        BLACK = 0
2684        RED = 1
2685        GREEN = 2
2686        BLUE = 4
2687        PURPLE = RED|BLUE
2688
2689    def test_type(self):
2690        Perm = self.Perm
2691        self.assertTrue(Perm._member_type_ is int)
2692        Open = self.Open
2693        for f in Perm:
2694            self.assertTrue(isinstance(f, Perm))
2695            self.assertEqual(f, f.value)
2696        self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2697        self.assertEqual(Perm.W | Perm.X, 3)
2698        for f in Open:
2699            self.assertTrue(isinstance(f, Open))
2700            self.assertEqual(f, f.value)
2701        self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2702        self.assertEqual(Open.WO | Open.RW, 3)
2703
2704
2705    def test_str(self):
2706        Perm = self.Perm
2707        self.assertEqual(str(Perm.R), 'Perm.R')
2708        self.assertEqual(str(Perm.W), 'Perm.W')
2709        self.assertEqual(str(Perm.X), 'Perm.X')
2710        self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2711        self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2712        self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2713        self.assertEqual(str(Perm(0)), 'Perm.0')
2714        self.assertEqual(str(Perm(8)), 'Perm.8')
2715        self.assertEqual(str(~Perm.R), 'Perm.W|X')
2716        self.assertEqual(str(~Perm.W), 'Perm.R|X')
2717        self.assertEqual(str(~Perm.X), 'Perm.R|W')
2718        self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2719        self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
2720        self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2721        self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2722        self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
2723
2724        Open = self.Open
2725        self.assertEqual(str(Open.RO), 'Open.RO')
2726        self.assertEqual(str(Open.WO), 'Open.WO')
2727        self.assertEqual(str(Open.AC), 'Open.AC')
2728        self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2729        self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2730        self.assertEqual(str(Open(4)), 'Open.4')
2731        self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2732        self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2733        self.assertEqual(str(~Open.AC), 'Open.CE')
2734        self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2735        self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2736        self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
2737
2738    def test_repr(self):
2739        Perm = self.Perm
2740        self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2741        self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2742        self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2743        self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2744        self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2745        self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
2746        self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2747        self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
2748        self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2749        self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2750        self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2751        self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
2752        self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
2753        self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2754        self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2755        self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
2756
2757        Open = self.Open
2758        self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2759        self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2760        self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2761        self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2762        self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2763        self.assertEqual(repr(Open(4)), '<Open.4: 4>')
2764        self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2765        self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2766        self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2767        self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2768        self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2769        self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
2770
2771    def test_format(self):
2772        Perm = self.Perm
2773        self.assertEqual(format(Perm.R, ''), '4')
2774        self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2775
2776    def test_or(self):
2777        Perm = self.Perm
2778        for i in Perm:
2779            for j in Perm:
2780                self.assertEqual(i | j, i.value | j.value)
2781                self.assertEqual((i | j).value, i.value | j.value)
2782                self.assertIs(type(i | j), Perm)
2783            for j in range(8):
2784                self.assertEqual(i | j, i.value | j)
2785                self.assertEqual((i | j).value, i.value | j)
2786                self.assertIs(type(i | j), Perm)
2787                self.assertEqual(j | i, j | i.value)
2788                self.assertEqual((j | i).value, j | i.value)
2789                self.assertIs(type(j | i), Perm)
2790        for i in Perm:
2791            self.assertIs(i | i, i)
2792            self.assertIs(i | 0, i)
2793            self.assertIs(0 | i, i)
2794        Open = self.Open
2795        self.assertIs(Open.RO | Open.CE, Open.CE)
2796
2797    def test_and(self):
2798        Perm = self.Perm
2799        RW = Perm.R | Perm.W
2800        RX = Perm.R | Perm.X
2801        WX = Perm.W | Perm.X
2802        RWX = Perm.R | Perm.W | Perm.X
2803        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2804        for i in values:
2805            for j in values:
2806                self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2807                self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2808                self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2809            for j in range(8):
2810                self.assertEqual(i & j, i.value & j)
2811                self.assertEqual((i & j).value, i.value & j)
2812                self.assertIs(type(i & j), Perm)
2813                self.assertEqual(j & i, j & i.value)
2814                self.assertEqual((j & i).value, j & i.value)
2815                self.assertIs(type(j & i), Perm)
2816        for i in Perm:
2817            self.assertIs(i & i, i)
2818            self.assertIs(i & 7, i)
2819            self.assertIs(7 & i, i)
2820        Open = self.Open
2821        self.assertIs(Open.RO & Open.CE, Open.RO)
2822
2823    def test_xor(self):
2824        Perm = self.Perm
2825        for i in Perm:
2826            for j in Perm:
2827                self.assertEqual(i ^ j, i.value ^ j.value)
2828                self.assertEqual((i ^ j).value, i.value ^ j.value)
2829                self.assertIs(type(i ^ j), Perm)
2830            for j in range(8):
2831                self.assertEqual(i ^ j, i.value ^ j)
2832                self.assertEqual((i ^ j).value, i.value ^ j)
2833                self.assertIs(type(i ^ j), Perm)
2834                self.assertEqual(j ^ i, j ^ i.value)
2835                self.assertEqual((j ^ i).value, j ^ i.value)
2836                self.assertIs(type(j ^ i), Perm)
2837        for i in Perm:
2838            self.assertIs(i ^ 0, i)
2839            self.assertIs(0 ^ i, i)
2840        Open = self.Open
2841        self.assertIs(Open.RO ^ Open.CE, Open.CE)
2842        self.assertIs(Open.CE ^ Open.CE, Open.RO)
2843
2844    def test_invert(self):
2845        Perm = self.Perm
2846        RW = Perm.R | Perm.W
2847        RX = Perm.R | Perm.X
2848        WX = Perm.W | Perm.X
2849        RWX = Perm.R | Perm.W | Perm.X
2850        values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2851        for i in values:
2852            self.assertEqual(~i, ~i.value)
2853            self.assertEqual((~i).value, ~i.value)
2854            self.assertIs(type(~i), Perm)
2855            self.assertEqual(~~i, i)
2856        for i in Perm:
2857            self.assertIs(~~i, i)
2858        Open = self.Open
2859        self.assertIs(Open.WO & ~Open.WO, Open.RO)
2860        self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2861
2862    def test_programatic_function_string(self):
2863        Perm = IntFlag('Perm', 'R W X')
2864        lst = list(Perm)
2865        self.assertEqual(len(lst), len(Perm))
2866        self.assertEqual(len(Perm), 3, Perm)
2867        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2868        for i, n in enumerate('R W X'.split()):
2869            v = 1<<i
2870            e = Perm(v)
2871            self.assertEqual(e.value, v)
2872            self.assertEqual(type(e.value), int)
2873            self.assertEqual(e, v)
2874            self.assertEqual(e.name, n)
2875            self.assertIn(e, Perm)
2876            self.assertIs(type(e), Perm)
2877
2878    def test_programatic_function_string_with_start(self):
2879        Perm = IntFlag('Perm', 'R W X', start=8)
2880        lst = list(Perm)
2881        self.assertEqual(len(lst), len(Perm))
2882        self.assertEqual(len(Perm), 3, Perm)
2883        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2884        for i, n in enumerate('R W X'.split()):
2885            v = 8<<i
2886            e = Perm(v)
2887            self.assertEqual(e.value, v)
2888            self.assertEqual(type(e.value), int)
2889            self.assertEqual(e, v)
2890            self.assertEqual(e.name, n)
2891            self.assertIn(e, Perm)
2892            self.assertIs(type(e), Perm)
2893
2894    def test_programatic_function_string_list(self):
2895        Perm = IntFlag('Perm', ['R', 'W', 'X'])
2896        lst = list(Perm)
2897        self.assertEqual(len(lst), len(Perm))
2898        self.assertEqual(len(Perm), 3, Perm)
2899        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2900        for i, n in enumerate('R W X'.split()):
2901            v = 1<<i
2902            e = Perm(v)
2903            self.assertEqual(e.value, v)
2904            self.assertEqual(type(e.value), int)
2905            self.assertEqual(e, v)
2906            self.assertEqual(e.name, n)
2907            self.assertIn(e, Perm)
2908            self.assertIs(type(e), Perm)
2909
2910    def test_programatic_function_iterable(self):
2911        Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
2912        lst = list(Perm)
2913        self.assertEqual(len(lst), len(Perm))
2914        self.assertEqual(len(Perm), 3, Perm)
2915        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2916        for i, n in enumerate('R W X'.split()):
2917            v = 1<<(2*i+1)
2918            e = Perm(v)
2919            self.assertEqual(e.value, v)
2920            self.assertEqual(type(e.value), int)
2921            self.assertEqual(e, v)
2922            self.assertEqual(e.name, n)
2923            self.assertIn(e, Perm)
2924            self.assertIs(type(e), Perm)
2925
2926    def test_programatic_function_from_dict(self):
2927        Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
2928        lst = list(Perm)
2929        self.assertEqual(len(lst), len(Perm))
2930        self.assertEqual(len(Perm), 3, Perm)
2931        self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2932        for i, n in enumerate('R W X'.split()):
2933            v = 1<<(2*i+1)
2934            e = Perm(v)
2935            self.assertEqual(e.value, v)
2936            self.assertEqual(type(e.value), int)
2937            self.assertEqual(e, v)
2938            self.assertEqual(e.name, n)
2939            self.assertIn(e, Perm)
2940            self.assertIs(type(e), Perm)
2941
2942
2943    def test_programatic_function_from_empty_list(self):
2944        Perm = enum.IntFlag('Perm', [])
2945        lst = list(Perm)
2946        self.assertEqual(len(lst), len(Perm))
2947        self.assertEqual(len(Perm), 0, Perm)
2948        Thing = enum.Enum('Thing', [])
2949        lst = list(Thing)
2950        self.assertEqual(len(lst), len(Thing))
2951        self.assertEqual(len(Thing), 0, Thing)
2952
2953
2954    def test_programatic_function_from_empty_tuple(self):
2955        Perm = enum.IntFlag('Perm', ())
2956        lst = list(Perm)
2957        self.assertEqual(len(lst), len(Perm))
2958        self.assertEqual(len(Perm), 0, Perm)
2959        Thing = enum.Enum('Thing', ())
2960        self.assertEqual(len(lst), len(Thing))
2961        self.assertEqual(len(Thing), 0, Thing)
2962
2963    @unittest.skipIf(
2964            python_version >= (3, 12),
2965            '__contains__ now returns True/False for all inputs',
2966            )
2967    def test_contains_er(self):
2968        Open = self.Open
2969        Color = self.Color
2970        self.assertTrue(Color.GREEN in Color)
2971        self.assertTrue(Open.RW in Open)
2972        self.assertFalse(Color.GREEN in Open)
2973        self.assertFalse(Open.RW in Color)
2974        with self.assertRaises(TypeError):
2975            with self.assertWarns(DeprecationWarning):
2976                'GREEN' in Color
2977        with self.assertRaises(TypeError):
2978            with self.assertWarns(DeprecationWarning):
2979                'RW' in Open
2980        with self.assertRaises(TypeError):
2981            with self.assertWarns(DeprecationWarning):
2982                2 in Color
2983        with self.assertRaises(TypeError):
2984            with self.assertWarns(DeprecationWarning):
2985                2 in Open
2986
2987    @unittest.skipIf(
2988            python_version < (3, 12),
2989            '__contains__ only works with enum memmbers before 3.12',
2990            )
2991    def test_contains_tf(self):
2992        Open = self.Open
2993        Color = self.Color
2994        self.assertTrue(Color.GREEN in Color)
2995        self.assertTrue(Open.RW in Open)
2996        self.assertTrue(Color.GREEN in Open)
2997        self.assertTrue(Open.RW in Color)
2998        self.assertFalse('GREEN' in Color)
2999        self.assertFalse('RW' in Open)
3000        self.assertTrue(2 in Color)
3001        self.assertTrue(2 in Open)
3002
3003    def test_member_contains(self):
3004        Perm = self.Perm
3005        R, W, X = Perm
3006        RW = R | W
3007        RX = R | X
3008        WX = W | X
3009        RWX = R | W | X
3010        self.assertTrue(R in RW)
3011        self.assertTrue(R in RX)
3012        self.assertTrue(R in RWX)
3013        self.assertTrue(W in RW)
3014        self.assertTrue(W in WX)
3015        self.assertTrue(W in RWX)
3016        self.assertTrue(X in RX)
3017        self.assertTrue(X in WX)
3018        self.assertTrue(X in RWX)
3019        self.assertFalse(R in WX)
3020        self.assertFalse(W in RX)
3021        self.assertFalse(X in RW)
3022        with self.assertRaises(TypeError):
3023            self.assertFalse('test' in RW)
3024
3025    def test_bool(self):
3026        Perm = self.Perm
3027        for f in Perm:
3028            self.assertTrue(f)
3029        Open = self.Open
3030        for f in Open:
3031            self.assertEqual(bool(f.value), bool(f))
3032
3033    def test_multiple_mixin(self):
3034        class AllMixin:
3035            @classproperty
3036            def ALL(cls):
3037                members = list(cls)
3038                all_value = None
3039                if members:
3040                    all_value = members[0]
3041                    for member in members[1:]:
3042                        all_value |= member
3043                cls.ALL = all_value
3044                return all_value
3045        class StrMixin:
3046            def __str__(self):
3047                return self._name_.lower()
3048        class Color(AllMixin, IntFlag):
3049            RED = auto()
3050            GREEN = auto()
3051            BLUE = auto()
3052        self.assertEqual(Color.RED.value, 1)
3053        self.assertEqual(Color.GREEN.value, 2)
3054        self.assertEqual(Color.BLUE.value, 4)
3055        self.assertEqual(Color.ALL.value, 7)
3056        self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3057        class Color(AllMixin, StrMixin, IntFlag):
3058            RED = auto()
3059            GREEN = auto()
3060            BLUE = auto()
3061        self.assertEqual(Color.RED.value, 1)
3062        self.assertEqual(Color.GREEN.value, 2)
3063        self.assertEqual(Color.BLUE.value, 4)
3064        self.assertEqual(Color.ALL.value, 7)
3065        self.assertEqual(str(Color.BLUE), 'blue')
3066        class Color(StrMixin, AllMixin, IntFlag):
3067            RED = auto()
3068            GREEN = auto()
3069            BLUE = auto()
3070        self.assertEqual(Color.RED.value, 1)
3071        self.assertEqual(Color.GREEN.value, 2)
3072        self.assertEqual(Color.BLUE.value, 4)
3073        self.assertEqual(Color.ALL.value, 7)
3074        self.assertEqual(str(Color.BLUE), 'blue')
3075
3076    @threading_helper.reap_threads
3077    def test_unique_composite(self):
3078        # override __eq__ to be identity only
3079        class TestFlag(IntFlag):
3080            one = auto()
3081            two = auto()
3082            three = auto()
3083            four = auto()
3084            five = auto()
3085            six = auto()
3086            seven = auto()
3087            eight = auto()
3088            def __eq__(self, other):
3089                return self is other
3090            def __hash__(self):
3091                return hash(self._value_)
3092        # have multiple threads competing to complete the composite members
3093        seen = set()
3094        failed = False
3095        def cycle_enum():
3096            nonlocal failed
3097            try:
3098                for i in range(256):
3099                    seen.add(TestFlag(i))
3100            except Exception:
3101                failed = True
3102        threads = [
3103                threading.Thread(target=cycle_enum)
3104                for _ in range(8)
3105                ]
3106        with threading_helper.start_threads(threads):
3107            pass
3108        # check that only 248 members were created
3109        self.assertFalse(
3110                failed,
3111                'at least one thread failed while creating composite members')
3112        self.assertEqual(256, len(seen), 'too many composite members created')
3113
3114
3115class TestEmptyAndNonLatinStrings(unittest.TestCase):
3116
3117    def test_empty_string(self):
3118        with self.assertRaises(ValueError):
3119            empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3120
3121    def test_non_latin_character_string(self):
3122        greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3123        item = getattr(greek_abc, '\u03B1')
3124        self.assertEqual(item.value, 1)
3125
3126    def test_non_latin_number_string(self):
3127        hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3128        item = getattr(hebrew_123, '\u05D0')
3129        self.assertEqual(item.value, 1)
3130
3131
3132class TestUnique(unittest.TestCase):
3133
3134    def test_unique_clean(self):
3135        @unique
3136        class Clean(Enum):
3137            one = 1
3138            two = 'dos'
3139            tres = 4.0
3140        @unique
3141        class Cleaner(IntEnum):
3142            single = 1
3143            double = 2
3144            triple = 3
3145
3146    def test_unique_dirty(self):
3147        with self.assertRaisesRegex(ValueError, 'tres.*one'):
3148            @unique
3149            class Dirty(Enum):
3150                one = 1
3151                two = 'dos'
3152                tres = 1
3153        with self.assertRaisesRegex(
3154                ValueError,
3155                'double.*single.*turkey.*triple',
3156                ):
3157            @unique
3158            class Dirtier(IntEnum):
3159                single = 1
3160                double = 1
3161                triple = 3
3162                turkey = 3
3163
3164    def test_unique_with_name(self):
3165        @unique
3166        class Silly(Enum):
3167            one = 1
3168            two = 'dos'
3169            name = 3
3170        @unique
3171        class Sillier(IntEnum):
3172            single = 1
3173            name = 2
3174            triple = 3
3175            value = 4
3176
3177
3178
3179expected_help_output_with_docs = """\
3180Help on class Color in module %s:
3181
3182class Color(enum.Enum)
3183 |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3184 |\x20\x20
3185 |  An enumeration.
3186 |\x20\x20
3187 |  Method resolution order:
3188 |      Color
3189 |      enum.Enum
3190 |      builtins.object
3191 |\x20\x20
3192 |  Data and other attributes defined here:
3193 |\x20\x20
3194 |  blue = <Color.blue: 3>
3195 |\x20\x20
3196 |  green = <Color.green: 2>
3197 |\x20\x20
3198 |  red = <Color.red: 1>
3199 |\x20\x20
3200 |  ----------------------------------------------------------------------
3201 |  Data descriptors inherited from enum.Enum:
3202 |\x20\x20
3203 |  name
3204 |      The name of the Enum member.
3205 |\x20\x20
3206 |  value
3207 |      The value of the Enum member.
3208 |\x20\x20
3209 |  ----------------------------------------------------------------------
3210 |  Readonly properties inherited from enum.EnumMeta:
3211 |\x20\x20
3212 |  __members__
3213 |      Returns a mapping of member name->value.
3214 |\x20\x20\x20\x20\x20\x20
3215 |      This mapping lists all enum members, including aliases. Note that this
3216 |      is a read-only view of the internal mapping."""
3217
3218expected_help_output_without_docs = """\
3219Help on class Color in module %s:
3220
3221class Color(enum.Enum)
3222 |  Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3223 |\x20\x20
3224 |  Method resolution order:
3225 |      Color
3226 |      enum.Enum
3227 |      builtins.object
3228 |\x20\x20
3229 |  Data and other attributes defined here:
3230 |\x20\x20
3231 |  blue = <Color.blue: 3>
3232 |\x20\x20
3233 |  green = <Color.green: 2>
3234 |\x20\x20
3235 |  red = <Color.red: 1>
3236 |\x20\x20
3237 |  ----------------------------------------------------------------------
3238 |  Data descriptors inherited from enum.Enum:
3239 |\x20\x20
3240 |  name
3241 |\x20\x20
3242 |  value
3243 |\x20\x20
3244 |  ----------------------------------------------------------------------
3245 |  Data descriptors inherited from enum.EnumMeta:
3246 |\x20\x20
3247 |  __members__"""
3248
3249class TestStdLib(unittest.TestCase):
3250
3251    maxDiff = None
3252
3253    class Color(Enum):
3254        red = 1
3255        green = 2
3256        blue = 3
3257
3258    def test_pydoc(self):
3259        # indirectly test __objclass__
3260        if StrEnum.__doc__ is None:
3261            expected_text = expected_help_output_without_docs % __name__
3262        else:
3263            expected_text = expected_help_output_with_docs % __name__
3264        output = StringIO()
3265        helper = pydoc.Helper(output=output)
3266        helper(self.Color)
3267        result = output.getvalue().strip()
3268        self.assertEqual(result, expected_text)
3269
3270    def test_inspect_getmembers(self):
3271        values = dict((
3272                ('__class__', EnumMeta),
3273                ('__doc__', 'An enumeration.'),
3274                ('__members__', self.Color.__members__),
3275                ('__module__', __name__),
3276                ('blue', self.Color.blue),
3277                ('green', self.Color.green),
3278                ('name', Enum.__dict__['name']),
3279                ('red', self.Color.red),
3280                ('value', Enum.__dict__['value']),
3281                ))
3282        result = dict(inspect.getmembers(self.Color))
3283        self.assertEqual(values.keys(), result.keys())
3284        failed = False
3285        for k in values.keys():
3286            if result[k] != values[k]:
3287                print()
3288                print('\n%s\n     key: %s\n  result: %s\nexpected: %s\n%s\n' %
3289                        ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3290                failed = True
3291        if failed:
3292            self.fail("result does not equal expected, see print above")
3293
3294    def test_inspect_classify_class_attrs(self):
3295        # indirectly test __objclass__
3296        from inspect import Attribute
3297        values = [
3298                Attribute(name='__class__', kind='data',
3299                    defining_class=object, object=EnumMeta),
3300                Attribute(name='__doc__', kind='data',
3301                    defining_class=self.Color, object='An enumeration.'),
3302                Attribute(name='__members__', kind='property',
3303                    defining_class=EnumMeta, object=EnumMeta.__members__),
3304                Attribute(name='__module__', kind='data',
3305                    defining_class=self.Color, object=__name__),
3306                Attribute(name='blue', kind='data',
3307                    defining_class=self.Color, object=self.Color.blue),
3308                Attribute(name='green', kind='data',
3309                    defining_class=self.Color, object=self.Color.green),
3310                Attribute(name='red', kind='data',
3311                    defining_class=self.Color, object=self.Color.red),
3312                Attribute(name='name', kind='data',
3313                    defining_class=Enum, object=Enum.__dict__['name']),
3314                Attribute(name='value', kind='data',
3315                    defining_class=Enum, object=Enum.__dict__['value']),
3316                ]
3317        values.sort(key=lambda item: item.name)
3318        result = list(inspect.classify_class_attrs(self.Color))
3319        result.sort(key=lambda item: item.name)
3320        failed = False
3321        for v, r in zip(values, result):
3322            if r != v:
3323                print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3324                failed = True
3325        if failed:
3326            self.fail("result does not equal expected, see print above")
3327
3328
3329class MiscTestCase(unittest.TestCase):
3330    def test__all__(self):
3331        check__all__(self, enum)
3332
3333
3334# These are unordered here on purpose to ensure that declaration order
3335# makes no difference.
3336CONVERT_TEST_NAME_D = 5
3337CONVERT_TEST_NAME_C = 5
3338CONVERT_TEST_NAME_B = 5
3339CONVERT_TEST_NAME_A = 5  # This one should sort first.
3340CONVERT_TEST_NAME_E = 5
3341CONVERT_TEST_NAME_F = 5
3342
3343class TestIntEnumConvert(unittest.TestCase):
3344    def test_convert_value_lookup_priority(self):
3345        test_type = enum.IntEnum._convert_(
3346                'UnittestConvert',
3347                ('test.test_enum', '__main__')[__name__=='__main__'],
3348                filter=lambda x: x.startswith('CONVERT_TEST_'))
3349        # We don't want the reverse lookup value to vary when there are
3350        # multiple possible names for a given value.  It should always
3351        # report the first lexigraphical name in that case.
3352        self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3353
3354    def test_convert(self):
3355        test_type = enum.IntEnum._convert_(
3356                'UnittestConvert',
3357                ('test.test_enum', '__main__')[__name__=='__main__'],
3358                filter=lambda x: x.startswith('CONVERT_TEST_'))
3359        # Ensure that test_type has all of the desired names and values.
3360        self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3361                         test_type.CONVERT_TEST_NAME_A)
3362        self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3363        self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3364        self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3365        self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3366        # Ensure that test_type only picked up names matching the filter.
3367        self.assertEqual([name for name in dir(test_type)
3368                          if name[0:2] not in ('CO', '__')],
3369                         [], msg='Names other than CONVERT_TEST_* found.')
3370
3371    @unittest.skipUnless(python_version == (3, 8),
3372                         '_convert was deprecated in 3.8')
3373    def test_convert_warn(self):
3374        with self.assertWarns(DeprecationWarning):
3375            enum.IntEnum._convert(
3376                'UnittestConvert',
3377                ('test.test_enum', '__main__')[__name__=='__main__'],
3378                filter=lambda x: x.startswith('CONVERT_TEST_'))
3379
3380    @unittest.skipUnless(python_version >= (3, 9),
3381                         '_convert was removed in 3.9')
3382    def test_convert_raise(self):
3383        with self.assertRaises(AttributeError):
3384            enum.IntEnum._convert(
3385                'UnittestConvert',
3386                ('test.test_enum', '__main__')[__name__=='__main__'],
3387                filter=lambda x: x.startswith('CONVERT_TEST_'))
3388
3389class TestHelpers(unittest.TestCase):
3390
3391    sunder_names = '_bad_', '_good_', '_what_ho_'
3392    dunder_names = '__mal__', '__bien__', '__que_que__'
3393    private_names = '_MyEnum__private', '_MyEnum__still_private'
3394    private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3395    random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3396
3397    def test_sunder(self):
3398        for name in self.sunder_names + self.private_and_sunder_names:
3399            self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3400        for name in self.dunder_names + self.private_names + self.random_names:
3401            self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3402
3403    def test_dunder(self):
3404        for name in self.dunder_names:
3405            self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3406        for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3407            self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3408
3409    def test_is_private(self):
3410        for name in self.private_names + self.private_and_sunder_names:
3411            self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3412        for name in self.sunder_names + self.dunder_names + self.random_names:
3413            self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
3414
3415
3416if __name__ == '__main__':
3417    unittest.main()
3418
3419