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

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