blob: b221045328dbd3509906cd2ad24fc337afa2668a [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02005import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07006from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07007from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07008from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -08009from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000010from test import support
Ethan Furmana4b1bb42018-01-22 07:56:37 -080011from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080012
Ethan Furmana4b1bb42018-01-22 07:56:37 -080013try:
14 import threading
15except ImportError:
16 threading = None
Ethan Furman6b3d64a2013-06-14 16:55:46 -070017
18# for pickle tests
19try:
20 class Stooges(Enum):
21 LARRY = 1
22 CURLY = 2
23 MOE = 3
24except Exception as exc:
25 Stooges = exc
26
27try:
28 class IntStooges(int, Enum):
29 LARRY = 1
30 CURLY = 2
31 MOE = 3
32except Exception as exc:
33 IntStooges = exc
34
35try:
36 class FloatStooges(float, Enum):
37 LARRY = 1.39
38 CURLY = 2.72
39 MOE = 3.142596
40except Exception as exc:
41 FloatStooges = exc
42
Ethan Furman65a5a472016-09-01 23:55:19 -070043try:
44 class FlagStooges(Flag):
45 LARRY = 1
46 CURLY = 2
47 MOE = 3
48except Exception as exc:
49 FlagStooges = exc
50
Ethan Furman6b3d64a2013-06-14 16:55:46 -070051# for pickle test and subclass tests
52try:
53 class StrEnum(str, Enum):
54 'accepts only string values'
55 class Name(StrEnum):
56 BDFL = 'Guido van Rossum'
57 FLUFL = 'Barry Warsaw'
58except Exception as exc:
59 Name = exc
60
61try:
62 Question = Enum('Question', 'who what when where why', module=__name__)
63except Exception as exc:
64 Question = exc
65
66try:
67 Answer = Enum('Answer', 'him this then there because')
68except Exception as exc:
69 Answer = exc
70
Ethan Furmanca1b7942014-02-08 11:36:27 -080071try:
72 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
73except Exception as exc:
74 Theory = exc
75
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076# for doctests
77try:
78 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080079 TOMATO = 1
80 BANANA = 2
81 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070082except Exception:
83 pass
84
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080086 if target is None:
87 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030088 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080089 assertion(loads(dumps(source, protocol=protocol)), target)
90
Serhiy Storchakae50e7802015-03-31 16:56:49 +030091def test_pickle_exception(assertion, exception, obj):
92 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080093 with assertion(exception):
94 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070095
96class TestHelpers(unittest.TestCase):
97 # _is_descriptor, _is_sunder, _is_dunder
98
99 def test_is_descriptor(self):
100 class foo:
101 pass
102 for attr in ('__get__','__set__','__delete__'):
103 obj = foo()
104 self.assertFalse(enum._is_descriptor(obj))
105 setattr(obj, attr, 1)
106 self.assertTrue(enum._is_descriptor(obj))
107
108 def test_is_sunder(self):
109 for s in ('_a_', '_aa_'):
110 self.assertTrue(enum._is_sunder(s))
111
112 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
113 '__', '___', '____', '_____',):
114 self.assertFalse(enum._is_sunder(s))
115
116 def test_is_dunder(self):
117 for s in ('__a__', '__aa__'):
118 self.assertTrue(enum._is_dunder(s))
119 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
120 '__', '___', '____', '_____',):
121 self.assertFalse(enum._is_dunder(s))
122
Ethan Furman0c076ca2018-09-21 22:26:32 -0700123# for subclassing tests
124
125class classproperty:
126
127 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
128 self.fget = fget
129 self.fset = fset
130 self.fdel = fdel
131 if doc is None and fget is not None:
132 doc = fget.__doc__
133 self.__doc__ = doc
134
135 def __get__(self, instance, ownerclass):
136 return self.fget(ownerclass)
137
138
Ethan Furmanc16595e2016-09-10 23:36:59 -0700139# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700140
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700141class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800142
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700143 def setUp(self):
144 class Season(Enum):
145 SPRING = 1
146 SUMMER = 2
147 AUTUMN = 3
148 WINTER = 4
149 self.Season = Season
150
Ethan Furmanec15a822013-08-31 19:17:41 -0700151 class Konstants(float, Enum):
152 E = 2.7182818
153 PI = 3.1415926
154 TAU = 2 * PI
155 self.Konstants = Konstants
156
157 class Grades(IntEnum):
158 A = 5
159 B = 4
160 C = 3
161 D = 2
162 F = 0
163 self.Grades = Grades
164
165 class Directional(str, Enum):
166 EAST = 'east'
167 WEST = 'west'
168 NORTH = 'north'
169 SOUTH = 'south'
170 self.Directional = Directional
171
172 from datetime import date
173 class Holiday(date, Enum):
174 NEW_YEAR = 2013, 1, 1
175 IDES_OF_MARCH = 2013, 3, 15
176 self.Holiday = Holiday
177
Ethan Furman388a3922013-08-12 06:51:41 -0700178 def test_dir_on_class(self):
179 Season = self.Season
180 self.assertEqual(
181 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700182 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700183 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
184 )
185
186 def test_dir_on_item(self):
187 Season = self.Season
188 self.assertEqual(
189 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700190 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700191 )
192
Ethan Furmanc850f342013-09-15 16:59:35 -0700193 def test_dir_with_added_behavior(self):
194 class Test(Enum):
195 this = 'that'
196 these = 'those'
197 def wowser(self):
198 return ("Wowser! I'm %s!" % self.name)
199 self.assertEqual(
200 set(dir(Test)),
201 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
202 )
203 self.assertEqual(
204 set(dir(Test.this)),
205 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
206 )
207
Ethan Furman0ae550b2014-10-14 08:58:32 -0700208 def test_dir_on_sub_with_behavior_on_super(self):
209 # see issue22506
210 class SuperEnum(Enum):
211 def invisible(self):
212 return "did you see me?"
213 class SubEnum(SuperEnum):
214 sample = 5
215 self.assertEqual(
216 set(dir(SubEnum.sample)),
217 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
218 )
219
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700220 def test_enum_in_enum_out(self):
221 Season = self.Season
222 self.assertIs(Season(Season.WINTER), Season.WINTER)
223
224 def test_enum_value(self):
225 Season = self.Season
226 self.assertEqual(Season.SPRING.value, 1)
227
228 def test_intenum_value(self):
229 self.assertEqual(IntStooges.CURLY.value, 2)
230
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700231 def test_enum(self):
232 Season = self.Season
233 lst = list(Season)
234 self.assertEqual(len(lst), len(Season))
235 self.assertEqual(len(Season), 4, Season)
236 self.assertEqual(
237 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
238
239 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
240 e = Season(i)
241 self.assertEqual(e, getattr(Season, season))
242 self.assertEqual(e.value, i)
243 self.assertNotEqual(e, i)
244 self.assertEqual(e.name, season)
245 self.assertIn(e, Season)
246 self.assertIs(type(e), Season)
247 self.assertIsInstance(e, Season)
248 self.assertEqual(str(e), 'Season.' + season)
249 self.assertEqual(
250 repr(e),
251 '<Season.{0}: {1}>'.format(season, i),
252 )
253
254 def test_value_name(self):
255 Season = self.Season
256 self.assertEqual(Season.SPRING.name, 'SPRING')
257 self.assertEqual(Season.SPRING.value, 1)
258 with self.assertRaises(AttributeError):
259 Season.SPRING.name = 'invierno'
260 with self.assertRaises(AttributeError):
261 Season.SPRING.value = 2
262
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700263 def test_changing_member(self):
264 Season = self.Season
265 with self.assertRaises(AttributeError):
266 Season.WINTER = 'really cold'
267
Ethan Furman64a99722013-09-22 16:18:19 -0700268 def test_attribute_deletion(self):
269 class Season(Enum):
270 SPRING = 1
271 SUMMER = 2
272 AUTUMN = 3
273 WINTER = 4
274
275 def spam(cls):
276 pass
277
278 self.assertTrue(hasattr(Season, 'spam'))
279 del Season.spam
280 self.assertFalse(hasattr(Season, 'spam'))
281
282 with self.assertRaises(AttributeError):
283 del Season.SPRING
284 with self.assertRaises(AttributeError):
285 del Season.DRY
286 with self.assertRaises(AttributeError):
287 del Season.SPRING.name
288
Ethan Furman5de67b12016-04-13 23:52:09 -0700289 def test_bool_of_class(self):
290 class Empty(Enum):
291 pass
292 self.assertTrue(bool(Empty))
293
294 def test_bool_of_member(self):
295 class Count(Enum):
296 zero = 0
297 one = 1
298 two = 2
299 for member in Count:
300 self.assertTrue(bool(member))
301
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700302 def test_invalid_names(self):
303 with self.assertRaises(ValueError):
304 class Wrong(Enum):
305 mro = 9
306 with self.assertRaises(ValueError):
307 class Wrong(Enum):
308 _create_= 11
309 with self.assertRaises(ValueError):
310 class Wrong(Enum):
311 _get_mixins_ = 9
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 _find_new_ = 1
315 with self.assertRaises(ValueError):
316 class Wrong(Enum):
317 _any_name_ = 9
318
Ethan Furman6db1fd52015-09-17 21:49:12 -0700319 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800320 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700321 class Logic(Enum):
322 true = True
323 false = False
324 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800325 self.assertTrue(Logic.false)
326 # unless overridden
327 class RealLogic(Enum):
328 true = True
329 false = False
330 def __bool__(self):
331 return bool(self._value_)
332 self.assertTrue(RealLogic.true)
333 self.assertFalse(RealLogic.false)
334 # mixed Enums depend on mixed-in type
335 class IntLogic(int, Enum):
336 true = 1
337 false = 0
338 self.assertTrue(IntLogic.true)
339 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700340
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700341 def test_contains(self):
342 Season = self.Season
343 self.assertIn(Season.AUTUMN, Season)
Ethan Furman37151762018-04-11 18:56:25 -0700344 with self.assertWarns(DeprecationWarning):
345 self.assertNotIn(3, Season)
346 with self.assertWarns(DeprecationWarning):
347 self.assertNotIn('AUTUMN', Season)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700348
349 val = Season(3)
350 self.assertIn(val, Season)
351
352 class OtherEnum(Enum):
353 one = 1; two = 2
354 self.assertNotIn(OtherEnum.two, Season)
355
Ethan Furman37151762018-04-11 18:56:25 -0700356 def test_member_contains(self):
357 self.assertRaises(TypeError, lambda: 'test' in self.Season.AUTUMN)
358 self.assertRaises(TypeError, lambda: 3 in self.Season.AUTUMN)
359 self.assertRaises(TypeError, lambda: 'AUTUMN' in self.Season.AUTUMN)
360
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700361 def test_comparisons(self):
362 Season = self.Season
363 with self.assertRaises(TypeError):
364 Season.SPRING < Season.WINTER
365 with self.assertRaises(TypeError):
366 Season.SPRING > 4
367
368 self.assertNotEqual(Season.SPRING, 1)
369
370 class Part(Enum):
371 SPRING = 1
372 CLIP = 2
373 BARREL = 3
374
375 self.assertNotEqual(Season.SPRING, Part.SPRING)
376 with self.assertRaises(TypeError):
377 Season.SPRING < Part.CLIP
378
379 def test_enum_duplicates(self):
380 class Season(Enum):
381 SPRING = 1
382 SUMMER = 2
383 AUTUMN = FALL = 3
384 WINTER = 4
385 ANOTHER_SPRING = 1
386 lst = list(Season)
387 self.assertEqual(
388 lst,
389 [Season.SPRING, Season.SUMMER,
390 Season.AUTUMN, Season.WINTER,
391 ])
392 self.assertIs(Season.FALL, Season.AUTUMN)
393 self.assertEqual(Season.FALL.value, 3)
394 self.assertEqual(Season.AUTUMN.value, 3)
395 self.assertIs(Season(3), Season.AUTUMN)
396 self.assertIs(Season(1), Season.SPRING)
397 self.assertEqual(Season.FALL.name, 'AUTUMN')
398 self.assertEqual(
399 [k for k,v in Season.__members__.items() if v.name != k],
400 ['FALL', 'ANOTHER_SPRING'],
401 )
402
Ethan Furman101e0742013-09-15 12:34:36 -0700403 def test_duplicate_name(self):
404 with self.assertRaises(TypeError):
405 class Color(Enum):
406 red = 1
407 green = 2
408 blue = 3
409 red = 4
410
411 with self.assertRaises(TypeError):
412 class Color(Enum):
413 red = 1
414 green = 2
415 blue = 3
416 def red(self):
417 return 'red'
418
419 with self.assertRaises(TypeError):
420 class Color(Enum):
421 @property
422 def red(self):
423 return 'redder'
424 red = 1
425 green = 2
426 blue = 3
427
428
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700429 def test_enum_with_value_name(self):
430 class Huh(Enum):
431 name = 1
432 value = 2
433 self.assertEqual(
434 list(Huh),
435 [Huh.name, Huh.value],
436 )
437 self.assertIs(type(Huh.name), Huh)
438 self.assertEqual(Huh.name.name, 'name')
439 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700440
441 def test_format_enum(self):
442 Season = self.Season
443 self.assertEqual('{}'.format(Season.SPRING),
444 '{}'.format(str(Season.SPRING)))
445 self.assertEqual( '{:}'.format(Season.SPRING),
446 '{:}'.format(str(Season.SPRING)))
447 self.assertEqual('{:20}'.format(Season.SPRING),
448 '{:20}'.format(str(Season.SPRING)))
449 self.assertEqual('{:^20}'.format(Season.SPRING),
450 '{:^20}'.format(str(Season.SPRING)))
451 self.assertEqual('{:>20}'.format(Season.SPRING),
452 '{:>20}'.format(str(Season.SPRING)))
453 self.assertEqual('{:<20}'.format(Season.SPRING),
454 '{:<20}'.format(str(Season.SPRING)))
455
456 def test_format_enum_custom(self):
457 class TestFloat(float, Enum):
458 one = 1.0
459 two = 2.0
460 def __format__(self, spec):
461 return 'TestFloat success!'
462 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
463
464 def assertFormatIsValue(self, spec, member):
465 self.assertEqual(spec.format(member), spec.format(member.value))
466
467 def test_format_enum_date(self):
468 Holiday = self.Holiday
469 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
470 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
471 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
472 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
473 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
474 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
475 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
476 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
477
478 def test_format_enum_float(self):
479 Konstants = self.Konstants
480 self.assertFormatIsValue('{}', Konstants.TAU)
481 self.assertFormatIsValue('{:}', Konstants.TAU)
482 self.assertFormatIsValue('{:20}', Konstants.TAU)
483 self.assertFormatIsValue('{:^20}', Konstants.TAU)
484 self.assertFormatIsValue('{:>20}', Konstants.TAU)
485 self.assertFormatIsValue('{:<20}', Konstants.TAU)
486 self.assertFormatIsValue('{:n}', Konstants.TAU)
487 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
488 self.assertFormatIsValue('{:f}', Konstants.TAU)
489
490 def test_format_enum_int(self):
491 Grades = self.Grades
492 self.assertFormatIsValue('{}', Grades.C)
493 self.assertFormatIsValue('{:}', Grades.C)
494 self.assertFormatIsValue('{:20}', Grades.C)
495 self.assertFormatIsValue('{:^20}', Grades.C)
496 self.assertFormatIsValue('{:>20}', Grades.C)
497 self.assertFormatIsValue('{:<20}', Grades.C)
498 self.assertFormatIsValue('{:+}', Grades.C)
499 self.assertFormatIsValue('{:08X}', Grades.C)
500 self.assertFormatIsValue('{:b}', Grades.C)
501
502 def test_format_enum_str(self):
503 Directional = self.Directional
504 self.assertFormatIsValue('{}', Directional.WEST)
505 self.assertFormatIsValue('{:}', Directional.WEST)
506 self.assertFormatIsValue('{:20}', Directional.WEST)
507 self.assertFormatIsValue('{:^20}', Directional.WEST)
508 self.assertFormatIsValue('{:>20}', Directional.WEST)
509 self.assertFormatIsValue('{:<20}', Directional.WEST)
510
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700511 def test_hash(self):
512 Season = self.Season
513 dates = {}
514 dates[Season.WINTER] = '1225'
515 dates[Season.SPRING] = '0315'
516 dates[Season.SUMMER] = '0704'
517 dates[Season.AUTUMN] = '1031'
518 self.assertEqual(dates[Season.AUTUMN], '1031')
519
520 def test_intenum_from_scratch(self):
521 class phy(int, Enum):
522 pi = 3
523 tau = 2 * pi
524 self.assertTrue(phy.pi < phy.tau)
525
526 def test_intenum_inherited(self):
527 class IntEnum(int, Enum):
528 pass
529 class phy(IntEnum):
530 pi = 3
531 tau = 2 * pi
532 self.assertTrue(phy.pi < phy.tau)
533
534 def test_floatenum_from_scratch(self):
535 class phy(float, Enum):
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_floatenum_inherited(self):
541 class FloatEnum(float, Enum):
542 pass
543 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700544 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700545 tau = 2 * pi
546 self.assertTrue(phy.pi < phy.tau)
547
548 def test_strenum_from_scratch(self):
549 class phy(str, Enum):
550 pi = 'Pi'
551 tau = 'Tau'
552 self.assertTrue(phy.pi < phy.tau)
553
554 def test_strenum_inherited(self):
555 class StrEnum(str, Enum):
556 pass
557 class phy(StrEnum):
558 pi = 'Pi'
559 tau = 'Tau'
560 self.assertTrue(phy.pi < phy.tau)
561
562
563 def test_intenum(self):
564 class WeekDay(IntEnum):
565 SUNDAY = 1
566 MONDAY = 2
567 TUESDAY = 3
568 WEDNESDAY = 4
569 THURSDAY = 5
570 FRIDAY = 6
571 SATURDAY = 7
572
573 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
574 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
575
576 lst = list(WeekDay)
577 self.assertEqual(len(lst), len(WeekDay))
578 self.assertEqual(len(WeekDay), 7)
579 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
580 target = target.split()
581 for i, weekday in enumerate(target, 1):
582 e = WeekDay(i)
583 self.assertEqual(e, i)
584 self.assertEqual(int(e), i)
585 self.assertEqual(e.name, weekday)
586 self.assertIn(e, WeekDay)
587 self.assertEqual(lst.index(e)+1, i)
588 self.assertTrue(0 < e < 8)
589 self.assertIs(type(e), WeekDay)
590 self.assertIsInstance(e, int)
591 self.assertIsInstance(e, Enum)
592
593 def test_intenum_duplicates(self):
594 class WeekDay(IntEnum):
595 SUNDAY = 1
596 MONDAY = 2
597 TUESDAY = TEUSDAY = 3
598 WEDNESDAY = 4
599 THURSDAY = 5
600 FRIDAY = 6
601 SATURDAY = 7
602 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
603 self.assertEqual(WeekDay(3).name, 'TUESDAY')
604 self.assertEqual([k for k,v in WeekDay.__members__.items()
605 if v.name != k], ['TEUSDAY', ])
606
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300607 def test_intenum_from_bytes(self):
608 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
609 with self.assertRaises(ValueError):
610 IntStooges.from_bytes(b'\x00\x05', 'big')
611
612 def test_floatenum_fromhex(self):
613 h = float.hex(FloatStooges.MOE.value)
614 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
615 h = float.hex(FloatStooges.MOE.value + 0.01)
616 with self.assertRaises(ValueError):
617 FloatStooges.fromhex(h)
618
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700619 def test_pickle_enum(self):
620 if isinstance(Stooges, Exception):
621 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800622 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
623 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700624
625 def test_pickle_int(self):
626 if isinstance(IntStooges, Exception):
627 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800628 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
629 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700630
631 def test_pickle_float(self):
632 if isinstance(FloatStooges, Exception):
633 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800634 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
635 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700636
637 def test_pickle_enum_function(self):
638 if isinstance(Answer, Exception):
639 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800640 test_pickle_dump_load(self.assertIs, Answer.him)
641 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700642
643 def test_pickle_enum_function_with_module(self):
644 if isinstance(Question, Exception):
645 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800646 test_pickle_dump_load(self.assertIs, Question.who)
647 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700648
Ethan Furmanca1b7942014-02-08 11:36:27 -0800649 def test_enum_function_with_qualname(self):
650 if isinstance(Theory, Exception):
651 raise Theory
652 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
653
654 def test_class_nested_enum_and_pickle_protocol_four(self):
655 # would normally just have this directly in the class namespace
656 class NestedEnum(Enum):
657 twigs = 'common'
658 shiny = 'rare'
659
660 self.__class__.NestedEnum = NestedEnum
661 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300662 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800663
Ethan Furman24e837f2015-03-18 17:27:57 -0700664 def test_pickle_by_name(self):
665 class ReplaceGlobalInt(IntEnum):
666 ONE = 1
667 TWO = 2
668 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
669 for proto in range(HIGHEST_PROTOCOL):
670 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
671
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700672 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800673 BadPickle = Enum(
674 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700675 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800676 # now break BadPickle to test exception raising
677 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800678 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
679 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700680
681 def test_string_enum(self):
682 class SkillLevel(str, Enum):
683 master = 'what is the sound of one hand clapping?'
684 journeyman = 'why did the chicken cross the road?'
685 apprentice = 'knock, knock!'
686 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
687
688 def test_getattr_getitem(self):
689 class Period(Enum):
690 morning = 1
691 noon = 2
692 evening = 3
693 night = 4
694 self.assertIs(Period(2), Period.noon)
695 self.assertIs(getattr(Period, 'night'), Period.night)
696 self.assertIs(Period['morning'], Period.morning)
697
698 def test_getattr_dunder(self):
699 Season = self.Season
700 self.assertTrue(getattr(Season, '__eq__'))
701
702 def test_iteration_order(self):
703 class Season(Enum):
704 SUMMER = 2
705 WINTER = 4
706 AUTUMN = 3
707 SPRING = 1
708 self.assertEqual(
709 list(Season),
710 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
711 )
712
Ethan Furman2131a4a2013-09-14 18:11:24 -0700713 def test_reversed_iteration_order(self):
714 self.assertEqual(
715 list(reversed(self.Season)),
716 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
717 self.Season.SPRING]
718 )
719
Martin Pantereb995702016-07-28 01:11:04 +0000720 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700721 SummerMonth = Enum('SummerMonth', 'june july august')
722 lst = list(SummerMonth)
723 self.assertEqual(len(lst), len(SummerMonth))
724 self.assertEqual(len(SummerMonth), 3, SummerMonth)
725 self.assertEqual(
726 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
727 lst,
728 )
729 for i, month in enumerate('june july august'.split(), 1):
730 e = SummerMonth(i)
731 self.assertEqual(int(e.value), i)
732 self.assertNotEqual(e, i)
733 self.assertEqual(e.name, month)
734 self.assertIn(e, SummerMonth)
735 self.assertIs(type(e), SummerMonth)
736
Martin Pantereb995702016-07-28 01:11:04 +0000737 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700738 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
739 lst = list(SummerMonth)
740 self.assertEqual(len(lst), len(SummerMonth))
741 self.assertEqual(len(SummerMonth), 3, SummerMonth)
742 self.assertEqual(
743 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
744 lst,
745 )
746 for i, month in enumerate('june july august'.split(), 10):
747 e = SummerMonth(i)
748 self.assertEqual(int(e.value), i)
749 self.assertNotEqual(e, i)
750 self.assertEqual(e.name, month)
751 self.assertIn(e, SummerMonth)
752 self.assertIs(type(e), SummerMonth)
753
Martin Pantereb995702016-07-28 01:11:04 +0000754 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700755 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
756 lst = list(SummerMonth)
757 self.assertEqual(len(lst), len(SummerMonth))
758 self.assertEqual(len(SummerMonth), 3, SummerMonth)
759 self.assertEqual(
760 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
761 lst,
762 )
763 for i, month in enumerate('june july august'.split(), 1):
764 e = SummerMonth(i)
765 self.assertEqual(int(e.value), i)
766 self.assertNotEqual(e, i)
767 self.assertEqual(e.name, month)
768 self.assertIn(e, SummerMonth)
769 self.assertIs(type(e), SummerMonth)
770
Martin Pantereb995702016-07-28 01:11:04 +0000771 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700772 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
773 lst = list(SummerMonth)
774 self.assertEqual(len(lst), len(SummerMonth))
775 self.assertEqual(len(SummerMonth), 3, SummerMonth)
776 self.assertEqual(
777 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
778 lst,
779 )
780 for i, month in enumerate('june july august'.split(), 20):
781 e = SummerMonth(i)
782 self.assertEqual(int(e.value), i)
783 self.assertNotEqual(e, i)
784 self.assertEqual(e.name, month)
785 self.assertIn(e, SummerMonth)
786 self.assertIs(type(e), SummerMonth)
787
Martin Pantereb995702016-07-28 01:11:04 +0000788 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700789 SummerMonth = Enum(
790 'SummerMonth',
791 (('june', 1), ('july', 2), ('august', 3))
792 )
793 lst = list(SummerMonth)
794 self.assertEqual(len(lst), len(SummerMonth))
795 self.assertEqual(len(SummerMonth), 3, SummerMonth)
796 self.assertEqual(
797 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
798 lst,
799 )
800 for i, month in enumerate('june july august'.split(), 1):
801 e = SummerMonth(i)
802 self.assertEqual(int(e.value), i)
803 self.assertNotEqual(e, i)
804 self.assertEqual(e.name, month)
805 self.assertIn(e, SummerMonth)
806 self.assertIs(type(e), SummerMonth)
807
Martin Pantereb995702016-07-28 01:11:04 +0000808 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700809 SummerMonth = Enum(
810 'SummerMonth',
811 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
812 )
813 lst = list(SummerMonth)
814 self.assertEqual(len(lst), len(SummerMonth))
815 self.assertEqual(len(SummerMonth), 3, SummerMonth)
816 self.assertEqual(
817 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
818 lst,
819 )
820 for i, month in enumerate('june july august'.split(), 1):
821 e = SummerMonth(i)
822 self.assertEqual(int(e.value), i)
823 self.assertNotEqual(e, i)
824 self.assertEqual(e.name, month)
825 self.assertIn(e, SummerMonth)
826 self.assertIs(type(e), SummerMonth)
827
Martin Pantereb995702016-07-28 01:11:04 +0000828 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700829 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
830 lst = list(SummerMonth)
831 self.assertEqual(len(lst), len(SummerMonth))
832 self.assertEqual(len(SummerMonth), 3, SummerMonth)
833 self.assertEqual(
834 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
835 lst,
836 )
837 for i, month in enumerate('june july august'.split(), 1):
838 e = SummerMonth(i)
839 self.assertEqual(e, i)
840 self.assertEqual(e.name, month)
841 self.assertIn(e, SummerMonth)
842 self.assertIs(type(e), SummerMonth)
843
Martin Pantereb995702016-07-28 01:11:04 +0000844 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700845 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
846 lst = list(SummerMonth)
847 self.assertEqual(len(lst), len(SummerMonth))
848 self.assertEqual(len(SummerMonth), 3, SummerMonth)
849 self.assertEqual(
850 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
851 lst,
852 )
853 for i, month in enumerate('june july august'.split(), 30):
854 e = SummerMonth(i)
855 self.assertEqual(e, i)
856 self.assertEqual(e.name, month)
857 self.assertIn(e, SummerMonth)
858 self.assertIs(type(e), SummerMonth)
859
Martin Pantereb995702016-07-28 01:11:04 +0000860 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700861 SummerMonth = IntEnum('SummerMonth', 'june july august')
862 lst = list(SummerMonth)
863 self.assertEqual(len(lst), len(SummerMonth))
864 self.assertEqual(len(SummerMonth), 3, SummerMonth)
865 self.assertEqual(
866 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
867 lst,
868 )
869 for i, month in enumerate('june july august'.split(), 1):
870 e = SummerMonth(i)
871 self.assertEqual(e, i)
872 self.assertEqual(e.name, month)
873 self.assertIn(e, SummerMonth)
874 self.assertIs(type(e), SummerMonth)
875
Martin Pantereb995702016-07-28 01:11:04 +0000876 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700877 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
878 lst = list(SummerMonth)
879 self.assertEqual(len(lst), len(SummerMonth))
880 self.assertEqual(len(SummerMonth), 3, SummerMonth)
881 self.assertEqual(
882 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
883 lst,
884 )
885 for i, month in enumerate('june july august'.split(), 40):
886 e = SummerMonth(i)
887 self.assertEqual(e, i)
888 self.assertEqual(e.name, month)
889 self.assertIn(e, SummerMonth)
890 self.assertIs(type(e), SummerMonth)
891
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700892 def test_subclassing(self):
893 if isinstance(Name, Exception):
894 raise Name
895 self.assertEqual(Name.BDFL, 'Guido van Rossum')
896 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
897 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800898 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700899
900 def test_extending(self):
901 class Color(Enum):
902 red = 1
903 green = 2
904 blue = 3
905 with self.assertRaises(TypeError):
906 class MoreColor(Color):
907 cyan = 4
908 magenta = 5
909 yellow = 6
910
911 def test_exclude_methods(self):
912 class whatever(Enum):
913 this = 'that'
914 these = 'those'
915 def really(self):
916 return 'no, not %s' % self.value
917 self.assertIsNot(type(whatever.really), whatever)
918 self.assertEqual(whatever.this.really(), 'no, not that')
919
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700920 def test_wrong_inheritance_order(self):
921 with self.assertRaises(TypeError):
922 class Wrong(Enum, str):
923 NotHere = 'error before this point'
924
925 def test_intenum_transitivity(self):
926 class number(IntEnum):
927 one = 1
928 two = 2
929 three = 3
930 class numero(IntEnum):
931 uno = 1
932 dos = 2
933 tres = 3
934 self.assertEqual(number.one, numero.uno)
935 self.assertEqual(number.two, numero.dos)
936 self.assertEqual(number.three, numero.tres)
937
938 def test_wrong_enum_in_call(self):
939 class Monochrome(Enum):
940 black = 0
941 white = 1
942 class Gender(Enum):
943 male = 0
944 female = 1
945 self.assertRaises(ValueError, Monochrome, Gender.male)
946
947 def test_wrong_enum_in_mixed_call(self):
948 class Monochrome(IntEnum):
949 black = 0
950 white = 1
951 class Gender(Enum):
952 male = 0
953 female = 1
954 self.assertRaises(ValueError, Monochrome, Gender.male)
955
956 def test_mixed_enum_in_call_1(self):
957 class Monochrome(IntEnum):
958 black = 0
959 white = 1
960 class Gender(IntEnum):
961 male = 0
962 female = 1
963 self.assertIs(Monochrome(Gender.female), Monochrome.white)
964
965 def test_mixed_enum_in_call_2(self):
966 class Monochrome(Enum):
967 black = 0
968 white = 1
969 class Gender(IntEnum):
970 male = 0
971 female = 1
972 self.assertIs(Monochrome(Gender.male), Monochrome.black)
973
974 def test_flufl_enum(self):
975 class Fluflnum(Enum):
976 def __int__(self):
977 return int(self.value)
978 class MailManOptions(Fluflnum):
979 option1 = 1
980 option2 = 2
981 option3 = 3
982 self.assertEqual(int(MailManOptions.option1), 1)
983
Ethan Furman5e5a8232013-08-04 08:42:23 -0700984 def test_introspection(self):
985 class Number(IntEnum):
986 one = 100
987 two = 200
988 self.assertIs(Number.one._member_type_, int)
989 self.assertIs(Number._member_type_, int)
990 class String(str, Enum):
991 yarn = 'soft'
992 rope = 'rough'
993 wire = 'hard'
994 self.assertIs(String.yarn._member_type_, str)
995 self.assertIs(String._member_type_, str)
996 class Plain(Enum):
997 vanilla = 'white'
998 one = 1
999 self.assertIs(Plain.vanilla._member_type_, object)
1000 self.assertIs(Plain._member_type_, object)
1001
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001002 def test_no_such_enum_member(self):
1003 class Color(Enum):
1004 red = 1
1005 green = 2
1006 blue = 3
1007 with self.assertRaises(ValueError):
1008 Color(4)
1009 with self.assertRaises(KeyError):
1010 Color['chartreuse']
1011
1012 def test_new_repr(self):
1013 class Color(Enum):
1014 red = 1
1015 green = 2
1016 blue = 3
1017 def __repr__(self):
1018 return "don't you just love shades of %s?" % self.name
1019 self.assertEqual(
1020 repr(Color.blue),
1021 "don't you just love shades of blue?",
1022 )
1023
1024 def test_inherited_repr(self):
1025 class MyEnum(Enum):
1026 def __repr__(self):
1027 return "My name is %s." % self.name
1028 class MyIntEnum(int, MyEnum):
1029 this = 1
1030 that = 2
1031 theother = 3
1032 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1033
1034 def test_multiple_mixin_mro(self):
1035 class auto_enum(type(Enum)):
1036 def __new__(metacls, cls, bases, classdict):
1037 temp = type(classdict)()
1038 names = set(classdict._member_names)
1039 i = 0
1040 for k in classdict._member_names:
1041 v = classdict[k]
1042 if v is Ellipsis:
1043 v = i
1044 else:
1045 i = v
1046 i += 1
1047 temp[k] = v
1048 for k, v in classdict.items():
1049 if k not in names:
1050 temp[k] = v
1051 return super(auto_enum, metacls).__new__(
1052 metacls, cls, bases, temp)
1053
1054 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1055 pass
1056
1057 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1058 pass
1059
1060 class TestAutoNumber(AutoNumberedEnum):
1061 a = ...
1062 b = 3
1063 c = ...
1064
1065 class TestAutoInt(AutoIntEnum):
1066 a = ...
1067 b = 3
1068 c = ...
1069
1070 def test_subclasses_with_getnewargs(self):
1071 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001072 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001073 def __new__(cls, *args):
1074 _args = args
1075 name, *args = args
1076 if len(args) == 0:
1077 raise TypeError("name and value must be specified")
1078 self = int.__new__(cls, *args)
1079 self._intname = name
1080 self._args = _args
1081 return self
1082 def __getnewargs__(self):
1083 return self._args
1084 @property
1085 def __name__(self):
1086 return self._intname
1087 def __repr__(self):
1088 # repr() is updated to include the name and type info
1089 return "{}({!r}, {})".format(type(self).__name__,
1090 self.__name__,
1091 int.__repr__(self))
1092 def __str__(self):
1093 # str() is unchanged, even if it relies on the repr() fallback
1094 base = int
1095 base_str = base.__str__
1096 if base_str.__objclass__ is object:
1097 return base.__repr__(self)
1098 return base_str(self)
1099 # for simplicity, we only define one operator that
1100 # propagates expressions
1101 def __add__(self, other):
1102 temp = int(self) + int( other)
1103 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1104 return NamedInt(
1105 '({0} + {1})'.format(self.__name__, other.__name__),
1106 temp )
1107 else:
1108 return temp
1109
1110 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001111 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001112 x = ('the-x', 1)
1113 y = ('the-y', 2)
1114
Ethan Furman2aa27322013-07-19 19:35:56 -07001115
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001116 self.assertIs(NEI.__new__, Enum.__new__)
1117 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1118 globals()['NamedInt'] = NamedInt
1119 globals()['NEI'] = NEI
1120 NI5 = NamedInt('test', 5)
1121 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001122 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001123 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001124 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001125 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001126
Ethan Furmanca1b7942014-02-08 11:36:27 -08001127 def test_subclasses_with_getnewargs_ex(self):
1128 class NamedInt(int):
1129 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1130 def __new__(cls, *args):
1131 _args = args
1132 name, *args = args
1133 if len(args) == 0:
1134 raise TypeError("name and value must be specified")
1135 self = int.__new__(cls, *args)
1136 self._intname = name
1137 self._args = _args
1138 return self
1139 def __getnewargs_ex__(self):
1140 return self._args, {}
1141 @property
1142 def __name__(self):
1143 return self._intname
1144 def __repr__(self):
1145 # repr() is updated to include the name and type info
1146 return "{}({!r}, {})".format(type(self).__name__,
1147 self.__name__,
1148 int.__repr__(self))
1149 def __str__(self):
1150 # str() is unchanged, even if it relies on the repr() fallback
1151 base = int
1152 base_str = base.__str__
1153 if base_str.__objclass__ is object:
1154 return base.__repr__(self)
1155 return base_str(self)
1156 # for simplicity, we only define one operator that
1157 # propagates expressions
1158 def __add__(self, other):
1159 temp = int(self) + int( other)
1160 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1161 return NamedInt(
1162 '({0} + {1})'.format(self.__name__, other.__name__),
1163 temp )
1164 else:
1165 return temp
1166
1167 class NEI(NamedInt, Enum):
1168 __qualname__ = 'NEI' # needed for pickle protocol 4
1169 x = ('the-x', 1)
1170 y = ('the-y', 2)
1171
1172
1173 self.assertIs(NEI.__new__, Enum.__new__)
1174 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1175 globals()['NamedInt'] = NamedInt
1176 globals()['NEI'] = NEI
1177 NI5 = NamedInt('test', 5)
1178 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001179 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001180 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001181 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001182 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001183
1184 def test_subclasses_with_reduce(self):
1185 class NamedInt(int):
1186 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1187 def __new__(cls, *args):
1188 _args = args
1189 name, *args = args
1190 if len(args) == 0:
1191 raise TypeError("name and value must be specified")
1192 self = int.__new__(cls, *args)
1193 self._intname = name
1194 self._args = _args
1195 return self
1196 def __reduce__(self):
1197 return self.__class__, self._args
1198 @property
1199 def __name__(self):
1200 return self._intname
1201 def __repr__(self):
1202 # repr() is updated to include the name and type info
1203 return "{}({!r}, {})".format(type(self).__name__,
1204 self.__name__,
1205 int.__repr__(self))
1206 def __str__(self):
1207 # str() is unchanged, even if it relies on the repr() fallback
1208 base = int
1209 base_str = base.__str__
1210 if base_str.__objclass__ is object:
1211 return base.__repr__(self)
1212 return base_str(self)
1213 # for simplicity, we only define one operator that
1214 # propagates expressions
1215 def __add__(self, other):
1216 temp = int(self) + int( other)
1217 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1218 return NamedInt(
1219 '({0} + {1})'.format(self.__name__, other.__name__),
1220 temp )
1221 else:
1222 return temp
1223
1224 class NEI(NamedInt, Enum):
1225 __qualname__ = 'NEI' # needed for pickle protocol 4
1226 x = ('the-x', 1)
1227 y = ('the-y', 2)
1228
1229
1230 self.assertIs(NEI.__new__, Enum.__new__)
1231 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1232 globals()['NamedInt'] = NamedInt
1233 globals()['NEI'] = NEI
1234 NI5 = NamedInt('test', 5)
1235 self.assertEqual(NI5, 5)
1236 test_pickle_dump_load(self.assertEqual, NI5, 5)
1237 self.assertEqual(NEI.y.value, 2)
1238 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001239 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001240
1241 def test_subclasses_with_reduce_ex(self):
1242 class NamedInt(int):
1243 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1244 def __new__(cls, *args):
1245 _args = args
1246 name, *args = args
1247 if len(args) == 0:
1248 raise TypeError("name and value must be specified")
1249 self = int.__new__(cls, *args)
1250 self._intname = name
1251 self._args = _args
1252 return self
1253 def __reduce_ex__(self, proto):
1254 return self.__class__, self._args
1255 @property
1256 def __name__(self):
1257 return self._intname
1258 def __repr__(self):
1259 # repr() is updated to include the name and type info
1260 return "{}({!r}, {})".format(type(self).__name__,
1261 self.__name__,
1262 int.__repr__(self))
1263 def __str__(self):
1264 # str() is unchanged, even if it relies on the repr() fallback
1265 base = int
1266 base_str = base.__str__
1267 if base_str.__objclass__ is object:
1268 return base.__repr__(self)
1269 return base_str(self)
1270 # for simplicity, we only define one operator that
1271 # propagates expressions
1272 def __add__(self, other):
1273 temp = int(self) + int( other)
1274 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1275 return NamedInt(
1276 '({0} + {1})'.format(self.__name__, other.__name__),
1277 temp )
1278 else:
1279 return temp
1280
1281 class NEI(NamedInt, Enum):
1282 __qualname__ = 'NEI' # needed for pickle protocol 4
1283 x = ('the-x', 1)
1284 y = ('the-y', 2)
1285
1286
1287 self.assertIs(NEI.__new__, Enum.__new__)
1288 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1289 globals()['NamedInt'] = NamedInt
1290 globals()['NEI'] = NEI
1291 NI5 = NamedInt('test', 5)
1292 self.assertEqual(NI5, 5)
1293 test_pickle_dump_load(self.assertEqual, NI5, 5)
1294 self.assertEqual(NEI.y.value, 2)
1295 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001296 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001297
Ethan Furmandc870522014-02-18 12:37:12 -08001298 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001299 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001300 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001301 def __new__(cls, *args):
1302 _args = args
1303 name, *args = args
1304 if len(args) == 0:
1305 raise TypeError("name and value must be specified")
1306 self = int.__new__(cls, *args)
1307 self._intname = name
1308 self._args = _args
1309 return self
1310 @property
1311 def __name__(self):
1312 return self._intname
1313 def __repr__(self):
1314 # repr() is updated to include the name and type info
1315 return "{}({!r}, {})".format(type(self).__name__,
1316 self.__name__,
1317 int.__repr__(self))
1318 def __str__(self):
1319 # str() is unchanged, even if it relies on the repr() fallback
1320 base = int
1321 base_str = base.__str__
1322 if base_str.__objclass__ is object:
1323 return base.__repr__(self)
1324 return base_str(self)
1325 # for simplicity, we only define one operator that
1326 # propagates expressions
1327 def __add__(self, other):
1328 temp = int(self) + int( other)
1329 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1330 return NamedInt(
1331 '({0} + {1})'.format(self.__name__, other.__name__),
1332 temp )
1333 else:
1334 return temp
1335
1336 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001337 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001338 x = ('the-x', 1)
1339 y = ('the-y', 2)
1340
1341 self.assertIs(NEI.__new__, Enum.__new__)
1342 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1343 globals()['NamedInt'] = NamedInt
1344 globals()['NEI'] = NEI
1345 NI5 = NamedInt('test', 5)
1346 self.assertEqual(NI5, 5)
1347 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001348 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1349 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001350
Ethan Furmandc870522014-02-18 12:37:12 -08001351 def test_subclasses_without_direct_pickle_support_using_name(self):
1352 class NamedInt(int):
1353 __qualname__ = 'NamedInt'
1354 def __new__(cls, *args):
1355 _args = args
1356 name, *args = args
1357 if len(args) == 0:
1358 raise TypeError("name and value must be specified")
1359 self = int.__new__(cls, *args)
1360 self._intname = name
1361 self._args = _args
1362 return self
1363 @property
1364 def __name__(self):
1365 return self._intname
1366 def __repr__(self):
1367 # repr() is updated to include the name and type info
1368 return "{}({!r}, {})".format(type(self).__name__,
1369 self.__name__,
1370 int.__repr__(self))
1371 def __str__(self):
1372 # str() is unchanged, even if it relies on the repr() fallback
1373 base = int
1374 base_str = base.__str__
1375 if base_str.__objclass__ is object:
1376 return base.__repr__(self)
1377 return base_str(self)
1378 # for simplicity, we only define one operator that
1379 # propagates expressions
1380 def __add__(self, other):
1381 temp = int(self) + int( other)
1382 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1383 return NamedInt(
1384 '({0} + {1})'.format(self.__name__, other.__name__),
1385 temp )
1386 else:
1387 return temp
1388
1389 class NEI(NamedInt, Enum):
1390 __qualname__ = 'NEI'
1391 x = ('the-x', 1)
1392 y = ('the-y', 2)
1393 def __reduce_ex__(self, proto):
1394 return getattr, (self.__class__, self._name_)
1395
1396 self.assertIs(NEI.__new__, Enum.__new__)
1397 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1398 globals()['NamedInt'] = NamedInt
1399 globals()['NEI'] = NEI
1400 NI5 = NamedInt('test', 5)
1401 self.assertEqual(NI5, 5)
1402 self.assertEqual(NEI.y.value, 2)
1403 test_pickle_dump_load(self.assertIs, NEI.y)
1404 test_pickle_dump_load(self.assertIs, NEI)
1405
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001406 def test_tuple_subclass(self):
1407 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001408 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001409 first = (1, 'for the money')
1410 second = (2, 'for the show')
1411 third = (3, 'for the music')
1412 self.assertIs(type(SomeTuple.first), SomeTuple)
1413 self.assertIsInstance(SomeTuple.second, tuple)
1414 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1415 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001416 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001417
1418 def test_duplicate_values_give_unique_enum_items(self):
1419 class AutoNumber(Enum):
1420 first = ()
1421 second = ()
1422 third = ()
1423 def __new__(cls):
1424 value = len(cls.__members__) + 1
1425 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001426 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001427 return obj
1428 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001429 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001430 self.assertEqual(
1431 list(AutoNumber),
1432 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1433 )
1434 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001435 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 self.assertIs(AutoNumber(1), AutoNumber.first)
1437
1438 def test_inherited_new_from_enhanced_enum(self):
1439 class AutoNumber(Enum):
1440 def __new__(cls):
1441 value = len(cls.__members__) + 1
1442 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001443 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001444 return obj
1445 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001446 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001447 class Color(AutoNumber):
1448 red = ()
1449 green = ()
1450 blue = ()
1451 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1452 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1453
1454 def test_inherited_new_from_mixed_enum(self):
1455 class AutoNumber(IntEnum):
1456 def __new__(cls):
1457 value = len(cls.__members__) + 1
1458 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001459 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001460 return obj
1461 class Color(AutoNumber):
1462 red = ()
1463 green = ()
1464 blue = ()
1465 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1466 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1467
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001468 def test_equality(self):
1469 class AlwaysEqual:
1470 def __eq__(self, other):
1471 return True
1472 class OrdinaryEnum(Enum):
1473 a = 1
1474 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1475 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1476
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477 def test_ordered_mixin(self):
1478 class OrderedEnum(Enum):
1479 def __ge__(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 __gt__(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 def __le__(self, other):
1488 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001489 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001490 return NotImplemented
1491 def __lt__(self, other):
1492 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001493 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001494 return NotImplemented
1495 class Grade(OrderedEnum):
1496 A = 5
1497 B = 4
1498 C = 3
1499 D = 2
1500 F = 1
1501 self.assertGreater(Grade.A, Grade.B)
1502 self.assertLessEqual(Grade.F, Grade.C)
1503 self.assertLess(Grade.D, Grade.A)
1504 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001505 self.assertEqual(Grade.B, Grade.B)
1506 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001507
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001508 def test_extending2(self):
1509 class Shade(Enum):
1510 def shade(self):
1511 print(self.name)
1512 class Color(Shade):
1513 red = 1
1514 green = 2
1515 blue = 3
1516 with self.assertRaises(TypeError):
1517 class MoreColor(Color):
1518 cyan = 4
1519 magenta = 5
1520 yellow = 6
1521
1522 def test_extending3(self):
1523 class Shade(Enum):
1524 def shade(self):
1525 return self.name
1526 class Color(Shade):
1527 def hex(self):
1528 return '%s hexlified!' % self.value
1529 class MoreColor(Color):
1530 cyan = 4
1531 magenta = 5
1532 yellow = 6
1533 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1534
orlnub123c0d63bf2018-09-10 19:39:48 +03001535 def test_subclass_duplicate_name(self):
1536 class Base(Enum):
1537 def test(self):
1538 pass
1539 class Test(Base):
1540 test = 1
1541 self.assertIs(type(Test.test), Test)
1542
1543 def test_subclass_duplicate_name_dynamic(self):
1544 from types import DynamicClassAttribute
1545 class Base(Enum):
1546 @DynamicClassAttribute
1547 def test(self):
1548 return 'dynamic'
1549 class Test(Base):
1550 test = 1
1551 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001552
1553 def test_no_duplicates(self):
1554 class UniqueEnum(Enum):
1555 def __init__(self, *args):
1556 cls = self.__class__
1557 if any(self.value == e.value for e in cls):
1558 a = self.name
1559 e = cls(self.value).name
1560 raise ValueError(
1561 "aliases not allowed in UniqueEnum: %r --> %r"
1562 % (a, e)
1563 )
1564 class Color(UniqueEnum):
1565 red = 1
1566 green = 2
1567 blue = 3
1568 with self.assertRaises(ValueError):
1569 class Color(UniqueEnum):
1570 red = 1
1571 green = 2
1572 blue = 3
1573 grene = 2
1574
1575 def test_init(self):
1576 class Planet(Enum):
1577 MERCURY = (3.303e+23, 2.4397e6)
1578 VENUS = (4.869e+24, 6.0518e6)
1579 EARTH = (5.976e+24, 6.37814e6)
1580 MARS = (6.421e+23, 3.3972e6)
1581 JUPITER = (1.9e+27, 7.1492e7)
1582 SATURN = (5.688e+26, 6.0268e7)
1583 URANUS = (8.686e+25, 2.5559e7)
1584 NEPTUNE = (1.024e+26, 2.4746e7)
1585 def __init__(self, mass, radius):
1586 self.mass = mass # in kilograms
1587 self.radius = radius # in meters
1588 @property
1589 def surface_gravity(self):
1590 # universal gravitational constant (m3 kg-1 s-2)
1591 G = 6.67300E-11
1592 return G * self.mass / (self.radius * self.radius)
1593 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1594 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1595
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001596 def test_ignore(self):
1597 class Period(timedelta, Enum):
1598 '''
1599 different lengths of time
1600 '''
1601 def __new__(cls, value, period):
1602 obj = timedelta.__new__(cls, value)
1603 obj._value_ = value
1604 obj.period = period
1605 return obj
1606 _ignore_ = 'Period i'
1607 Period = vars()
1608 for i in range(13):
1609 Period['month_%d' % i] = i*30, 'month'
1610 for i in range(53):
1611 Period['week_%d' % i] = i*7, 'week'
1612 for i in range(32):
1613 Period['day_%d' % i] = i, 'day'
1614 OneDay = day_1
1615 OneWeek = week_1
1616 OneMonth = month_1
1617 self.assertFalse(hasattr(Period, '_ignore_'))
1618 self.assertFalse(hasattr(Period, 'Period'))
1619 self.assertFalse(hasattr(Period, 'i'))
1620 self.assertTrue(isinstance(Period.day_1, timedelta))
1621 self.assertTrue(Period.month_1 is Period.day_30)
1622 self.assertTrue(Period.week_4 is Period.day_28)
1623
Ethan Furman2aa27322013-07-19 19:35:56 -07001624 def test_nonhash_value(self):
1625 class AutoNumberInAList(Enum):
1626 def __new__(cls):
1627 value = [len(cls.__members__) + 1]
1628 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001629 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001630 return obj
1631 class ColorInAList(AutoNumberInAList):
1632 red = ()
1633 green = ()
1634 blue = ()
1635 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001636 for enum, value in zip(ColorInAList, range(3)):
1637 value += 1
1638 self.assertEqual(enum.value, [value])
1639 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001640
Ethan Furmanb41803e2013-07-25 13:50:45 -07001641 def test_conflicting_types_resolved_in_new(self):
1642 class LabelledIntEnum(int, Enum):
1643 def __new__(cls, *args):
1644 value, label = args
1645 obj = int.__new__(cls, value)
1646 obj.label = label
1647 obj._value_ = value
1648 return obj
1649
1650 class LabelledList(LabelledIntEnum):
1651 unprocessed = (1, "Unprocessed")
1652 payment_complete = (2, "Payment Complete")
1653
1654 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1655 self.assertEqual(LabelledList.unprocessed, 1)
1656 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001657
Ethan Furmanc16595e2016-09-10 23:36:59 -07001658 def test_auto_number(self):
1659 class Color(Enum):
1660 red = auto()
1661 blue = auto()
1662 green = auto()
1663
1664 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1665 self.assertEqual(Color.red.value, 1)
1666 self.assertEqual(Color.blue.value, 2)
1667 self.assertEqual(Color.green.value, 3)
1668
1669 def test_auto_name(self):
1670 class Color(Enum):
1671 def _generate_next_value_(name, start, count, last):
1672 return name
1673 red = auto()
1674 blue = auto()
1675 green = auto()
1676
1677 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1678 self.assertEqual(Color.red.value, 'red')
1679 self.assertEqual(Color.blue.value, 'blue')
1680 self.assertEqual(Color.green.value, 'green')
1681
1682 def test_auto_name_inherit(self):
1683 class AutoNameEnum(Enum):
1684 def _generate_next_value_(name, start, count, last):
1685 return name
1686 class Color(AutoNameEnum):
1687 red = auto()
1688 blue = auto()
1689 green = auto()
1690
1691 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1692 self.assertEqual(Color.red.value, 'red')
1693 self.assertEqual(Color.blue.value, 'blue')
1694 self.assertEqual(Color.green.value, 'green')
1695
1696 def test_auto_garbage(self):
1697 class Color(Enum):
1698 red = 'red'
1699 blue = auto()
1700 self.assertEqual(Color.blue.value, 1)
1701
1702 def test_auto_garbage_corrected(self):
1703 class Color(Enum):
1704 red = 'red'
1705 blue = 2
1706 green = auto()
1707
1708 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1709 self.assertEqual(Color.red.value, 'red')
1710 self.assertEqual(Color.blue.value, 2)
1711 self.assertEqual(Color.green.value, 3)
1712
Ethan Furman3515dcc2016-09-18 13:15:41 -07001713 def test_duplicate_auto(self):
1714 class Dupes(Enum):
1715 first = primero = auto()
1716 second = auto()
1717 third = auto()
1718 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1719
Victor Stinner0f2fc8b2018-10-20 01:49:30 +02001720 def test_missing(self):
1721 class Color(Enum):
1722 red = 1
1723 green = 2
1724 blue = 3
1725 @classmethod
1726 def _missing_(cls, item):
1727 if item == 'three':
1728 return cls.blue
1729 elif item == 'bad return':
1730 # trigger internal error
1731 return 5
1732 elif item == 'error out':
1733 raise ZeroDivisionError
1734 else:
1735 # trigger not found
1736 return None
1737 self.assertIs(Color('three'), Color.blue)
1738 self.assertRaises(ValueError, Color, 7)
1739 try:
1740 Color('bad return')
1741 except TypeError as exc:
1742 self.assertTrue(isinstance(exc.__context__, ValueError))
1743 else:
1744 raise Exception('Exception not raised.')
1745 try:
1746 Color('error out')
1747 except ZeroDivisionError as exc:
1748 self.assertTrue(isinstance(exc.__context__, ValueError))
1749 else:
1750 raise Exception('Exception not raised.')
1751
Ethan Furman0c076ca2018-09-21 22:26:32 -07001752 def test_multiple_mixin(self):
1753 class MaxMixin:
1754 @classproperty
1755 def MAX(cls):
1756 max = len(cls)
1757 cls.MAX = max
1758 return max
1759 class StrMixin:
1760 def __str__(self):
1761 return self._name_.lower()
1762 class SomeEnum(Enum):
1763 def behavior(self):
1764 return 'booyah'
1765 class AnotherEnum(Enum):
1766 def behavior(self):
1767 return 'nuhuh!'
1768 def social(self):
1769 return "what's up?"
1770 class Color(MaxMixin, Enum):
1771 RED = auto()
1772 GREEN = auto()
1773 BLUE = auto()
1774 self.assertEqual(Color.RED.value, 1)
1775 self.assertEqual(Color.GREEN.value, 2)
1776 self.assertEqual(Color.BLUE.value, 3)
1777 self.assertEqual(Color.MAX, 3)
1778 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1779 class Color(MaxMixin, StrMixin, Enum):
1780 RED = auto()
1781 GREEN = auto()
1782 BLUE = auto()
1783 self.assertEqual(Color.RED.value, 1)
1784 self.assertEqual(Color.GREEN.value, 2)
1785 self.assertEqual(Color.BLUE.value, 3)
1786 self.assertEqual(Color.MAX, 3)
1787 self.assertEqual(str(Color.BLUE), 'blue')
1788 class Color(StrMixin, MaxMixin, Enum):
1789 RED = auto()
1790 GREEN = auto()
1791 BLUE = auto()
1792 self.assertEqual(Color.RED.value, 1)
1793 self.assertEqual(Color.GREEN.value, 2)
1794 self.assertEqual(Color.BLUE.value, 3)
1795 self.assertEqual(Color.MAX, 3)
1796 self.assertEqual(str(Color.BLUE), 'blue')
1797 class CoolColor(StrMixin, SomeEnum, Enum):
1798 RED = auto()
1799 GREEN = auto()
1800 BLUE = auto()
1801 self.assertEqual(CoolColor.RED.value, 1)
1802 self.assertEqual(CoolColor.GREEN.value, 2)
1803 self.assertEqual(CoolColor.BLUE.value, 3)
1804 self.assertEqual(str(CoolColor.BLUE), 'blue')
1805 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1806 class CoolerColor(StrMixin, AnotherEnum, Enum):
1807 RED = auto()
1808 GREEN = auto()
1809 BLUE = auto()
1810 self.assertEqual(CoolerColor.RED.value, 1)
1811 self.assertEqual(CoolerColor.GREEN.value, 2)
1812 self.assertEqual(CoolerColor.BLUE.value, 3)
1813 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1814 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1815 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1816 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1817 RED = auto()
1818 GREEN = auto()
1819 BLUE = auto()
1820 self.assertEqual(CoolestColor.RED.value, 1)
1821 self.assertEqual(CoolestColor.GREEN.value, 2)
1822 self.assertEqual(CoolestColor.BLUE.value, 3)
1823 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1824 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1825 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1826 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1827 RED = auto()
1828 GREEN = auto()
1829 BLUE = auto()
1830 self.assertEqual(ConfusedColor.RED.value, 1)
1831 self.assertEqual(ConfusedColor.GREEN.value, 2)
1832 self.assertEqual(ConfusedColor.BLUE.value, 3)
1833 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1834 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1835 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1836 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1837 RED = auto()
1838 GREEN = auto()
1839 BLUE = auto()
1840 self.assertEqual(ReformedColor.RED.value, 1)
1841 self.assertEqual(ReformedColor.GREEN.value, 2)
1842 self.assertEqual(ReformedColor.BLUE.value, 3)
1843 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1844 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1845 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1846 self.assertTrue(issubclass(ReformedColor, int))
1847
Miss Islington (bot)453b3b02018-10-06 00:43:20 -07001848 def test_multiple_inherited_mixin(self):
1849 class StrEnum(str, Enum):
1850 def __new__(cls, *args, **kwargs):
1851 for a in args:
1852 if not isinstance(a, str):
1853 raise TypeError("Enumeration '%s' (%s) is not"
1854 " a string" % (a, type(a).__name__))
1855 return str.__new__(cls, *args, **kwargs)
1856 @unique
1857 class Decision1(StrEnum):
1858 REVERT = "REVERT"
1859 REVERT_ALL = "REVERT_ALL"
1860 RETRY = "RETRY"
1861 class MyEnum(StrEnum):
1862 pass
1863 @unique
1864 class Decision2(MyEnum):
1865 REVERT = "REVERT"
1866 REVERT_ALL = "REVERT_ALL"
1867 RETRY = "RETRY"
1868
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001869
Ethan Furmane8e61272016-08-20 07:19:31 -07001870class TestOrder(unittest.TestCase):
1871
1872 def test_same_members(self):
1873 class Color(Enum):
1874 _order_ = 'red green blue'
1875 red = 1
1876 green = 2
1877 blue = 3
1878
1879 def test_same_members_with_aliases(self):
1880 class Color(Enum):
1881 _order_ = 'red green blue'
1882 red = 1
1883 green = 2
1884 blue = 3
1885 verde = green
1886
1887 def test_same_members_wrong_order(self):
1888 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1889 class Color(Enum):
1890 _order_ = 'red green blue'
1891 red = 1
1892 blue = 3
1893 green = 2
1894
1895 def test_order_has_extra_members(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
1903 def test_order_has_extra_members_with_aliases(self):
1904 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1905 class Color(Enum):
1906 _order_ = 'red green blue purple'
1907 red = 1
1908 green = 2
1909 blue = 3
1910 verde = green
1911
1912 def test_enum_has_extra_members(self):
1913 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1914 class Color(Enum):
1915 _order_ = 'red green blue'
1916 red = 1
1917 green = 2
1918 blue = 3
1919 purple = 4
1920
1921 def test_enum_has_extra_members_with_aliases(self):
1922 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1923 class Color(Enum):
1924 _order_ = 'red green blue'
1925 red = 1
1926 green = 2
1927 blue = 3
1928 purple = 4
1929 verde = green
1930
1931
Ethan Furman65a5a472016-09-01 23:55:19 -07001932class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001933 """Tests of the Flags."""
1934
Ethan Furman65a5a472016-09-01 23:55:19 -07001935 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001936 R, W, X = 4, 2, 1
1937
Ethan Furman37151762018-04-11 18:56:25 -07001938 class Color(Flag):
1939 BLACK = 0
1940 RED = 1
1941 GREEN = 2
1942 BLUE = 4
1943 PURPLE = RED|BLUE
1944
Ethan Furman65a5a472016-09-01 23:55:19 -07001945 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001946 RO = 0
1947 WO = 1
1948 RW = 2
1949 AC = 3
1950 CE = 1<<19
1951
1952 def test_str(self):
1953 Perm = self.Perm
1954 self.assertEqual(str(Perm.R), 'Perm.R')
1955 self.assertEqual(str(Perm.W), 'Perm.W')
1956 self.assertEqual(str(Perm.X), 'Perm.X')
1957 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1958 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1959 self.assertEqual(str(Perm(0)), 'Perm.0')
1960 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1961 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1962 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1963 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1964 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1965 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1966
1967 Open = self.Open
1968 self.assertEqual(str(Open.RO), 'Open.RO')
1969 self.assertEqual(str(Open.WO), 'Open.WO')
1970 self.assertEqual(str(Open.AC), 'Open.AC')
1971 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1972 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001973 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001974 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1975 self.assertEqual(str(~Open.AC), 'Open.CE')
1976 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1977 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1978
1979 def test_repr(self):
1980 Perm = self.Perm
1981 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1982 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1983 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1984 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1985 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001986 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001987 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1988 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1989 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1990 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001991 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001992 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1993
1994 Open = self.Open
1995 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1996 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1997 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1998 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1999 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002000 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002001 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2002 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2003 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2004 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2005
2006 def test_or(self):
2007 Perm = self.Perm
2008 for i in Perm:
2009 for j in Perm:
2010 self.assertEqual((i | j), Perm(i.value | j.value))
2011 self.assertEqual((i | j).value, i.value | j.value)
2012 self.assertIs(type(i | j), Perm)
2013 for i in Perm:
2014 self.assertIs(i | i, i)
2015 Open = self.Open
2016 self.assertIs(Open.RO | Open.CE, Open.CE)
2017
2018 def test_and(self):
2019 Perm = self.Perm
2020 RW = Perm.R | Perm.W
2021 RX = Perm.R | Perm.X
2022 WX = Perm.W | Perm.X
2023 RWX = Perm.R | Perm.W | Perm.X
2024 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2025 for i in values:
2026 for j in values:
2027 self.assertEqual((i & j).value, i.value & j.value)
2028 self.assertIs(type(i & j), Perm)
2029 for i in Perm:
2030 self.assertIs(i & i, i)
2031 self.assertIs(i & RWX, i)
2032 self.assertIs(RWX & i, i)
2033 Open = self.Open
2034 self.assertIs(Open.RO & Open.CE, Open.RO)
2035
2036 def test_xor(self):
2037 Perm = self.Perm
2038 for i in Perm:
2039 for j in Perm:
2040 self.assertEqual((i ^ j).value, i.value ^ j.value)
2041 self.assertIs(type(i ^ j), Perm)
2042 for i in Perm:
2043 self.assertIs(i ^ Perm(0), i)
2044 self.assertIs(Perm(0) ^ i, i)
2045 Open = self.Open
2046 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2047 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2048
2049 def test_invert(self):
2050 Perm = self.Perm
2051 RW = Perm.R | Perm.W
2052 RX = Perm.R | Perm.X
2053 WX = Perm.W | Perm.X
2054 RWX = Perm.R | Perm.W | Perm.X
2055 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2056 for i in values:
2057 self.assertIs(type(~i), Perm)
2058 self.assertEqual(~~i, i)
2059 for i in Perm:
2060 self.assertIs(~~i, i)
2061 Open = self.Open
2062 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2063 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2064
Ethan Furman25d94bb2016-09-02 16:32:32 -07002065 def test_bool(self):
2066 Perm = self.Perm
2067 for f in Perm:
2068 self.assertTrue(f)
2069 Open = self.Open
2070 for f in Open:
2071 self.assertEqual(bool(f.value), bool(f))
2072
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002073 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002074 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002075 lst = list(Perm)
2076 self.assertEqual(len(lst), len(Perm))
2077 self.assertEqual(len(Perm), 3, Perm)
2078 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2079 for i, n in enumerate('R W X'.split()):
2080 v = 1<<i
2081 e = Perm(v)
2082 self.assertEqual(e.value, v)
2083 self.assertEqual(type(e.value), int)
2084 self.assertEqual(e.name, n)
2085 self.assertIn(e, Perm)
2086 self.assertIs(type(e), Perm)
2087
2088 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002089 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002090 lst = list(Perm)
2091 self.assertEqual(len(lst), len(Perm))
2092 self.assertEqual(len(Perm), 3, Perm)
2093 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2094 for i, n in enumerate('R W X'.split()):
2095 v = 8<<i
2096 e = Perm(v)
2097 self.assertEqual(e.value, v)
2098 self.assertEqual(type(e.value), int)
2099 self.assertEqual(e.name, n)
2100 self.assertIn(e, Perm)
2101 self.assertIs(type(e), Perm)
2102
2103 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002104 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002105 lst = list(Perm)
2106 self.assertEqual(len(lst), len(Perm))
2107 self.assertEqual(len(Perm), 3, Perm)
2108 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2109 for i, n in enumerate('R W X'.split()):
2110 v = 1<<i
2111 e = Perm(v)
2112 self.assertEqual(e.value, v)
2113 self.assertEqual(type(e.value), int)
2114 self.assertEqual(e.name, n)
2115 self.assertIn(e, Perm)
2116 self.assertIs(type(e), Perm)
2117
2118 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002119 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002120 lst = list(Perm)
2121 self.assertEqual(len(lst), len(Perm))
2122 self.assertEqual(len(Perm), 3, Perm)
2123 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2124 for i, n in enumerate('R W X'.split()):
2125 v = 1<<(2*i+1)
2126 e = Perm(v)
2127 self.assertEqual(e.value, v)
2128 self.assertEqual(type(e.value), int)
2129 self.assertEqual(e.name, n)
2130 self.assertIn(e, Perm)
2131 self.assertIs(type(e), Perm)
2132
2133 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002134 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002135 lst = list(Perm)
2136 self.assertEqual(len(lst), len(Perm))
2137 self.assertEqual(len(Perm), 3, Perm)
2138 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2139 for i, n in enumerate('R W X'.split()):
2140 v = 1<<(2*i+1)
2141 e = Perm(v)
2142 self.assertEqual(e.value, v)
2143 self.assertEqual(type(e.value), int)
2144 self.assertEqual(e.name, n)
2145 self.assertIn(e, Perm)
2146 self.assertIs(type(e), Perm)
2147
Ethan Furman65a5a472016-09-01 23:55:19 -07002148 def test_pickle(self):
2149 if isinstance(FlagStooges, Exception):
2150 raise FlagStooges
2151 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2152 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002153
Ethan Furman37151762018-04-11 18:56:25 -07002154 def test_contains(self):
2155 Open = self.Open
2156 Color = self.Color
2157 self.assertFalse(Color.BLACK in Open)
2158 self.assertFalse(Open.RO in Color)
2159 with self.assertWarns(DeprecationWarning):
2160 self.assertFalse('BLACK' in Color)
2161 with self.assertWarns(DeprecationWarning):
2162 self.assertFalse('RO' in Open)
2163 with self.assertWarns(DeprecationWarning):
2164 self.assertFalse(1 in Color)
2165 with self.assertWarns(DeprecationWarning):
2166 self.assertFalse(1 in Open)
2167
2168 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002169 Perm = self.Perm
2170 R, W, X = Perm
2171 RW = R | W
2172 RX = R | X
2173 WX = W | X
2174 RWX = R | W | X
2175 self.assertTrue(R in RW)
2176 self.assertTrue(R in RX)
2177 self.assertTrue(R in RWX)
2178 self.assertTrue(W in RW)
2179 self.assertTrue(W in WX)
2180 self.assertTrue(W in RWX)
2181 self.assertTrue(X in RX)
2182 self.assertTrue(X in WX)
2183 self.assertTrue(X in RWX)
2184 self.assertFalse(R in WX)
2185 self.assertFalse(W in RX)
2186 self.assertFalse(X in RW)
2187
Ethan Furmanc16595e2016-09-10 23:36:59 -07002188 def test_auto_number(self):
2189 class Color(Flag):
2190 red = auto()
2191 blue = auto()
2192 green = auto()
2193
2194 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2195 self.assertEqual(Color.red.value, 1)
2196 self.assertEqual(Color.blue.value, 2)
2197 self.assertEqual(Color.green.value, 4)
2198
2199 def test_auto_number_garbage(self):
2200 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2201 class Color(Flag):
2202 red = 'not an int'
2203 blue = auto()
2204
Ethan Furman3515dcc2016-09-18 13:15:41 -07002205 def test_cascading_failure(self):
2206 class Bizarre(Flag):
2207 c = 3
2208 d = 4
2209 f = 6
2210 # Bizarre.c | Bizarre.d
2211 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2212 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2213 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2214 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2215 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2216 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2217
2218 def test_duplicate_auto(self):
2219 class Dupes(Enum):
2220 first = primero = auto()
2221 second = auto()
2222 third = auto()
2223 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2224
2225 def test_bizarre(self):
2226 class Bizarre(Flag):
2227 b = 3
2228 c = 4
2229 d = 6
2230 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2231
Ethan Furman0c076ca2018-09-21 22:26:32 -07002232 def test_multiple_mixin(self):
2233 class AllMixin:
2234 @classproperty
2235 def ALL(cls):
2236 members = list(cls)
2237 all_value = None
2238 if members:
2239 all_value = members[0]
2240 for member in members[1:]:
2241 all_value |= member
2242 cls.ALL = all_value
2243 return all_value
2244 class StrMixin:
2245 def __str__(self):
2246 return self._name_.lower()
2247 class Color(AllMixin, Flag):
2248 RED = auto()
2249 GREEN = auto()
2250 BLUE = auto()
2251 self.assertEqual(Color.RED.value, 1)
2252 self.assertEqual(Color.GREEN.value, 2)
2253 self.assertEqual(Color.BLUE.value, 4)
2254 self.assertEqual(Color.ALL.value, 7)
2255 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2256 class Color(AllMixin, StrMixin, Flag):
2257 RED = auto()
2258 GREEN = auto()
2259 BLUE = auto()
2260 self.assertEqual(Color.RED.value, 1)
2261 self.assertEqual(Color.GREEN.value, 2)
2262 self.assertEqual(Color.BLUE.value, 4)
2263 self.assertEqual(Color.ALL.value, 7)
2264 self.assertEqual(str(Color.BLUE), 'blue')
2265 class Color(StrMixin, AllMixin, Flag):
2266 RED = auto()
2267 GREEN = auto()
2268 BLUE = auto()
2269 self.assertEqual(Color.RED.value, 1)
2270 self.assertEqual(Color.GREEN.value, 2)
2271 self.assertEqual(Color.BLUE.value, 4)
2272 self.assertEqual(Color.ALL.value, 7)
2273 self.assertEqual(str(Color.BLUE), 'blue')
2274
Ethan Furman28cf6632017-01-24 12:12:06 -08002275 @support.reap_threads
2276 def test_unique_composite(self):
2277 # override __eq__ to be identity only
2278 class TestFlag(Flag):
2279 one = auto()
2280 two = auto()
2281 three = auto()
2282 four = auto()
2283 five = auto()
2284 six = auto()
2285 seven = auto()
2286 eight = auto()
2287 def __eq__(self, other):
2288 return self is other
2289 def __hash__(self):
2290 return hash(self._value_)
2291 # have multiple threads competing to complete the composite members
2292 seen = set()
2293 failed = False
2294 def cycle_enum():
2295 nonlocal failed
2296 try:
2297 for i in range(256):
2298 seen.add(TestFlag(i))
2299 except Exception:
2300 failed = True
2301 threads = [
2302 threading.Thread(target=cycle_enum)
2303 for _ in range(8)
2304 ]
2305 with support.start_threads(threads):
2306 pass
2307 # check that only 248 members were created
2308 self.assertFalse(
2309 failed,
2310 'at least one thread failed while creating composite members')
2311 self.assertEqual(256, len(seen), 'too many composite members created')
2312
Ethan Furmanc16595e2016-09-10 23:36:59 -07002313
Ethan Furman65a5a472016-09-01 23:55:19 -07002314class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002315 """Tests of the IntFlags."""
2316
Ethan Furman65a5a472016-09-01 23:55:19 -07002317 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002318 X = 1 << 0
2319 W = 1 << 1
2320 R = 1 << 2
2321
Ethan Furman37151762018-04-11 18:56:25 -07002322 class Color(IntFlag):
2323 BLACK = 0
2324 RED = 1
2325 GREEN = 2
2326 BLUE = 4
2327 PURPLE = RED|BLUE
2328
Ethan Furman65a5a472016-09-01 23:55:19 -07002329 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002330 RO = 0
2331 WO = 1
2332 RW = 2
2333 AC = 3
2334 CE = 1<<19
2335
Ethan Furman3515dcc2016-09-18 13:15:41 -07002336 def test_type(self):
2337 Perm = self.Perm
2338 Open = self.Open
2339 for f in Perm:
2340 self.assertTrue(isinstance(f, Perm))
2341 self.assertEqual(f, f.value)
2342 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2343 self.assertEqual(Perm.W | Perm.X, 3)
2344 for f in Open:
2345 self.assertTrue(isinstance(f, Open))
2346 self.assertEqual(f, f.value)
2347 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2348 self.assertEqual(Open.WO | Open.RW, 3)
2349
2350
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002351 def test_str(self):
2352 Perm = self.Perm
2353 self.assertEqual(str(Perm.R), 'Perm.R')
2354 self.assertEqual(str(Perm.W), 'Perm.W')
2355 self.assertEqual(str(Perm.X), 'Perm.X')
2356 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2357 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2358 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2359 self.assertEqual(str(Perm(0)), 'Perm.0')
2360 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002361 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2362 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2363 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2364 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002365 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002366 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2367 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2368 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002369
2370 Open = self.Open
2371 self.assertEqual(str(Open.RO), 'Open.RO')
2372 self.assertEqual(str(Open.WO), 'Open.WO')
2373 self.assertEqual(str(Open.AC), 'Open.AC')
2374 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2375 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2376 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002377 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2378 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2379 self.assertEqual(str(~Open.AC), 'Open.CE')
2380 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2381 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2382 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383
2384 def test_repr(self):
2385 Perm = self.Perm
2386 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2387 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2388 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2389 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2390 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2391 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002392 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2393 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002394 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2395 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2396 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2397 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002398 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002399 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2400 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2401 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002402
2403 Open = self.Open
2404 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2405 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2406 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2407 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2408 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002409 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002410 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2411 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2412 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2413 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2414 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2415 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002416
2417 def test_or(self):
2418 Perm = self.Perm
2419 for i in Perm:
2420 for j in Perm:
2421 self.assertEqual(i | j, i.value | j.value)
2422 self.assertEqual((i | j).value, i.value | j.value)
2423 self.assertIs(type(i | j), Perm)
2424 for j in range(8):
2425 self.assertEqual(i | j, i.value | j)
2426 self.assertEqual((i | j).value, i.value | j)
2427 self.assertIs(type(i | j), Perm)
2428 self.assertEqual(j | i, j | i.value)
2429 self.assertEqual((j | i).value, j | i.value)
2430 self.assertIs(type(j | i), Perm)
2431 for i in Perm:
2432 self.assertIs(i | i, i)
2433 self.assertIs(i | 0, i)
2434 self.assertIs(0 | i, i)
2435 Open = self.Open
2436 self.assertIs(Open.RO | Open.CE, Open.CE)
2437
2438 def test_and(self):
2439 Perm = self.Perm
2440 RW = Perm.R | Perm.W
2441 RX = Perm.R | Perm.X
2442 WX = Perm.W | Perm.X
2443 RWX = Perm.R | Perm.W | Perm.X
2444 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2445 for i in values:
2446 for j in values:
2447 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2448 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2449 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2450 for j in range(8):
2451 self.assertEqual(i & j, i.value & j)
2452 self.assertEqual((i & j).value, i.value & j)
2453 self.assertIs(type(i & j), Perm)
2454 self.assertEqual(j & i, j & i.value)
2455 self.assertEqual((j & i).value, j & i.value)
2456 self.assertIs(type(j & i), Perm)
2457 for i in Perm:
2458 self.assertIs(i & i, i)
2459 self.assertIs(i & 7, i)
2460 self.assertIs(7 & i, i)
2461 Open = self.Open
2462 self.assertIs(Open.RO & Open.CE, Open.RO)
2463
2464 def test_xor(self):
2465 Perm = self.Perm
2466 for i in Perm:
2467 for j in Perm:
2468 self.assertEqual(i ^ j, i.value ^ j.value)
2469 self.assertEqual((i ^ j).value, i.value ^ j.value)
2470 self.assertIs(type(i ^ j), Perm)
2471 for j in range(8):
2472 self.assertEqual(i ^ j, i.value ^ j)
2473 self.assertEqual((i ^ j).value, i.value ^ j)
2474 self.assertIs(type(i ^ j), Perm)
2475 self.assertEqual(j ^ i, j ^ i.value)
2476 self.assertEqual((j ^ i).value, j ^ i.value)
2477 self.assertIs(type(j ^ i), Perm)
2478 for i in Perm:
2479 self.assertIs(i ^ 0, i)
2480 self.assertIs(0 ^ i, i)
2481 Open = self.Open
2482 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2483 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2484
2485 def test_invert(self):
2486 Perm = self.Perm
2487 RW = Perm.R | Perm.W
2488 RX = Perm.R | Perm.X
2489 WX = Perm.W | Perm.X
2490 RWX = Perm.R | Perm.W | Perm.X
2491 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2492 for i in values:
2493 self.assertEqual(~i, ~i.value)
2494 self.assertEqual((~i).value, ~i.value)
2495 self.assertIs(type(~i), Perm)
2496 self.assertEqual(~~i, i)
2497 for i in Perm:
2498 self.assertIs(~~i, i)
2499 Open = self.Open
2500 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2501 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2502
2503 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002504 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002505 lst = list(Perm)
2506 self.assertEqual(len(lst), len(Perm))
2507 self.assertEqual(len(Perm), 3, Perm)
2508 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2509 for i, n in enumerate('R W X'.split()):
2510 v = 1<<i
2511 e = Perm(v)
2512 self.assertEqual(e.value, v)
2513 self.assertEqual(type(e.value), int)
2514 self.assertEqual(e, v)
2515 self.assertEqual(e.name, n)
2516 self.assertIn(e, Perm)
2517 self.assertIs(type(e), Perm)
2518
2519 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002520 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002521 lst = list(Perm)
2522 self.assertEqual(len(lst), len(Perm))
2523 self.assertEqual(len(Perm), 3, Perm)
2524 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2525 for i, n in enumerate('R W X'.split()):
2526 v = 8<<i
2527 e = Perm(v)
2528 self.assertEqual(e.value, v)
2529 self.assertEqual(type(e.value), int)
2530 self.assertEqual(e, v)
2531 self.assertEqual(e.name, n)
2532 self.assertIn(e, Perm)
2533 self.assertIs(type(e), Perm)
2534
2535 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002536 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002537 lst = list(Perm)
2538 self.assertEqual(len(lst), len(Perm))
2539 self.assertEqual(len(Perm), 3, Perm)
2540 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2541 for i, n in enumerate('R W X'.split()):
2542 v = 1<<i
2543 e = Perm(v)
2544 self.assertEqual(e.value, v)
2545 self.assertEqual(type(e.value), int)
2546 self.assertEqual(e, v)
2547 self.assertEqual(e.name, n)
2548 self.assertIn(e, Perm)
2549 self.assertIs(type(e), Perm)
2550
2551 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002552 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002553 lst = list(Perm)
2554 self.assertEqual(len(lst), len(Perm))
2555 self.assertEqual(len(Perm), 3, Perm)
2556 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2557 for i, n in enumerate('R W X'.split()):
2558 v = 1<<(2*i+1)
2559 e = Perm(v)
2560 self.assertEqual(e.value, v)
2561 self.assertEqual(type(e.value), int)
2562 self.assertEqual(e, v)
2563 self.assertEqual(e.name, n)
2564 self.assertIn(e, Perm)
2565 self.assertIs(type(e), Perm)
2566
2567 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002568 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002569 lst = list(Perm)
2570 self.assertEqual(len(lst), len(Perm))
2571 self.assertEqual(len(Perm), 3, Perm)
2572 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2573 for i, n in enumerate('R W X'.split()):
2574 v = 1<<(2*i+1)
2575 e = Perm(v)
2576 self.assertEqual(e.value, v)
2577 self.assertEqual(type(e.value), int)
2578 self.assertEqual(e, v)
2579 self.assertEqual(e.name, n)
2580 self.assertIn(e, Perm)
2581 self.assertIs(type(e), Perm)
2582
2583
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002584 def test_programatic_function_from_empty_list(self):
2585 Perm = enum.IntFlag('Perm', [])
2586 lst = list(Perm)
2587 self.assertEqual(len(lst), len(Perm))
2588 self.assertEqual(len(Perm), 0, Perm)
2589 Thing = enum.Enum('Thing', [])
2590 lst = list(Thing)
2591 self.assertEqual(len(lst), len(Thing))
2592 self.assertEqual(len(Thing), 0, Thing)
2593
2594
2595 def test_programatic_function_from_empty_tuple(self):
2596 Perm = enum.IntFlag('Perm', ())
2597 lst = list(Perm)
2598 self.assertEqual(len(lst), len(Perm))
2599 self.assertEqual(len(Perm), 0, Perm)
2600 Thing = enum.Enum('Thing', ())
2601 self.assertEqual(len(lst), len(Thing))
2602 self.assertEqual(len(Thing), 0, Thing)
2603
Ethan Furman37151762018-04-11 18:56:25 -07002604 def test_contains(self):
2605 Color = self.Color
2606 Open = self.Open
2607 self.assertTrue(Color.GREEN in Color)
2608 self.assertTrue(Open.RW in Open)
2609 self.assertFalse(Color.GREEN in Open)
2610 self.assertFalse(Open.RW in Color)
2611 with self.assertWarns(DeprecationWarning):
2612 self.assertFalse('GREEN' in Color)
2613 with self.assertWarns(DeprecationWarning):
2614 self.assertFalse('RW' in Open)
2615 with self.assertWarns(DeprecationWarning):
2616 self.assertFalse(2 in Color)
2617 with self.assertWarns(DeprecationWarning):
2618 self.assertFalse(2 in Open)
2619
2620 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002621 Perm = self.Perm
2622 R, W, X = Perm
2623 RW = R | W
2624 RX = R | X
2625 WX = W | X
2626 RWX = R | W | X
2627 self.assertTrue(R in RW)
2628 self.assertTrue(R in RX)
2629 self.assertTrue(R in RWX)
2630 self.assertTrue(W in RW)
2631 self.assertTrue(W in WX)
2632 self.assertTrue(W in RWX)
2633 self.assertTrue(X in RX)
2634 self.assertTrue(X in WX)
2635 self.assertTrue(X in RWX)
2636 self.assertFalse(R in WX)
2637 self.assertFalse(W in RX)
2638 self.assertFalse(X in RW)
Ethan Furman37151762018-04-11 18:56:25 -07002639 with self.assertWarns(DeprecationWarning):
2640 self.assertFalse('swallow' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002641
Ethan Furman25d94bb2016-09-02 16:32:32 -07002642 def test_bool(self):
2643 Perm = self.Perm
2644 for f in Perm:
2645 self.assertTrue(f)
2646 Open = self.Open
2647 for f in Open:
2648 self.assertEqual(bool(f.value), bool(f))
2649
Ethan Furman0c076ca2018-09-21 22:26:32 -07002650 def test_multiple_mixin(self):
2651 class AllMixin:
2652 @classproperty
2653 def ALL(cls):
2654 members = list(cls)
2655 all_value = None
2656 if members:
2657 all_value = members[0]
2658 for member in members[1:]:
2659 all_value |= member
2660 cls.ALL = all_value
2661 return all_value
2662 class StrMixin:
2663 def __str__(self):
2664 return self._name_.lower()
2665 class Color(AllMixin, IntFlag):
2666 RED = auto()
2667 GREEN = auto()
2668 BLUE = auto()
2669 self.assertEqual(Color.RED.value, 1)
2670 self.assertEqual(Color.GREEN.value, 2)
2671 self.assertEqual(Color.BLUE.value, 4)
2672 self.assertEqual(Color.ALL.value, 7)
2673 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2674 class Color(AllMixin, StrMixin, IntFlag):
2675 RED = auto()
2676 GREEN = auto()
2677 BLUE = auto()
2678 self.assertEqual(Color.RED.value, 1)
2679 self.assertEqual(Color.GREEN.value, 2)
2680 self.assertEqual(Color.BLUE.value, 4)
2681 self.assertEqual(Color.ALL.value, 7)
2682 self.assertEqual(str(Color.BLUE), 'blue')
2683 class Color(StrMixin, AllMixin, IntFlag):
2684 RED = auto()
2685 GREEN = auto()
2686 BLUE = auto()
2687 self.assertEqual(Color.RED.value, 1)
2688 self.assertEqual(Color.GREEN.value, 2)
2689 self.assertEqual(Color.BLUE.value, 4)
2690 self.assertEqual(Color.ALL.value, 7)
2691 self.assertEqual(str(Color.BLUE), 'blue')
2692
Ethan Furman28cf6632017-01-24 12:12:06 -08002693 @support.reap_threads
2694 def test_unique_composite(self):
2695 # override __eq__ to be identity only
2696 class TestFlag(IntFlag):
2697 one = auto()
2698 two = auto()
2699 three = auto()
2700 four = auto()
2701 five = auto()
2702 six = auto()
2703 seven = auto()
2704 eight = auto()
2705 def __eq__(self, other):
2706 return self is other
2707 def __hash__(self):
2708 return hash(self._value_)
2709 # have multiple threads competing to complete the composite members
2710 seen = set()
2711 failed = False
2712 def cycle_enum():
2713 nonlocal failed
2714 try:
2715 for i in range(256):
2716 seen.add(TestFlag(i))
2717 except Exception:
2718 failed = True
2719 threads = [
2720 threading.Thread(target=cycle_enum)
2721 for _ in range(8)
2722 ]
2723 with support.start_threads(threads):
2724 pass
2725 # check that only 248 members were created
2726 self.assertFalse(
2727 failed,
2728 'at least one thread failed while creating composite members')
2729 self.assertEqual(256, len(seen), 'too many composite members created')
2730
2731
Ethan Furmanf24bb352013-07-18 17:05:39 -07002732class TestUnique(unittest.TestCase):
2733
2734 def test_unique_clean(self):
2735 @unique
2736 class Clean(Enum):
2737 one = 1
2738 two = 'dos'
2739 tres = 4.0
2740 @unique
2741 class Cleaner(IntEnum):
2742 single = 1
2743 double = 2
2744 triple = 3
2745
2746 def test_unique_dirty(self):
2747 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2748 @unique
2749 class Dirty(Enum):
2750 one = 1
2751 two = 'dos'
2752 tres = 1
2753 with self.assertRaisesRegex(
2754 ValueError,
2755 'double.*single.*turkey.*triple',
2756 ):
2757 @unique
2758 class Dirtier(IntEnum):
2759 single = 1
2760 double = 1
2761 triple = 3
2762 turkey = 3
2763
Ethan Furman3803ad42016-05-01 10:03:53 -07002764 def test_unique_with_name(self):
2765 @unique
2766 class Silly(Enum):
2767 one = 1
2768 two = 'dos'
2769 name = 3
2770 @unique
2771 class Sillier(IntEnum):
2772 single = 1
2773 name = 2
2774 triple = 3
2775 value = 4
2776
Ethan Furmanf24bb352013-07-18 17:05:39 -07002777
Ethan Furman0c076ca2018-09-21 22:26:32 -07002778
Ethan Furman3323da92015-04-11 09:39:59 -07002779expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002780Help on class Color in module %s:
2781
2782class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002783 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2784 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002785 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002786 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002787 | Method resolution order:
2788 | Color
2789 | enum.Enum
2790 | builtins.object
2791 |\x20\x20
2792 | Data and other attributes defined here:
2793 |\x20\x20
2794 | blue = <Color.blue: 3>
2795 |\x20\x20
2796 | green = <Color.green: 2>
2797 |\x20\x20
2798 | red = <Color.red: 1>
2799 |\x20\x20
2800 | ----------------------------------------------------------------------
2801 | Data descriptors inherited from enum.Enum:
2802 |\x20\x20
2803 | name
2804 | The name of the Enum member.
2805 |\x20\x20
2806 | value
2807 | The value of the Enum member.
2808 |\x20\x20
2809 | ----------------------------------------------------------------------
2810 | Data descriptors inherited from enum.EnumMeta:
2811 |\x20\x20
2812 | __members__
2813 | Returns a mapping of member name->value.
2814 |\x20\x20\x20\x20\x20\x20
2815 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002816 | is a read-only view of the internal mapping."""
2817
2818expected_help_output_without_docs = """\
2819Help on class Color in module %s:
2820
2821class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002822 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2823 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002824 | Method resolution order:
2825 | Color
2826 | enum.Enum
2827 | builtins.object
2828 |\x20\x20
2829 | Data and other attributes defined here:
2830 |\x20\x20
2831 | blue = <Color.blue: 3>
2832 |\x20\x20
2833 | green = <Color.green: 2>
2834 |\x20\x20
2835 | red = <Color.red: 1>
2836 |\x20\x20
2837 | ----------------------------------------------------------------------
2838 | Data descriptors inherited from enum.Enum:
2839 |\x20\x20
2840 | name
2841 |\x20\x20
2842 | value
2843 |\x20\x20
2844 | ----------------------------------------------------------------------
2845 | Data descriptors inherited from enum.EnumMeta:
2846 |\x20\x20
2847 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002848
2849class TestStdLib(unittest.TestCase):
2850
Ethan Furman48a724f2015-04-11 23:23:06 -07002851 maxDiff = None
2852
Ethan Furman5875d742013-10-21 20:45:55 -07002853 class Color(Enum):
2854 red = 1
2855 green = 2
2856 blue = 3
2857
2858 def test_pydoc(self):
2859 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002860 if StrEnum.__doc__ is None:
2861 expected_text = expected_help_output_without_docs % __name__
2862 else:
2863 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002864 output = StringIO()
2865 helper = pydoc.Helper(output=output)
2866 helper(self.Color)
2867 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002868 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002869
2870 def test_inspect_getmembers(self):
2871 values = dict((
2872 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002873 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002874 ('__members__', self.Color.__members__),
2875 ('__module__', __name__),
2876 ('blue', self.Color.blue),
2877 ('green', self.Color.green),
2878 ('name', Enum.__dict__['name']),
2879 ('red', self.Color.red),
2880 ('value', Enum.__dict__['value']),
2881 ))
2882 result = dict(inspect.getmembers(self.Color))
2883 self.assertEqual(values.keys(), result.keys())
2884 failed = False
2885 for k in values.keys():
2886 if result[k] != values[k]:
2887 print()
2888 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2889 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2890 failed = True
2891 if failed:
2892 self.fail("result does not equal expected, see print above")
2893
2894 def test_inspect_classify_class_attrs(self):
2895 # indirectly test __objclass__
2896 from inspect import Attribute
2897 values = [
2898 Attribute(name='__class__', kind='data',
2899 defining_class=object, object=EnumMeta),
2900 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002901 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002902 Attribute(name='__members__', kind='property',
2903 defining_class=EnumMeta, object=EnumMeta.__members__),
2904 Attribute(name='__module__', kind='data',
2905 defining_class=self.Color, object=__name__),
2906 Attribute(name='blue', kind='data',
2907 defining_class=self.Color, object=self.Color.blue),
2908 Attribute(name='green', kind='data',
2909 defining_class=self.Color, object=self.Color.green),
2910 Attribute(name='red', kind='data',
2911 defining_class=self.Color, object=self.Color.red),
2912 Attribute(name='name', kind='data',
2913 defining_class=Enum, object=Enum.__dict__['name']),
2914 Attribute(name='value', kind='data',
2915 defining_class=Enum, object=Enum.__dict__['value']),
2916 ]
2917 values.sort(key=lambda item: item.name)
2918 result = list(inspect.classify_class_attrs(self.Color))
2919 result.sort(key=lambda item: item.name)
2920 failed = False
2921 for v, r in zip(values, result):
2922 if r != v:
2923 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2924 failed = True
2925 if failed:
2926 self.fail("result does not equal expected, see print above")
2927
Martin Panter19e69c52015-11-14 12:46:42 +00002928
2929class MiscTestCase(unittest.TestCase):
2930 def test__all__(self):
2931 support.check__all__(self, enum)
2932
2933
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002934# These are unordered here on purpose to ensure that declaration order
2935# makes no difference.
2936CONVERT_TEST_NAME_D = 5
2937CONVERT_TEST_NAME_C = 5
2938CONVERT_TEST_NAME_B = 5
2939CONVERT_TEST_NAME_A = 5 # This one should sort first.
2940CONVERT_TEST_NAME_E = 5
2941CONVERT_TEST_NAME_F = 5
2942
2943class TestIntEnumConvert(unittest.TestCase):
2944 def test_convert_value_lookup_priority(self):
2945 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002946 'UnittestConvert',
2947 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002948 filter=lambda x: x.startswith('CONVERT_TEST_'))
2949 # We don't want the reverse lookup value to vary when there are
2950 # multiple possible names for a given value. It should always
2951 # report the first lexigraphical name in that case.
2952 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2953
2954 def test_convert(self):
2955 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002956 'UnittestConvert',
2957 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002958 filter=lambda x: x.startswith('CONVERT_TEST_'))
2959 # Ensure that test_type has all of the desired names and values.
2960 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2961 test_type.CONVERT_TEST_NAME_A)
2962 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2963 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2964 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2965 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2966 # Ensure that test_type only picked up names matching the filter.
2967 self.assertEqual([name for name in dir(test_type)
2968 if name[0:2] not in ('CO', '__')],
2969 [], msg='Names other than CONVERT_TEST_* found.')
2970
2971
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002972if __name__ == '__main__':
2973 unittest.main()