Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(198084)

Side by Side Diff: Lib/test/test_enum.py

Issue 17947: Code, test, and doc review for PEP-0435 Enum
Patch Set: Created 6 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« Lib/enum.py ('K') | « Lib/enum.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 from collections import OrderedDict
2 from pickle import dumps, loads
3 import unittest
4 from enum import Enum, IntEnum
5 import sys
6
7
8 # for pickle tests
9 _errors = []
Zach Ware 2013/05/11 06:42:08 No longer needed.
stoneleaf 2013/05/12 14:47:01 Done.
10 try:
11 class Stooges(Enum):
12 LARRY = 1
13 CURLY = 2
14 MOE = 3
15 except Exception as exc:
16 Stooges = exc
Zach Ware 2013/05/11 06:42:08 Not quite what I had in mind, but it does seem to
stoneleaf 2013/05/12 14:47:01 It is entirely possible (and, indeed, it happened
17
18 try:
19 class IntStooges(int, Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23 except Exception as exc:
24 IntStooges = exc
25
26 try:
27 class FloatStooges(float, Enum):
28 LARRY = 1.39
29 CURLY = 2.72
30 MOE = 3.142596
31 except Exception as exc:
32 FloatStooges = exc
33
34 # for pickle test and subclass tests
35 try:
36 class StrEnum(str, Enum):
37 'accepts only string values'
38 class Name(StrEnum):
39 BDFL = 'Guido van Rossum'
40 FLUFL = 'Barry Warsaw'
41 except Exception as exc:
42 Name = exc
43
44 try:
45 Question = Enum('Question', 'who what when where why', module='__main__')
46 except Exception as exc:
47 Question = exc
48
49 try:
50 Answer = Enum('Answer', 'him this then there because')
51 except Exception as exc:
52 Answer = exc
53
54 class TestEnum(unittest.TestCase):
55 def setUp(self):
56 class Season(Enum):
57 SPRING = 1
58 SUMMER = 2
59 AUTUMN = 3
60 WINTER = 4
61 self.Season = Season
62
63 def test_global_class_creation(self):
64 self.assertFalse(_errors)
Zach Ware 2013/05/11 06:42:08 This test is now useless, it can go.
stoneleaf 2013/05/12 14:47:01 Done.
65
66 def test_enum_in_enum_out(self):
67 Season = self.Season
68 self.assertIs(Season(Season.WINTER), Season.WINTER)
69
70 def test_dir_on_class(self):
71 Season = self.Season
72 self.assertEqual(
73 set(dir(Season)),
74 set(['__class__', '__doc__', '__members__',
75 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
76 )
77
78 def test_dir_on_item(self):
79 Season = self.Season
80 self.assertEqual(
81 set(dir(Season.WINTER)),
82 set(['__class__', '__doc__', 'name', 'value']),
83 )
84
85 def test_enum(self):
86 Season = self.Season
87 lst = list(Season)
88 self.assertEqual(len(lst), len(Season))
89 self.assertEqual(len(Season), 4, Season)
90 self.assertEqual(
91 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
92
93 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
94 e = Season(i)
95 self.assertEqual(e, getattr(Season, season))
96 self.assertEqual(e.value, i)
97 self.assertNotEqual(e, i)
98 self.assertEqual(e.name, season)
99 self.assertIn(e, Season)
100 self.assertIs(type(e), Season)
101 self.assertIsInstance(e, Season)
102 self.assertEqual(str(e), 'Season.' + season)
103 self.assertEqual(repr(e),
104 '<Season.{0}: {1}>'.format(season, i))
105
106 def test_value_name(self):
107 Season = self.Season
108 self.assertEqual(Season.SPRING.name, 'SPRING')
109 self.assertEqual(Season.SPRING.value, 1)
110 with self.assertRaises(AttributeError):
111 Season.SPRING.name = 'invierno'
112 with self.assertRaises(AttributeError):
113 Season.SPRING.value = 2
114
115 def test_contains(self):
116 Season = self.Season
117 self.assertIn(Season.AUTUMN, Season)
118 self.assertNotIn(3, Season)
119
120 val = Season(3)
121 self.assertIn(val, Season)
122
123 class OtherEnum(Enum):
124 one = 1; two = 2
125 self.assertNotIn(OtherEnum.two, Season)
126
127 def test_comparisons(self):
128 Season = self.Season
129 with self.assertRaises(TypeError):
130 Season.SPRING < Season.WINTER
131 with self.assertRaises(TypeError):
132 Season.SPRING > 4
133
134 self.assertNotEqual(Season.SPRING, 1)
135
136 class Part(Enum):
137 SPRING = 1
138 CLIP = 2
139 BARREL = 3
140
141 self.assertNotEqual(Season.SPRING, Part.SPRING)
142 with self.assertRaises(TypeError):
143 Season.SPRING < Part.CLIP
144
145 def test_enum_duplicates(self):
146 class Season(Enum):
147 SPRING = 1
148 SUMMER = 2
149 AUTUMN = FALL = 3
150 WINTER = 4
151 ANOTHER_SPRING = 1
152 lst = list(Season)
153 self.assertEqual(
154 lst,
155 [Season.SPRING, Season.SUMMER,
156 Season.AUTUMN, Season.WINTER,
157 ])
158 self.assertIs(Season.FALL, Season.AUTUMN)
159 self.assertEqual(Season.FALL.value, 3)
160 self.assertEqual(Season.AUTUMN.value, 3)
161 self.assertIs(Season(3), Season.AUTUMN)
162 self.assertIs(Season(1), Season.SPRING)
163 self.assertEqual(Season.FALL.name, 'AUTUMN')
164 self.assertEqual([k for k,v in Season.__members__.items()
165 if v.name != k], ['FALL', 'ANOTHER_SPRING'])
166
167 def test_enum_with_value_name(self):
168 class Huh(Enum):
169 name = 1
170 value = 2
171 self.assertEqual(
172 list(Huh),
173 [Huh.name, Huh.value],
174 )
175 self.assertIs(type(Huh.name), Huh)
176 self.assertEqual(Huh.name.name, 'name')
177 self.assertEqual(Huh.name.value, 1)
178
179 def test_intenum(self):
180 class WeekDay(IntEnum):
181 SUNDAY = 1
182 MONDAY = 2
183 TUESDAY = 3
184 WEDNESDAY = 4
185 THURSDAY = 5
186 FRIDAY = 6
187 SATURDAY = 7
188
189 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
190 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
191
192 lst = list(WeekDay)
193 self.assertEqual(len(lst), len(WeekDay))
194 self.assertEqual(len(WeekDay), 7)
195 for i, weekday in enumerate(r'''SUNDAY MONDAY TUESDAY WEDNESDAY
196 THURSDAY FRIDAY SATURDAY'''.split(), 1):
197 e = WeekDay(i)
198 self.assertEqual(e, i)
199 self.assertEqual(int(e), i)
200 self.assertEqual(e.name, weekday)
201 self.assertIn(e, WeekDay)
202 self.assertEqual(lst.index(e)+1, i)
203 self.assertTrue(0 < e < 8)
204 self.assertIs(type(e), WeekDay)
205 self.assertIsInstance(e, int)
206 self.assertIsInstance(e, Enum)
207
208 def test_intenum_duplicates(self):
209 class WeekDay(IntEnum):
210 SUNDAY = 1
211 MONDAY = 2
212 TUESDAY = TEUSDAY = 3
213 WEDNESDAY = 4
214 THURSDAY = 5
215 FRIDAY = 6
216 SATURDAY = 7
217 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
218 self.assertEqual(WeekDay(3).name, 'TUESDAY')
219 self.assertEqual([k for k,v in WeekDay.__members__.items()
220 if v.name != k], ['TEUSDAY', ])
221
222 def test_pickle_enum(self):
223 if isinstance(Stooges, Exception):
224 raise Stooges
225 self.assertIs(Stooges.CURLY, loads(dumps(Stooges.CURLY)))
226
227 def test_pickle_int(self):
228 if isinstance(IntStooges, Exception):
229 raise IntStooges
230 self.assertIs(IntStooges.CURLY, loads(dumps(IntStooges.CURLY)))
231
232 def test_pickle_float(self):
233 if isinstance(FloatStooges, Exception):
234 raise FloatStooges
235 self.assertIs(FloatStooges.CURLY, loads(dumps(FloatStooges.CURLY)))
236
237 def test_pickle_enum_function(self):
238 if isinstance(Answer, Exception):
239 raise Answer
240 self.assertIs(Answer.him, loads(dumps(Answer.him)))
241
242 def test_pickle_enum_function_with_module(self):
243 if isinstance(Question, Exception):
244 raise Question
245 self.assertIs(Question.who, loads(dumps(Question.who)))
246
247 # not sure how to make this work; create the .py file somewhere importable?
248 # def test_pickle_enum_function_from_other_module(self):
249 # from test_module import Duh
250 # self.assertIs(Duh.umm, loads(dumps(Duh.umm)))
251
252 def test_string_enum(self):
253 class SkillLevel(str, Enum):
254 master = 'what is the sound of one hand clapping?'
255 journeyman = 'why did the chicken cross the road?'
256 apprentice = 'knock, knock!'
257 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
258
259 def test_getattr_getitem(self):
260 class Period(Enum):
261 morning = 1
262 noon = 2
263 evening = 3
264 night = 4
265 self.assertIs(Period(2), Period.noon)
266 self.assertIs(getattr(Period, 'night'), Period.night)
267 self.assertIs(Period['morning'], Period.morning)
268
269 def test_getattr_dunder(self):
270 Season = self.Season
271 self.assertTrue(getattr(Season, '__eq__'))
272
273 def test_iteration_order(self):
274 class Season(Enum):
275 SUMMER = 2
276 WINTER = 4
277 AUTUMN = 3
278 SPRING = 1
279 self.assertEqual(
280 list(Season),
281 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
282 )
283
284 def test_programatic_function_string(self):
285 SummerMonth = Enum('SummerMonth', 'june july august')
286 lst = list(SummerMonth)
287 self.assertEqual(len(lst), len(SummerMonth))
288 self.assertEqual(len(SummerMonth), 3, SummerMonth)
289 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
290 for i, month in enumerate('june july august'.split(), 1):
291 e = SummerMonth(i)
292 self.assertEqual(int(e.value), i)
293 self.assertNotEqual(e, i)
294 self.assertEqual(e.name, month)
295 self.assertIn(e, SummerMonth)
296 self.assertIs(type(e), SummerMonth)
297
298 def test_programatic_function_string_list(self):
299 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
300 lst = list(SummerMonth)
301 self.assertEqual(len(lst), len(SummerMonth))
302 self.assertEqual(len(SummerMonth), 3, SummerMonth)
303 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
304 for i, month in enumerate('june july august'.split(), 1):
305 e = SummerMonth(i)
306 self.assertEqual(int(e.value), i)
307 self.assertNotEqual(e, i)
308 self.assertEqual(e.name, month)
309 self.assertIn(e, SummerMonth)
310 self.assertIs(type(e), SummerMonth)
311
312 def test_programatic_function_iterable(self):
313 SummerMonth = Enum('SummerMonth', (('june', 1), ('july', 2), ('august', 3)))
314 lst = list(SummerMonth)
315 self.assertEqual(len(lst), len(SummerMonth))
316 self.assertEqual(len(SummerMonth), 3, SummerMonth)
317 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
318 for i, month in enumerate('june july august'.split(), 1):
319 e = SummerMonth(i)
320 self.assertEqual(int(e.value), i)
321 self.assertNotEqual(e, i)
322 self.assertEqual(e.name, month)
323 self.assertIn(e, SummerMonth)
324 self.assertIs(type(e), SummerMonth)
325
326 def test_programatic_function_from_dict(self):
327 SummerMonth = Enum('SummerMonth', OrderedDict((('june', 1), ('july', 2), ('august', 3))))
328 lst = list(SummerMonth)
329 self.assertEqual(len(lst), len(SummerMonth))
330 self.assertEqual(len(SummerMonth), 3, SummerMonth)
331 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
332 for i, month in enumerate('june july august'.split(), 1):
333 e = SummerMonth(i)
334 self.assertEqual(int(e.value), i)
335 self.assertNotEqual(e, i)
336 self.assertEqual(e.name, month)
337 self.assertIn(e, SummerMonth)
338 self.assertIs(type(e), SummerMonth)
339
340 def test_programatic_function_type(self):
341 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
342 lst = list(SummerMonth)
343 self.assertEqual(len(lst), len(SummerMonth))
344 self.assertEqual(len(SummerMonth), 3, SummerMonth)
345 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
346 for i, month in enumerate('june july august'.split(), 1):
347 e = SummerMonth(i)
348 self.assertEqual(e, i)
349 self.assertEqual(e.name, month)
350 self.assertIn(e, SummerMonth)
351 self.assertIs(type(e), SummerMonth)
352
353 def test_programatic_function_type_from_subclass(self):
354 SummerMonth = IntEnum('SummerMonth', 'june july august')
355 lst = list(SummerMonth)
356 self.assertEqual(len(lst), len(SummerMonth))
357 self.assertEqual(len(SummerMonth), 3, SummerMonth)
358 self.assertEqual([SummerMonth.june, SummerMonth.july, SummerMonth.august ], lst)
359 for i, month in enumerate('june july august'.split(), 1):
360 e = SummerMonth(i)
361 self.assertEqual(e, i)
362 self.assertEqual(e.name, month)
363 self.assertIn(e, SummerMonth)
364 self.assertIs(type(e), SummerMonth)
365
366 def test_subclassing(self):
367 if isinstance(Name, Exception):
368 raise Name
369 self.assertEqual(Name.BDFL, 'Guido van Rossum')
370 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
371 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
372 self.assertIs(Name.BDFL, loads(dumps(Name.BDFL)))
373
374 def test_extending(self):
375 class Color(Enum):
376 red = 1
377 green = 2
378 blue = 3
379 with self.assertRaises(TypeError):
380 class MoreColor(Color):
381 cyan = 4
382 magenta = 5
383 yellow = 6
384
385 def test_exclude_methods(self):
386 class whatever(Enum):
387 this = 'that'
388 these = 'those'
389 def really(self):
390 return 'no, not %s' % self.value
391 self.assertIsNot(type(whatever.really), whatever)
392 self.assertEqual(whatever.this.really(), 'no, not that')
393
394 def test_overwrite_enums(self):
395 class Why(Enum):
396 question = 1
397 answer = 2
398 propisition = 3
399 def question(self):
400 print(42)
401 self.assertIsNot(type(Why.question), Why)
402 self.assertNotIn(Why.question, Why._enum_names)
403 self.assertNotIn(Why.question, Why)
404
405 def test_wrong_inheritance_order(self):
406 with self.assertRaises(TypeError):
407 class Wrong(Enum, str):
408 NotHere = 'error before this point'
409
410 def test_wrong_enum_in_call(self):
411 class Monochrome(Enum):
412 black = 0
413 white = 1
414 class Gender(Enum):
415 male = 0
416 female = 1
417 self.assertRaises(ValueError, Monochrome, Gender.male)
418
419 def test_wrong_enum_in_mixed_call(self):
420 class Monochrome(IntEnum):
421 black = 0
422 white = 1
423 class Gender(Enum):
424 male = 0
425 female = 1
426 self.assertRaises(ValueError, Monochrome, Gender.male)
427
428 def test_mixed_enum_in_call_1(self):
429 class Monochrome(IntEnum):
430 black = 0
431 white = 1
432 class Gender(IntEnum):
433 male = 0
434 female = 1
435 self.assertIs(Monochrome(Gender.female), Monochrome.white)
436
437 def test_mixed_enum_in_call_2(self):
438 class Monochrome(Enum):
439 black = 0
440 white = 1
441 class Gender(IntEnum):
442 male = 0
443 female = 1
444 self.assertIs(Monochrome(Gender.male), Monochrome.black)
445
446 def test_flufl_enum(self):
447 class Fluflnum(Enum):
448 def __int__(self):
449 return int(self.value)
450 class MailManOptions(Fluflnum):
451 option1 = 1
452 option2 = 2
453 option3 = 3
454 self.assertEqual(int(MailManOptions.option1), 1)
455
456 def test_no_such_enum_member(self):
457 class Color(Enum):
458 red = 1
459 green = 2
460 blue = 3
461 with self.assertRaises(ValueError):
462 Color(4)
463 with self.assertRaises(KeyError):
464 Color['chartreuse']
465
466 def test_new_repr(self):
467 class Color(Enum):
468 red = 1
469 green = 2
470 blue = 3
471 def __repr__(self):
472 return "don't you just love shades of %s?" % self.name
473 self.assertEqual(repr(Color.blue), "don't you just love shades of blue?" )
474
475 def test_inherited_repr(self):
476 class MyEnum(Enum):
477 def __repr__(self):
478 return "My name is %s." % self.name
479 class MyIntEnum(int, MyEnum):
480 this = 1
481 that = 2
482 theother = 3
483 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
484
485 def test_multiple_mixin_mro(self):
486 class auto_enum(type(Enum)):
487 def __new__(metacls, cls, bases, classdict):
488 temp = type(classdict)()
489 names = set(classdict._enum_names)
490 i = 0
491 for k in classdict._enum_names:
492 v = classdict[k]
493 if v is Ellipsis:
494 v = i
495 else:
496 i = v
497 i += 1
498 temp[k] = v
499 for k, v in classdict.items():
500 if k not in names:
501 temp[k] = v
502 return super(auto_enum, metacls).__new__(metacls, cls, bases, te mp)
503
504 class AutoNumberedEnum(Enum, metaclass=auto_enum):
505 pass
506
507 class AutoIntEnum(IntEnum, metaclass=auto_enum):
508 pass
509
510 class TestAutoNumber(AutoNumberedEnum):
511 a = ...
512 b = 3
513 c = ...
514
515 class TestAutoInt(AutoIntEnum):
516 a = ...
517 b = 3
518 c = ...
519
520 def test_subclasses_with_getnewargs(self):
521 class NamedInt(int):
522 def __new__(cls, *args, **kwds):
523 _args = args
524 name, *args = args
525 if len(args) == 0:
526 raise TypeError("name and value must be specified")
527 self = int.__new__(cls, *args, **kwds)
528 self._intname = name
529 return self
530 @property
531 def __name__(self):
532 return self._intname
533 def __repr__(self):
534 # repr() is updated to include the name and type info
535 return "{}({!r}, {})".format(type(self).__name__,
536 self.__name__,
537 int.__repr__(self))
538 def __str__(self):
539 # str() is unchanged, even if it relies on the repr() fallback
540 base = int
541 base_str = base.__str__
542 if base_str.__objclass__ is object:
543 return base.__repr__(self)
544 return base_str(self)
545 # for simplicity, we only define one operator that propagates expres sions
546 def __add__(self, other):
547 temp = int(self) + int( other)
548 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
549 return NamedInt(
550 '({0} + {1})'.format(self.__name__, other.__name__),
551 temp )
552 else:
553 return temp
554
555 class NEI(NamedInt, Enum):
556 x = ('the-x', 1)
557 y = ('the-y', 2)
558
559 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
560 globals()['NamedInt'] = NamedInt
561 globals()['NEI'] = NEI
562 self.assertIs(loads(dumps(NEI.y)), NEI.y)
563
564 def test_tuple_subclass(self):
565 class SomeTuple(tuple, Enum):
566 first = (1, 'for the money')
567 second = (2, 'for the show')
568 third = (3, 'for the music')
569 self.assertIs(type(SomeTuple.first), SomeTuple)
570 self.assertIsInstance(SomeTuple.second, tuple)
571 self.assertEqual(SomeTuple.third, (3, 'for the music'))
572 globals()['SomeTuple'] = SomeTuple
573 self.assertIs(loads(dumps(SomeTuple.first)), SomeTuple.first)
574
575 def test_duplicate_values_give_unique_enum_items(self):
576 class AutoNumber(Enum):
577 first = ()
578 second = ()
579 third = ()
580 def __new__(cls):
581 value = len(cls.__members__) + 1
582 obj = object.__new__(cls)
583 obj._value = value
584 return obj
585 def __int__(self):
586 return self.value
587 self.assertEqual(list(AutoNumber), [AutoNumber.first, AutoNumber.second, AutoNumber.third])
588 self.assertEqual(int(AutoNumber.second), 2)
589 self.assertIs(AutoNumber(1), AutoNumber.first)
590
591 def test_inherited_new_from_enhanced_enum(self):
592 class AutoNumber(Enum):
593 def __new__(cls):
594 value = len(cls.__members__) + 1
595 obj = object.__new__(cls)
596 obj._value = value
597 return obj
598 def __int__(self):
599 return self._value
600 class Color(AutoNumber):
601 red = ()
602 green = ()
603 blue = ()
604 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
605 self.assertEqual(list(map(int, Color)), [1, 2, 3])
606
607 def test_inherited_new_from_mixed_enum(self):
608 class AutoNumber(IntEnum):
609 def __new__(cls):
610 value = len(cls.__members__) + 1
611 obj = int.__new__(cls, value)
612 obj._value = value
613 return obj
614 class Color(AutoNumber):
615 red = ()
616 green = ()
617 blue = ()
618 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
619 self.assertEqual(list(map(int, Color)), [1, 2, 3])
620
621 def test_ordered_mixin(self):
622 class OrderedEnum(Enum):
623 def __ge__(self, other):
624 if self.__class__ is other.__class__:
625 return self._value >= other._value
626 return NotImplemented
627 def __gt__(self, other):
628 if self.__class__ is other.__class__:
629 return self._value > other._value
630 return NotImplemented
631 def __le__(self, other):
632 if self.__class__ is other.__class__:
633 return self._value <= other._value
634 return NotImplemented
635 def __lt__(self, other):
636 if self.__class__ is other.__class__:
637 return self._value < other._value
638 return NotImplemented
639 class Grade(OrderedEnum):
640 A = 5
641 B = 4
642 C = 3
643 D = 2
644 F = 1
645 self.assertGreater(Grade.A, Grade.B)
646 self.assertLessEqual(Grade.F, Grade.C)
647 self.assertLess(Grade.D, Grade.A)
648 self.assertGreaterEqual(Grade.B, Grade.B)
649
650
651 if __name__ == '__main__':
652 unittest.main()
OLDNEW
« Lib/enum.py ('K') | « Lib/enum.py ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+