blob: 572e8733f45b86258a1cf76f7a0c9132ca2f3c20 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07008from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000011from test import support
Ethan Furmana4b1bb42018-01-22 07:56:37 -080012from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080013
Ethan Furman6b3d64a2013-06-14 16:55:46 -070014
15# for pickle tests
16try:
17 class Stooges(Enum):
18 LARRY = 1
19 CURLY = 2
20 MOE = 3
21except Exception as exc:
22 Stooges = exc
23
24try:
25 class IntStooges(int, Enum):
26 LARRY = 1
27 CURLY = 2
28 MOE = 3
29except Exception as exc:
30 IntStooges = exc
31
32try:
33 class FloatStooges(float, Enum):
34 LARRY = 1.39
35 CURLY = 2.72
36 MOE = 3.142596
37except Exception as exc:
38 FloatStooges = exc
39
Ethan Furman65a5a472016-09-01 23:55:19 -070040try:
41 class FlagStooges(Flag):
42 LARRY = 1
43 CURLY = 2
44 MOE = 3
45except Exception as exc:
46 FlagStooges = exc
47
Ethan Furman6b3d64a2013-06-14 16:55:46 -070048# for pickle test and subclass tests
49try:
50 class StrEnum(str, Enum):
51 'accepts only string values'
52 class Name(StrEnum):
53 BDFL = 'Guido van Rossum'
54 FLUFL = 'Barry Warsaw'
55except Exception as exc:
56 Name = exc
57
58try:
59 Question = Enum('Question', 'who what when where why', module=__name__)
60except Exception as exc:
61 Question = exc
62
63try:
64 Answer = Enum('Answer', 'him this then there because')
65except Exception as exc:
66 Answer = exc
67
Ethan Furmanca1b7942014-02-08 11:36:27 -080068try:
69 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
70except Exception as exc:
71 Theory = exc
72
Ethan Furman6b3d64a2013-06-14 16:55:46 -070073# for doctests
74try:
75 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080076 TOMATO = 1
77 BANANA = 2
78 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070079except Exception:
80 pass
81
Serhiy Storchakae50e7802015-03-31 16:56:49 +030082def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080083 if target is None:
84 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080086 assertion(loads(dumps(source, protocol=protocol)), target)
87
Serhiy Storchakae50e7802015-03-31 16:56:49 +030088def test_pickle_exception(assertion, exception, obj):
89 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080090 with assertion(exception):
91 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070092
93class TestHelpers(unittest.TestCase):
94 # _is_descriptor, _is_sunder, _is_dunder
95
96 def test_is_descriptor(self):
97 class foo:
98 pass
99 for attr in ('__get__','__set__','__delete__'):
100 obj = foo()
101 self.assertFalse(enum._is_descriptor(obj))
102 setattr(obj, attr, 1)
103 self.assertTrue(enum._is_descriptor(obj))
104
105 def test_is_sunder(self):
106 for s in ('_a_', '_aa_'):
107 self.assertTrue(enum._is_sunder(s))
108
109 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
110 '__', '___', '____', '_____',):
111 self.assertFalse(enum._is_sunder(s))
112
113 def test_is_dunder(self):
114 for s in ('__a__', '__aa__'):
115 self.assertTrue(enum._is_dunder(s))
116 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
117 '__', '___', '____', '_____',):
118 self.assertFalse(enum._is_dunder(s))
119
Ethan Furman5bdab642018-09-21 19:03:09 -0700120# for subclassing tests
121
122class classproperty:
123
124 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
125 self.fget = fget
126 self.fset = fset
127 self.fdel = fdel
128 if doc is None and fget is not None:
129 doc = fget.__doc__
130 self.__doc__ = doc
131
132 def __get__(self, instance, ownerclass):
133 return self.fget(ownerclass)
134
135
Ethan Furmanc16595e2016-09-10 23:36:59 -0700136# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700137
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700138class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800139
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700140 def setUp(self):
141 class Season(Enum):
142 SPRING = 1
143 SUMMER = 2
144 AUTUMN = 3
145 WINTER = 4
146 self.Season = Season
147
Ethan Furmanec15a822013-08-31 19:17:41 -0700148 class Konstants(float, Enum):
149 E = 2.7182818
150 PI = 3.1415926
151 TAU = 2 * PI
152 self.Konstants = Konstants
153
154 class Grades(IntEnum):
155 A = 5
156 B = 4
157 C = 3
158 D = 2
159 F = 0
160 self.Grades = Grades
161
162 class Directional(str, Enum):
163 EAST = 'east'
164 WEST = 'west'
165 NORTH = 'north'
166 SOUTH = 'south'
167 self.Directional = Directional
168
169 from datetime import date
170 class Holiday(date, Enum):
171 NEW_YEAR = 2013, 1, 1
172 IDES_OF_MARCH = 2013, 3, 15
173 self.Holiday = Holiday
174
Ethan Furman388a3922013-08-12 06:51:41 -0700175 def test_dir_on_class(self):
176 Season = self.Season
177 self.assertEqual(
178 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700179 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700180 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
181 )
182
183 def test_dir_on_item(self):
184 Season = self.Season
185 self.assertEqual(
186 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700188 )
189
Ethan Furmanc850f342013-09-15 16:59:35 -0700190 def test_dir_with_added_behavior(self):
191 class Test(Enum):
192 this = 'that'
193 these = 'those'
194 def wowser(self):
195 return ("Wowser! I'm %s!" % self.name)
196 self.assertEqual(
197 set(dir(Test)),
198 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
199 )
200 self.assertEqual(
201 set(dir(Test.this)),
202 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
203 )
204
Ethan Furman0ae550b2014-10-14 08:58:32 -0700205 def test_dir_on_sub_with_behavior_on_super(self):
206 # see issue22506
207 class SuperEnum(Enum):
208 def invisible(self):
209 return "did you see me?"
210 class SubEnum(SuperEnum):
211 sample = 5
212 self.assertEqual(
213 set(dir(SubEnum.sample)),
214 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
215 )
216
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700217 def test_enum_in_enum_out(self):
218 Season = self.Season
219 self.assertIs(Season(Season.WINTER), Season.WINTER)
220
221 def test_enum_value(self):
222 Season = self.Season
223 self.assertEqual(Season.SPRING.value, 1)
224
225 def test_intenum_value(self):
226 self.assertEqual(IntStooges.CURLY.value, 2)
227
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700228 def test_enum(self):
229 Season = self.Season
230 lst = list(Season)
231 self.assertEqual(len(lst), len(Season))
232 self.assertEqual(len(Season), 4, Season)
233 self.assertEqual(
234 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
235
236 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
237 e = Season(i)
238 self.assertEqual(e, getattr(Season, season))
239 self.assertEqual(e.value, i)
240 self.assertNotEqual(e, i)
241 self.assertEqual(e.name, season)
242 self.assertIn(e, Season)
243 self.assertIs(type(e), Season)
244 self.assertIsInstance(e, Season)
245 self.assertEqual(str(e), 'Season.' + season)
246 self.assertEqual(
247 repr(e),
248 '<Season.{0}: {1}>'.format(season, i),
249 )
250
251 def test_value_name(self):
252 Season = self.Season
253 self.assertEqual(Season.SPRING.name, 'SPRING')
254 self.assertEqual(Season.SPRING.value, 1)
255 with self.assertRaises(AttributeError):
256 Season.SPRING.name = 'invierno'
257 with self.assertRaises(AttributeError):
258 Season.SPRING.value = 2
259
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700260 def test_changing_member(self):
261 Season = self.Season
262 with self.assertRaises(AttributeError):
263 Season.WINTER = 'really cold'
264
Ethan Furman64a99722013-09-22 16:18:19 -0700265 def test_attribute_deletion(self):
266 class Season(Enum):
267 SPRING = 1
268 SUMMER = 2
269 AUTUMN = 3
270 WINTER = 4
271
272 def spam(cls):
273 pass
274
275 self.assertTrue(hasattr(Season, 'spam'))
276 del Season.spam
277 self.assertFalse(hasattr(Season, 'spam'))
278
279 with self.assertRaises(AttributeError):
280 del Season.SPRING
281 with self.assertRaises(AttributeError):
282 del Season.DRY
283 with self.assertRaises(AttributeError):
284 del Season.SPRING.name
285
Ethan Furman5de67b12016-04-13 23:52:09 -0700286 def test_bool_of_class(self):
287 class Empty(Enum):
288 pass
289 self.assertTrue(bool(Empty))
290
291 def test_bool_of_member(self):
292 class Count(Enum):
293 zero = 0
294 one = 1
295 two = 2
296 for member in Count:
297 self.assertTrue(bool(member))
298
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700299 def test_invalid_names(self):
300 with self.assertRaises(ValueError):
301 class Wrong(Enum):
302 mro = 9
303 with self.assertRaises(ValueError):
304 class Wrong(Enum):
305 _create_= 11
306 with self.assertRaises(ValueError):
307 class Wrong(Enum):
308 _get_mixins_ = 9
309 with self.assertRaises(ValueError):
310 class Wrong(Enum):
311 _find_new_ = 1
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 _any_name_ = 9
315
Ethan Furman6db1fd52015-09-17 21:49:12 -0700316 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800317 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700318 class Logic(Enum):
319 true = True
320 false = False
321 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800322 self.assertTrue(Logic.false)
323 # unless overridden
324 class RealLogic(Enum):
325 true = True
326 false = False
327 def __bool__(self):
328 return bool(self._value_)
329 self.assertTrue(RealLogic.true)
330 self.assertFalse(RealLogic.false)
331 # mixed Enums depend on mixed-in type
332 class IntLogic(int, Enum):
333 true = 1
334 false = 0
335 self.assertTrue(IntLogic.true)
336 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700337
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700338 def test_contains(self):
339 Season = self.Season
340 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530341 with self.assertRaises(TypeError):
342 3 in Season
343 with self.assertRaises(TypeError):
344 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700345
346 val = Season(3)
347 self.assertIn(val, Season)
348
349 class OtherEnum(Enum):
350 one = 1; two = 2
351 self.assertNotIn(OtherEnum.two, Season)
352
353 def test_comparisons(self):
354 Season = self.Season
355 with self.assertRaises(TypeError):
356 Season.SPRING < Season.WINTER
357 with self.assertRaises(TypeError):
358 Season.SPRING > 4
359
360 self.assertNotEqual(Season.SPRING, 1)
361
362 class Part(Enum):
363 SPRING = 1
364 CLIP = 2
365 BARREL = 3
366
367 self.assertNotEqual(Season.SPRING, Part.SPRING)
368 with self.assertRaises(TypeError):
369 Season.SPRING < Part.CLIP
370
371 def test_enum_duplicates(self):
372 class Season(Enum):
373 SPRING = 1
374 SUMMER = 2
375 AUTUMN = FALL = 3
376 WINTER = 4
377 ANOTHER_SPRING = 1
378 lst = list(Season)
379 self.assertEqual(
380 lst,
381 [Season.SPRING, Season.SUMMER,
382 Season.AUTUMN, Season.WINTER,
383 ])
384 self.assertIs(Season.FALL, Season.AUTUMN)
385 self.assertEqual(Season.FALL.value, 3)
386 self.assertEqual(Season.AUTUMN.value, 3)
387 self.assertIs(Season(3), Season.AUTUMN)
388 self.assertIs(Season(1), Season.SPRING)
389 self.assertEqual(Season.FALL.name, 'AUTUMN')
390 self.assertEqual(
391 [k for k,v in Season.__members__.items() if v.name != k],
392 ['FALL', 'ANOTHER_SPRING'],
393 )
394
Ethan Furman101e0742013-09-15 12:34:36 -0700395 def test_duplicate_name(self):
396 with self.assertRaises(TypeError):
397 class Color(Enum):
398 red = 1
399 green = 2
400 blue = 3
401 red = 4
402
403 with self.assertRaises(TypeError):
404 class Color(Enum):
405 red = 1
406 green = 2
407 blue = 3
408 def red(self):
409 return 'red'
410
411 with self.assertRaises(TypeError):
412 class Color(Enum):
413 @property
414 def red(self):
415 return 'redder'
416 red = 1
417 green = 2
418 blue = 3
419
420
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700421 def test_enum_with_value_name(self):
422 class Huh(Enum):
423 name = 1
424 value = 2
425 self.assertEqual(
426 list(Huh),
427 [Huh.name, Huh.value],
428 )
429 self.assertIs(type(Huh.name), Huh)
430 self.assertEqual(Huh.name.name, 'name')
431 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700432
433 def test_format_enum(self):
434 Season = self.Season
435 self.assertEqual('{}'.format(Season.SPRING),
436 '{}'.format(str(Season.SPRING)))
437 self.assertEqual( '{:}'.format(Season.SPRING),
438 '{:}'.format(str(Season.SPRING)))
439 self.assertEqual('{:20}'.format(Season.SPRING),
440 '{:20}'.format(str(Season.SPRING)))
441 self.assertEqual('{:^20}'.format(Season.SPRING),
442 '{:^20}'.format(str(Season.SPRING)))
443 self.assertEqual('{:>20}'.format(Season.SPRING),
444 '{:>20}'.format(str(Season.SPRING)))
445 self.assertEqual('{:<20}'.format(Season.SPRING),
446 '{:<20}'.format(str(Season.SPRING)))
447
448 def test_format_enum_custom(self):
449 class TestFloat(float, Enum):
450 one = 1.0
451 two = 2.0
452 def __format__(self, spec):
453 return 'TestFloat success!'
454 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
455
456 def assertFormatIsValue(self, spec, member):
457 self.assertEqual(spec.format(member), spec.format(member.value))
458
459 def test_format_enum_date(self):
460 Holiday = self.Holiday
461 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
462 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
463 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
464 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
465 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
466 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
467 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
468 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
469
470 def test_format_enum_float(self):
471 Konstants = self.Konstants
472 self.assertFormatIsValue('{}', Konstants.TAU)
473 self.assertFormatIsValue('{:}', Konstants.TAU)
474 self.assertFormatIsValue('{:20}', Konstants.TAU)
475 self.assertFormatIsValue('{:^20}', Konstants.TAU)
476 self.assertFormatIsValue('{:>20}', Konstants.TAU)
477 self.assertFormatIsValue('{:<20}', Konstants.TAU)
478 self.assertFormatIsValue('{:n}', Konstants.TAU)
479 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
480 self.assertFormatIsValue('{:f}', Konstants.TAU)
481
482 def test_format_enum_int(self):
483 Grades = self.Grades
484 self.assertFormatIsValue('{}', Grades.C)
485 self.assertFormatIsValue('{:}', Grades.C)
486 self.assertFormatIsValue('{:20}', Grades.C)
487 self.assertFormatIsValue('{:^20}', Grades.C)
488 self.assertFormatIsValue('{:>20}', Grades.C)
489 self.assertFormatIsValue('{:<20}', Grades.C)
490 self.assertFormatIsValue('{:+}', Grades.C)
491 self.assertFormatIsValue('{:08X}', Grades.C)
492 self.assertFormatIsValue('{:b}', Grades.C)
493
494 def test_format_enum_str(self):
495 Directional = self.Directional
496 self.assertFormatIsValue('{}', Directional.WEST)
497 self.assertFormatIsValue('{:}', Directional.WEST)
498 self.assertFormatIsValue('{:20}', Directional.WEST)
499 self.assertFormatIsValue('{:^20}', Directional.WEST)
500 self.assertFormatIsValue('{:>20}', Directional.WEST)
501 self.assertFormatIsValue('{:<20}', Directional.WEST)
502
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700503 def test_hash(self):
504 Season = self.Season
505 dates = {}
506 dates[Season.WINTER] = '1225'
507 dates[Season.SPRING] = '0315'
508 dates[Season.SUMMER] = '0704'
509 dates[Season.AUTUMN] = '1031'
510 self.assertEqual(dates[Season.AUTUMN], '1031')
511
512 def test_intenum_from_scratch(self):
513 class phy(int, Enum):
514 pi = 3
515 tau = 2 * pi
516 self.assertTrue(phy.pi < phy.tau)
517
518 def test_intenum_inherited(self):
519 class IntEnum(int, Enum):
520 pass
521 class phy(IntEnum):
522 pi = 3
523 tau = 2 * pi
524 self.assertTrue(phy.pi < phy.tau)
525
526 def test_floatenum_from_scratch(self):
527 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700528 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700529 tau = 2 * pi
530 self.assertTrue(phy.pi < phy.tau)
531
532 def test_floatenum_inherited(self):
533 class FloatEnum(float, Enum):
534 pass
535 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700536 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700537 tau = 2 * pi
538 self.assertTrue(phy.pi < phy.tau)
539
540 def test_strenum_from_scratch(self):
541 class phy(str, Enum):
542 pi = 'Pi'
543 tau = 'Tau'
544 self.assertTrue(phy.pi < phy.tau)
545
546 def test_strenum_inherited(self):
547 class StrEnum(str, Enum):
548 pass
549 class phy(StrEnum):
550 pi = 'Pi'
551 tau = 'Tau'
552 self.assertTrue(phy.pi < phy.tau)
553
554
555 def test_intenum(self):
556 class WeekDay(IntEnum):
557 SUNDAY = 1
558 MONDAY = 2
559 TUESDAY = 3
560 WEDNESDAY = 4
561 THURSDAY = 5
562 FRIDAY = 6
563 SATURDAY = 7
564
565 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
566 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
567
568 lst = list(WeekDay)
569 self.assertEqual(len(lst), len(WeekDay))
570 self.assertEqual(len(WeekDay), 7)
571 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
572 target = target.split()
573 for i, weekday in enumerate(target, 1):
574 e = WeekDay(i)
575 self.assertEqual(e, i)
576 self.assertEqual(int(e), i)
577 self.assertEqual(e.name, weekday)
578 self.assertIn(e, WeekDay)
579 self.assertEqual(lst.index(e)+1, i)
580 self.assertTrue(0 < e < 8)
581 self.assertIs(type(e), WeekDay)
582 self.assertIsInstance(e, int)
583 self.assertIsInstance(e, Enum)
584
585 def test_intenum_duplicates(self):
586 class WeekDay(IntEnum):
587 SUNDAY = 1
588 MONDAY = 2
589 TUESDAY = TEUSDAY = 3
590 WEDNESDAY = 4
591 THURSDAY = 5
592 FRIDAY = 6
593 SATURDAY = 7
594 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
595 self.assertEqual(WeekDay(3).name, 'TUESDAY')
596 self.assertEqual([k for k,v in WeekDay.__members__.items()
597 if v.name != k], ['TEUSDAY', ])
598
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300599 def test_intenum_from_bytes(self):
600 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
601 with self.assertRaises(ValueError):
602 IntStooges.from_bytes(b'\x00\x05', 'big')
603
604 def test_floatenum_fromhex(self):
605 h = float.hex(FloatStooges.MOE.value)
606 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
607 h = float.hex(FloatStooges.MOE.value + 0.01)
608 with self.assertRaises(ValueError):
609 FloatStooges.fromhex(h)
610
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700611 def test_pickle_enum(self):
612 if isinstance(Stooges, Exception):
613 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800614 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
615 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700616
617 def test_pickle_int(self):
618 if isinstance(IntStooges, Exception):
619 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800620 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
621 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700622
623 def test_pickle_float(self):
624 if isinstance(FloatStooges, Exception):
625 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800626 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
627 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700628
629 def test_pickle_enum_function(self):
630 if isinstance(Answer, Exception):
631 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800632 test_pickle_dump_load(self.assertIs, Answer.him)
633 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700634
635 def test_pickle_enum_function_with_module(self):
636 if isinstance(Question, Exception):
637 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800638 test_pickle_dump_load(self.assertIs, Question.who)
639 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700640
Ethan Furmanca1b7942014-02-08 11:36:27 -0800641 def test_enum_function_with_qualname(self):
642 if isinstance(Theory, Exception):
643 raise Theory
644 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
645
646 def test_class_nested_enum_and_pickle_protocol_four(self):
647 # would normally just have this directly in the class namespace
648 class NestedEnum(Enum):
649 twigs = 'common'
650 shiny = 'rare'
651
652 self.__class__.NestedEnum = NestedEnum
653 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300654 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800655
Ethan Furman24e837f2015-03-18 17:27:57 -0700656 def test_pickle_by_name(self):
657 class ReplaceGlobalInt(IntEnum):
658 ONE = 1
659 TWO = 2
660 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
661 for proto in range(HIGHEST_PROTOCOL):
662 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
663
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700664 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800665 BadPickle = Enum(
666 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800668 # now break BadPickle to test exception raising
669 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800670 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
671 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700672
673 def test_string_enum(self):
674 class SkillLevel(str, Enum):
675 master = 'what is the sound of one hand clapping?'
676 journeyman = 'why did the chicken cross the road?'
677 apprentice = 'knock, knock!'
678 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
679
680 def test_getattr_getitem(self):
681 class Period(Enum):
682 morning = 1
683 noon = 2
684 evening = 3
685 night = 4
686 self.assertIs(Period(2), Period.noon)
687 self.assertIs(getattr(Period, 'night'), Period.night)
688 self.assertIs(Period['morning'], Period.morning)
689
690 def test_getattr_dunder(self):
691 Season = self.Season
692 self.assertTrue(getattr(Season, '__eq__'))
693
694 def test_iteration_order(self):
695 class Season(Enum):
696 SUMMER = 2
697 WINTER = 4
698 AUTUMN = 3
699 SPRING = 1
700 self.assertEqual(
701 list(Season),
702 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
703 )
704
Ethan Furman2131a4a2013-09-14 18:11:24 -0700705 def test_reversed_iteration_order(self):
706 self.assertEqual(
707 list(reversed(self.Season)),
708 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
709 self.Season.SPRING]
710 )
711
Martin Pantereb995702016-07-28 01:11:04 +0000712 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700713 SummerMonth = Enum('SummerMonth', 'june july august')
714 lst = list(SummerMonth)
715 self.assertEqual(len(lst), len(SummerMonth))
716 self.assertEqual(len(SummerMonth), 3, SummerMonth)
717 self.assertEqual(
718 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
719 lst,
720 )
721 for i, month in enumerate('june july august'.split(), 1):
722 e = SummerMonth(i)
723 self.assertEqual(int(e.value), i)
724 self.assertNotEqual(e, i)
725 self.assertEqual(e.name, month)
726 self.assertIn(e, SummerMonth)
727 self.assertIs(type(e), SummerMonth)
728
Martin Pantereb995702016-07-28 01:11:04 +0000729 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700730 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
731 lst = list(SummerMonth)
732 self.assertEqual(len(lst), len(SummerMonth))
733 self.assertEqual(len(SummerMonth), 3, SummerMonth)
734 self.assertEqual(
735 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
736 lst,
737 )
738 for i, month in enumerate('june july august'.split(), 10):
739 e = SummerMonth(i)
740 self.assertEqual(int(e.value), i)
741 self.assertNotEqual(e, i)
742 self.assertEqual(e.name, month)
743 self.assertIn(e, SummerMonth)
744 self.assertIs(type(e), SummerMonth)
745
Martin Pantereb995702016-07-28 01:11:04 +0000746 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700747 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
748 lst = list(SummerMonth)
749 self.assertEqual(len(lst), len(SummerMonth))
750 self.assertEqual(len(SummerMonth), 3, SummerMonth)
751 self.assertEqual(
752 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
753 lst,
754 )
755 for i, month in enumerate('june july august'.split(), 1):
756 e = SummerMonth(i)
757 self.assertEqual(int(e.value), i)
758 self.assertNotEqual(e, i)
759 self.assertEqual(e.name, month)
760 self.assertIn(e, SummerMonth)
761 self.assertIs(type(e), SummerMonth)
762
Martin Pantereb995702016-07-28 01:11:04 +0000763 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700764 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
765 lst = list(SummerMonth)
766 self.assertEqual(len(lst), len(SummerMonth))
767 self.assertEqual(len(SummerMonth), 3, SummerMonth)
768 self.assertEqual(
769 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
770 lst,
771 )
772 for i, month in enumerate('june july august'.split(), 20):
773 e = SummerMonth(i)
774 self.assertEqual(int(e.value), i)
775 self.assertNotEqual(e, i)
776 self.assertEqual(e.name, month)
777 self.assertIn(e, SummerMonth)
778 self.assertIs(type(e), SummerMonth)
779
Martin Pantereb995702016-07-28 01:11:04 +0000780 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700781 SummerMonth = Enum(
782 'SummerMonth',
783 (('june', 1), ('july', 2), ('august', 3))
784 )
785 lst = list(SummerMonth)
786 self.assertEqual(len(lst), len(SummerMonth))
787 self.assertEqual(len(SummerMonth), 3, SummerMonth)
788 self.assertEqual(
789 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
790 lst,
791 )
792 for i, month in enumerate('june july august'.split(), 1):
793 e = SummerMonth(i)
794 self.assertEqual(int(e.value), i)
795 self.assertNotEqual(e, i)
796 self.assertEqual(e.name, month)
797 self.assertIn(e, SummerMonth)
798 self.assertIs(type(e), SummerMonth)
799
Martin Pantereb995702016-07-28 01:11:04 +0000800 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700801 SummerMonth = Enum(
802 'SummerMonth',
803 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
804 )
805 lst = list(SummerMonth)
806 self.assertEqual(len(lst), len(SummerMonth))
807 self.assertEqual(len(SummerMonth), 3, SummerMonth)
808 self.assertEqual(
809 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
810 lst,
811 )
812 for i, month in enumerate('june july august'.split(), 1):
813 e = SummerMonth(i)
814 self.assertEqual(int(e.value), i)
815 self.assertNotEqual(e, i)
816 self.assertEqual(e.name, month)
817 self.assertIn(e, SummerMonth)
818 self.assertIs(type(e), SummerMonth)
819
Martin Pantereb995702016-07-28 01:11:04 +0000820 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700821 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
822 lst = list(SummerMonth)
823 self.assertEqual(len(lst), len(SummerMonth))
824 self.assertEqual(len(SummerMonth), 3, SummerMonth)
825 self.assertEqual(
826 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
827 lst,
828 )
829 for i, month in enumerate('june july august'.split(), 1):
830 e = SummerMonth(i)
831 self.assertEqual(e, i)
832 self.assertEqual(e.name, month)
833 self.assertIn(e, SummerMonth)
834 self.assertIs(type(e), SummerMonth)
835
Martin Pantereb995702016-07-28 01:11:04 +0000836 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700837 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
838 lst = list(SummerMonth)
839 self.assertEqual(len(lst), len(SummerMonth))
840 self.assertEqual(len(SummerMonth), 3, SummerMonth)
841 self.assertEqual(
842 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
843 lst,
844 )
845 for i, month in enumerate('june july august'.split(), 30):
846 e = SummerMonth(i)
847 self.assertEqual(e, i)
848 self.assertEqual(e.name, month)
849 self.assertIn(e, SummerMonth)
850 self.assertIs(type(e), SummerMonth)
851
Martin Pantereb995702016-07-28 01:11:04 +0000852 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700853 SummerMonth = IntEnum('SummerMonth', 'june july august')
854 lst = list(SummerMonth)
855 self.assertEqual(len(lst), len(SummerMonth))
856 self.assertEqual(len(SummerMonth), 3, SummerMonth)
857 self.assertEqual(
858 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
859 lst,
860 )
861 for i, month in enumerate('june july august'.split(), 1):
862 e = SummerMonth(i)
863 self.assertEqual(e, i)
864 self.assertEqual(e.name, month)
865 self.assertIn(e, SummerMonth)
866 self.assertIs(type(e), SummerMonth)
867
Martin Pantereb995702016-07-28 01:11:04 +0000868 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700869 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
870 lst = list(SummerMonth)
871 self.assertEqual(len(lst), len(SummerMonth))
872 self.assertEqual(len(SummerMonth), 3, SummerMonth)
873 self.assertEqual(
874 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
875 lst,
876 )
877 for i, month in enumerate('june july august'.split(), 40):
878 e = SummerMonth(i)
879 self.assertEqual(e, i)
880 self.assertEqual(e.name, month)
881 self.assertIn(e, SummerMonth)
882 self.assertIs(type(e), SummerMonth)
883
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700884 def test_subclassing(self):
885 if isinstance(Name, Exception):
886 raise Name
887 self.assertEqual(Name.BDFL, 'Guido van Rossum')
888 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
889 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800890 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700891
892 def test_extending(self):
893 class Color(Enum):
894 red = 1
895 green = 2
896 blue = 3
897 with self.assertRaises(TypeError):
898 class MoreColor(Color):
899 cyan = 4
900 magenta = 5
901 yellow = 6
902
903 def test_exclude_methods(self):
904 class whatever(Enum):
905 this = 'that'
906 these = 'those'
907 def really(self):
908 return 'no, not %s' % self.value
909 self.assertIsNot(type(whatever.really), whatever)
910 self.assertEqual(whatever.this.really(), 'no, not that')
911
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700912 def test_wrong_inheritance_order(self):
913 with self.assertRaises(TypeError):
914 class Wrong(Enum, str):
915 NotHere = 'error before this point'
916
917 def test_intenum_transitivity(self):
918 class number(IntEnum):
919 one = 1
920 two = 2
921 three = 3
922 class numero(IntEnum):
923 uno = 1
924 dos = 2
925 tres = 3
926 self.assertEqual(number.one, numero.uno)
927 self.assertEqual(number.two, numero.dos)
928 self.assertEqual(number.three, numero.tres)
929
930 def test_wrong_enum_in_call(self):
931 class Monochrome(Enum):
932 black = 0
933 white = 1
934 class Gender(Enum):
935 male = 0
936 female = 1
937 self.assertRaises(ValueError, Monochrome, Gender.male)
938
939 def test_wrong_enum_in_mixed_call(self):
940 class Monochrome(IntEnum):
941 black = 0
942 white = 1
943 class Gender(Enum):
944 male = 0
945 female = 1
946 self.assertRaises(ValueError, Monochrome, Gender.male)
947
948 def test_mixed_enum_in_call_1(self):
949 class Monochrome(IntEnum):
950 black = 0
951 white = 1
952 class Gender(IntEnum):
953 male = 0
954 female = 1
955 self.assertIs(Monochrome(Gender.female), Monochrome.white)
956
957 def test_mixed_enum_in_call_2(self):
958 class Monochrome(Enum):
959 black = 0
960 white = 1
961 class Gender(IntEnum):
962 male = 0
963 female = 1
964 self.assertIs(Monochrome(Gender.male), Monochrome.black)
965
966 def test_flufl_enum(self):
967 class Fluflnum(Enum):
968 def __int__(self):
969 return int(self.value)
970 class MailManOptions(Fluflnum):
971 option1 = 1
972 option2 = 2
973 option3 = 3
974 self.assertEqual(int(MailManOptions.option1), 1)
975
Ethan Furman5e5a8232013-08-04 08:42:23 -0700976 def test_introspection(self):
977 class Number(IntEnum):
978 one = 100
979 two = 200
980 self.assertIs(Number.one._member_type_, int)
981 self.assertIs(Number._member_type_, int)
982 class String(str, Enum):
983 yarn = 'soft'
984 rope = 'rough'
985 wire = 'hard'
986 self.assertIs(String.yarn._member_type_, str)
987 self.assertIs(String._member_type_, str)
988 class Plain(Enum):
989 vanilla = 'white'
990 one = 1
991 self.assertIs(Plain.vanilla._member_type_, object)
992 self.assertIs(Plain._member_type_, object)
993
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700994 def test_no_such_enum_member(self):
995 class Color(Enum):
996 red = 1
997 green = 2
998 blue = 3
999 with self.assertRaises(ValueError):
1000 Color(4)
1001 with self.assertRaises(KeyError):
1002 Color['chartreuse']
1003
1004 def test_new_repr(self):
1005 class Color(Enum):
1006 red = 1
1007 green = 2
1008 blue = 3
1009 def __repr__(self):
1010 return "don't you just love shades of %s?" % self.name
1011 self.assertEqual(
1012 repr(Color.blue),
1013 "don't you just love shades of blue?",
1014 )
1015
1016 def test_inherited_repr(self):
1017 class MyEnum(Enum):
1018 def __repr__(self):
1019 return "My name is %s." % self.name
1020 class MyIntEnum(int, MyEnum):
1021 this = 1
1022 that = 2
1023 theother = 3
1024 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1025
1026 def test_multiple_mixin_mro(self):
1027 class auto_enum(type(Enum)):
1028 def __new__(metacls, cls, bases, classdict):
1029 temp = type(classdict)()
1030 names = set(classdict._member_names)
1031 i = 0
1032 for k in classdict._member_names:
1033 v = classdict[k]
1034 if v is Ellipsis:
1035 v = i
1036 else:
1037 i = v
1038 i += 1
1039 temp[k] = v
1040 for k, v in classdict.items():
1041 if k not in names:
1042 temp[k] = v
1043 return super(auto_enum, metacls).__new__(
1044 metacls, cls, bases, temp)
1045
1046 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1047 pass
1048
1049 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1050 pass
1051
1052 class TestAutoNumber(AutoNumberedEnum):
1053 a = ...
1054 b = 3
1055 c = ...
1056
1057 class TestAutoInt(AutoIntEnum):
1058 a = ...
1059 b = 3
1060 c = ...
1061
1062 def test_subclasses_with_getnewargs(self):
1063 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001064 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001065 def __new__(cls, *args):
1066 _args = args
1067 name, *args = args
1068 if len(args) == 0:
1069 raise TypeError("name and value must be specified")
1070 self = int.__new__(cls, *args)
1071 self._intname = name
1072 self._args = _args
1073 return self
1074 def __getnewargs__(self):
1075 return self._args
1076 @property
1077 def __name__(self):
1078 return self._intname
1079 def __repr__(self):
1080 # repr() is updated to include the name and type info
1081 return "{}({!r}, {})".format(type(self).__name__,
1082 self.__name__,
1083 int.__repr__(self))
1084 def __str__(self):
1085 # str() is unchanged, even if it relies on the repr() fallback
1086 base = int
1087 base_str = base.__str__
1088 if base_str.__objclass__ is object:
1089 return base.__repr__(self)
1090 return base_str(self)
1091 # for simplicity, we only define one operator that
1092 # propagates expressions
1093 def __add__(self, other):
1094 temp = int(self) + int( other)
1095 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1096 return NamedInt(
1097 '({0} + {1})'.format(self.__name__, other.__name__),
1098 temp )
1099 else:
1100 return temp
1101
1102 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001103 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001104 x = ('the-x', 1)
1105 y = ('the-y', 2)
1106
Ethan Furman2aa27322013-07-19 19:35:56 -07001107
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001108 self.assertIs(NEI.__new__, Enum.__new__)
1109 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1110 globals()['NamedInt'] = NamedInt
1111 globals()['NEI'] = NEI
1112 NI5 = NamedInt('test', 5)
1113 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001114 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001115 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001116 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001117 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001118
Ethan Furmanca1b7942014-02-08 11:36:27 -08001119 def test_subclasses_with_getnewargs_ex(self):
1120 class NamedInt(int):
1121 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1122 def __new__(cls, *args):
1123 _args = args
1124 name, *args = args
1125 if len(args) == 0:
1126 raise TypeError("name and value must be specified")
1127 self = int.__new__(cls, *args)
1128 self._intname = name
1129 self._args = _args
1130 return self
1131 def __getnewargs_ex__(self):
1132 return self._args, {}
1133 @property
1134 def __name__(self):
1135 return self._intname
1136 def __repr__(self):
1137 # repr() is updated to include the name and type info
1138 return "{}({!r}, {})".format(type(self).__name__,
1139 self.__name__,
1140 int.__repr__(self))
1141 def __str__(self):
1142 # str() is unchanged, even if it relies on the repr() fallback
1143 base = int
1144 base_str = base.__str__
1145 if base_str.__objclass__ is object:
1146 return base.__repr__(self)
1147 return base_str(self)
1148 # for simplicity, we only define one operator that
1149 # propagates expressions
1150 def __add__(self, other):
1151 temp = int(self) + int( other)
1152 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1153 return NamedInt(
1154 '({0} + {1})'.format(self.__name__, other.__name__),
1155 temp )
1156 else:
1157 return temp
1158
1159 class NEI(NamedInt, Enum):
1160 __qualname__ = 'NEI' # needed for pickle protocol 4
1161 x = ('the-x', 1)
1162 y = ('the-y', 2)
1163
1164
1165 self.assertIs(NEI.__new__, Enum.__new__)
1166 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1167 globals()['NamedInt'] = NamedInt
1168 globals()['NEI'] = NEI
1169 NI5 = NamedInt('test', 5)
1170 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001171 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001172 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001173 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001174 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001175
1176 def test_subclasses_with_reduce(self):
1177 class NamedInt(int):
1178 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1179 def __new__(cls, *args):
1180 _args = args
1181 name, *args = args
1182 if len(args) == 0:
1183 raise TypeError("name and value must be specified")
1184 self = int.__new__(cls, *args)
1185 self._intname = name
1186 self._args = _args
1187 return self
1188 def __reduce__(self):
1189 return self.__class__, self._args
1190 @property
1191 def __name__(self):
1192 return self._intname
1193 def __repr__(self):
1194 # repr() is updated to include the name and type info
1195 return "{}({!r}, {})".format(type(self).__name__,
1196 self.__name__,
1197 int.__repr__(self))
1198 def __str__(self):
1199 # str() is unchanged, even if it relies on the repr() fallback
1200 base = int
1201 base_str = base.__str__
1202 if base_str.__objclass__ is object:
1203 return base.__repr__(self)
1204 return base_str(self)
1205 # for simplicity, we only define one operator that
1206 # propagates expressions
1207 def __add__(self, other):
1208 temp = int(self) + int( other)
1209 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1210 return NamedInt(
1211 '({0} + {1})'.format(self.__name__, other.__name__),
1212 temp )
1213 else:
1214 return temp
1215
1216 class NEI(NamedInt, Enum):
1217 __qualname__ = 'NEI' # needed for pickle protocol 4
1218 x = ('the-x', 1)
1219 y = ('the-y', 2)
1220
1221
1222 self.assertIs(NEI.__new__, Enum.__new__)
1223 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1224 globals()['NamedInt'] = NamedInt
1225 globals()['NEI'] = NEI
1226 NI5 = NamedInt('test', 5)
1227 self.assertEqual(NI5, 5)
1228 test_pickle_dump_load(self.assertEqual, NI5, 5)
1229 self.assertEqual(NEI.y.value, 2)
1230 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001231 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001232
1233 def test_subclasses_with_reduce_ex(self):
1234 class NamedInt(int):
1235 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1236 def __new__(cls, *args):
1237 _args = args
1238 name, *args = args
1239 if len(args) == 0:
1240 raise TypeError("name and value must be specified")
1241 self = int.__new__(cls, *args)
1242 self._intname = name
1243 self._args = _args
1244 return self
1245 def __reduce_ex__(self, proto):
1246 return self.__class__, self._args
1247 @property
1248 def __name__(self):
1249 return self._intname
1250 def __repr__(self):
1251 # repr() is updated to include the name and type info
1252 return "{}({!r}, {})".format(type(self).__name__,
1253 self.__name__,
1254 int.__repr__(self))
1255 def __str__(self):
1256 # str() is unchanged, even if it relies on the repr() fallback
1257 base = int
1258 base_str = base.__str__
1259 if base_str.__objclass__ is object:
1260 return base.__repr__(self)
1261 return base_str(self)
1262 # for simplicity, we only define one operator that
1263 # propagates expressions
1264 def __add__(self, other):
1265 temp = int(self) + int( other)
1266 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1267 return NamedInt(
1268 '({0} + {1})'.format(self.__name__, other.__name__),
1269 temp )
1270 else:
1271 return temp
1272
1273 class NEI(NamedInt, Enum):
1274 __qualname__ = 'NEI' # needed for pickle protocol 4
1275 x = ('the-x', 1)
1276 y = ('the-y', 2)
1277
1278
1279 self.assertIs(NEI.__new__, Enum.__new__)
1280 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1281 globals()['NamedInt'] = NamedInt
1282 globals()['NEI'] = NEI
1283 NI5 = NamedInt('test', 5)
1284 self.assertEqual(NI5, 5)
1285 test_pickle_dump_load(self.assertEqual, NI5, 5)
1286 self.assertEqual(NEI.y.value, 2)
1287 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001288 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001289
Ethan Furmandc870522014-02-18 12:37:12 -08001290 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001291 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001292 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001293 def __new__(cls, *args):
1294 _args = args
1295 name, *args = args
1296 if len(args) == 0:
1297 raise TypeError("name and value must be specified")
1298 self = int.__new__(cls, *args)
1299 self._intname = name
1300 self._args = _args
1301 return self
1302 @property
1303 def __name__(self):
1304 return self._intname
1305 def __repr__(self):
1306 # repr() is updated to include the name and type info
1307 return "{}({!r}, {})".format(type(self).__name__,
1308 self.__name__,
1309 int.__repr__(self))
1310 def __str__(self):
1311 # str() is unchanged, even if it relies on the repr() fallback
1312 base = int
1313 base_str = base.__str__
1314 if base_str.__objclass__ is object:
1315 return base.__repr__(self)
1316 return base_str(self)
1317 # for simplicity, we only define one operator that
1318 # propagates expressions
1319 def __add__(self, other):
1320 temp = int(self) + int( other)
1321 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1322 return NamedInt(
1323 '({0} + {1})'.format(self.__name__, other.__name__),
1324 temp )
1325 else:
1326 return temp
1327
1328 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001329 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001330 x = ('the-x', 1)
1331 y = ('the-y', 2)
1332
1333 self.assertIs(NEI.__new__, Enum.__new__)
1334 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1335 globals()['NamedInt'] = NamedInt
1336 globals()['NEI'] = NEI
1337 NI5 = NamedInt('test', 5)
1338 self.assertEqual(NI5, 5)
1339 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001340 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1341 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001342
Ethan Furmandc870522014-02-18 12:37:12 -08001343 def test_subclasses_without_direct_pickle_support_using_name(self):
1344 class NamedInt(int):
1345 __qualname__ = 'NamedInt'
1346 def __new__(cls, *args):
1347 _args = args
1348 name, *args = args
1349 if len(args) == 0:
1350 raise TypeError("name and value must be specified")
1351 self = int.__new__(cls, *args)
1352 self._intname = name
1353 self._args = _args
1354 return self
1355 @property
1356 def __name__(self):
1357 return self._intname
1358 def __repr__(self):
1359 # repr() is updated to include the name and type info
1360 return "{}({!r}, {})".format(type(self).__name__,
1361 self.__name__,
1362 int.__repr__(self))
1363 def __str__(self):
1364 # str() is unchanged, even if it relies on the repr() fallback
1365 base = int
1366 base_str = base.__str__
1367 if base_str.__objclass__ is object:
1368 return base.__repr__(self)
1369 return base_str(self)
1370 # for simplicity, we only define one operator that
1371 # propagates expressions
1372 def __add__(self, other):
1373 temp = int(self) + int( other)
1374 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1375 return NamedInt(
1376 '({0} + {1})'.format(self.__name__, other.__name__),
1377 temp )
1378 else:
1379 return temp
1380
1381 class NEI(NamedInt, Enum):
1382 __qualname__ = 'NEI'
1383 x = ('the-x', 1)
1384 y = ('the-y', 2)
1385 def __reduce_ex__(self, proto):
1386 return getattr, (self.__class__, self._name_)
1387
1388 self.assertIs(NEI.__new__, Enum.__new__)
1389 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1390 globals()['NamedInt'] = NamedInt
1391 globals()['NEI'] = NEI
1392 NI5 = NamedInt('test', 5)
1393 self.assertEqual(NI5, 5)
1394 self.assertEqual(NEI.y.value, 2)
1395 test_pickle_dump_load(self.assertIs, NEI.y)
1396 test_pickle_dump_load(self.assertIs, NEI)
1397
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001398 def test_tuple_subclass(self):
1399 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001400 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001401 first = (1, 'for the money')
1402 second = (2, 'for the show')
1403 third = (3, 'for the music')
1404 self.assertIs(type(SomeTuple.first), SomeTuple)
1405 self.assertIsInstance(SomeTuple.second, tuple)
1406 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1407 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001408 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001409
1410 def test_duplicate_values_give_unique_enum_items(self):
1411 class AutoNumber(Enum):
1412 first = ()
1413 second = ()
1414 third = ()
1415 def __new__(cls):
1416 value = len(cls.__members__) + 1
1417 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001418 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001419 return obj
1420 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001421 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001422 self.assertEqual(
1423 list(AutoNumber),
1424 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1425 )
1426 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001427 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001428 self.assertIs(AutoNumber(1), AutoNumber.first)
1429
1430 def test_inherited_new_from_enhanced_enum(self):
1431 class AutoNumber(Enum):
1432 def __new__(cls):
1433 value = len(cls.__members__) + 1
1434 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001435 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 return obj
1437 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001438 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001439 class Color(AutoNumber):
1440 red = ()
1441 green = ()
1442 blue = ()
1443 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1444 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1445
1446 def test_inherited_new_from_mixed_enum(self):
1447 class AutoNumber(IntEnum):
1448 def __new__(cls):
1449 value = len(cls.__members__) + 1
1450 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001451 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001452 return obj
1453 class Color(AutoNumber):
1454 red = ()
1455 green = ()
1456 blue = ()
1457 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1458 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1459
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001460 def test_equality(self):
1461 class AlwaysEqual:
1462 def __eq__(self, other):
1463 return True
1464 class OrdinaryEnum(Enum):
1465 a = 1
1466 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1467 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1468
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001469 def test_ordered_mixin(self):
1470 class OrderedEnum(Enum):
1471 def __ge__(self, other):
1472 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001473 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001474 return NotImplemented
1475 def __gt__(self, other):
1476 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001477 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001478 return NotImplemented
1479 def __le__(self, other):
1480 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001481 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001482 return NotImplemented
1483 def __lt__(self, other):
1484 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001485 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001486 return NotImplemented
1487 class Grade(OrderedEnum):
1488 A = 5
1489 B = 4
1490 C = 3
1491 D = 2
1492 F = 1
1493 self.assertGreater(Grade.A, Grade.B)
1494 self.assertLessEqual(Grade.F, Grade.C)
1495 self.assertLess(Grade.D, Grade.A)
1496 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001497 self.assertEqual(Grade.B, Grade.B)
1498 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001499
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001500 def test_extending2(self):
1501 class Shade(Enum):
1502 def shade(self):
1503 print(self.name)
1504 class Color(Shade):
1505 red = 1
1506 green = 2
1507 blue = 3
1508 with self.assertRaises(TypeError):
1509 class MoreColor(Color):
1510 cyan = 4
1511 magenta = 5
1512 yellow = 6
1513
1514 def test_extending3(self):
1515 class Shade(Enum):
1516 def shade(self):
1517 return self.name
1518 class Color(Shade):
1519 def hex(self):
1520 return '%s hexlified!' % self.value
1521 class MoreColor(Color):
1522 cyan = 4
1523 magenta = 5
1524 yellow = 6
1525 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1526
orlnub1230fb9fad2018-09-12 20:28:53 +03001527 def test_subclass_duplicate_name(self):
1528 class Base(Enum):
1529 def test(self):
1530 pass
1531 class Test(Base):
1532 test = 1
1533 self.assertIs(type(Test.test), Test)
1534
1535 def test_subclass_duplicate_name_dynamic(self):
1536 from types import DynamicClassAttribute
1537 class Base(Enum):
1538 @DynamicClassAttribute
1539 def test(self):
1540 return 'dynamic'
1541 class Test(Base):
1542 test = 1
1543 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001544
1545 def test_no_duplicates(self):
1546 class UniqueEnum(Enum):
1547 def __init__(self, *args):
1548 cls = self.__class__
1549 if any(self.value == e.value for e in cls):
1550 a = self.name
1551 e = cls(self.value).name
1552 raise ValueError(
1553 "aliases not allowed in UniqueEnum: %r --> %r"
1554 % (a, e)
1555 )
1556 class Color(UniqueEnum):
1557 red = 1
1558 green = 2
1559 blue = 3
1560 with self.assertRaises(ValueError):
1561 class Color(UniqueEnum):
1562 red = 1
1563 green = 2
1564 blue = 3
1565 grene = 2
1566
1567 def test_init(self):
1568 class Planet(Enum):
1569 MERCURY = (3.303e+23, 2.4397e6)
1570 VENUS = (4.869e+24, 6.0518e6)
1571 EARTH = (5.976e+24, 6.37814e6)
1572 MARS = (6.421e+23, 3.3972e6)
1573 JUPITER = (1.9e+27, 7.1492e7)
1574 SATURN = (5.688e+26, 6.0268e7)
1575 URANUS = (8.686e+25, 2.5559e7)
1576 NEPTUNE = (1.024e+26, 2.4746e7)
1577 def __init__(self, mass, radius):
1578 self.mass = mass # in kilograms
1579 self.radius = radius # in meters
1580 @property
1581 def surface_gravity(self):
1582 # universal gravitational constant (m3 kg-1 s-2)
1583 G = 6.67300E-11
1584 return G * self.mass / (self.radius * self.radius)
1585 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1586 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1587
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001588 def test_ignore(self):
1589 class Period(timedelta, Enum):
1590 '''
1591 different lengths of time
1592 '''
1593 def __new__(cls, value, period):
1594 obj = timedelta.__new__(cls, value)
1595 obj._value_ = value
1596 obj.period = period
1597 return obj
1598 _ignore_ = 'Period i'
1599 Period = vars()
1600 for i in range(13):
1601 Period['month_%d' % i] = i*30, 'month'
1602 for i in range(53):
1603 Period['week_%d' % i] = i*7, 'week'
1604 for i in range(32):
1605 Period['day_%d' % i] = i, 'day'
1606 OneDay = day_1
1607 OneWeek = week_1
1608 OneMonth = month_1
1609 self.assertFalse(hasattr(Period, '_ignore_'))
1610 self.assertFalse(hasattr(Period, 'Period'))
1611 self.assertFalse(hasattr(Period, 'i'))
1612 self.assertTrue(isinstance(Period.day_1, timedelta))
1613 self.assertTrue(Period.month_1 is Period.day_30)
1614 self.assertTrue(Period.week_4 is Period.day_28)
1615
Ethan Furman2aa27322013-07-19 19:35:56 -07001616 def test_nonhash_value(self):
1617 class AutoNumberInAList(Enum):
1618 def __new__(cls):
1619 value = [len(cls.__members__) + 1]
1620 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001621 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001622 return obj
1623 class ColorInAList(AutoNumberInAList):
1624 red = ()
1625 green = ()
1626 blue = ()
1627 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001628 for enum, value in zip(ColorInAList, range(3)):
1629 value += 1
1630 self.assertEqual(enum.value, [value])
1631 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001632
Ethan Furmanb41803e2013-07-25 13:50:45 -07001633 def test_conflicting_types_resolved_in_new(self):
1634 class LabelledIntEnum(int, Enum):
1635 def __new__(cls, *args):
1636 value, label = args
1637 obj = int.__new__(cls, value)
1638 obj.label = label
1639 obj._value_ = value
1640 return obj
1641
1642 class LabelledList(LabelledIntEnum):
1643 unprocessed = (1, "Unprocessed")
1644 payment_complete = (2, "Payment Complete")
1645
1646 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1647 self.assertEqual(LabelledList.unprocessed, 1)
1648 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001649
Ethan Furmanc16595e2016-09-10 23:36:59 -07001650 def test_auto_number(self):
1651 class Color(Enum):
1652 red = auto()
1653 blue = auto()
1654 green = auto()
1655
1656 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1657 self.assertEqual(Color.red.value, 1)
1658 self.assertEqual(Color.blue.value, 2)
1659 self.assertEqual(Color.green.value, 3)
1660
1661 def test_auto_name(self):
1662 class Color(Enum):
1663 def _generate_next_value_(name, start, count, last):
1664 return name
1665 red = auto()
1666 blue = auto()
1667 green = auto()
1668
1669 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1670 self.assertEqual(Color.red.value, 'red')
1671 self.assertEqual(Color.blue.value, 'blue')
1672 self.assertEqual(Color.green.value, 'green')
1673
1674 def test_auto_name_inherit(self):
1675 class AutoNameEnum(Enum):
1676 def _generate_next_value_(name, start, count, last):
1677 return name
1678 class Color(AutoNameEnum):
1679 red = auto()
1680 blue = auto()
1681 green = auto()
1682
1683 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1684 self.assertEqual(Color.red.value, 'red')
1685 self.assertEqual(Color.blue.value, 'blue')
1686 self.assertEqual(Color.green.value, 'green')
1687
1688 def test_auto_garbage(self):
1689 class Color(Enum):
1690 red = 'red'
1691 blue = auto()
1692 self.assertEqual(Color.blue.value, 1)
1693
1694 def test_auto_garbage_corrected(self):
1695 class Color(Enum):
1696 red = 'red'
1697 blue = 2
1698 green = auto()
1699
1700 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1701 self.assertEqual(Color.red.value, 'red')
1702 self.assertEqual(Color.blue.value, 2)
1703 self.assertEqual(Color.green.value, 3)
1704
Ethan Furman3515dcc2016-09-18 13:15:41 -07001705 def test_duplicate_auto(self):
1706 class Dupes(Enum):
1707 first = primero = auto()
1708 second = auto()
1709 third = auto()
1710 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1711
Ethan Furman019f0a02018-09-12 11:43:34 -07001712 def test_missing(self):
1713 class Color(Enum):
1714 red = 1
1715 green = 2
1716 blue = 3
1717 @classmethod
1718 def _missing_(cls, item):
1719 if item == 'three':
1720 return cls.blue
1721 elif item == 'bad return':
1722 # trigger internal error
1723 return 5
1724 elif item == 'error out':
1725 raise ZeroDivisionError
1726 else:
1727 # trigger not found
1728 return None
1729 self.assertIs(Color('three'), Color.blue)
1730 self.assertRaises(ValueError, Color, 7)
1731 try:
1732 Color('bad return')
1733 except TypeError as exc:
1734 self.assertTrue(isinstance(exc.__context__, ValueError))
1735 else:
1736 raise Exception('Exception not raised.')
1737 try:
1738 Color('error out')
1739 except ZeroDivisionError as exc:
1740 self.assertTrue(isinstance(exc.__context__, ValueError))
1741 else:
1742 raise Exception('Exception not raised.')
1743
Ethan Furman5bdab642018-09-21 19:03:09 -07001744 def test_multiple_mixin(self):
1745 class MaxMixin:
1746 @classproperty
1747 def MAX(cls):
1748 max = len(cls)
1749 cls.MAX = max
1750 return max
1751 class StrMixin:
1752 def __str__(self):
1753 return self._name_.lower()
1754 class SomeEnum(Enum):
1755 def behavior(self):
1756 return 'booyah'
1757 class AnotherEnum(Enum):
1758 def behavior(self):
1759 return 'nuhuh!'
1760 def social(self):
1761 return "what's up?"
1762 class Color(MaxMixin, Enum):
1763 RED = auto()
1764 GREEN = auto()
1765 BLUE = auto()
1766 self.assertEqual(Color.RED.value, 1)
1767 self.assertEqual(Color.GREEN.value, 2)
1768 self.assertEqual(Color.BLUE.value, 3)
1769 self.assertEqual(Color.MAX, 3)
1770 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1771 class Color(MaxMixin, StrMixin, Enum):
1772 RED = auto()
1773 GREEN = auto()
1774 BLUE = auto()
1775 self.assertEqual(Color.RED.value, 1)
1776 self.assertEqual(Color.GREEN.value, 2)
1777 self.assertEqual(Color.BLUE.value, 3)
1778 self.assertEqual(Color.MAX, 3)
1779 self.assertEqual(str(Color.BLUE), 'blue')
1780 class Color(StrMixin, MaxMixin, Enum):
1781 RED = auto()
1782 GREEN = auto()
1783 BLUE = auto()
1784 self.assertEqual(Color.RED.value, 1)
1785 self.assertEqual(Color.GREEN.value, 2)
1786 self.assertEqual(Color.BLUE.value, 3)
1787 self.assertEqual(Color.MAX, 3)
1788 self.assertEqual(str(Color.BLUE), 'blue')
1789 class CoolColor(StrMixin, SomeEnum, Enum):
1790 RED = auto()
1791 GREEN = auto()
1792 BLUE = auto()
1793 self.assertEqual(CoolColor.RED.value, 1)
1794 self.assertEqual(CoolColor.GREEN.value, 2)
1795 self.assertEqual(CoolColor.BLUE.value, 3)
1796 self.assertEqual(str(CoolColor.BLUE), 'blue')
1797 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1798 class CoolerColor(StrMixin, AnotherEnum, Enum):
1799 RED = auto()
1800 GREEN = auto()
1801 BLUE = auto()
1802 self.assertEqual(CoolerColor.RED.value, 1)
1803 self.assertEqual(CoolerColor.GREEN.value, 2)
1804 self.assertEqual(CoolerColor.BLUE.value, 3)
1805 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1806 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1807 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1808 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1809 RED = auto()
1810 GREEN = auto()
1811 BLUE = auto()
1812 self.assertEqual(CoolestColor.RED.value, 1)
1813 self.assertEqual(CoolestColor.GREEN.value, 2)
1814 self.assertEqual(CoolestColor.BLUE.value, 3)
1815 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1816 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1817 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1818 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1819 RED = auto()
1820 GREEN = auto()
1821 BLUE = auto()
1822 self.assertEqual(ConfusedColor.RED.value, 1)
1823 self.assertEqual(ConfusedColor.GREEN.value, 2)
1824 self.assertEqual(ConfusedColor.BLUE.value, 3)
1825 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1826 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1827 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1828 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1829 RED = auto()
1830 GREEN = auto()
1831 BLUE = auto()
1832 self.assertEqual(ReformedColor.RED.value, 1)
1833 self.assertEqual(ReformedColor.GREEN.value, 2)
1834 self.assertEqual(ReformedColor.BLUE.value, 3)
1835 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1836 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1837 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1838 self.assertTrue(issubclass(ReformedColor, int))
1839
Ethan Furmancd453852018-10-05 23:29:36 -07001840 def test_multiple_inherited_mixin(self):
1841 class StrEnum(str, Enum):
1842 def __new__(cls, *args, **kwargs):
1843 for a in args:
1844 if not isinstance(a, str):
1845 raise TypeError("Enumeration '%s' (%s) is not"
1846 " a string" % (a, type(a).__name__))
1847 return str.__new__(cls, *args, **kwargs)
1848 @unique
1849 class Decision1(StrEnum):
1850 REVERT = "REVERT"
1851 REVERT_ALL = "REVERT_ALL"
1852 RETRY = "RETRY"
1853 class MyEnum(StrEnum):
1854 pass
1855 @unique
1856 class Decision2(MyEnum):
1857 REVERT = "REVERT"
1858 REVERT_ALL = "REVERT_ALL"
1859 RETRY = "RETRY"
1860
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001861
Ethan Furmane8e61272016-08-20 07:19:31 -07001862class TestOrder(unittest.TestCase):
1863
1864 def test_same_members(self):
1865 class Color(Enum):
1866 _order_ = 'red green blue'
1867 red = 1
1868 green = 2
1869 blue = 3
1870
1871 def test_same_members_with_aliases(self):
1872 class Color(Enum):
1873 _order_ = 'red green blue'
1874 red = 1
1875 green = 2
1876 blue = 3
1877 verde = green
1878
1879 def test_same_members_wrong_order(self):
1880 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1881 class Color(Enum):
1882 _order_ = 'red green blue'
1883 red = 1
1884 blue = 3
1885 green = 2
1886
1887 def test_order_has_extra_members(self):
1888 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1889 class Color(Enum):
1890 _order_ = 'red green blue purple'
1891 red = 1
1892 green = 2
1893 blue = 3
1894
1895 def test_order_has_extra_members_with_aliases(self):
1896 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1897 class Color(Enum):
1898 _order_ = 'red green blue purple'
1899 red = 1
1900 green = 2
1901 blue = 3
1902 verde = green
1903
1904 def test_enum_has_extra_members(self):
1905 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1906 class Color(Enum):
1907 _order_ = 'red green blue'
1908 red = 1
1909 green = 2
1910 blue = 3
1911 purple = 4
1912
1913 def test_enum_has_extra_members_with_aliases(self):
1914 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1915 class Color(Enum):
1916 _order_ = 'red green blue'
1917 red = 1
1918 green = 2
1919 blue = 3
1920 purple = 4
1921 verde = green
1922
1923
Ethan Furman65a5a472016-09-01 23:55:19 -07001924class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001925 """Tests of the Flags."""
1926
Ethan Furman65a5a472016-09-01 23:55:19 -07001927 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001928 R, W, X = 4, 2, 1
1929
Ethan Furman65a5a472016-09-01 23:55:19 -07001930 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001931 RO = 0
1932 WO = 1
1933 RW = 2
1934 AC = 3
1935 CE = 1<<19
1936
Rahul Jha94306522018-09-10 23:51:04 +05301937 class Color(Flag):
1938 BLACK = 0
1939 RED = 1
1940 GREEN = 2
1941 BLUE = 4
1942 PURPLE = RED|BLUE
1943
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001944 def test_str(self):
1945 Perm = self.Perm
1946 self.assertEqual(str(Perm.R), 'Perm.R')
1947 self.assertEqual(str(Perm.W), 'Perm.W')
1948 self.assertEqual(str(Perm.X), 'Perm.X')
1949 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1950 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1951 self.assertEqual(str(Perm(0)), 'Perm.0')
1952 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1953 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1954 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1955 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1956 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1957 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1958
1959 Open = self.Open
1960 self.assertEqual(str(Open.RO), 'Open.RO')
1961 self.assertEqual(str(Open.WO), 'Open.WO')
1962 self.assertEqual(str(Open.AC), 'Open.AC')
1963 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1964 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001965 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001966 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1967 self.assertEqual(str(~Open.AC), 'Open.CE')
1968 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1969 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1970
1971 def test_repr(self):
1972 Perm = self.Perm
1973 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1974 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1975 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1976 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1977 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001978 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001979 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1980 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1981 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1982 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001983 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001984 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1985
1986 Open = self.Open
1987 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1988 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1989 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1990 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1991 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001992 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001993 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1994 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1995 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1996 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1997
1998 def test_or(self):
1999 Perm = self.Perm
2000 for i in Perm:
2001 for j in Perm:
2002 self.assertEqual((i | j), Perm(i.value | j.value))
2003 self.assertEqual((i | j).value, i.value | j.value)
2004 self.assertIs(type(i | j), Perm)
2005 for i in Perm:
2006 self.assertIs(i | i, i)
2007 Open = self.Open
2008 self.assertIs(Open.RO | Open.CE, Open.CE)
2009
2010 def test_and(self):
2011 Perm = self.Perm
2012 RW = Perm.R | Perm.W
2013 RX = Perm.R | Perm.X
2014 WX = Perm.W | Perm.X
2015 RWX = Perm.R | Perm.W | Perm.X
2016 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2017 for i in values:
2018 for j in values:
2019 self.assertEqual((i & j).value, i.value & j.value)
2020 self.assertIs(type(i & j), Perm)
2021 for i in Perm:
2022 self.assertIs(i & i, i)
2023 self.assertIs(i & RWX, i)
2024 self.assertIs(RWX & i, i)
2025 Open = self.Open
2026 self.assertIs(Open.RO & Open.CE, Open.RO)
2027
2028 def test_xor(self):
2029 Perm = self.Perm
2030 for i in Perm:
2031 for j in Perm:
2032 self.assertEqual((i ^ j).value, i.value ^ j.value)
2033 self.assertIs(type(i ^ j), Perm)
2034 for i in Perm:
2035 self.assertIs(i ^ Perm(0), i)
2036 self.assertIs(Perm(0) ^ i, i)
2037 Open = self.Open
2038 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2039 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2040
2041 def test_invert(self):
2042 Perm = self.Perm
2043 RW = Perm.R | Perm.W
2044 RX = Perm.R | Perm.X
2045 WX = Perm.W | Perm.X
2046 RWX = Perm.R | Perm.W | Perm.X
2047 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2048 for i in values:
2049 self.assertIs(type(~i), Perm)
2050 self.assertEqual(~~i, i)
2051 for i in Perm:
2052 self.assertIs(~~i, i)
2053 Open = self.Open
2054 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2055 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2056
Ethan Furman25d94bb2016-09-02 16:32:32 -07002057 def test_bool(self):
2058 Perm = self.Perm
2059 for f in Perm:
2060 self.assertTrue(f)
2061 Open = self.Open
2062 for f in Open:
2063 self.assertEqual(bool(f.value), bool(f))
2064
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002065 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002066 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002067 lst = list(Perm)
2068 self.assertEqual(len(lst), len(Perm))
2069 self.assertEqual(len(Perm), 3, Perm)
2070 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2071 for i, n in enumerate('R W X'.split()):
2072 v = 1<<i
2073 e = Perm(v)
2074 self.assertEqual(e.value, v)
2075 self.assertEqual(type(e.value), int)
2076 self.assertEqual(e.name, n)
2077 self.assertIn(e, Perm)
2078 self.assertIs(type(e), Perm)
2079
2080 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002081 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002082 lst = list(Perm)
2083 self.assertEqual(len(lst), len(Perm))
2084 self.assertEqual(len(Perm), 3, Perm)
2085 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2086 for i, n in enumerate('R W X'.split()):
2087 v = 8<<i
2088 e = Perm(v)
2089 self.assertEqual(e.value, v)
2090 self.assertEqual(type(e.value), int)
2091 self.assertEqual(e.name, n)
2092 self.assertIn(e, Perm)
2093 self.assertIs(type(e), Perm)
2094
2095 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002096 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002097 lst = list(Perm)
2098 self.assertEqual(len(lst), len(Perm))
2099 self.assertEqual(len(Perm), 3, Perm)
2100 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2101 for i, n in enumerate('R W X'.split()):
2102 v = 1<<i
2103 e = Perm(v)
2104 self.assertEqual(e.value, v)
2105 self.assertEqual(type(e.value), int)
2106 self.assertEqual(e.name, n)
2107 self.assertIn(e, Perm)
2108 self.assertIs(type(e), Perm)
2109
2110 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002111 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002112 lst = list(Perm)
2113 self.assertEqual(len(lst), len(Perm))
2114 self.assertEqual(len(Perm), 3, Perm)
2115 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2116 for i, n in enumerate('R W X'.split()):
2117 v = 1<<(2*i+1)
2118 e = Perm(v)
2119 self.assertEqual(e.value, v)
2120 self.assertEqual(type(e.value), int)
2121 self.assertEqual(e.name, n)
2122 self.assertIn(e, Perm)
2123 self.assertIs(type(e), Perm)
2124
2125 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002126 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002127 lst = list(Perm)
2128 self.assertEqual(len(lst), len(Perm))
2129 self.assertEqual(len(Perm), 3, Perm)
2130 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2131 for i, n in enumerate('R W X'.split()):
2132 v = 1<<(2*i+1)
2133 e = Perm(v)
2134 self.assertEqual(e.value, v)
2135 self.assertEqual(type(e.value), int)
2136 self.assertEqual(e.name, n)
2137 self.assertIn(e, Perm)
2138 self.assertIs(type(e), Perm)
2139
Ethan Furman65a5a472016-09-01 23:55:19 -07002140 def test_pickle(self):
2141 if isinstance(FlagStooges, Exception):
2142 raise FlagStooges
2143 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2144 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002145
Rahul Jha94306522018-09-10 23:51:04 +05302146 def test_contains(self):
2147 Open = self.Open
2148 Color = self.Color
2149 self.assertFalse(Color.BLACK in Open)
2150 self.assertFalse(Open.RO in Color)
2151 with self.assertRaises(TypeError):
2152 'BLACK' in Color
2153 with self.assertRaises(TypeError):
2154 'RO' in Open
2155 with self.assertRaises(TypeError):
2156 1 in Color
2157 with self.assertRaises(TypeError):
2158 1 in Open
2159
2160 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002161 Perm = self.Perm
2162 R, W, X = Perm
2163 RW = R | W
2164 RX = R | X
2165 WX = W | X
2166 RWX = R | W | X
2167 self.assertTrue(R in RW)
2168 self.assertTrue(R in RX)
2169 self.assertTrue(R in RWX)
2170 self.assertTrue(W in RW)
2171 self.assertTrue(W in WX)
2172 self.assertTrue(W in RWX)
2173 self.assertTrue(X in RX)
2174 self.assertTrue(X in WX)
2175 self.assertTrue(X in RWX)
2176 self.assertFalse(R in WX)
2177 self.assertFalse(W in RX)
2178 self.assertFalse(X in RW)
2179
Ethan Furmanc16595e2016-09-10 23:36:59 -07002180 def test_auto_number(self):
2181 class Color(Flag):
2182 red = auto()
2183 blue = auto()
2184 green = auto()
2185
2186 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2187 self.assertEqual(Color.red.value, 1)
2188 self.assertEqual(Color.blue.value, 2)
2189 self.assertEqual(Color.green.value, 4)
2190
2191 def test_auto_number_garbage(self):
2192 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2193 class Color(Flag):
2194 red = 'not an int'
2195 blue = auto()
2196
Ethan Furman3515dcc2016-09-18 13:15:41 -07002197 def test_cascading_failure(self):
2198 class Bizarre(Flag):
2199 c = 3
2200 d = 4
2201 f = 6
2202 # Bizarre.c | Bizarre.d
2203 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2204 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2205 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2206 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2207 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2208 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2209
2210 def test_duplicate_auto(self):
2211 class Dupes(Enum):
2212 first = primero = auto()
2213 second = auto()
2214 third = auto()
2215 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2216
2217 def test_bizarre(self):
2218 class Bizarre(Flag):
2219 b = 3
2220 c = 4
2221 d = 6
2222 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2223
Ethan Furman5bdab642018-09-21 19:03:09 -07002224 def test_multiple_mixin(self):
2225 class AllMixin:
2226 @classproperty
2227 def ALL(cls):
2228 members = list(cls)
2229 all_value = None
2230 if members:
2231 all_value = members[0]
2232 for member in members[1:]:
2233 all_value |= member
2234 cls.ALL = all_value
2235 return all_value
2236 class StrMixin:
2237 def __str__(self):
2238 return self._name_.lower()
2239 class Color(AllMixin, Flag):
2240 RED = auto()
2241 GREEN = auto()
2242 BLUE = auto()
2243 self.assertEqual(Color.RED.value, 1)
2244 self.assertEqual(Color.GREEN.value, 2)
2245 self.assertEqual(Color.BLUE.value, 4)
2246 self.assertEqual(Color.ALL.value, 7)
2247 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2248 class Color(AllMixin, StrMixin, Flag):
2249 RED = auto()
2250 GREEN = auto()
2251 BLUE = auto()
2252 self.assertEqual(Color.RED.value, 1)
2253 self.assertEqual(Color.GREEN.value, 2)
2254 self.assertEqual(Color.BLUE.value, 4)
2255 self.assertEqual(Color.ALL.value, 7)
2256 self.assertEqual(str(Color.BLUE), 'blue')
2257 class Color(StrMixin, AllMixin, Flag):
2258 RED = auto()
2259 GREEN = auto()
2260 BLUE = auto()
2261 self.assertEqual(Color.RED.value, 1)
2262 self.assertEqual(Color.GREEN.value, 2)
2263 self.assertEqual(Color.BLUE.value, 4)
2264 self.assertEqual(Color.ALL.value, 7)
2265 self.assertEqual(str(Color.BLUE), 'blue')
2266
Ethan Furman28cf6632017-01-24 12:12:06 -08002267 @support.reap_threads
2268 def test_unique_composite(self):
2269 # override __eq__ to be identity only
2270 class TestFlag(Flag):
2271 one = auto()
2272 two = auto()
2273 three = auto()
2274 four = auto()
2275 five = auto()
2276 six = auto()
2277 seven = auto()
2278 eight = auto()
2279 def __eq__(self, other):
2280 return self is other
2281 def __hash__(self):
2282 return hash(self._value_)
2283 # have multiple threads competing to complete the composite members
2284 seen = set()
2285 failed = False
2286 def cycle_enum():
2287 nonlocal failed
2288 try:
2289 for i in range(256):
2290 seen.add(TestFlag(i))
2291 except Exception:
2292 failed = True
2293 threads = [
2294 threading.Thread(target=cycle_enum)
2295 for _ in range(8)
2296 ]
2297 with support.start_threads(threads):
2298 pass
2299 # check that only 248 members were created
2300 self.assertFalse(
2301 failed,
2302 'at least one thread failed while creating composite members')
2303 self.assertEqual(256, len(seen), 'too many composite members created')
2304
Ethan Furmanc16595e2016-09-10 23:36:59 -07002305
Ethan Furman65a5a472016-09-01 23:55:19 -07002306class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002307 """Tests of the IntFlags."""
2308
Ethan Furman65a5a472016-09-01 23:55:19 -07002309 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002310 X = 1 << 0
2311 W = 1 << 1
2312 R = 1 << 2
2313
Ethan Furman65a5a472016-09-01 23:55:19 -07002314 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002315 RO = 0
2316 WO = 1
2317 RW = 2
2318 AC = 3
2319 CE = 1<<19
2320
Rahul Jha94306522018-09-10 23:51:04 +05302321 class Color(IntFlag):
2322 BLACK = 0
2323 RED = 1
2324 GREEN = 2
2325 BLUE = 4
2326 PURPLE = RED|BLUE
2327
Ethan Furman3515dcc2016-09-18 13:15:41 -07002328 def test_type(self):
2329 Perm = self.Perm
2330 Open = self.Open
2331 for f in Perm:
2332 self.assertTrue(isinstance(f, Perm))
2333 self.assertEqual(f, f.value)
2334 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2335 self.assertEqual(Perm.W | Perm.X, 3)
2336 for f in Open:
2337 self.assertTrue(isinstance(f, Open))
2338 self.assertEqual(f, f.value)
2339 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2340 self.assertEqual(Open.WO | Open.RW, 3)
2341
2342
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002343 def test_str(self):
2344 Perm = self.Perm
2345 self.assertEqual(str(Perm.R), 'Perm.R')
2346 self.assertEqual(str(Perm.W), 'Perm.W')
2347 self.assertEqual(str(Perm.X), 'Perm.X')
2348 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2349 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2350 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2351 self.assertEqual(str(Perm(0)), 'Perm.0')
2352 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002353 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2354 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2355 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2356 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002357 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002358 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2359 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2360 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002361
2362 Open = self.Open
2363 self.assertEqual(str(Open.RO), 'Open.RO')
2364 self.assertEqual(str(Open.WO), 'Open.WO')
2365 self.assertEqual(str(Open.AC), 'Open.AC')
2366 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2367 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2368 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002369 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2370 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2371 self.assertEqual(str(~Open.AC), 'Open.CE')
2372 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2373 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2374 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002375
2376 def test_repr(self):
2377 Perm = self.Perm
2378 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2379 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2380 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2381 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2382 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2383 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002384 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2385 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002386 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2387 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2388 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2389 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002390 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002391 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2392 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2393 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002394
2395 Open = self.Open
2396 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2397 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2398 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2399 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2400 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002401 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002402 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2403 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2404 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2405 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2406 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2407 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002408
2409 def test_or(self):
2410 Perm = self.Perm
2411 for i in Perm:
2412 for j in Perm:
2413 self.assertEqual(i | j, i.value | j.value)
2414 self.assertEqual((i | j).value, i.value | j.value)
2415 self.assertIs(type(i | j), Perm)
2416 for j in range(8):
2417 self.assertEqual(i | j, i.value | j)
2418 self.assertEqual((i | j).value, i.value | j)
2419 self.assertIs(type(i | j), Perm)
2420 self.assertEqual(j | i, j | i.value)
2421 self.assertEqual((j | i).value, j | i.value)
2422 self.assertIs(type(j | i), Perm)
2423 for i in Perm:
2424 self.assertIs(i | i, i)
2425 self.assertIs(i | 0, i)
2426 self.assertIs(0 | i, i)
2427 Open = self.Open
2428 self.assertIs(Open.RO | Open.CE, Open.CE)
2429
2430 def test_and(self):
2431 Perm = self.Perm
2432 RW = Perm.R | Perm.W
2433 RX = Perm.R | Perm.X
2434 WX = Perm.W | Perm.X
2435 RWX = Perm.R | Perm.W | Perm.X
2436 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2437 for i in values:
2438 for j in values:
2439 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2440 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2441 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2442 for j in range(8):
2443 self.assertEqual(i & j, i.value & j)
2444 self.assertEqual((i & j).value, i.value & j)
2445 self.assertIs(type(i & j), Perm)
2446 self.assertEqual(j & i, j & i.value)
2447 self.assertEqual((j & i).value, j & i.value)
2448 self.assertIs(type(j & i), Perm)
2449 for i in Perm:
2450 self.assertIs(i & i, i)
2451 self.assertIs(i & 7, i)
2452 self.assertIs(7 & i, i)
2453 Open = self.Open
2454 self.assertIs(Open.RO & Open.CE, Open.RO)
2455
2456 def test_xor(self):
2457 Perm = self.Perm
2458 for i in Perm:
2459 for j in Perm:
2460 self.assertEqual(i ^ j, i.value ^ j.value)
2461 self.assertEqual((i ^ j).value, i.value ^ j.value)
2462 self.assertIs(type(i ^ j), Perm)
2463 for j in range(8):
2464 self.assertEqual(i ^ j, i.value ^ j)
2465 self.assertEqual((i ^ j).value, i.value ^ j)
2466 self.assertIs(type(i ^ j), Perm)
2467 self.assertEqual(j ^ i, j ^ i.value)
2468 self.assertEqual((j ^ i).value, j ^ i.value)
2469 self.assertIs(type(j ^ i), Perm)
2470 for i in Perm:
2471 self.assertIs(i ^ 0, i)
2472 self.assertIs(0 ^ i, i)
2473 Open = self.Open
2474 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2475 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2476
2477 def test_invert(self):
2478 Perm = self.Perm
2479 RW = Perm.R | Perm.W
2480 RX = Perm.R | Perm.X
2481 WX = Perm.W | Perm.X
2482 RWX = Perm.R | Perm.W | Perm.X
2483 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2484 for i in values:
2485 self.assertEqual(~i, ~i.value)
2486 self.assertEqual((~i).value, ~i.value)
2487 self.assertIs(type(~i), Perm)
2488 self.assertEqual(~~i, i)
2489 for i in Perm:
2490 self.assertIs(~~i, i)
2491 Open = self.Open
2492 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2493 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2494
2495 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002496 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002497 lst = list(Perm)
2498 self.assertEqual(len(lst), len(Perm))
2499 self.assertEqual(len(Perm), 3, Perm)
2500 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2501 for i, n in enumerate('R W X'.split()):
2502 v = 1<<i
2503 e = Perm(v)
2504 self.assertEqual(e.value, v)
2505 self.assertEqual(type(e.value), int)
2506 self.assertEqual(e, v)
2507 self.assertEqual(e.name, n)
2508 self.assertIn(e, Perm)
2509 self.assertIs(type(e), Perm)
2510
2511 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002512 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002513 lst = list(Perm)
2514 self.assertEqual(len(lst), len(Perm))
2515 self.assertEqual(len(Perm), 3, Perm)
2516 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2517 for i, n in enumerate('R W X'.split()):
2518 v = 8<<i
2519 e = Perm(v)
2520 self.assertEqual(e.value, v)
2521 self.assertEqual(type(e.value), int)
2522 self.assertEqual(e, v)
2523 self.assertEqual(e.name, n)
2524 self.assertIn(e, Perm)
2525 self.assertIs(type(e), Perm)
2526
2527 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002528 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002529 lst = list(Perm)
2530 self.assertEqual(len(lst), len(Perm))
2531 self.assertEqual(len(Perm), 3, Perm)
2532 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2533 for i, n in enumerate('R W X'.split()):
2534 v = 1<<i
2535 e = Perm(v)
2536 self.assertEqual(e.value, v)
2537 self.assertEqual(type(e.value), int)
2538 self.assertEqual(e, v)
2539 self.assertEqual(e.name, n)
2540 self.assertIn(e, Perm)
2541 self.assertIs(type(e), Perm)
2542
2543 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002544 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002545 lst = list(Perm)
2546 self.assertEqual(len(lst), len(Perm))
2547 self.assertEqual(len(Perm), 3, Perm)
2548 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2549 for i, n in enumerate('R W X'.split()):
2550 v = 1<<(2*i+1)
2551 e = Perm(v)
2552 self.assertEqual(e.value, v)
2553 self.assertEqual(type(e.value), int)
2554 self.assertEqual(e, v)
2555 self.assertEqual(e.name, n)
2556 self.assertIn(e, Perm)
2557 self.assertIs(type(e), Perm)
2558
2559 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002560 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002561 lst = list(Perm)
2562 self.assertEqual(len(lst), len(Perm))
2563 self.assertEqual(len(Perm), 3, Perm)
2564 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2565 for i, n in enumerate('R W X'.split()):
2566 v = 1<<(2*i+1)
2567 e = Perm(v)
2568 self.assertEqual(e.value, v)
2569 self.assertEqual(type(e.value), int)
2570 self.assertEqual(e, v)
2571 self.assertEqual(e.name, n)
2572 self.assertIn(e, Perm)
2573 self.assertIs(type(e), Perm)
2574
2575
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002576 def test_programatic_function_from_empty_list(self):
2577 Perm = enum.IntFlag('Perm', [])
2578 lst = list(Perm)
2579 self.assertEqual(len(lst), len(Perm))
2580 self.assertEqual(len(Perm), 0, Perm)
2581 Thing = enum.Enum('Thing', [])
2582 lst = list(Thing)
2583 self.assertEqual(len(lst), len(Thing))
2584 self.assertEqual(len(Thing), 0, Thing)
2585
2586
2587 def test_programatic_function_from_empty_tuple(self):
2588 Perm = enum.IntFlag('Perm', ())
2589 lst = list(Perm)
2590 self.assertEqual(len(lst), len(Perm))
2591 self.assertEqual(len(Perm), 0, Perm)
2592 Thing = enum.Enum('Thing', ())
2593 self.assertEqual(len(lst), len(Thing))
2594 self.assertEqual(len(Thing), 0, Thing)
2595
Rahul Jha94306522018-09-10 23:51:04 +05302596 def test_contains(self):
2597 Open = self.Open
2598 Color = self.Color
2599 self.assertTrue(Color.GREEN in Color)
2600 self.assertTrue(Open.RW in Open)
2601 self.assertFalse(Color.GREEN in Open)
2602 self.assertFalse(Open.RW in Color)
2603 with self.assertRaises(TypeError):
2604 'GREEN' in Color
2605 with self.assertRaises(TypeError):
2606 'RW' in Open
2607 with self.assertRaises(TypeError):
2608 2 in Color
2609 with self.assertRaises(TypeError):
2610 2 in Open
2611
2612 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002613 Perm = self.Perm
2614 R, W, X = Perm
2615 RW = R | W
2616 RX = R | X
2617 WX = W | X
2618 RWX = R | W | X
2619 self.assertTrue(R in RW)
2620 self.assertTrue(R in RX)
2621 self.assertTrue(R in RWX)
2622 self.assertTrue(W in RW)
2623 self.assertTrue(W in WX)
2624 self.assertTrue(W in RWX)
2625 self.assertTrue(X in RX)
2626 self.assertTrue(X in WX)
2627 self.assertTrue(X in RWX)
2628 self.assertFalse(R in WX)
2629 self.assertFalse(W in RX)
2630 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302631 with self.assertRaises(TypeError):
2632 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002633
Ethan Furman25d94bb2016-09-02 16:32:32 -07002634 def test_bool(self):
2635 Perm = self.Perm
2636 for f in Perm:
2637 self.assertTrue(f)
2638 Open = self.Open
2639 for f in Open:
2640 self.assertEqual(bool(f.value), bool(f))
2641
Ethan Furman5bdab642018-09-21 19:03:09 -07002642 def test_multiple_mixin(self):
2643 class AllMixin:
2644 @classproperty
2645 def ALL(cls):
2646 members = list(cls)
2647 all_value = None
2648 if members:
2649 all_value = members[0]
2650 for member in members[1:]:
2651 all_value |= member
2652 cls.ALL = all_value
2653 return all_value
2654 class StrMixin:
2655 def __str__(self):
2656 return self._name_.lower()
2657 class Color(AllMixin, IntFlag):
2658 RED = auto()
2659 GREEN = auto()
2660 BLUE = auto()
2661 self.assertEqual(Color.RED.value, 1)
2662 self.assertEqual(Color.GREEN.value, 2)
2663 self.assertEqual(Color.BLUE.value, 4)
2664 self.assertEqual(Color.ALL.value, 7)
2665 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2666 class Color(AllMixin, StrMixin, IntFlag):
2667 RED = auto()
2668 GREEN = auto()
2669 BLUE = auto()
2670 self.assertEqual(Color.RED.value, 1)
2671 self.assertEqual(Color.GREEN.value, 2)
2672 self.assertEqual(Color.BLUE.value, 4)
2673 self.assertEqual(Color.ALL.value, 7)
2674 self.assertEqual(str(Color.BLUE), 'blue')
2675 class Color(StrMixin, AllMixin, IntFlag):
2676 RED = auto()
2677 GREEN = auto()
2678 BLUE = auto()
2679 self.assertEqual(Color.RED.value, 1)
2680 self.assertEqual(Color.GREEN.value, 2)
2681 self.assertEqual(Color.BLUE.value, 4)
2682 self.assertEqual(Color.ALL.value, 7)
2683 self.assertEqual(str(Color.BLUE), 'blue')
2684
Ethan Furman28cf6632017-01-24 12:12:06 -08002685 @support.reap_threads
2686 def test_unique_composite(self):
2687 # override __eq__ to be identity only
2688 class TestFlag(IntFlag):
2689 one = auto()
2690 two = auto()
2691 three = auto()
2692 four = auto()
2693 five = auto()
2694 six = auto()
2695 seven = auto()
2696 eight = auto()
2697 def __eq__(self, other):
2698 return self is other
2699 def __hash__(self):
2700 return hash(self._value_)
2701 # have multiple threads competing to complete the composite members
2702 seen = set()
2703 failed = False
2704 def cycle_enum():
2705 nonlocal failed
2706 try:
2707 for i in range(256):
2708 seen.add(TestFlag(i))
2709 except Exception:
2710 failed = True
2711 threads = [
2712 threading.Thread(target=cycle_enum)
2713 for _ in range(8)
2714 ]
2715 with support.start_threads(threads):
2716 pass
2717 # check that only 248 members were created
2718 self.assertFalse(
2719 failed,
2720 'at least one thread failed while creating composite members')
2721 self.assertEqual(256, len(seen), 'too many composite members created')
2722
2723
Ethan Furmanf24bb352013-07-18 17:05:39 -07002724class TestUnique(unittest.TestCase):
2725
2726 def test_unique_clean(self):
2727 @unique
2728 class Clean(Enum):
2729 one = 1
2730 two = 'dos'
2731 tres = 4.0
2732 @unique
2733 class Cleaner(IntEnum):
2734 single = 1
2735 double = 2
2736 triple = 3
2737
2738 def test_unique_dirty(self):
2739 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2740 @unique
2741 class Dirty(Enum):
2742 one = 1
2743 two = 'dos'
2744 tres = 1
2745 with self.assertRaisesRegex(
2746 ValueError,
2747 'double.*single.*turkey.*triple',
2748 ):
2749 @unique
2750 class Dirtier(IntEnum):
2751 single = 1
2752 double = 1
2753 triple = 3
2754 turkey = 3
2755
Ethan Furman3803ad42016-05-01 10:03:53 -07002756 def test_unique_with_name(self):
2757 @unique
2758 class Silly(Enum):
2759 one = 1
2760 two = 'dos'
2761 name = 3
2762 @unique
2763 class Sillier(IntEnum):
2764 single = 1
2765 name = 2
2766 triple = 3
2767 value = 4
2768
Ethan Furmanf24bb352013-07-18 17:05:39 -07002769
Ethan Furman5bdab642018-09-21 19:03:09 -07002770
Ethan Furman3323da92015-04-11 09:39:59 -07002771expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002772Help on class Color in module %s:
2773
2774class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002775 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2776 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002777 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002778 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002779 | Method resolution order:
2780 | Color
2781 | enum.Enum
2782 | builtins.object
2783 |\x20\x20
2784 | Data and other attributes defined here:
2785 |\x20\x20
2786 | blue = <Color.blue: 3>
2787 |\x20\x20
2788 | green = <Color.green: 2>
2789 |\x20\x20
2790 | red = <Color.red: 1>
2791 |\x20\x20
2792 | ----------------------------------------------------------------------
2793 | Data descriptors inherited from enum.Enum:
2794 |\x20\x20
2795 | name
2796 | The name of the Enum member.
2797 |\x20\x20
2798 | value
2799 | The value of the Enum member.
2800 |\x20\x20
2801 | ----------------------------------------------------------------------
2802 | Data descriptors inherited from enum.EnumMeta:
2803 |\x20\x20
2804 | __members__
2805 | Returns a mapping of member name->value.
2806 |\x20\x20\x20\x20\x20\x20
2807 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002808 | is a read-only view of the internal mapping."""
2809
2810expected_help_output_without_docs = """\
2811Help on class Color in module %s:
2812
2813class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002814 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2815 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002816 | Method resolution order:
2817 | Color
2818 | enum.Enum
2819 | builtins.object
2820 |\x20\x20
2821 | Data and other attributes defined here:
2822 |\x20\x20
2823 | blue = <Color.blue: 3>
2824 |\x20\x20
2825 | green = <Color.green: 2>
2826 |\x20\x20
2827 | red = <Color.red: 1>
2828 |\x20\x20
2829 | ----------------------------------------------------------------------
2830 | Data descriptors inherited from enum.Enum:
2831 |\x20\x20
2832 | name
2833 |\x20\x20
2834 | value
2835 |\x20\x20
2836 | ----------------------------------------------------------------------
2837 | Data descriptors inherited from enum.EnumMeta:
2838 |\x20\x20
2839 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002840
2841class TestStdLib(unittest.TestCase):
2842
Ethan Furman48a724f2015-04-11 23:23:06 -07002843 maxDiff = None
2844
Ethan Furman5875d742013-10-21 20:45:55 -07002845 class Color(Enum):
2846 red = 1
2847 green = 2
2848 blue = 3
2849
2850 def test_pydoc(self):
2851 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002852 if StrEnum.__doc__ is None:
2853 expected_text = expected_help_output_without_docs % __name__
2854 else:
2855 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002856 output = StringIO()
2857 helper = pydoc.Helper(output=output)
2858 helper(self.Color)
2859 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002860 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002861
2862 def test_inspect_getmembers(self):
2863 values = dict((
2864 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002865 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002866 ('__members__', self.Color.__members__),
2867 ('__module__', __name__),
2868 ('blue', self.Color.blue),
2869 ('green', self.Color.green),
2870 ('name', Enum.__dict__['name']),
2871 ('red', self.Color.red),
2872 ('value', Enum.__dict__['value']),
2873 ))
2874 result = dict(inspect.getmembers(self.Color))
2875 self.assertEqual(values.keys(), result.keys())
2876 failed = False
2877 for k in values.keys():
2878 if result[k] != values[k]:
2879 print()
2880 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2881 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2882 failed = True
2883 if failed:
2884 self.fail("result does not equal expected, see print above")
2885
2886 def test_inspect_classify_class_attrs(self):
2887 # indirectly test __objclass__
2888 from inspect import Attribute
2889 values = [
2890 Attribute(name='__class__', kind='data',
2891 defining_class=object, object=EnumMeta),
2892 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002893 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002894 Attribute(name='__members__', kind='property',
2895 defining_class=EnumMeta, object=EnumMeta.__members__),
2896 Attribute(name='__module__', kind='data',
2897 defining_class=self.Color, object=__name__),
2898 Attribute(name='blue', kind='data',
2899 defining_class=self.Color, object=self.Color.blue),
2900 Attribute(name='green', kind='data',
2901 defining_class=self.Color, object=self.Color.green),
2902 Attribute(name='red', kind='data',
2903 defining_class=self.Color, object=self.Color.red),
2904 Attribute(name='name', kind='data',
2905 defining_class=Enum, object=Enum.__dict__['name']),
2906 Attribute(name='value', kind='data',
2907 defining_class=Enum, object=Enum.__dict__['value']),
2908 ]
2909 values.sort(key=lambda item: item.name)
2910 result = list(inspect.classify_class_attrs(self.Color))
2911 result.sort(key=lambda item: item.name)
2912 failed = False
2913 for v, r in zip(values, result):
2914 if r != v:
2915 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2916 failed = True
2917 if failed:
2918 self.fail("result does not equal expected, see print above")
2919
Martin Panter19e69c52015-11-14 12:46:42 +00002920
2921class MiscTestCase(unittest.TestCase):
2922 def test__all__(self):
2923 support.check__all__(self, enum)
2924
2925
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002926# These are unordered here on purpose to ensure that declaration order
2927# makes no difference.
2928CONVERT_TEST_NAME_D = 5
2929CONVERT_TEST_NAME_C = 5
2930CONVERT_TEST_NAME_B = 5
2931CONVERT_TEST_NAME_A = 5 # This one should sort first.
2932CONVERT_TEST_NAME_E = 5
2933CONVERT_TEST_NAME_F = 5
2934
2935class TestIntEnumConvert(unittest.TestCase):
2936 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03002937 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08002938 'UnittestConvert',
2939 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002940 filter=lambda x: x.startswith('CONVERT_TEST_'))
2941 # We don't want the reverse lookup value to vary when there are
2942 # multiple possible names for a given value. It should always
2943 # report the first lexigraphical name in that case.
2944 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2945
2946 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03002947 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08002948 'UnittestConvert',
2949 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002950 filter=lambda x: x.startswith('CONVERT_TEST_'))
2951 # Ensure that test_type has all of the desired names and values.
2952 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2953 test_type.CONVERT_TEST_NAME_A)
2954 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2955 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2956 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2957 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2958 # Ensure that test_type only picked up names matching the filter.
2959 self.assertEqual([name for name in dir(test_type)
2960 if name[0:2] not in ('CO', '__')],
2961 [], msg='Names other than CONVERT_TEST_* found.')
2962
orlnub1230fb9fad2018-09-12 20:28:53 +03002963 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
2964 '_convert was deprecated in 3.8')
2965 def test_convert_warn(self):
2966 with self.assertWarns(DeprecationWarning):
2967 enum.IntEnum._convert(
2968 'UnittestConvert',
2969 ('test.test_enum', '__main__')[__name__=='__main__'],
2970 filter=lambda x: x.startswith('CONVERT_TEST_'))
2971
2972 @unittest.skipUnless(sys.version_info >= (3, 9),
2973 '_convert was removed in 3.9')
2974 def test_convert_raise(self):
2975 with self.assertRaises(AttributeError):
2976 enum.IntEnum._convert(
2977 'UnittestConvert',
2978 ('test.test_enum', '__main__')[__name__=='__main__'],
2979 filter=lambda x: x.startswith('CONVERT_TEST_'))
2980
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002981
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002982if __name__ == '__main__':
2983 unittest.main()