blob: 29a429ccd998f2c1d9c361826bc8b58d2fbced37 [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
Miss Islington (bot)1c798912019-01-30 09:36:51 -08001869 def test_empty_globals(self):
1870 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1871 # when using compile and exec because f_globals is empty
1872 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1873 code = compile(code, "<string>", "exec")
1874 global_ns = {}
1875 local_ls = {}
1876 exec(code, global_ns, local_ls)
1877
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001878
Ethan Furmane8e61272016-08-20 07:19:31 -07001879class TestOrder(unittest.TestCase):
1880
1881 def test_same_members(self):
1882 class Color(Enum):
1883 _order_ = 'red green blue'
1884 red = 1
1885 green = 2
1886 blue = 3
1887
1888 def test_same_members_with_aliases(self):
1889 class Color(Enum):
1890 _order_ = 'red green blue'
1891 red = 1
1892 green = 2
1893 blue = 3
1894 verde = green
1895
1896 def test_same_members_wrong_order(self):
1897 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1898 class Color(Enum):
1899 _order_ = 'red green blue'
1900 red = 1
1901 blue = 3
1902 green = 2
1903
1904 def test_order_has_extra_members(self):
1905 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1906 class Color(Enum):
1907 _order_ = 'red green blue purple'
1908 red = 1
1909 green = 2
1910 blue = 3
1911
1912 def test_order_has_extra_members_with_aliases(self):
1913 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1914 class Color(Enum):
1915 _order_ = 'red green blue purple'
1916 red = 1
1917 green = 2
1918 blue = 3
1919 verde = green
1920
1921 def test_enum_has_extra_members(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
1930 def test_enum_has_extra_members_with_aliases(self):
1931 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1932 class Color(Enum):
1933 _order_ = 'red green blue'
1934 red = 1
1935 green = 2
1936 blue = 3
1937 purple = 4
1938 verde = green
1939
1940
Ethan Furman65a5a472016-09-01 23:55:19 -07001941class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001942 """Tests of the Flags."""
1943
Ethan Furman65a5a472016-09-01 23:55:19 -07001944 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001945 R, W, X = 4, 2, 1
1946
Ethan Furman37151762018-04-11 18:56:25 -07001947 class Color(Flag):
1948 BLACK = 0
1949 RED = 1
1950 GREEN = 2
1951 BLUE = 4
1952 PURPLE = RED|BLUE
1953
Ethan Furman65a5a472016-09-01 23:55:19 -07001954 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001955 RO = 0
1956 WO = 1
1957 RW = 2
1958 AC = 3
1959 CE = 1<<19
1960
1961 def test_str(self):
1962 Perm = self.Perm
1963 self.assertEqual(str(Perm.R), 'Perm.R')
1964 self.assertEqual(str(Perm.W), 'Perm.W')
1965 self.assertEqual(str(Perm.X), 'Perm.X')
1966 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1967 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1968 self.assertEqual(str(Perm(0)), 'Perm.0')
1969 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1970 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1971 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1972 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1973 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1974 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1975
1976 Open = self.Open
1977 self.assertEqual(str(Open.RO), 'Open.RO')
1978 self.assertEqual(str(Open.WO), 'Open.WO')
1979 self.assertEqual(str(Open.AC), 'Open.AC')
1980 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1981 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001982 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001983 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1984 self.assertEqual(str(~Open.AC), 'Open.CE')
1985 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1986 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1987
1988 def test_repr(self):
1989 Perm = self.Perm
1990 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1991 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1992 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1993 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1994 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001995 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001996 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1997 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1998 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1999 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002000 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002001 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2002
2003 Open = self.Open
2004 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2005 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2006 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2007 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2008 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002009 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002010 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2011 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2012 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2013 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2014
2015 def test_or(self):
2016 Perm = self.Perm
2017 for i in Perm:
2018 for j in Perm:
2019 self.assertEqual((i | j), Perm(i.value | j.value))
2020 self.assertEqual((i | j).value, i.value | j.value)
2021 self.assertIs(type(i | j), Perm)
2022 for i in Perm:
2023 self.assertIs(i | i, i)
2024 Open = self.Open
2025 self.assertIs(Open.RO | Open.CE, Open.CE)
2026
2027 def test_and(self):
2028 Perm = self.Perm
2029 RW = Perm.R | Perm.W
2030 RX = Perm.R | Perm.X
2031 WX = Perm.W | Perm.X
2032 RWX = Perm.R | Perm.W | Perm.X
2033 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2034 for i in values:
2035 for j in values:
2036 self.assertEqual((i & j).value, i.value & j.value)
2037 self.assertIs(type(i & j), Perm)
2038 for i in Perm:
2039 self.assertIs(i & i, i)
2040 self.assertIs(i & RWX, i)
2041 self.assertIs(RWX & i, i)
2042 Open = self.Open
2043 self.assertIs(Open.RO & Open.CE, Open.RO)
2044
2045 def test_xor(self):
2046 Perm = self.Perm
2047 for i in Perm:
2048 for j in Perm:
2049 self.assertEqual((i ^ j).value, i.value ^ j.value)
2050 self.assertIs(type(i ^ j), Perm)
2051 for i in Perm:
2052 self.assertIs(i ^ Perm(0), i)
2053 self.assertIs(Perm(0) ^ i, i)
2054 Open = self.Open
2055 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2056 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2057
2058 def test_invert(self):
2059 Perm = self.Perm
2060 RW = Perm.R | Perm.W
2061 RX = Perm.R | Perm.X
2062 WX = Perm.W | Perm.X
2063 RWX = Perm.R | Perm.W | Perm.X
2064 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2065 for i in values:
2066 self.assertIs(type(~i), Perm)
2067 self.assertEqual(~~i, i)
2068 for i in Perm:
2069 self.assertIs(~~i, i)
2070 Open = self.Open
2071 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2072 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2073
Ethan Furman25d94bb2016-09-02 16:32:32 -07002074 def test_bool(self):
2075 Perm = self.Perm
2076 for f in Perm:
2077 self.assertTrue(f)
2078 Open = self.Open
2079 for f in Open:
2080 self.assertEqual(bool(f.value), bool(f))
2081
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002082 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002083 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002084 lst = list(Perm)
2085 self.assertEqual(len(lst), len(Perm))
2086 self.assertEqual(len(Perm), 3, Perm)
2087 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2088 for i, n in enumerate('R W X'.split()):
2089 v = 1<<i
2090 e = Perm(v)
2091 self.assertEqual(e.value, v)
2092 self.assertEqual(type(e.value), int)
2093 self.assertEqual(e.name, n)
2094 self.assertIn(e, Perm)
2095 self.assertIs(type(e), Perm)
2096
2097 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002098 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002099 lst = list(Perm)
2100 self.assertEqual(len(lst), len(Perm))
2101 self.assertEqual(len(Perm), 3, Perm)
2102 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2103 for i, n in enumerate('R W X'.split()):
2104 v = 8<<i
2105 e = Perm(v)
2106 self.assertEqual(e.value, v)
2107 self.assertEqual(type(e.value), int)
2108 self.assertEqual(e.name, n)
2109 self.assertIn(e, Perm)
2110 self.assertIs(type(e), Perm)
2111
2112 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002113 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002114 lst = list(Perm)
2115 self.assertEqual(len(lst), len(Perm))
2116 self.assertEqual(len(Perm), 3, Perm)
2117 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2118 for i, n in enumerate('R W X'.split()):
2119 v = 1<<i
2120 e = Perm(v)
2121 self.assertEqual(e.value, v)
2122 self.assertEqual(type(e.value), int)
2123 self.assertEqual(e.name, n)
2124 self.assertIn(e, Perm)
2125 self.assertIs(type(e), Perm)
2126
2127 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002128 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002129 lst = list(Perm)
2130 self.assertEqual(len(lst), len(Perm))
2131 self.assertEqual(len(Perm), 3, Perm)
2132 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2133 for i, n in enumerate('R W X'.split()):
2134 v = 1<<(2*i+1)
2135 e = Perm(v)
2136 self.assertEqual(e.value, v)
2137 self.assertEqual(type(e.value), int)
2138 self.assertEqual(e.name, n)
2139 self.assertIn(e, Perm)
2140 self.assertIs(type(e), Perm)
2141
2142 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002143 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002144 lst = list(Perm)
2145 self.assertEqual(len(lst), len(Perm))
2146 self.assertEqual(len(Perm), 3, Perm)
2147 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2148 for i, n in enumerate('R W X'.split()):
2149 v = 1<<(2*i+1)
2150 e = Perm(v)
2151 self.assertEqual(e.value, v)
2152 self.assertEqual(type(e.value), int)
2153 self.assertEqual(e.name, n)
2154 self.assertIn(e, Perm)
2155 self.assertIs(type(e), Perm)
2156
Ethan Furman65a5a472016-09-01 23:55:19 -07002157 def test_pickle(self):
2158 if isinstance(FlagStooges, Exception):
2159 raise FlagStooges
2160 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2161 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002162
Ethan Furman37151762018-04-11 18:56:25 -07002163 def test_contains(self):
2164 Open = self.Open
2165 Color = self.Color
2166 self.assertFalse(Color.BLACK in Open)
2167 self.assertFalse(Open.RO in Color)
2168 with self.assertWarns(DeprecationWarning):
2169 self.assertFalse('BLACK' in Color)
2170 with self.assertWarns(DeprecationWarning):
2171 self.assertFalse('RO' in Open)
2172 with self.assertWarns(DeprecationWarning):
2173 self.assertFalse(1 in Color)
2174 with self.assertWarns(DeprecationWarning):
2175 self.assertFalse(1 in Open)
2176
2177 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002178 Perm = self.Perm
2179 R, W, X = Perm
2180 RW = R | W
2181 RX = R | X
2182 WX = W | X
2183 RWX = R | W | X
2184 self.assertTrue(R in RW)
2185 self.assertTrue(R in RX)
2186 self.assertTrue(R in RWX)
2187 self.assertTrue(W in RW)
2188 self.assertTrue(W in WX)
2189 self.assertTrue(W in RWX)
2190 self.assertTrue(X in RX)
2191 self.assertTrue(X in WX)
2192 self.assertTrue(X in RWX)
2193 self.assertFalse(R in WX)
2194 self.assertFalse(W in RX)
2195 self.assertFalse(X in RW)
2196
Ethan Furmanc16595e2016-09-10 23:36:59 -07002197 def test_auto_number(self):
2198 class Color(Flag):
2199 red = auto()
2200 blue = auto()
2201 green = auto()
2202
2203 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2204 self.assertEqual(Color.red.value, 1)
2205 self.assertEqual(Color.blue.value, 2)
2206 self.assertEqual(Color.green.value, 4)
2207
2208 def test_auto_number_garbage(self):
2209 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2210 class Color(Flag):
2211 red = 'not an int'
2212 blue = auto()
2213
Ethan Furman3515dcc2016-09-18 13:15:41 -07002214 def test_cascading_failure(self):
2215 class Bizarre(Flag):
2216 c = 3
2217 d = 4
2218 f = 6
2219 # Bizarre.c | Bizarre.d
2220 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2221 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2222 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2223 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2224 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2225 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2226
2227 def test_duplicate_auto(self):
2228 class Dupes(Enum):
2229 first = primero = auto()
2230 second = auto()
2231 third = auto()
2232 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2233
2234 def test_bizarre(self):
2235 class Bizarre(Flag):
2236 b = 3
2237 c = 4
2238 d = 6
2239 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2240
Ethan Furman0c076ca2018-09-21 22:26:32 -07002241 def test_multiple_mixin(self):
2242 class AllMixin:
2243 @classproperty
2244 def ALL(cls):
2245 members = list(cls)
2246 all_value = None
2247 if members:
2248 all_value = members[0]
2249 for member in members[1:]:
2250 all_value |= member
2251 cls.ALL = all_value
2252 return all_value
2253 class StrMixin:
2254 def __str__(self):
2255 return self._name_.lower()
2256 class Color(AllMixin, 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), 'Color.BLUE')
2265 class Color(AllMixin, StrMixin, 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 class Color(StrMixin, AllMixin, Flag):
2275 RED = auto()
2276 GREEN = auto()
2277 BLUE = auto()
2278 self.assertEqual(Color.RED.value, 1)
2279 self.assertEqual(Color.GREEN.value, 2)
2280 self.assertEqual(Color.BLUE.value, 4)
2281 self.assertEqual(Color.ALL.value, 7)
2282 self.assertEqual(str(Color.BLUE), 'blue')
2283
Ethan Furman28cf6632017-01-24 12:12:06 -08002284 @support.reap_threads
2285 def test_unique_composite(self):
2286 # override __eq__ to be identity only
2287 class TestFlag(Flag):
2288 one = auto()
2289 two = auto()
2290 three = auto()
2291 four = auto()
2292 five = auto()
2293 six = auto()
2294 seven = auto()
2295 eight = auto()
2296 def __eq__(self, other):
2297 return self is other
2298 def __hash__(self):
2299 return hash(self._value_)
2300 # have multiple threads competing to complete the composite members
2301 seen = set()
2302 failed = False
2303 def cycle_enum():
2304 nonlocal failed
2305 try:
2306 for i in range(256):
2307 seen.add(TestFlag(i))
2308 except Exception:
2309 failed = True
2310 threads = [
2311 threading.Thread(target=cycle_enum)
2312 for _ in range(8)
2313 ]
2314 with support.start_threads(threads):
2315 pass
2316 # check that only 248 members were created
2317 self.assertFalse(
2318 failed,
2319 'at least one thread failed while creating composite members')
2320 self.assertEqual(256, len(seen), 'too many composite members created')
2321
Ethan Furmanc16595e2016-09-10 23:36:59 -07002322
Ethan Furman65a5a472016-09-01 23:55:19 -07002323class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002324 """Tests of the IntFlags."""
2325
Ethan Furman65a5a472016-09-01 23:55:19 -07002326 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002327 X = 1 << 0
2328 W = 1 << 1
2329 R = 1 << 2
2330
Ethan Furman37151762018-04-11 18:56:25 -07002331 class Color(IntFlag):
2332 BLACK = 0
2333 RED = 1
2334 GREEN = 2
2335 BLUE = 4
2336 PURPLE = RED|BLUE
2337
Ethan Furman65a5a472016-09-01 23:55:19 -07002338 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002339 RO = 0
2340 WO = 1
2341 RW = 2
2342 AC = 3
2343 CE = 1<<19
2344
Ethan Furman3515dcc2016-09-18 13:15:41 -07002345 def test_type(self):
2346 Perm = self.Perm
2347 Open = self.Open
2348 for f in Perm:
2349 self.assertTrue(isinstance(f, Perm))
2350 self.assertEqual(f, f.value)
2351 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2352 self.assertEqual(Perm.W | Perm.X, 3)
2353 for f in Open:
2354 self.assertTrue(isinstance(f, Open))
2355 self.assertEqual(f, f.value)
2356 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2357 self.assertEqual(Open.WO | Open.RW, 3)
2358
2359
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002360 def test_str(self):
2361 Perm = self.Perm
2362 self.assertEqual(str(Perm.R), 'Perm.R')
2363 self.assertEqual(str(Perm.W), 'Perm.W')
2364 self.assertEqual(str(Perm.X), 'Perm.X')
2365 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2366 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2367 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2368 self.assertEqual(str(Perm(0)), 'Perm.0')
2369 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002370 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2371 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2372 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2373 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002374 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002375 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2376 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2377 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002378
2379 Open = self.Open
2380 self.assertEqual(str(Open.RO), 'Open.RO')
2381 self.assertEqual(str(Open.WO), 'Open.WO')
2382 self.assertEqual(str(Open.AC), 'Open.AC')
2383 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2384 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2385 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002386 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2387 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2388 self.assertEqual(str(~Open.AC), 'Open.CE')
2389 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2390 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2391 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002392
2393 def test_repr(self):
2394 Perm = self.Perm
2395 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2396 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2397 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2398 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2399 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2400 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002401 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2402 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002403 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2404 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2405 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2406 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002407 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002408 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2409 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2410 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002411
2412 Open = self.Open
2413 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2414 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2415 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2416 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2417 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002418 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002419 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2420 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2421 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2422 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2423 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2424 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002425
2426 def test_or(self):
2427 Perm = self.Perm
2428 for i in Perm:
2429 for j in Perm:
2430 self.assertEqual(i | j, i.value | j.value)
2431 self.assertEqual((i | j).value, i.value | j.value)
2432 self.assertIs(type(i | j), Perm)
2433 for j in range(8):
2434 self.assertEqual(i | j, i.value | j)
2435 self.assertEqual((i | j).value, i.value | j)
2436 self.assertIs(type(i | j), Perm)
2437 self.assertEqual(j | i, j | i.value)
2438 self.assertEqual((j | i).value, j | i.value)
2439 self.assertIs(type(j | i), Perm)
2440 for i in Perm:
2441 self.assertIs(i | i, i)
2442 self.assertIs(i | 0, i)
2443 self.assertIs(0 | i, i)
2444 Open = self.Open
2445 self.assertIs(Open.RO | Open.CE, Open.CE)
2446
2447 def test_and(self):
2448 Perm = self.Perm
2449 RW = Perm.R | Perm.W
2450 RX = Perm.R | Perm.X
2451 WX = Perm.W | Perm.X
2452 RWX = Perm.R | Perm.W | Perm.X
2453 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2454 for i in values:
2455 for j in values:
2456 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2457 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2458 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2459 for j in range(8):
2460 self.assertEqual(i & j, i.value & j)
2461 self.assertEqual((i & j).value, i.value & j)
2462 self.assertIs(type(i & j), Perm)
2463 self.assertEqual(j & i, j & i.value)
2464 self.assertEqual((j & i).value, j & i.value)
2465 self.assertIs(type(j & i), Perm)
2466 for i in Perm:
2467 self.assertIs(i & i, i)
2468 self.assertIs(i & 7, i)
2469 self.assertIs(7 & i, i)
2470 Open = self.Open
2471 self.assertIs(Open.RO & Open.CE, Open.RO)
2472
2473 def test_xor(self):
2474 Perm = self.Perm
2475 for i in Perm:
2476 for j in Perm:
2477 self.assertEqual(i ^ j, i.value ^ j.value)
2478 self.assertEqual((i ^ j).value, i.value ^ j.value)
2479 self.assertIs(type(i ^ j), Perm)
2480 for j in range(8):
2481 self.assertEqual(i ^ j, i.value ^ j)
2482 self.assertEqual((i ^ j).value, i.value ^ j)
2483 self.assertIs(type(i ^ j), Perm)
2484 self.assertEqual(j ^ i, j ^ i.value)
2485 self.assertEqual((j ^ i).value, j ^ i.value)
2486 self.assertIs(type(j ^ i), Perm)
2487 for i in Perm:
2488 self.assertIs(i ^ 0, i)
2489 self.assertIs(0 ^ i, i)
2490 Open = self.Open
2491 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2492 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2493
2494 def test_invert(self):
2495 Perm = self.Perm
2496 RW = Perm.R | Perm.W
2497 RX = Perm.R | Perm.X
2498 WX = Perm.W | Perm.X
2499 RWX = Perm.R | Perm.W | Perm.X
2500 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2501 for i in values:
2502 self.assertEqual(~i, ~i.value)
2503 self.assertEqual((~i).value, ~i.value)
2504 self.assertIs(type(~i), Perm)
2505 self.assertEqual(~~i, i)
2506 for i in Perm:
2507 self.assertIs(~~i, i)
2508 Open = self.Open
2509 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2510 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2511
2512 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002513 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002514 lst = list(Perm)
2515 self.assertEqual(len(lst), len(Perm))
2516 self.assertEqual(len(Perm), 3, Perm)
2517 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2518 for i, n in enumerate('R W X'.split()):
2519 v = 1<<i
2520 e = Perm(v)
2521 self.assertEqual(e.value, v)
2522 self.assertEqual(type(e.value), int)
2523 self.assertEqual(e, v)
2524 self.assertEqual(e.name, n)
2525 self.assertIn(e, Perm)
2526 self.assertIs(type(e), Perm)
2527
2528 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002529 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002530 lst = list(Perm)
2531 self.assertEqual(len(lst), len(Perm))
2532 self.assertEqual(len(Perm), 3, Perm)
2533 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2534 for i, n in enumerate('R W X'.split()):
2535 v = 8<<i
2536 e = Perm(v)
2537 self.assertEqual(e.value, v)
2538 self.assertEqual(type(e.value), int)
2539 self.assertEqual(e, v)
2540 self.assertEqual(e.name, n)
2541 self.assertIn(e, Perm)
2542 self.assertIs(type(e), Perm)
2543
2544 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002545 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002546 lst = list(Perm)
2547 self.assertEqual(len(lst), len(Perm))
2548 self.assertEqual(len(Perm), 3, Perm)
2549 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2550 for i, n in enumerate('R W X'.split()):
2551 v = 1<<i
2552 e = Perm(v)
2553 self.assertEqual(e.value, v)
2554 self.assertEqual(type(e.value), int)
2555 self.assertEqual(e, v)
2556 self.assertEqual(e.name, n)
2557 self.assertIn(e, Perm)
2558 self.assertIs(type(e), Perm)
2559
2560 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002561 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002562 lst = list(Perm)
2563 self.assertEqual(len(lst), len(Perm))
2564 self.assertEqual(len(Perm), 3, Perm)
2565 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2566 for i, n in enumerate('R W X'.split()):
2567 v = 1<<(2*i+1)
2568 e = Perm(v)
2569 self.assertEqual(e.value, v)
2570 self.assertEqual(type(e.value), int)
2571 self.assertEqual(e, v)
2572 self.assertEqual(e.name, n)
2573 self.assertIn(e, Perm)
2574 self.assertIs(type(e), Perm)
2575
2576 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002577 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002578 lst = list(Perm)
2579 self.assertEqual(len(lst), len(Perm))
2580 self.assertEqual(len(Perm), 3, Perm)
2581 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2582 for i, n in enumerate('R W X'.split()):
2583 v = 1<<(2*i+1)
2584 e = Perm(v)
2585 self.assertEqual(e.value, v)
2586 self.assertEqual(type(e.value), int)
2587 self.assertEqual(e, v)
2588 self.assertEqual(e.name, n)
2589 self.assertIn(e, Perm)
2590 self.assertIs(type(e), Perm)
2591
2592
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002593 def test_programatic_function_from_empty_list(self):
2594 Perm = enum.IntFlag('Perm', [])
2595 lst = list(Perm)
2596 self.assertEqual(len(lst), len(Perm))
2597 self.assertEqual(len(Perm), 0, Perm)
2598 Thing = enum.Enum('Thing', [])
2599 lst = list(Thing)
2600 self.assertEqual(len(lst), len(Thing))
2601 self.assertEqual(len(Thing), 0, Thing)
2602
2603
2604 def test_programatic_function_from_empty_tuple(self):
2605 Perm = enum.IntFlag('Perm', ())
2606 lst = list(Perm)
2607 self.assertEqual(len(lst), len(Perm))
2608 self.assertEqual(len(Perm), 0, Perm)
2609 Thing = enum.Enum('Thing', ())
2610 self.assertEqual(len(lst), len(Thing))
2611 self.assertEqual(len(Thing), 0, Thing)
2612
Ethan Furman37151762018-04-11 18:56:25 -07002613 def test_contains(self):
2614 Color = self.Color
2615 Open = self.Open
2616 self.assertTrue(Color.GREEN in Color)
2617 self.assertTrue(Open.RW in Open)
2618 self.assertFalse(Color.GREEN in Open)
2619 self.assertFalse(Open.RW in Color)
2620 with self.assertWarns(DeprecationWarning):
2621 self.assertFalse('GREEN' in Color)
2622 with self.assertWarns(DeprecationWarning):
2623 self.assertFalse('RW' in Open)
2624 with self.assertWarns(DeprecationWarning):
2625 self.assertFalse(2 in Color)
2626 with self.assertWarns(DeprecationWarning):
2627 self.assertFalse(2 in Open)
2628
2629 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002630 Perm = self.Perm
2631 R, W, X = Perm
2632 RW = R | W
2633 RX = R | X
2634 WX = W | X
2635 RWX = R | W | X
2636 self.assertTrue(R in RW)
2637 self.assertTrue(R in RX)
2638 self.assertTrue(R in RWX)
2639 self.assertTrue(W in RW)
2640 self.assertTrue(W in WX)
2641 self.assertTrue(W in RWX)
2642 self.assertTrue(X in RX)
2643 self.assertTrue(X in WX)
2644 self.assertTrue(X in RWX)
2645 self.assertFalse(R in WX)
2646 self.assertFalse(W in RX)
2647 self.assertFalse(X in RW)
Ethan Furman37151762018-04-11 18:56:25 -07002648 with self.assertWarns(DeprecationWarning):
2649 self.assertFalse('swallow' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002650
Ethan Furman25d94bb2016-09-02 16:32:32 -07002651 def test_bool(self):
2652 Perm = self.Perm
2653 for f in Perm:
2654 self.assertTrue(f)
2655 Open = self.Open
2656 for f in Open:
2657 self.assertEqual(bool(f.value), bool(f))
2658
Ethan Furman0c076ca2018-09-21 22:26:32 -07002659 def test_multiple_mixin(self):
2660 class AllMixin:
2661 @classproperty
2662 def ALL(cls):
2663 members = list(cls)
2664 all_value = None
2665 if members:
2666 all_value = members[0]
2667 for member in members[1:]:
2668 all_value |= member
2669 cls.ALL = all_value
2670 return all_value
2671 class StrMixin:
2672 def __str__(self):
2673 return self._name_.lower()
2674 class Color(AllMixin, 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), 'Color.BLUE')
2683 class Color(AllMixin, StrMixin, 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 class Color(StrMixin, AllMixin, IntFlag):
2693 RED = auto()
2694 GREEN = auto()
2695 BLUE = auto()
2696 self.assertEqual(Color.RED.value, 1)
2697 self.assertEqual(Color.GREEN.value, 2)
2698 self.assertEqual(Color.BLUE.value, 4)
2699 self.assertEqual(Color.ALL.value, 7)
2700 self.assertEqual(str(Color.BLUE), 'blue')
2701
Ethan Furman28cf6632017-01-24 12:12:06 -08002702 @support.reap_threads
2703 def test_unique_composite(self):
2704 # override __eq__ to be identity only
2705 class TestFlag(IntFlag):
2706 one = auto()
2707 two = auto()
2708 three = auto()
2709 four = auto()
2710 five = auto()
2711 six = auto()
2712 seven = auto()
2713 eight = auto()
2714 def __eq__(self, other):
2715 return self is other
2716 def __hash__(self):
2717 return hash(self._value_)
2718 # have multiple threads competing to complete the composite members
2719 seen = set()
2720 failed = False
2721 def cycle_enum():
2722 nonlocal failed
2723 try:
2724 for i in range(256):
2725 seen.add(TestFlag(i))
2726 except Exception:
2727 failed = True
2728 threads = [
2729 threading.Thread(target=cycle_enum)
2730 for _ in range(8)
2731 ]
2732 with support.start_threads(threads):
2733 pass
2734 # check that only 248 members were created
2735 self.assertFalse(
2736 failed,
2737 'at least one thread failed while creating composite members')
2738 self.assertEqual(256, len(seen), 'too many composite members created')
2739
2740
Miss Islington (bot)8755f0a2019-03-08 13:44:21 -08002741class TestEmptyAndNonLatinStrings(unittest.TestCase):
2742
2743 def test_empty_string(self):
2744 with self.assertRaises(ValueError):
2745 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2746
2747 def test_non_latin_character_string(self):
2748 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2749 item = getattr(greek_abc, '\u03B1')
2750 self.assertEqual(item.value, 1)
2751
2752 def test_non_latin_number_string(self):
2753 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2754 item = getattr(hebrew_123, '\u05D0')
2755 self.assertEqual(item.value, 1)
2756
2757
Ethan Furmanf24bb352013-07-18 17:05:39 -07002758class TestUnique(unittest.TestCase):
2759
2760 def test_unique_clean(self):
2761 @unique
2762 class Clean(Enum):
2763 one = 1
2764 two = 'dos'
2765 tres = 4.0
2766 @unique
2767 class Cleaner(IntEnum):
2768 single = 1
2769 double = 2
2770 triple = 3
2771
2772 def test_unique_dirty(self):
2773 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2774 @unique
2775 class Dirty(Enum):
2776 one = 1
2777 two = 'dos'
2778 tres = 1
2779 with self.assertRaisesRegex(
2780 ValueError,
2781 'double.*single.*turkey.*triple',
2782 ):
2783 @unique
2784 class Dirtier(IntEnum):
2785 single = 1
2786 double = 1
2787 triple = 3
2788 turkey = 3
2789
Ethan Furman3803ad42016-05-01 10:03:53 -07002790 def test_unique_with_name(self):
2791 @unique
2792 class Silly(Enum):
2793 one = 1
2794 two = 'dos'
2795 name = 3
2796 @unique
2797 class Sillier(IntEnum):
2798 single = 1
2799 name = 2
2800 triple = 3
2801 value = 4
2802
Ethan Furmanf24bb352013-07-18 17:05:39 -07002803
Ethan Furman0c076ca2018-09-21 22:26:32 -07002804
Ethan Furman3323da92015-04-11 09:39:59 -07002805expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002806Help on class Color in module %s:
2807
2808class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002809 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2810 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002811 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002812 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002813 | Method resolution order:
2814 | Color
2815 | enum.Enum
2816 | builtins.object
2817 |\x20\x20
2818 | Data and other attributes defined here:
2819 |\x20\x20
2820 | blue = <Color.blue: 3>
2821 |\x20\x20
2822 | green = <Color.green: 2>
2823 |\x20\x20
2824 | red = <Color.red: 1>
2825 |\x20\x20
2826 | ----------------------------------------------------------------------
2827 | Data descriptors inherited from enum.Enum:
2828 |\x20\x20
2829 | name
2830 | The name of the Enum member.
2831 |\x20\x20
2832 | value
2833 | The value of the Enum member.
2834 |\x20\x20
2835 | ----------------------------------------------------------------------
2836 | Data descriptors inherited from enum.EnumMeta:
2837 |\x20\x20
2838 | __members__
2839 | Returns a mapping of member name->value.
2840 |\x20\x20\x20\x20\x20\x20
2841 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002842 | is a read-only view of the internal mapping."""
2843
2844expected_help_output_without_docs = """\
2845Help on class Color in module %s:
2846
2847class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002848 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2849 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002850 | Method resolution order:
2851 | Color
2852 | enum.Enum
2853 | builtins.object
2854 |\x20\x20
2855 | Data and other attributes defined here:
2856 |\x20\x20
2857 | blue = <Color.blue: 3>
2858 |\x20\x20
2859 | green = <Color.green: 2>
2860 |\x20\x20
2861 | red = <Color.red: 1>
2862 |\x20\x20
2863 | ----------------------------------------------------------------------
2864 | Data descriptors inherited from enum.Enum:
2865 |\x20\x20
2866 | name
2867 |\x20\x20
2868 | value
2869 |\x20\x20
2870 | ----------------------------------------------------------------------
2871 | Data descriptors inherited from enum.EnumMeta:
2872 |\x20\x20
2873 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002874
2875class TestStdLib(unittest.TestCase):
2876
Ethan Furman48a724f2015-04-11 23:23:06 -07002877 maxDiff = None
2878
Ethan Furman5875d742013-10-21 20:45:55 -07002879 class Color(Enum):
2880 red = 1
2881 green = 2
2882 blue = 3
2883
2884 def test_pydoc(self):
2885 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002886 if StrEnum.__doc__ is None:
2887 expected_text = expected_help_output_without_docs % __name__
2888 else:
2889 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002890 output = StringIO()
2891 helper = pydoc.Helper(output=output)
2892 helper(self.Color)
2893 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002894 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002895
2896 def test_inspect_getmembers(self):
2897 values = dict((
2898 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002899 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002900 ('__members__', self.Color.__members__),
2901 ('__module__', __name__),
2902 ('blue', self.Color.blue),
2903 ('green', self.Color.green),
2904 ('name', Enum.__dict__['name']),
2905 ('red', self.Color.red),
2906 ('value', Enum.__dict__['value']),
2907 ))
2908 result = dict(inspect.getmembers(self.Color))
2909 self.assertEqual(values.keys(), result.keys())
2910 failed = False
2911 for k in values.keys():
2912 if result[k] != values[k]:
2913 print()
2914 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2915 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2916 failed = True
2917 if failed:
2918 self.fail("result does not equal expected, see print above")
2919
2920 def test_inspect_classify_class_attrs(self):
2921 # indirectly test __objclass__
2922 from inspect import Attribute
2923 values = [
2924 Attribute(name='__class__', kind='data',
2925 defining_class=object, object=EnumMeta),
2926 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002927 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002928 Attribute(name='__members__', kind='property',
2929 defining_class=EnumMeta, object=EnumMeta.__members__),
2930 Attribute(name='__module__', kind='data',
2931 defining_class=self.Color, object=__name__),
2932 Attribute(name='blue', kind='data',
2933 defining_class=self.Color, object=self.Color.blue),
2934 Attribute(name='green', kind='data',
2935 defining_class=self.Color, object=self.Color.green),
2936 Attribute(name='red', kind='data',
2937 defining_class=self.Color, object=self.Color.red),
2938 Attribute(name='name', kind='data',
2939 defining_class=Enum, object=Enum.__dict__['name']),
2940 Attribute(name='value', kind='data',
2941 defining_class=Enum, object=Enum.__dict__['value']),
2942 ]
2943 values.sort(key=lambda item: item.name)
2944 result = list(inspect.classify_class_attrs(self.Color))
2945 result.sort(key=lambda item: item.name)
2946 failed = False
2947 for v, r in zip(values, result):
2948 if r != v:
2949 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2950 failed = True
2951 if failed:
2952 self.fail("result does not equal expected, see print above")
2953
Martin Panter19e69c52015-11-14 12:46:42 +00002954
2955class MiscTestCase(unittest.TestCase):
2956 def test__all__(self):
2957 support.check__all__(self, enum)
2958
2959
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002960# These are unordered here on purpose to ensure that declaration order
2961# makes no difference.
2962CONVERT_TEST_NAME_D = 5
2963CONVERT_TEST_NAME_C = 5
2964CONVERT_TEST_NAME_B = 5
2965CONVERT_TEST_NAME_A = 5 # This one should sort first.
2966CONVERT_TEST_NAME_E = 5
2967CONVERT_TEST_NAME_F = 5
2968
2969class TestIntEnumConvert(unittest.TestCase):
2970 def test_convert_value_lookup_priority(self):
2971 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002972 'UnittestConvert',
2973 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002974 filter=lambda x: x.startswith('CONVERT_TEST_'))
2975 # We don't want the reverse lookup value to vary when there are
2976 # multiple possible names for a given value. It should always
2977 # report the first lexigraphical name in that case.
2978 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2979
2980 def test_convert(self):
2981 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002982 'UnittestConvert',
2983 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002984 filter=lambda x: x.startswith('CONVERT_TEST_'))
2985 # Ensure that test_type has all of the desired names and values.
2986 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2987 test_type.CONVERT_TEST_NAME_A)
2988 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2989 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2990 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2991 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2992 # Ensure that test_type only picked up names matching the filter.
2993 self.assertEqual([name for name in dir(test_type)
2994 if name[0:2] not in ('CO', '__')],
2995 [], msg='Names other than CONVERT_TEST_* found.')
2996
2997
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002998if __name__ == '__main__':
2999 unittest.main()