• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
2import sys
3import unittest
4pyver = float('%s.%s' % sys.version_info[:2])
5if pyver < 2.5:
6    sys.path.insert(0, '.')
7import enum
8from enum import Enum, IntEnum, unique, EnumMeta
9
10if pyver < 2.6:
11    from __builtin__ import enumerate as bltin_enumerate
12    def enumerate(thing, start=0):
13        result = []
14        for i, item in bltin_enumerate(thing):
15            i = i + start
16            result.append((i, item))
17        return result
18
19try:
20    any
21except NameError:
22    def any(iterable):
23        for element in iterable:
24            if element:
25                return True
26        return False
27
28try:
29    unicode
30except NameError:
31    unicode = str
32
33try:
34    from collections import OrderedDict
35except ImportError:
36    OrderedDict = None
37
38# for pickle tests
39try:
40    class Stooges(Enum):
41        LARRY = 1
42        CURLY = 2
43        MOE = 3
44except Exception:
45    Stooges = sys.exc_info()[1]
46
47try:
48    class IntStooges(int, Enum):
49        LARRY = 1
50        CURLY = 2
51        MOE = 3
52except Exception:
53    IntStooges = sys.exc_info()[1]
54
55try:
56    class FloatStooges(float, Enum):
57        LARRY = 1.39
58        CURLY = 2.72
59        MOE = 3.142596
60except Exception:
61    FloatStooges = sys.exc_info()[1]
62
63# for pickle test and subclass tests
64try:
65    class StrEnum(str, Enum):
66        'accepts only string values'
67    class Name(StrEnum):
68        BDFL = 'Guido van Rossum'
69        FLUFL = 'Barry Warsaw'
70except Exception:
71    Name = sys.exc_info()[1]
72
73try:
74    Question = Enum('Question', 'who what when where why', module=__name__)
75except Exception:
76    Question = sys.exc_info()[1]
77
78try:
79    Answer = Enum('Answer', 'him this then there because')
80except Exception:
81    Answer = sys.exc_info()[1]
82
83try:
84    Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
85except Exception:
86    Theory = sys.exc_info()[1]
87
88# for doctests
89try:
90    class Fruit(Enum):
91        tomato = 1
92        banana = 2
93        cherry = 3
94except Exception:
95    pass
96
97def test_pickle_dump_load(assertion, source, target=None,
98        protocol=(0, HIGHEST_PROTOCOL)):
99    start, stop = protocol
100    failures = []
101    for protocol in range(start, stop+1):
102        try:
103            if target is None:
104                assertion(loads(dumps(source, protocol=protocol)) is source)
105            else:
106                assertion(loads(dumps(source, protocol=protocol)), target)
107        except Exception:
108            exc, tb = sys.exc_info()[1:]
109            failures.append('%2d: %s' %(protocol, exc))
110    if failures:
111        raise ValueError('Failed with protocols: %s' % ', '.join(failures))
112
113def test_pickle_exception(assertion, exception, obj,
114        protocol=(0, HIGHEST_PROTOCOL)):
115    start, stop = protocol
116    failures = []
117    for protocol in range(start, stop+1):
118        try:
119            assertion(exception, dumps, obj, protocol=protocol)
120        except Exception:
121            exc = sys.exc_info()[1]
122            failures.append('%d: %s %s' % (protocol, exc.__class__.__name__, exc))
123    if failures:
124        raise ValueError('Failed with protocols: %s' % ', '.join(failures))
125
126
127class TestHelpers(unittest.TestCase):
128    # _is_descriptor, _is_sunder, _is_dunder
129
130    def test_is_descriptor(self):
131        class foo:
132            pass
133        for attr in ('__get__','__set__','__delete__'):
134            obj = foo()
135            self.assertFalse(enum._is_descriptor(obj))
136            setattr(obj, attr, 1)
137            self.assertTrue(enum._is_descriptor(obj))
138
139    def test_is_sunder(self):
140        for s in ('_a_', '_aa_'):
141            self.assertTrue(enum._is_sunder(s))
142
143        for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
144                '__', '___', '____', '_____',):
145            self.assertFalse(enum._is_sunder(s))
146
147    def test_is_dunder(self):
148        for s in ('__a__', '__aa__'):
149            self.assertTrue(enum._is_dunder(s))
150        for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
151                '__', '___', '____', '_____',):
152            self.assertFalse(enum._is_dunder(s))
153
154
155class TestEnum(unittest.TestCase):
156    def setUp(self):
157        class Season(Enum):
158            SPRING = 1
159            SUMMER = 2
160            AUTUMN = 3
161            WINTER = 4
162        self.Season = Season
163
164        class Konstants(float, Enum):
165            E = 2.7182818
166            PI = 3.1415926
167            TAU = 2 * PI
168        self.Konstants = Konstants
169
170        class Grades(IntEnum):
171            A = 5
172            B = 4
173            C = 3
174            D = 2
175            F = 0
176        self.Grades = Grades
177
178        class Directional(str, Enum):
179            EAST = 'east'
180            WEST = 'west'
181            NORTH = 'north'
182            SOUTH = 'south'
183        self.Directional = Directional
184
185        from datetime import date
186        class Holiday(date, Enum):
187            NEW_YEAR = 2013, 1, 1
188            IDES_OF_MARCH = 2013, 3, 15
189        self.Holiday = Holiday
190
191    if pyver >= 3.0:     # do not specify custom `dir` on previous versions
192        def test_dir_on_class(self):
193            Season = self.Season
194            self.assertEqual(
195                set(dir(Season)),
196                set(['__class__', '__doc__', '__members__', '__module__',
197                    'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
198                )
199
200        def test_dir_on_item(self):
201            Season = self.Season
202            self.assertEqual(
203                set(dir(Season.WINTER)),
204                set(['__class__', '__doc__', '__module__', 'name', 'value']),
205                )
206
207        def test_dir_with_added_behavior(self):
208            class Test(Enum):
209                this = 'that'
210                these = 'those'
211                def wowser(self):
212                    return ("Wowser! I'm %s!" % self.name)
213            self.assertEqual(
214                    set(dir(Test)),
215                    set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
216                    )
217            self.assertEqual(
218                    set(dir(Test.this)),
219                    set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
220                    )
221
222        def test_dir_on_sub_with_behavior_on_super(self):
223            # see issue22506
224            class SuperEnum(Enum):
225                def invisible(self):
226                    return "did you see me?"
227            class SubEnum(SuperEnum):
228                sample = 5
229            self.assertEqual(
230                    set(dir(SubEnum.sample)),
231                    set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
232                    )
233
234    if pyver >= 2.7:    # OrderedDict first available here
235        def test_members_is_ordereddict_if_ordered(self):
236            class Ordered(Enum):
237                __order__ = 'first second third'
238                first = 'bippity'
239                second = 'boppity'
240                third = 'boo'
241            self.assertTrue(type(Ordered.__members__) is OrderedDict)
242
243        def test_members_is_ordereddict_if_not_ordered(self):
244            class Unordered(Enum):
245                this = 'that'
246                these = 'those'
247            self.assertTrue(type(Unordered.__members__) is OrderedDict)
248
249    if pyver >= 3.0:     # all objects are ordered in Python 2.x
250        def test_members_is_always_ordered(self):
251            class AlwaysOrdered(Enum):
252                first = 1
253                second = 2
254                third = 3
255            self.assertTrue(type(AlwaysOrdered.__members__) is OrderedDict)
256
257        def test_comparisons(self):
258            def bad_compare():
259                Season.SPRING > 4
260            Season = self.Season
261            self.assertNotEqual(Season.SPRING, 1)
262            self.assertRaises(TypeError, bad_compare)
263
264            class Part(Enum):
265                SPRING = 1
266                CLIP = 2
267                BARREL = 3
268
269            self.assertNotEqual(Season.SPRING, Part.SPRING)
270            def bad_compare():
271                Season.SPRING < Part.CLIP
272            self.assertRaises(TypeError, bad_compare)
273
274    def test_enum_in_enum_out(self):
275        Season = self.Season
276        self.assertTrue(Season(Season.WINTER) is Season.WINTER)
277
278    def test_enum_value(self):
279        Season = self.Season
280        self.assertEqual(Season.SPRING.value, 1)
281
282    def test_intenum_value(self):
283        self.assertEqual(IntStooges.CURLY.value, 2)
284
285    def test_enum(self):
286        Season = self.Season
287        lst = list(Season)
288        self.assertEqual(len(lst), len(Season))
289        self.assertEqual(len(Season), 4, Season)
290        self.assertEqual(
291            [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
292
293        for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split()):
294            i += 1
295            e = Season(i)
296            self.assertEqual(e, getattr(Season, season))
297            self.assertEqual(e.value, i)
298            self.assertNotEqual(e, i)
299            self.assertEqual(e.name, season)
300            self.assertTrue(e in Season)
301            self.assertTrue(type(e) is Season)
302            self.assertTrue(isinstance(e, Season))
303            self.assertEqual(str(e), 'Season.' + season)
304            self.assertEqual(
305                    repr(e),
306                    '<Season.%s: %s>' % (season, i),
307                    )
308
309    def test_value_name(self):
310        Season = self.Season
311        self.assertEqual(Season.SPRING.name, 'SPRING')
312        self.assertEqual(Season.SPRING.value, 1)
313        def set_name(obj, new_value):
314            obj.name = new_value
315        def set_value(obj, new_value):
316            obj.value = new_value
317        self.assertRaises(AttributeError, set_name, Season.SPRING, 'invierno', )
318        self.assertRaises(AttributeError, set_value, Season.SPRING, 2)
319
320    def test_attribute_deletion(self):
321        class Season(Enum):
322            SPRING = 1
323            SUMMER = 2
324            AUTUMN = 3
325            WINTER = 4
326
327            def spam(cls):
328                pass
329
330        self.assertTrue(hasattr(Season, 'spam'))
331        del Season.spam
332        self.assertFalse(hasattr(Season, 'spam'))
333
334        self.assertRaises(AttributeError, delattr, Season, 'SPRING')
335        self.assertRaises(AttributeError, delattr, Season, 'DRY')
336        self.assertRaises(AttributeError, delattr, Season.SPRING, 'name')
337
338    def test_bool_of_class(self):
339        class Empty(Enum):
340            pass
341        self.assertTrue(bool(Empty))
342
343    def test_bool_of_member(self):
344        class Count(Enum):
345            zero = 0
346            one = 1
347            two = 2
348        for member in Count:
349            self.assertTrue(bool(member))
350
351    def test_invalid_names(self):
352        def create_bad_class_1():
353            class Wrong(Enum):
354                mro = 9
355        def create_bad_class_2():
356            class Wrong(Enum):
357                _reserved_ = 3
358        self.assertRaises(ValueError, create_bad_class_1)
359        self.assertRaises(ValueError, create_bad_class_2)
360
361    def test_contains(self):
362        Season = self.Season
363        self.assertTrue(Season.AUTUMN in Season)
364        self.assertTrue(3 not in Season)
365
366        val = Season(3)
367        self.assertTrue(val in Season)
368
369        class OtherEnum(Enum):
370            one = 1; two = 2
371        self.assertTrue(OtherEnum.two not in Season)
372
373    if pyver >= 2.6:     # when `format` came into being
374
375        def test_format_enum(self):
376            Season = self.Season
377            self.assertEqual('{0}'.format(Season.SPRING),
378                             '{0}'.format(str(Season.SPRING)))
379            self.assertEqual( '{0:}'.format(Season.SPRING),
380                              '{0:}'.format(str(Season.SPRING)))
381            self.assertEqual('{0:20}'.format(Season.SPRING),
382                             '{0:20}'.format(str(Season.SPRING)))
383            self.assertEqual('{0:^20}'.format(Season.SPRING),
384                             '{0:^20}'.format(str(Season.SPRING)))
385            self.assertEqual('{0:>20}'.format(Season.SPRING),
386                             '{0:>20}'.format(str(Season.SPRING)))
387            self.assertEqual('{0:<20}'.format(Season.SPRING),
388                             '{0:<20}'.format(str(Season.SPRING)))
389
390        def test_format_enum_custom(self):
391            class TestFloat(float, Enum):
392                one = 1.0
393                two = 2.0
394                def __format__(self, spec):
395                    return 'TestFloat success!'
396            self.assertEqual('{0}'.format(TestFloat.one), 'TestFloat success!')
397
398        def assertFormatIsValue(self, spec, member):
399            self.assertEqual(spec.format(member), spec.format(member.value))
400
401        def test_format_enum_date(self):
402            Holiday = self.Holiday
403            self.assertFormatIsValue('{0}', Holiday.IDES_OF_MARCH)
404            self.assertFormatIsValue('{0:}', Holiday.IDES_OF_MARCH)
405            self.assertFormatIsValue('{0:20}', Holiday.IDES_OF_MARCH)
406            self.assertFormatIsValue('{0:^20}', Holiday.IDES_OF_MARCH)
407            self.assertFormatIsValue('{0:>20}', Holiday.IDES_OF_MARCH)
408            self.assertFormatIsValue('{0:<20}', Holiday.IDES_OF_MARCH)
409            self.assertFormatIsValue('{0:%Y %m}', Holiday.IDES_OF_MARCH)
410            self.assertFormatIsValue('{0:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
411
412        def test_format_enum_float(self):
413            Konstants = self.Konstants
414            self.assertFormatIsValue('{0}', Konstants.TAU)
415            self.assertFormatIsValue('{0:}', Konstants.TAU)
416            self.assertFormatIsValue('{0:20}', Konstants.TAU)
417            self.assertFormatIsValue('{0:^20}', Konstants.TAU)
418            self.assertFormatIsValue('{0:>20}', Konstants.TAU)
419            self.assertFormatIsValue('{0:<20}', Konstants.TAU)
420            self.assertFormatIsValue('{0:n}', Konstants.TAU)
421            self.assertFormatIsValue('{0:5.2}', Konstants.TAU)
422            self.assertFormatIsValue('{0:f}', Konstants.TAU)
423
424        def test_format_enum_int(self):
425            Grades = self.Grades
426            self.assertFormatIsValue('{0}', Grades.C)
427            self.assertFormatIsValue('{0:}', Grades.C)
428            self.assertFormatIsValue('{0:20}', Grades.C)
429            self.assertFormatIsValue('{0:^20}', Grades.C)
430            self.assertFormatIsValue('{0:>20}', Grades.C)
431            self.assertFormatIsValue('{0:<20}', Grades.C)
432            self.assertFormatIsValue('{0:+}', Grades.C)
433            self.assertFormatIsValue('{0:08X}', Grades.C)
434            self.assertFormatIsValue('{0:b}', Grades.C)
435
436        def test_format_enum_str(self):
437            Directional = self.Directional
438            self.assertFormatIsValue('{0}', Directional.WEST)
439            self.assertFormatIsValue('{0:}', Directional.WEST)
440            self.assertFormatIsValue('{0:20}', Directional.WEST)
441            self.assertFormatIsValue('{0:^20}', Directional.WEST)
442            self.assertFormatIsValue('{0:>20}', Directional.WEST)
443            self.assertFormatIsValue('{0:<20}', Directional.WEST)
444
445    def test_hash(self):
446        Season = self.Season
447        dates = {}
448        dates[Season.WINTER] = '1225'
449        dates[Season.SPRING] = '0315'
450        dates[Season.SUMMER] = '0704'
451        dates[Season.AUTUMN] = '1031'
452        self.assertEqual(dates[Season.AUTUMN], '1031')
453
454    def test_enum_duplicates(self):
455        _order_ = "SPRING SUMMER AUTUMN WINTER"
456        class Season(Enum):
457            SPRING = 1
458            SUMMER = 2
459            AUTUMN = FALL = 3
460            WINTER = 4
461            ANOTHER_SPRING = 1
462        lst = list(Season)
463        self.assertEqual(
464            lst,
465            [Season.SPRING, Season.SUMMER,
466             Season.AUTUMN, Season.WINTER,
467            ])
468        self.assertTrue(Season.FALL is Season.AUTUMN)
469        self.assertEqual(Season.FALL.value, 3)
470        self.assertEqual(Season.AUTUMN.value, 3)
471        self.assertTrue(Season(3) is Season.AUTUMN)
472        self.assertTrue(Season(1) is Season.SPRING)
473        self.assertEqual(Season.FALL.name, 'AUTUMN')
474        self.assertEqual(
475                set([k for k,v in Season.__members__.items() if v.name != k]),
476                set(['FALL', 'ANOTHER_SPRING']),
477                )
478
479    if pyver >= 3.0:
480        cls = vars()
481        result = {'Enum':Enum}
482        exec("""def test_duplicate_name(self):
483            with self.assertRaises(TypeError):
484                class Color(Enum):
485                    red = 1
486                    green = 2
487                    blue = 3
488                    red = 4
489
490            with self.assertRaises(TypeError):
491                class Color(Enum):
492                    red = 1
493                    green = 2
494                    blue = 3
495                    def red(self):
496                        return 'red'
497
498            with self.assertRaises(TypeError):
499                class Color(Enum):
500                    @property
501
502                    def red(self):
503                        return 'redder'
504                    red = 1
505                    green = 2
506                    blue = 3""",
507            result)
508        cls['test_duplicate_name'] = result['test_duplicate_name']
509
510    def test_enum_with_value_name(self):
511        class Huh(Enum):
512            name = 1
513            value = 2
514        self.assertEqual(
515            list(Huh),
516            [Huh.name, Huh.value],
517            )
518        self.assertTrue(type(Huh.name) is Huh)
519        self.assertEqual(Huh.name.name, 'name')
520        self.assertEqual(Huh.name.value, 1)
521
522    def test_intenum_from_scratch(self):
523        class phy(int, Enum):
524            pi = 3
525            tau = 2 * pi
526        self.assertTrue(phy.pi < phy.tau)
527
528    def test_intenum_inherited(self):
529        class IntEnum(int, Enum):
530            pass
531        class phy(IntEnum):
532            pi = 3
533            tau = 2 * pi
534        self.assertTrue(phy.pi < phy.tau)
535
536    def test_floatenum_from_scratch(self):
537        class phy(float, Enum):
538            pi = 3.1415926
539            tau = 2 * pi
540        self.assertTrue(phy.pi < phy.tau)
541
542    def test_floatenum_inherited(self):
543        class FloatEnum(float, Enum):
544            pass
545        class phy(FloatEnum):
546            pi = 3.1415926
547            tau = 2 * pi
548        self.assertTrue(phy.pi < phy.tau)
549
550    def test_strenum_from_scratch(self):
551        class phy(str, Enum):
552            pi = 'Pi'
553            tau = 'Tau'
554        self.assertTrue(phy.pi < phy.tau)
555
556    def test_strenum_inherited(self):
557        class StrEnum(str, Enum):
558            pass
559        class phy(StrEnum):
560            pi = 'Pi'
561            tau = 'Tau'
562        self.assertTrue(phy.pi < phy.tau)
563
564    def test_intenum(self):
565        class WeekDay(IntEnum):
566            SUNDAY = 1
567            MONDAY = 2
568            TUESDAY = 3
569            WEDNESDAY = 4
570            THURSDAY = 5
571            FRIDAY = 6
572            SATURDAY = 7
573
574        self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
575        self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
576
577        lst = list(WeekDay)
578        self.assertEqual(len(lst), len(WeekDay))
579        self.assertEqual(len(WeekDay), 7)
580        target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
581        target = target.split()
582        for i, weekday in enumerate(target):
583            i += 1
584            e = WeekDay(i)
585            self.assertEqual(e, i)
586            self.assertEqual(int(e), i)
587            self.assertEqual(e.name, weekday)
588            self.assertTrue(e in WeekDay)
589            self.assertEqual(lst.index(e)+1, i)
590            self.assertTrue(0 < e < 8)
591            self.assertTrue(type(e) is WeekDay)
592            self.assertTrue(isinstance(e, int))
593            self.assertTrue(isinstance(e, Enum))
594
595    def test_intenum_duplicates(self):
596        class WeekDay(IntEnum):
597            __order__ = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
598            SUNDAY = 1
599            MONDAY = 2
600            TUESDAY = TEUSDAY = 3
601            WEDNESDAY = 4
602            THURSDAY = 5
603            FRIDAY = 6
604            SATURDAY = 7
605        self.assertTrue(WeekDay.TEUSDAY is WeekDay.TUESDAY)
606        self.assertEqual(WeekDay(3).name, 'TUESDAY')
607        self.assertEqual([k for k,v in WeekDay.__members__.items()
608                if v.name != k], ['TEUSDAY', ])
609
610    def test_pickle_enum(self):
611        if isinstance(Stooges, Exception):
612            raise Stooges
613        test_pickle_dump_load(self.assertTrue, Stooges.CURLY)
614        test_pickle_dump_load(self.assertTrue, Stooges)
615
616    def test_pickle_int(self):
617        if isinstance(IntStooges, Exception):
618            raise IntStooges
619        test_pickle_dump_load(self.assertTrue, IntStooges.CURLY)
620        test_pickle_dump_load(self.assertTrue, IntStooges)
621
622    def test_pickle_float(self):
623        if isinstance(FloatStooges, Exception):
624            raise FloatStooges
625        test_pickle_dump_load(self.assertTrue, FloatStooges.CURLY)
626        test_pickle_dump_load(self.assertTrue, FloatStooges)
627
628    def test_pickle_enum_function(self):
629        if isinstance(Answer, Exception):
630            raise Answer
631        test_pickle_dump_load(self.assertTrue, Answer.him)
632        test_pickle_dump_load(self.assertTrue, Answer)
633
634    def test_pickle_enum_function_with_module(self):
635        if isinstance(Question, Exception):
636            raise Question
637        test_pickle_dump_load(self.assertTrue, Question.who)
638        test_pickle_dump_load(self.assertTrue, Question)
639
640    if pyver == 3.4:
641        def test_class_nested_enum_and_pickle_protocol_four(self):
642            # would normally just have this directly in the class namespace
643            class NestedEnum(Enum):
644                twigs = 'common'
645                shiny = 'rare'
646
647            self.__class__.NestedEnum = NestedEnum
648            self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
649            test_pickle_exception(
650                    self.assertRaises, PicklingError, self.NestedEnum.twigs,
651                    protocol=(0, 3))
652            test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs,
653                    protocol=(4, HIGHEST_PROTOCOL))
654
655    elif pyver == 3.5:
656        def test_class_nested_enum_and_pickle_protocol_four(self):
657            # would normally just have this directly in the class namespace
658            class NestedEnum(Enum):
659                twigs = 'common'
660                shiny = 'rare'
661
662            self.__class__.NestedEnum = NestedEnum
663            self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
664            test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs,
665                    protocol=(0, HIGHEST_PROTOCOL))
666
667    def test_exploding_pickle(self):
668        BadPickle = Enum('BadPickle', 'dill sweet bread-n-butter')
669        enum._make_class_unpicklable(BadPickle)
670        globals()['BadPickle'] = BadPickle
671        test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
672        test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
673
674    def test_string_enum(self):
675        class SkillLevel(str, Enum):
676            master = 'what is the sound of one hand clapping?'
677            journeyman = 'why did the chicken cross the road?'
678            apprentice = 'knock, knock!'
679        self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
680
681    def test_getattr_getitem(self):
682        class Period(Enum):
683            morning = 1
684            noon = 2
685            evening = 3
686            night = 4
687        self.assertTrue(Period(2) is Period.noon)
688        self.assertTrue(getattr(Period, 'night') is Period.night)
689        self.assertTrue(Period['morning'] is Period.morning)
690
691    def test_getattr_dunder(self):
692        Season = self.Season
693        self.assertTrue(getattr(Season, '__hash__'))
694
695    def test_iteration_order(self):
696        class Season(Enum):
697            _order_ = 'SUMMER WINTER AUTUMN SPRING'
698            SUMMER = 2
699            WINTER = 4
700            AUTUMN = 3
701            SPRING = 1
702        self.assertEqual(
703                list(Season),
704                [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
705                )
706
707    def test_iteration_order_reversed(self):
708        self.assertEqual(
709                list(reversed(self.Season)),
710                [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
711                 self.Season.SPRING]
712                )
713
714    def test_iteration_order_with_unorderable_values(self):
715        class Complex(Enum):
716            a = complex(7, 9)
717            b = complex(3.14, 2)
718            c = complex(1, -1)
719            d = complex(-77, 32)
720        self.assertEqual(
721                list(Complex),
722                [Complex.a, Complex.b, Complex.c, Complex.d],
723                )
724
725    def test_programatic_function_string(self):
726        SummerMonth = Enum('SummerMonth', 'june july august')
727        lst = list(SummerMonth)
728        self.assertEqual(len(lst), len(SummerMonth))
729        self.assertEqual(len(SummerMonth), 3, SummerMonth)
730        self.assertEqual(
731                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
732                lst,
733                )
734        for i, month in enumerate('june july august'.split()):
735            i += 1
736            e = SummerMonth(i)
737            self.assertEqual(int(e.value), i)
738            self.assertNotEqual(e, i)
739            self.assertEqual(e.name, month)
740            self.assertTrue(e in SummerMonth)
741            self.assertTrue(type(e) is SummerMonth)
742
743    def test_programatic_function_string_with_start(self):
744        SummerMonth = Enum('SummerMonth', 'june july august', start=10)
745        lst = list(SummerMonth)
746        self.assertEqual(len(lst), len(SummerMonth))
747        self.assertEqual(len(SummerMonth), 3, SummerMonth)
748        self.assertEqual(
749                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
750                lst,
751                )
752        for i, month in enumerate('june july august'.split(), 10):
753            e = SummerMonth(i)
754            self.assertEqual(int(e.value), i)
755            self.assertNotEqual(e, i)
756            self.assertEqual(e.name, month)
757            self.assertTrue(e in SummerMonth)
758            self.assertTrue(type(e) is SummerMonth)
759
760    def test_programatic_function_string_list(self):
761        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
762        lst = list(SummerMonth)
763        self.assertEqual(len(lst), len(SummerMonth))
764        self.assertEqual(len(SummerMonth), 3, SummerMonth)
765        self.assertEqual(
766                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
767                lst,
768                )
769        for i, month in enumerate('june july august'.split()):
770            i += 1
771            e = SummerMonth(i)
772            self.assertEqual(int(e.value), i)
773            self.assertNotEqual(e, i)
774            self.assertEqual(e.name, month)
775            self.assertTrue(e in SummerMonth)
776            self.assertTrue(type(e) is SummerMonth)
777
778    def test_programatic_function_string_list_with_start(self):
779        SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
780        lst = list(SummerMonth)
781        self.assertEqual(len(lst), len(SummerMonth))
782        self.assertEqual(len(SummerMonth), 3, SummerMonth)
783        self.assertEqual(
784                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
785                lst,
786                )
787        for i, month in enumerate('june july august'.split(), 20):
788            e = SummerMonth(i)
789            self.assertEqual(int(e.value), i)
790            self.assertNotEqual(e, i)
791            self.assertEqual(e.name, month)
792            self.assertTrue(e in SummerMonth)
793            self.assertTrue(type(e) is SummerMonth)
794
795    def test_programatic_function_iterable(self):
796        SummerMonth = Enum(
797                'SummerMonth',
798                (('june', 1), ('july', 2), ('august', 3))
799                )
800        lst = list(SummerMonth)
801        self.assertEqual(len(lst), len(SummerMonth))
802        self.assertEqual(len(SummerMonth), 3, SummerMonth)
803        self.assertEqual(
804                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
805                lst,
806                )
807        for i, month in enumerate('june july august'.split()):
808            i += 1
809            e = SummerMonth(i)
810            self.assertEqual(int(e.value), i)
811            self.assertNotEqual(e, i)
812            self.assertEqual(e.name, month)
813            self.assertTrue(e in SummerMonth)
814            self.assertTrue(type(e) is SummerMonth)
815
816    def test_programatic_function_from_dict(self):
817        SummerMonth = Enum(
818                'SummerMonth',
819                dict((('june', 1), ('july', 2), ('august', 3)))
820                )
821        lst = list(SummerMonth)
822        self.assertEqual(len(lst), len(SummerMonth))
823        self.assertEqual(len(SummerMonth), 3, SummerMonth)
824        if pyver < 3.0:
825            self.assertEqual(
826                    [SummerMonth.june, SummerMonth.july, SummerMonth.august],
827                    lst,
828                    )
829        for i, month in enumerate('june july august'.split()):
830            i += 1
831            e = SummerMonth(i)
832            self.assertEqual(int(e.value), i)
833            self.assertNotEqual(e, i)
834            self.assertEqual(e.name, month)
835            self.assertTrue(e in SummerMonth)
836            self.assertTrue(type(e) is SummerMonth)
837
838    def test_programatic_function_type(self):
839        SummerMonth = Enum('SummerMonth', 'june july august', type=int)
840        lst = list(SummerMonth)
841        self.assertEqual(len(lst), len(SummerMonth))
842        self.assertEqual(len(SummerMonth), 3, SummerMonth)
843        self.assertEqual(
844                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
845                lst,
846                )
847        for i, month in enumerate('june july august'.split()):
848            i += 1
849            e = SummerMonth(i)
850            self.assertEqual(e, i)
851            self.assertEqual(e.name, month)
852            self.assertTrue(e in SummerMonth)
853            self.assertTrue(type(e) is SummerMonth)
854
855    def test_programatic_function_type_with_start(self):
856        SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
857        lst = list(SummerMonth)
858        self.assertEqual(len(lst), len(SummerMonth))
859        self.assertEqual(len(SummerMonth), 3, SummerMonth)
860        self.assertEqual(
861                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
862                lst,
863                )
864        for i, month in enumerate('june july august'.split(), 30):
865            e = SummerMonth(i)
866            self.assertEqual(e, i)
867            self.assertEqual(e.name, month)
868            self.assertTrue(e in SummerMonth)
869            self.assertTrue(type(e) is SummerMonth)
870
871    def test_programatic_function_type_from_subclass(self):
872        SummerMonth = IntEnum('SummerMonth', 'june july august')
873        lst = list(SummerMonth)
874        self.assertEqual(len(lst), len(SummerMonth))
875        self.assertEqual(len(SummerMonth), 3, SummerMonth)
876        self.assertEqual(
877                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
878                lst,
879                )
880        for i, month in enumerate('june july august'.split()):
881            i += 1
882            e = SummerMonth(i)
883            self.assertEqual(e, i)
884            self.assertEqual(e.name, month)
885            self.assertTrue(e in SummerMonth)
886            self.assertTrue(type(e) is SummerMonth)
887
888    def test_programatic_function_type_from_subclass_with_start(self):
889        SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
890        lst = list(SummerMonth)
891        self.assertEqual(len(lst), len(SummerMonth))
892        self.assertEqual(len(SummerMonth), 3, SummerMonth)
893        self.assertEqual(
894                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
895                lst,
896                )
897        for i, month in enumerate('june july august'.split(), 40):
898            e = SummerMonth(i)
899            self.assertEqual(e, i)
900            self.assertEqual(e.name, month)
901            self.assertTrue(e in SummerMonth)
902            self.assertTrue(type(e) is SummerMonth)
903
904    def test_programatic_function_unicode(self):
905        SummerMonth = Enum('SummerMonth', unicode('june july august'))
906        lst = list(SummerMonth)
907        self.assertEqual(len(lst), len(SummerMonth))
908        self.assertEqual(len(SummerMonth), 3, SummerMonth)
909        self.assertEqual(
910                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
911                lst,
912                )
913        for i, month in enumerate(unicode('june july august').split()):
914            i += 1
915            e = SummerMonth(i)
916            self.assertEqual(int(e.value), i)
917            self.assertNotEqual(e, i)
918            self.assertEqual(e.name, month)
919            self.assertTrue(e in SummerMonth)
920            self.assertTrue(type(e) is SummerMonth)
921
922    def test_programatic_function_unicode_list(self):
923        SummerMonth = Enum('SummerMonth', [unicode('june'), unicode('july'), unicode('august')])
924        lst = list(SummerMonth)
925        self.assertEqual(len(lst), len(SummerMonth))
926        self.assertEqual(len(SummerMonth), 3, SummerMonth)
927        self.assertEqual(
928                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
929                lst,
930                )
931        for i, month in enumerate(unicode('june july august').split()):
932            i += 1
933            e = SummerMonth(i)
934            self.assertEqual(int(e.value), i)
935            self.assertNotEqual(e, i)
936            self.assertEqual(e.name, month)
937            self.assertTrue(e in SummerMonth)
938            self.assertTrue(type(e) is SummerMonth)
939
940    def test_programatic_function_unicode_iterable(self):
941        SummerMonth = Enum(
942                'SummerMonth',
943                ((unicode('june'), 1), (unicode('july'), 2), (unicode('august'), 3))
944                )
945        lst = list(SummerMonth)
946        self.assertEqual(len(lst), len(SummerMonth))
947        self.assertEqual(len(SummerMonth), 3, SummerMonth)
948        self.assertEqual(
949                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
950                lst,
951                )
952        for i, month in enumerate(unicode('june july august').split()):
953            i += 1
954            e = SummerMonth(i)
955            self.assertEqual(int(e.value), i)
956            self.assertNotEqual(e, i)
957            self.assertEqual(e.name, month)
958            self.assertTrue(e in SummerMonth)
959            self.assertTrue(type(e) is SummerMonth)
960
961    def test_programatic_function_from_unicode_dict(self):
962        SummerMonth = Enum(
963                'SummerMonth',
964                dict(((unicode('june'), 1), (unicode('july'), 2), (unicode('august'), 3)))
965                )
966        lst = list(SummerMonth)
967        self.assertEqual(len(lst), len(SummerMonth))
968        self.assertEqual(len(SummerMonth), 3, SummerMonth)
969        if pyver < 3.0:
970            self.assertEqual(
971                    [SummerMonth.june, SummerMonth.july, SummerMonth.august],
972                    lst,
973                    )
974        for i, month in enumerate(unicode('june july august').split()):
975            i += 1
976            e = SummerMonth(i)
977            self.assertEqual(int(e.value), i)
978            self.assertNotEqual(e, i)
979            self.assertEqual(e.name, month)
980            self.assertTrue(e in SummerMonth)
981            self.assertTrue(type(e) is SummerMonth)
982
983    def test_programatic_function_unicode_type(self):
984        SummerMonth = Enum('SummerMonth', unicode('june july august'), type=int)
985        lst = list(SummerMonth)
986        self.assertEqual(len(lst), len(SummerMonth))
987        self.assertEqual(len(SummerMonth), 3, SummerMonth)
988        self.assertEqual(
989                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
990                lst,
991                )
992        for i, month in enumerate(unicode('june july august').split()):
993            i += 1
994            e = SummerMonth(i)
995            self.assertEqual(e, i)
996            self.assertEqual(e.name, month)
997            self.assertTrue(e in SummerMonth)
998            self.assertTrue(type(e) is SummerMonth)
999
1000    def test_programatic_function_unicode_type_from_subclass(self):
1001        SummerMonth = IntEnum('SummerMonth', unicode('june july august'))
1002        lst = list(SummerMonth)
1003        self.assertEqual(len(lst), len(SummerMonth))
1004        self.assertEqual(len(SummerMonth), 3, SummerMonth)
1005        self.assertEqual(
1006                [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1007                lst,
1008                )
1009        for i, month in enumerate(unicode('june july august').split()):
1010            i += 1
1011            e = SummerMonth(i)
1012            self.assertEqual(e, i)
1013            self.assertEqual(e.name, month)
1014            self.assertTrue(e in SummerMonth)
1015            self.assertTrue(type(e) is SummerMonth)
1016
1017    def test_programmatic_function_unicode_class(self):
1018        if pyver < 3.0:
1019            class_names = unicode('SummerMonth'), 'S\xfcmm\xe9rM\xf6nth'.decode('latin1')
1020        else:
1021            class_names = 'SummerMonth', 'S\xfcmm\xe9rM\xf6nth'
1022        for i, class_name in enumerate(class_names):
1023            if pyver < 3.0 and i == 1:
1024                self.assertRaises(TypeError, Enum, class_name, unicode('june july august'))
1025            else:
1026                SummerMonth = Enum(class_name, unicode('june july august'))
1027                lst = list(SummerMonth)
1028                self.assertEqual(len(lst), len(SummerMonth))
1029                self.assertEqual(len(SummerMonth), 3, SummerMonth)
1030                self.assertEqual(
1031                        [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1032                        lst,
1033                        )
1034                for i, month in enumerate(unicode('june july august').split()):
1035                    i += 1
1036                    e = SummerMonth(i)
1037                    self.assertEqual(e.value, i)
1038                    self.assertEqual(e.name, month)
1039                    self.assertTrue(e in SummerMonth)
1040                    self.assertTrue(type(e) is SummerMonth)
1041
1042    def test_subclassing(self):
1043        if isinstance(Name, Exception):
1044            raise Name
1045        self.assertEqual(Name.BDFL, 'Guido van Rossum')
1046        self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1047        self.assertTrue(Name.BDFL is getattr(Name, 'BDFL'))
1048        test_pickle_dump_load(self.assertTrue, Name.BDFL)
1049
1050    def test_extending(self):
1051        def bad_extension():
1052            class Color(Enum):
1053                red = 1
1054                green = 2
1055                blue = 3
1056            class MoreColor(Color):
1057                cyan = 4
1058                magenta = 5
1059                yellow = 6
1060        self.assertRaises(TypeError, bad_extension)
1061
1062    def test_exclude_methods(self):
1063        class whatever(Enum):
1064            this = 'that'
1065            these = 'those'
1066            def really(self):
1067                return 'no, not %s' % self.value
1068        self.assertFalse(type(whatever.really) is whatever)
1069        self.assertEqual(whatever.this.really(), 'no, not that')
1070
1071    def test_wrong_inheritance_order(self):
1072        def wrong_inherit():
1073            class Wrong(Enum, str):
1074                NotHere = 'error before this point'
1075        self.assertRaises(TypeError, wrong_inherit)
1076
1077    def test_intenum_transitivity(self):
1078        class number(IntEnum):
1079            one = 1
1080            two = 2
1081            three = 3
1082        class numero(IntEnum):
1083            uno = 1
1084            dos = 2
1085            tres = 3
1086        self.assertEqual(number.one, numero.uno)
1087        self.assertEqual(number.two, numero.dos)
1088        self.assertEqual(number.three, numero.tres)
1089
1090    def test_introspection(self):
1091        class Number(IntEnum):
1092            one = 100
1093            two = 200
1094        self.assertTrue(Number.one._member_type_ is int)
1095        self.assertTrue(Number._member_type_ is int)
1096        class String(str, Enum):
1097            yarn = 'soft'
1098            rope = 'rough'
1099            wire = 'hard'
1100        self.assertTrue(String.yarn._member_type_ is str)
1101        self.assertTrue(String._member_type_ is str)
1102        class Plain(Enum):
1103            vanilla = 'white'
1104            one = 1
1105        self.assertTrue(Plain.vanilla._member_type_ is object)
1106        self.assertTrue(Plain._member_type_ is object)
1107
1108    def test_wrong_enum_in_call(self):
1109        class Monochrome(Enum):
1110            black = 0
1111            white = 1
1112        class Gender(Enum):
1113            male = 0
1114            female = 1
1115        self.assertRaises(ValueError, Monochrome, Gender.male)
1116
1117    def test_wrong_enum_in_mixed_call(self):
1118        class Monochrome(IntEnum):
1119            black = 0
1120            white = 1
1121        class Gender(Enum):
1122            male = 0
1123            female = 1
1124        self.assertRaises(ValueError, Monochrome, Gender.male)
1125
1126    def test_mixed_enum_in_call_1(self):
1127        class Monochrome(IntEnum):
1128            black = 0
1129            white = 1
1130        class Gender(IntEnum):
1131            male = 0
1132            female = 1
1133        self.assertTrue(Monochrome(Gender.female) is Monochrome.white)
1134
1135    def test_mixed_enum_in_call_2(self):
1136        class Monochrome(Enum):
1137            black = 0
1138            white = 1
1139        class Gender(IntEnum):
1140            male = 0
1141            female = 1
1142        self.assertTrue(Monochrome(Gender.male) is Monochrome.black)
1143
1144    def test_flufl_enum(self):
1145        class Fluflnum(Enum):
1146            def __int__(self):
1147                return int(self.value)
1148        class MailManOptions(Fluflnum):
1149            option1 = 1
1150            option2 = 2
1151            option3 = 3
1152        self.assertEqual(int(MailManOptions.option1), 1)
1153
1154    def test_no_such_enum_member(self):
1155        class Color(Enum):
1156            red = 1
1157            green = 2
1158            blue = 3
1159        self.assertRaises(ValueError, Color, 4)
1160        self.assertRaises(KeyError, Color.__getitem__, 'chartreuse')
1161
1162    def test_new_repr(self):
1163        class Color(Enum):
1164            red = 1
1165            green = 2
1166            blue = 3
1167            def __repr__(self):
1168                return "don't you just love shades of %s?" % self.name
1169        self.assertEqual(
1170                repr(Color.blue),
1171                "don't you just love shades of blue?",
1172                )
1173
1174    def test_inherited_repr(self):
1175        class MyEnum(Enum):
1176            def __repr__(self):
1177                return "My name is %s." % self.name
1178        class MyIntEnum(int, MyEnum):
1179            this = 1
1180            that = 2
1181            theother = 3
1182        self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1183
1184    def test_multiple_mixin_mro(self):
1185        class auto_enum(EnumMeta):
1186            def __new__(metacls, cls, bases, classdict):
1187                original_dict = classdict
1188                classdict = enum._EnumDict()
1189                for k, v in original_dict.items():
1190                    classdict[k] = v
1191                temp = type(classdict)()
1192                names = set(classdict._member_names)
1193                i = 0
1194                for k in classdict._member_names:
1195                    v = classdict[k]
1196                    if v == ():
1197                        v = i
1198                    else:
1199                        i = v
1200                    i += 1
1201                    temp[k] = v
1202                for k, v in classdict.items():
1203                    if k not in names:
1204                        temp[k] = v
1205                return super(auto_enum, metacls).__new__(
1206                        metacls, cls, bases, temp)
1207
1208        AutoNumberedEnum = auto_enum('AutoNumberedEnum', (Enum,), {})
1209
1210        AutoIntEnum = auto_enum('AutoIntEnum', (IntEnum,), {})
1211
1212        class TestAutoNumber(AutoNumberedEnum):
1213            a = ()
1214            b = 3
1215            c = ()
1216
1217        class TestAutoInt(AutoIntEnum):
1218            a = ()
1219            b = 3
1220            c = ()
1221
1222    def test_subclasses_with_getnewargs(self):
1223        class NamedInt(int):
1224            __qualname__ = 'NamedInt'  # needed for pickle protocol 4
1225            def __new__(cls, *args):
1226                _args = args
1227                if len(args) < 1:
1228                    raise TypeError("name and value must be specified")
1229                name, args = args[0], args[1:]
1230                self = int.__new__(cls, *args)
1231                self._intname = name
1232                self._args = _args
1233                return self
1234            def __getnewargs__(self):
1235                return self._args
1236            @property
1237            def __name__(self):
1238                return self._intname
1239            def __repr__(self):
1240                # repr() is updated to include the name and type info
1241                return "%s(%r, %s)" % (type(self).__name__,
1242                                             self.__name__,
1243                                             int.__repr__(self))
1244            def __str__(self):
1245                # str() is unchanged, even if it relies on the repr() fallback
1246                base = int
1247                base_str = base.__str__
1248                if base_str.__objclass__ is object:
1249                    return base.__repr__(self)
1250                return base_str(self)
1251            # for simplicity, we only define one operator that
1252            # propagates expressions
1253            def __add__(self, other):
1254                temp = int(self) + int( other)
1255                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1256                    return NamedInt(
1257                        '(%s + %s)' % (self.__name__, other.__name__),
1258                        temp )
1259                else:
1260                    return temp
1261
1262        class NEI(NamedInt, Enum):
1263            __qualname__ = 'NEI'  # needed for pickle protocol 4
1264            x = ('the-x', 1)
1265            y = ('the-y', 2)
1266
1267        self.assertTrue(NEI.__new__ is Enum.__new__)
1268        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1269        globals()['NamedInt'] = NamedInt
1270        globals()['NEI'] = NEI
1271        NI5 = NamedInt('test', 5)
1272        self.assertEqual(NI5, 5)
1273        test_pickle_dump_load(self.assertTrue, NI5, 5)
1274        self.assertEqual(NEI.y.value, 2)
1275        test_pickle_dump_load(self.assertTrue, NEI.y)
1276
1277    if pyver >= 3.4:
1278        def test_subclasses_with_getnewargs_ex(self):
1279            class NamedInt(int):
1280                __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1281                def __new__(cls, *args):
1282                    _args = args
1283                    if len(args) < 2:
1284                        raise TypeError("name and value must be specified")
1285                    name, args = args[0], args[1:]
1286                    self = int.__new__(cls, *args)
1287                    self._intname = name
1288                    self._args = _args
1289                    return self
1290                def __getnewargs_ex__(self):
1291                    return self._args, {}
1292                @property
1293                def __name__(self):
1294                    return self._intname
1295                def __repr__(self):
1296                    # repr() is updated to include the name and type info
1297                    return "{}({!r}, {})".format(type(self).__name__,
1298                                                 self.__name__,
1299                                                 int.__repr__(self))
1300                def __str__(self):
1301                    # str() is unchanged, even if it relies on the repr() fallback
1302                    base = int
1303                    base_str = base.__str__
1304                    if base_str.__objclass__ is object:
1305                        return base.__repr__(self)
1306                    return base_str(self)
1307                # for simplicity, we only define one operator that
1308                # propagates expressions
1309                def __add__(self, other):
1310                    temp = int(self) + int( other)
1311                    if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1312                        return NamedInt(
1313                            '({0} + {1})'.format(self.__name__, other.__name__),
1314                            temp )
1315                    else:
1316                        return temp
1317
1318            class NEI(NamedInt, Enum):
1319                __qualname__ = 'NEI'      # needed for pickle protocol 4
1320                x = ('the-x', 1)
1321                y = ('the-y', 2)
1322
1323
1324            self.assertIs(NEI.__new__, Enum.__new__)
1325            self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1326            globals()['NamedInt'] = NamedInt
1327            globals()['NEI'] = NEI
1328            NI5 = NamedInt('test', 5)
1329            self.assertEqual(NI5, 5)
1330            test_pickle_dump_load(self.assertEqual, NI5, 5, protocol=(4, HIGHEST_PROTOCOL))
1331            self.assertEqual(NEI.y.value, 2)
1332            test_pickle_dump_load(self.assertTrue, NEI.y, protocol=(4, HIGHEST_PROTOCOL))
1333
1334    def test_subclasses_with_reduce(self):
1335        class NamedInt(int):
1336            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1337            def __new__(cls, *args):
1338                _args = args
1339                if len(args) < 1:
1340                    raise TypeError("name and value must be specified")
1341                name, args = args[0], args[1:]
1342                self = int.__new__(cls, *args)
1343                self._intname = name
1344                self._args = _args
1345                return self
1346            def __reduce__(self):
1347                return self.__class__, self._args
1348            @property
1349            def __name__(self):
1350                return self._intname
1351            def __repr__(self):
1352                # repr() is updated to include the name and type info
1353                return "%s(%r, %s)" % (type(self).__name__,
1354                                             self.__name__,
1355                                             int.__repr__(self))
1356            def __str__(self):
1357                # str() is unchanged, even if it relies on the repr() fallback
1358                base = int
1359                base_str = base.__str__
1360                if base_str.__objclass__ is object:
1361                    return base.__repr__(self)
1362                return base_str(self)
1363            # for simplicity, we only define one operator that
1364            # propagates expressions
1365            def __add__(self, other):
1366                temp = int(self) + int( other)
1367                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1368                    return NamedInt(
1369                        '(%s + %s)' % (self.__name__, other.__name__),
1370                        temp )
1371                else:
1372                    return temp
1373
1374        class NEI(NamedInt, Enum):
1375            __qualname__ = 'NEI'      # needed for pickle protocol 4
1376            x = ('the-x', 1)
1377            y = ('the-y', 2)
1378
1379
1380        self.assertTrue(NEI.__new__ is Enum.__new__)
1381        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1382        globals()['NamedInt'] = NamedInt
1383        globals()['NEI'] = NEI
1384        NI5 = NamedInt('test', 5)
1385        self.assertEqual(NI5, 5)
1386        test_pickle_dump_load(self.assertEqual, NI5, 5)
1387        self.assertEqual(NEI.y.value, 2)
1388        test_pickle_dump_load(self.assertTrue, NEI.y)
1389
1390    def test_subclasses_with_reduce_ex(self):
1391        class NamedInt(int):
1392            __qualname__ = 'NamedInt'       # needed for pickle protocol 4
1393            def __new__(cls, *args):
1394                _args = args
1395                if len(args) < 1:
1396                    raise TypeError("name and value must be specified")
1397                name, args = args[0], args[1:]
1398                self = int.__new__(cls, *args)
1399                self._intname = name
1400                self._args = _args
1401                return self
1402            def __reduce_ex__(self, proto):
1403                return self.__class__, self._args
1404            @property
1405            def __name__(self):
1406                return self._intname
1407            def __repr__(self):
1408                # repr() is updated to include the name and type info
1409                return "%s(%r, %s)" % (type(self).__name__,
1410                                             self.__name__,
1411                                             int.__repr__(self))
1412            def __str__(self):
1413                # str() is unchanged, even if it relies on the repr() fallback
1414                base = int
1415                base_str = base.__str__
1416                if base_str.__objclass__ is object:
1417                    return base.__repr__(self)
1418                return base_str(self)
1419            # for simplicity, we only define one operator that
1420            # propagates expressions
1421            def __add__(self, other):
1422                temp = int(self) + int( other)
1423                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1424                    return NamedInt(
1425                        '(%s + %s)' % (self.__name__, other.__name__),
1426                        temp )
1427                else:
1428                    return temp
1429
1430        class NEI(NamedInt, Enum):
1431            __qualname__ = 'NEI'      # needed for pickle protocol 4
1432            x = ('the-x', 1)
1433            y = ('the-y', 2)
1434
1435
1436        self.assertTrue(NEI.__new__ is Enum.__new__)
1437        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1438        globals()['NamedInt'] = NamedInt
1439        globals()['NEI'] = NEI
1440        NI5 = NamedInt('test', 5)
1441        self.assertEqual(NI5, 5)
1442        test_pickle_dump_load(self.assertEqual, NI5, 5)
1443        self.assertEqual(NEI.y.value, 2)
1444        test_pickle_dump_load(self.assertTrue, NEI.y)
1445
1446    def test_subclasses_without_direct_pickle_support(self):
1447        class NamedInt(int):
1448            __qualname__ = 'NamedInt'
1449            def __new__(cls, *args):
1450                _args = args
1451                name, args = args[0], args[1:]
1452                if len(args) == 0:
1453                    raise TypeError("name and value must be specified")
1454                self = int.__new__(cls, *args)
1455                self._intname = name
1456                self._args = _args
1457                return self
1458            @property
1459            def __name__(self):
1460                return self._intname
1461            def __repr__(self):
1462                # repr() is updated to include the name and type info
1463                return "%s(%r, %s)" % (type(self).__name__,
1464                                             self.__name__,
1465                                             int.__repr__(self))
1466            def __str__(self):
1467                # str() is unchanged, even if it relies on the repr() fallback
1468                base = int
1469                base_str = base.__str__
1470                if base_str.__objclass__ is object:
1471                    return base.__repr__(self)
1472                return base_str(self)
1473            # for simplicity, we only define one operator that
1474            # propagates expressions
1475            def __add__(self, other):
1476                temp = int(self) + int( other)
1477                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1478                    return NamedInt(
1479                        '(%s + %s)' % (self.__name__, other.__name__),
1480                        temp )
1481                else:
1482                    return temp
1483
1484        class NEI(NamedInt, Enum):
1485            __qualname__ = 'NEI'
1486            x = ('the-x', 1)
1487            y = ('the-y', 2)
1488
1489        self.assertTrue(NEI.__new__ is Enum.__new__)
1490        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1491        globals()['NamedInt'] = NamedInt
1492        globals()['NEI'] = NEI
1493        NI5 = NamedInt('test', 5)
1494        self.assertEqual(NI5, 5)
1495        self.assertEqual(NEI.y.value, 2)
1496        test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1497        test_pickle_exception(self.assertRaises, PicklingError, NEI)
1498
1499    def test_subclasses_without_direct_pickle_support_using_name(self):
1500        class NamedInt(int):
1501            __qualname__ = 'NamedInt'
1502            def __new__(cls, *args):
1503                _args = args
1504                name, args = args[0], args[1:]
1505                if len(args) == 0:
1506                    raise TypeError("name and value must be specified")
1507                self = int.__new__(cls, *args)
1508                self._intname = name
1509                self._args = _args
1510                return self
1511            @property
1512            def __name__(self):
1513                return self._intname
1514            def __repr__(self):
1515                # repr() is updated to include the name and type info
1516                return "%s(%r, %s)" % (type(self).__name__,
1517                                             self.__name__,
1518                                             int.__repr__(self))
1519            def __str__(self):
1520                # str() is unchanged, even if it relies on the repr() fallback
1521                base = int
1522                base_str = base.__str__
1523                if base_str.__objclass__ is object:
1524                    return base.__repr__(self)
1525                return base_str(self)
1526            # for simplicity, we only define one operator that
1527            # propagates expressions
1528            def __add__(self, other):
1529                temp = int(self) + int( other)
1530                if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1531                    return NamedInt(
1532                        '(%s + %s)' % (self.__name__, other.__name__),
1533                        temp )
1534                else:
1535                    return temp
1536
1537        class NEI(NamedInt, Enum):
1538            __qualname__ = 'NEI'
1539            x = ('the-x', 1)
1540            y = ('the-y', 2)
1541            def __reduce_ex__(self, proto):
1542                return getattr, (self.__class__, self._name_)
1543
1544        self.assertTrue(NEI.__new__ is Enum.__new__)
1545        self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1546        globals()['NamedInt'] = NamedInt
1547        globals()['NEI'] = NEI
1548        NI5 = NamedInt('test', 5)
1549        self.assertEqual(NI5, 5)
1550        self.assertEqual(NEI.y.value, 2)
1551        test_pickle_dump_load(self.assertTrue, NEI.y)
1552        test_pickle_dump_load(self.assertTrue, NEI)
1553
1554    def test_tuple_subclass(self):
1555        class SomeTuple(tuple, Enum):
1556            __qualname__ = 'SomeTuple'
1557            first = (1, 'for the money')
1558            second = (2, 'for the show')
1559            third = (3, 'for the music')
1560        self.assertTrue(type(SomeTuple.first) is SomeTuple)
1561        self.assertTrue(isinstance(SomeTuple.second, tuple))
1562        self.assertEqual(SomeTuple.third, (3, 'for the music'))
1563        globals()['SomeTuple'] = SomeTuple
1564        test_pickle_dump_load(self.assertTrue, SomeTuple.first)
1565
1566    def test_duplicate_values_give_unique_enum_items(self):
1567        class AutoNumber(Enum):
1568            __order__ = 'enum_m enum_d enum_y'
1569            enum_m = ()
1570            enum_d = ()
1571            enum_y = ()
1572            def __new__(cls):
1573                value = len(cls.__members__) + 1
1574                obj = object.__new__(cls)
1575                obj._value_ = value
1576                return obj
1577            def __int__(self):
1578                return int(self._value_)
1579        self.assertEqual(int(AutoNumber.enum_d), 2)
1580        self.assertEqual(AutoNumber.enum_y.value, 3)
1581        self.assertTrue(AutoNumber(1) is AutoNumber.enum_m)
1582        self.assertEqual(
1583            list(AutoNumber),
1584            [AutoNumber.enum_m, AutoNumber.enum_d, AutoNumber.enum_y],
1585            )
1586
1587    def test_inherited_new_from_enhanced_enum(self):
1588        class AutoNumber2(Enum):
1589            def __new__(cls):
1590                value = len(cls.__members__) + 1
1591                obj = object.__new__(cls)
1592                obj._value_ = value
1593                return obj
1594            def __int__(self):
1595                return int(self._value_)
1596        class Color(AutoNumber2):
1597            _order_ = 'red green blue'
1598            red = ()
1599            green = ()
1600            blue = ()
1601        self.assertEqual(len(Color), 3, "wrong number of elements: %d (should be %d)" % (len(Color), 3))
1602        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1603        if pyver >= 3.0:
1604            self.assertEqual(list(map(int, Color)), [1, 2, 3])
1605
1606    def test_inherited_new_from_mixed_enum(self):
1607        class AutoNumber3(IntEnum):
1608            def __new__(cls):
1609                value = len(cls.__members__) + 1
1610                obj = int.__new__(cls, value)
1611                obj._value_ = value
1612                return obj
1613        class Color(AutoNumber3):
1614            red = ()
1615            green = ()
1616            blue = ()
1617        self.assertEqual(len(Color), 3, "wrong number of elements: %d (should be %d)" % (len(Color), 3))
1618        Color.red
1619        Color.green
1620        Color.blue
1621
1622    def test_equality(self):
1623        class AlwaysEqual:
1624            def __eq__(self, other):
1625                return True
1626        class OrdinaryEnum(Enum):
1627            a = 1
1628        self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1629        self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1630
1631    def test_ordered_mixin(self):
1632        class OrderedEnum(Enum):
1633            def __ge__(self, other):
1634                if self.__class__ is other.__class__:
1635                    return self._value_ >= other._value_
1636                return NotImplemented
1637            def __gt__(self, other):
1638                if self.__class__ is other.__class__:
1639                    return self._value_ > other._value_
1640                return NotImplemented
1641            def __le__(self, other):
1642                if self.__class__ is other.__class__:
1643                    return self._value_ <= other._value_
1644                return NotImplemented
1645            def __lt__(self, other):
1646                if self.__class__ is other.__class__:
1647                    return self._value_ < other._value_
1648                return NotImplemented
1649        class Grade(OrderedEnum):
1650            __order__ = 'A B C D F'
1651            A = 5
1652            B = 4
1653            C = 3
1654            D = 2
1655            F = 1
1656        self.assertEqual(list(Grade), [Grade.A, Grade.B, Grade.C, Grade.D, Grade.F])
1657        self.assertTrue(Grade.A > Grade.B)
1658        self.assertTrue(Grade.F <= Grade.C)
1659        self.assertTrue(Grade.D < Grade.A)
1660        self.assertTrue(Grade.B >= Grade.B)
1661
1662    def test_extending2(self):
1663        def bad_extension():
1664            class Shade(Enum):
1665                def shade(self):
1666                    print(self.name)
1667            class Color(Shade):
1668                red = 1
1669                green = 2
1670                blue = 3
1671            class MoreColor(Color):
1672                cyan = 4
1673                magenta = 5
1674                yellow = 6
1675        self.assertRaises(TypeError, bad_extension)
1676
1677    def test_extending3(self):
1678        class Shade(Enum):
1679            def shade(self):
1680                return self.name
1681        class Color(Shade):
1682            def hex(self):
1683                return '%s hexlified!' % self.value
1684        class MoreColor(Color):
1685            cyan = 4
1686            magenta = 5
1687            yellow = 6
1688        self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1689
1690    def test_no_duplicates(self):
1691        def bad_duplicates():
1692            class UniqueEnum(Enum):
1693                def __init__(self, *args):
1694                    cls = self.__class__
1695                    if any(self.value == e.value for e in cls):
1696                        a = self.name
1697                        e = cls(self.value).name
1698                        raise ValueError(
1699                                "aliases not allowed in UniqueEnum:  %r --> %r"
1700                                % (a, e)
1701                                )
1702            class Color(UniqueEnum):
1703                red = 1
1704                green = 2
1705                blue = 3
1706            class Color(UniqueEnum):
1707                red = 1
1708                green = 2
1709                blue = 3
1710                grene = 2
1711        self.assertRaises(ValueError, bad_duplicates)
1712
1713    def test_init(self):
1714        class Planet(Enum):
1715            MERCURY = (3.303e+23, 2.4397e6)
1716            VENUS   = (4.869e+24, 6.0518e6)
1717            EARTH   = (5.976e+24, 6.37814e6)
1718            MARS    = (6.421e+23, 3.3972e6)
1719            JUPITER = (1.9e+27,   7.1492e7)
1720            SATURN  = (5.688e+26, 6.0268e7)
1721            URANUS  = (8.686e+25, 2.5559e7)
1722            NEPTUNE = (1.024e+26, 2.4746e7)
1723            def __init__(self, mass, radius):
1724                self.mass = mass       # in kilograms
1725                self.radius = radius   # in meters
1726            @property
1727            def surface_gravity(self):
1728                # universal gravitational constant  (m3 kg-1 s-2)
1729                G = 6.67300E-11
1730                return G * self.mass / (self.radius * self.radius)
1731        self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1732        self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1733
1734    def test_nonhash_value(self):
1735        class AutoNumberInAList(Enum):
1736            def __new__(cls):
1737                value = [len(cls.__members__) + 1]
1738                obj = object.__new__(cls)
1739                obj._value_ = value
1740                return obj
1741        class ColorInAList(AutoNumberInAList):
1742            _order_ = 'red green blue'
1743            red = ()
1744            green = ()
1745            blue = ()
1746        self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
1747        self.assertEqual(ColorInAList.red.value, [1])
1748        self.assertEqual(ColorInAList([1]), ColorInAList.red)
1749
1750    def test_conflicting_types_resolved_in_new(self):
1751        class LabelledIntEnum(int, Enum):
1752            def __new__(cls, *args):
1753                value, label = args
1754                obj = int.__new__(cls, value)
1755                obj.label = label
1756                obj._value_ = value
1757                return obj
1758
1759        class LabelledList(LabelledIntEnum):
1760            unprocessed = (1, "Unprocessed")
1761            payment_complete = (2, "Payment Complete")
1762
1763        self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1764        self.assertEqual(LabelledList.unprocessed, 1)
1765        self.assertEqual(LabelledList(1), LabelledList.unprocessed)
1766
1767    def test_empty_with_functional_api(self):
1768        empty = enum.IntEnum('Foo', {})
1769        self.assertEqual(len(empty), 0)
1770
1771
1772class TestUnique(unittest.TestCase):
1773    """2.4 doesn't allow class decorators, use function syntax."""
1774
1775    def test_unique_clean(self):
1776        class Clean(Enum):
1777            one = 1
1778            two = 'dos'
1779            tres = 4.0
1780        unique(Clean)
1781        class Cleaner(IntEnum):
1782            single = 1
1783            double = 2
1784            triple = 3
1785        unique(Cleaner)
1786
1787    def test_unique_dirty(self):
1788        try:
1789            class Dirty(Enum):
1790                __order__ = 'one two tres'
1791                one = 1
1792                two = 'dos'
1793                tres = 1
1794            unique(Dirty)
1795        except ValueError:
1796            exc = sys.exc_info()[1]
1797            message = exc.args[0]
1798        self.assertTrue('tres -> one' in message)
1799
1800        try:
1801            class Dirtier(IntEnum):
1802                _order_ = 'single double triple turkey'
1803                single = 1
1804                double = 1
1805                triple = 3
1806                turkey = 3
1807            unique(Dirtier)
1808        except ValueError:
1809            exc = sys.exc_info()[1]
1810            message = exc.args[0]
1811        self.assertTrue('double -> single' in message)
1812        self.assertTrue('turkey -> triple' in message)
1813
1814
1815class TestMe(unittest.TestCase):
1816
1817    pass
1818
1819if __name__ == '__main__':
1820    unittest.main()
1821