blob: 6c147d7ca6e1f47fb7eeae01627023eaab7b1e8e [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
Ethan Furman0c076ca2018-09-21 22:26:32 -07001720 def test_multiple_mixin(self):
1721 class MaxMixin:
1722 @classproperty
1723 def MAX(cls):
1724 max = len(cls)
1725 cls.MAX = max
1726 return max
1727 class StrMixin:
1728 def __str__(self):
1729 return self._name_.lower()
1730 class SomeEnum(Enum):
1731 def behavior(self):
1732 return 'booyah'
1733 class AnotherEnum(Enum):
1734 def behavior(self):
1735 return 'nuhuh!'
1736 def social(self):
1737 return "what's up?"
1738 class Color(MaxMixin, Enum):
1739 RED = auto()
1740 GREEN = auto()
1741 BLUE = auto()
1742 self.assertEqual(Color.RED.value, 1)
1743 self.assertEqual(Color.GREEN.value, 2)
1744 self.assertEqual(Color.BLUE.value, 3)
1745 self.assertEqual(Color.MAX, 3)
1746 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1747 class Color(MaxMixin, StrMixin, Enum):
1748 RED = auto()
1749 GREEN = auto()
1750 BLUE = auto()
1751 self.assertEqual(Color.RED.value, 1)
1752 self.assertEqual(Color.GREEN.value, 2)
1753 self.assertEqual(Color.BLUE.value, 3)
1754 self.assertEqual(Color.MAX, 3)
1755 self.assertEqual(str(Color.BLUE), 'blue')
1756 class Color(StrMixin, MaxMixin, Enum):
1757 RED = auto()
1758 GREEN = auto()
1759 BLUE = auto()
1760 self.assertEqual(Color.RED.value, 1)
1761 self.assertEqual(Color.GREEN.value, 2)
1762 self.assertEqual(Color.BLUE.value, 3)
1763 self.assertEqual(Color.MAX, 3)
1764 self.assertEqual(str(Color.BLUE), 'blue')
1765 class CoolColor(StrMixin, SomeEnum, Enum):
1766 RED = auto()
1767 GREEN = auto()
1768 BLUE = auto()
1769 self.assertEqual(CoolColor.RED.value, 1)
1770 self.assertEqual(CoolColor.GREEN.value, 2)
1771 self.assertEqual(CoolColor.BLUE.value, 3)
1772 self.assertEqual(str(CoolColor.BLUE), 'blue')
1773 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1774 class CoolerColor(StrMixin, AnotherEnum, Enum):
1775 RED = auto()
1776 GREEN = auto()
1777 BLUE = auto()
1778 self.assertEqual(CoolerColor.RED.value, 1)
1779 self.assertEqual(CoolerColor.GREEN.value, 2)
1780 self.assertEqual(CoolerColor.BLUE.value, 3)
1781 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1782 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1783 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1784 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1785 RED = auto()
1786 GREEN = auto()
1787 BLUE = auto()
1788 self.assertEqual(CoolestColor.RED.value, 1)
1789 self.assertEqual(CoolestColor.GREEN.value, 2)
1790 self.assertEqual(CoolestColor.BLUE.value, 3)
1791 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1792 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1793 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1794 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1795 RED = auto()
1796 GREEN = auto()
1797 BLUE = auto()
1798 self.assertEqual(ConfusedColor.RED.value, 1)
1799 self.assertEqual(ConfusedColor.GREEN.value, 2)
1800 self.assertEqual(ConfusedColor.BLUE.value, 3)
1801 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1802 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1803 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1804 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1805 RED = auto()
1806 GREEN = auto()
1807 BLUE = auto()
1808 self.assertEqual(ReformedColor.RED.value, 1)
1809 self.assertEqual(ReformedColor.GREEN.value, 2)
1810 self.assertEqual(ReformedColor.BLUE.value, 3)
1811 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1812 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1813 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1814 self.assertTrue(issubclass(ReformedColor, int))
1815
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001816
Ethan Furmane8e61272016-08-20 07:19:31 -07001817class TestOrder(unittest.TestCase):
1818
1819 def test_same_members(self):
1820 class Color(Enum):
1821 _order_ = 'red green blue'
1822 red = 1
1823 green = 2
1824 blue = 3
1825
1826 def test_same_members_with_aliases(self):
1827 class Color(Enum):
1828 _order_ = 'red green blue'
1829 red = 1
1830 green = 2
1831 blue = 3
1832 verde = green
1833
1834 def test_same_members_wrong_order(self):
1835 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1836 class Color(Enum):
1837 _order_ = 'red green blue'
1838 red = 1
1839 blue = 3
1840 green = 2
1841
1842 def test_order_has_extra_members(self):
1843 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1844 class Color(Enum):
1845 _order_ = 'red green blue purple'
1846 red = 1
1847 green = 2
1848 blue = 3
1849
1850 def test_order_has_extra_members_with_aliases(self):
1851 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1852 class Color(Enum):
1853 _order_ = 'red green blue purple'
1854 red = 1
1855 green = 2
1856 blue = 3
1857 verde = green
1858
1859 def test_enum_has_extra_members(self):
1860 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1861 class Color(Enum):
1862 _order_ = 'red green blue'
1863 red = 1
1864 green = 2
1865 blue = 3
1866 purple = 4
1867
1868 def test_enum_has_extra_members_with_aliases(self):
1869 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1870 class Color(Enum):
1871 _order_ = 'red green blue'
1872 red = 1
1873 green = 2
1874 blue = 3
1875 purple = 4
1876 verde = green
1877
1878
Ethan Furman65a5a472016-09-01 23:55:19 -07001879class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001880 """Tests of the Flags."""
1881
Ethan Furman65a5a472016-09-01 23:55:19 -07001882 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001883 R, W, X = 4, 2, 1
1884
Ethan Furman37151762018-04-11 18:56:25 -07001885 class Color(Flag):
1886 BLACK = 0
1887 RED = 1
1888 GREEN = 2
1889 BLUE = 4
1890 PURPLE = RED|BLUE
1891
Ethan Furman65a5a472016-09-01 23:55:19 -07001892 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001893 RO = 0
1894 WO = 1
1895 RW = 2
1896 AC = 3
1897 CE = 1<<19
1898
1899 def test_str(self):
1900 Perm = self.Perm
1901 self.assertEqual(str(Perm.R), 'Perm.R')
1902 self.assertEqual(str(Perm.W), 'Perm.W')
1903 self.assertEqual(str(Perm.X), 'Perm.X')
1904 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1905 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1906 self.assertEqual(str(Perm(0)), 'Perm.0')
1907 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1908 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1909 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1910 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1911 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1912 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1913
1914 Open = self.Open
1915 self.assertEqual(str(Open.RO), 'Open.RO')
1916 self.assertEqual(str(Open.WO), 'Open.WO')
1917 self.assertEqual(str(Open.AC), 'Open.AC')
1918 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1919 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001920 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001921 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1922 self.assertEqual(str(~Open.AC), 'Open.CE')
1923 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1924 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1925
1926 def test_repr(self):
1927 Perm = self.Perm
1928 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1929 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1930 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1931 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1932 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001933 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001934 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1935 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1936 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1937 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001938 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001939 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1940
1941 Open = self.Open
1942 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1943 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1944 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1945 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1946 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001947 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001948 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1949 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1950 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1951 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1952
1953 def test_or(self):
1954 Perm = self.Perm
1955 for i in Perm:
1956 for j in Perm:
1957 self.assertEqual((i | j), Perm(i.value | j.value))
1958 self.assertEqual((i | j).value, i.value | j.value)
1959 self.assertIs(type(i | j), Perm)
1960 for i in Perm:
1961 self.assertIs(i | i, i)
1962 Open = self.Open
1963 self.assertIs(Open.RO | Open.CE, Open.CE)
1964
1965 def test_and(self):
1966 Perm = self.Perm
1967 RW = Perm.R | Perm.W
1968 RX = Perm.R | Perm.X
1969 WX = Perm.W | Perm.X
1970 RWX = Perm.R | Perm.W | Perm.X
1971 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1972 for i in values:
1973 for j in values:
1974 self.assertEqual((i & j).value, i.value & j.value)
1975 self.assertIs(type(i & j), Perm)
1976 for i in Perm:
1977 self.assertIs(i & i, i)
1978 self.assertIs(i & RWX, i)
1979 self.assertIs(RWX & i, i)
1980 Open = self.Open
1981 self.assertIs(Open.RO & Open.CE, Open.RO)
1982
1983 def test_xor(self):
1984 Perm = self.Perm
1985 for i in Perm:
1986 for j in Perm:
1987 self.assertEqual((i ^ j).value, i.value ^ j.value)
1988 self.assertIs(type(i ^ j), Perm)
1989 for i in Perm:
1990 self.assertIs(i ^ Perm(0), i)
1991 self.assertIs(Perm(0) ^ i, i)
1992 Open = self.Open
1993 self.assertIs(Open.RO ^ Open.CE, Open.CE)
1994 self.assertIs(Open.CE ^ Open.CE, Open.RO)
1995
1996 def test_invert(self):
1997 Perm = self.Perm
1998 RW = Perm.R | Perm.W
1999 RX = Perm.R | Perm.X
2000 WX = Perm.W | Perm.X
2001 RWX = Perm.R | Perm.W | Perm.X
2002 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2003 for i in values:
2004 self.assertIs(type(~i), Perm)
2005 self.assertEqual(~~i, i)
2006 for i in Perm:
2007 self.assertIs(~~i, i)
2008 Open = self.Open
2009 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2010 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2011
Ethan Furman25d94bb2016-09-02 16:32:32 -07002012 def test_bool(self):
2013 Perm = self.Perm
2014 for f in Perm:
2015 self.assertTrue(f)
2016 Open = self.Open
2017 for f in Open:
2018 self.assertEqual(bool(f.value), bool(f))
2019
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002020 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002021 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002022 lst = list(Perm)
2023 self.assertEqual(len(lst), len(Perm))
2024 self.assertEqual(len(Perm), 3, Perm)
2025 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2026 for i, n in enumerate('R W X'.split()):
2027 v = 1<<i
2028 e = Perm(v)
2029 self.assertEqual(e.value, v)
2030 self.assertEqual(type(e.value), int)
2031 self.assertEqual(e.name, n)
2032 self.assertIn(e, Perm)
2033 self.assertIs(type(e), Perm)
2034
2035 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002036 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002037 lst = list(Perm)
2038 self.assertEqual(len(lst), len(Perm))
2039 self.assertEqual(len(Perm), 3, Perm)
2040 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2041 for i, n in enumerate('R W X'.split()):
2042 v = 8<<i
2043 e = Perm(v)
2044 self.assertEqual(e.value, v)
2045 self.assertEqual(type(e.value), int)
2046 self.assertEqual(e.name, n)
2047 self.assertIn(e, Perm)
2048 self.assertIs(type(e), Perm)
2049
2050 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002051 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002052 lst = list(Perm)
2053 self.assertEqual(len(lst), len(Perm))
2054 self.assertEqual(len(Perm), 3, Perm)
2055 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2056 for i, n in enumerate('R W X'.split()):
2057 v = 1<<i
2058 e = Perm(v)
2059 self.assertEqual(e.value, v)
2060 self.assertEqual(type(e.value), int)
2061 self.assertEqual(e.name, n)
2062 self.assertIn(e, Perm)
2063 self.assertIs(type(e), Perm)
2064
2065 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002066 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002067 lst = list(Perm)
2068 self.assertEqual(len(lst), len(Perm))
2069 self.assertEqual(len(Perm), 3, Perm)
2070 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2071 for i, n in enumerate('R W X'.split()):
2072 v = 1<<(2*i+1)
2073 e = Perm(v)
2074 self.assertEqual(e.value, v)
2075 self.assertEqual(type(e.value), int)
2076 self.assertEqual(e.name, n)
2077 self.assertIn(e, Perm)
2078 self.assertIs(type(e), Perm)
2079
2080 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002081 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002082 lst = list(Perm)
2083 self.assertEqual(len(lst), len(Perm))
2084 self.assertEqual(len(Perm), 3, Perm)
2085 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2086 for i, n in enumerate('R W X'.split()):
2087 v = 1<<(2*i+1)
2088 e = Perm(v)
2089 self.assertEqual(e.value, v)
2090 self.assertEqual(type(e.value), int)
2091 self.assertEqual(e.name, n)
2092 self.assertIn(e, Perm)
2093 self.assertIs(type(e), Perm)
2094
Ethan Furman65a5a472016-09-01 23:55:19 -07002095 def test_pickle(self):
2096 if isinstance(FlagStooges, Exception):
2097 raise FlagStooges
2098 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2099 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002100
Ethan Furman37151762018-04-11 18:56:25 -07002101 def test_contains(self):
2102 Open = self.Open
2103 Color = self.Color
2104 self.assertFalse(Color.BLACK in Open)
2105 self.assertFalse(Open.RO in Color)
2106 with self.assertWarns(DeprecationWarning):
2107 self.assertFalse('BLACK' in Color)
2108 with self.assertWarns(DeprecationWarning):
2109 self.assertFalse('RO' in Open)
2110 with self.assertWarns(DeprecationWarning):
2111 self.assertFalse(1 in Color)
2112 with self.assertWarns(DeprecationWarning):
2113 self.assertFalse(1 in Open)
2114
2115 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002116 Perm = self.Perm
2117 R, W, X = Perm
2118 RW = R | W
2119 RX = R | X
2120 WX = W | X
2121 RWX = R | W | X
2122 self.assertTrue(R in RW)
2123 self.assertTrue(R in RX)
2124 self.assertTrue(R in RWX)
2125 self.assertTrue(W in RW)
2126 self.assertTrue(W in WX)
2127 self.assertTrue(W in RWX)
2128 self.assertTrue(X in RX)
2129 self.assertTrue(X in WX)
2130 self.assertTrue(X in RWX)
2131 self.assertFalse(R in WX)
2132 self.assertFalse(W in RX)
2133 self.assertFalse(X in RW)
2134
Ethan Furmanc16595e2016-09-10 23:36:59 -07002135 def test_auto_number(self):
2136 class Color(Flag):
2137 red = auto()
2138 blue = auto()
2139 green = auto()
2140
2141 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2142 self.assertEqual(Color.red.value, 1)
2143 self.assertEqual(Color.blue.value, 2)
2144 self.assertEqual(Color.green.value, 4)
2145
2146 def test_auto_number_garbage(self):
2147 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2148 class Color(Flag):
2149 red = 'not an int'
2150 blue = auto()
2151
Ethan Furman3515dcc2016-09-18 13:15:41 -07002152 def test_cascading_failure(self):
2153 class Bizarre(Flag):
2154 c = 3
2155 d = 4
2156 f = 6
2157 # Bizarre.c | Bizarre.d
2158 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2159 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2160 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2161 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2162 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2163 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2164
2165 def test_duplicate_auto(self):
2166 class Dupes(Enum):
2167 first = primero = auto()
2168 second = auto()
2169 third = auto()
2170 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2171
2172 def test_bizarre(self):
2173 class Bizarre(Flag):
2174 b = 3
2175 c = 4
2176 d = 6
2177 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2178
Ethan Furman0c076ca2018-09-21 22:26:32 -07002179 def test_multiple_mixin(self):
2180 class AllMixin:
2181 @classproperty
2182 def ALL(cls):
2183 members = list(cls)
2184 all_value = None
2185 if members:
2186 all_value = members[0]
2187 for member in members[1:]:
2188 all_value |= member
2189 cls.ALL = all_value
2190 return all_value
2191 class StrMixin:
2192 def __str__(self):
2193 return self._name_.lower()
2194 class Color(AllMixin, Flag):
2195 RED = auto()
2196 GREEN = auto()
2197 BLUE = auto()
2198 self.assertEqual(Color.RED.value, 1)
2199 self.assertEqual(Color.GREEN.value, 2)
2200 self.assertEqual(Color.BLUE.value, 4)
2201 self.assertEqual(Color.ALL.value, 7)
2202 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2203 class Color(AllMixin, StrMixin, Flag):
2204 RED = auto()
2205 GREEN = auto()
2206 BLUE = auto()
2207 self.assertEqual(Color.RED.value, 1)
2208 self.assertEqual(Color.GREEN.value, 2)
2209 self.assertEqual(Color.BLUE.value, 4)
2210 self.assertEqual(Color.ALL.value, 7)
2211 self.assertEqual(str(Color.BLUE), 'blue')
2212 class Color(StrMixin, AllMixin, Flag):
2213 RED = auto()
2214 GREEN = auto()
2215 BLUE = auto()
2216 self.assertEqual(Color.RED.value, 1)
2217 self.assertEqual(Color.GREEN.value, 2)
2218 self.assertEqual(Color.BLUE.value, 4)
2219 self.assertEqual(Color.ALL.value, 7)
2220 self.assertEqual(str(Color.BLUE), 'blue')
2221
Ethan Furman28cf6632017-01-24 12:12:06 -08002222 @support.reap_threads
2223 def test_unique_composite(self):
2224 # override __eq__ to be identity only
2225 class TestFlag(Flag):
2226 one = auto()
2227 two = auto()
2228 three = auto()
2229 four = auto()
2230 five = auto()
2231 six = auto()
2232 seven = auto()
2233 eight = auto()
2234 def __eq__(self, other):
2235 return self is other
2236 def __hash__(self):
2237 return hash(self._value_)
2238 # have multiple threads competing to complete the composite members
2239 seen = set()
2240 failed = False
2241 def cycle_enum():
2242 nonlocal failed
2243 try:
2244 for i in range(256):
2245 seen.add(TestFlag(i))
2246 except Exception:
2247 failed = True
2248 threads = [
2249 threading.Thread(target=cycle_enum)
2250 for _ in range(8)
2251 ]
2252 with support.start_threads(threads):
2253 pass
2254 # check that only 248 members were created
2255 self.assertFalse(
2256 failed,
2257 'at least one thread failed while creating composite members')
2258 self.assertEqual(256, len(seen), 'too many composite members created')
2259
Ethan Furmanc16595e2016-09-10 23:36:59 -07002260
Ethan Furman65a5a472016-09-01 23:55:19 -07002261class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002262 """Tests of the IntFlags."""
2263
Ethan Furman65a5a472016-09-01 23:55:19 -07002264 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002265 X = 1 << 0
2266 W = 1 << 1
2267 R = 1 << 2
2268
Ethan Furman37151762018-04-11 18:56:25 -07002269 class Color(IntFlag):
2270 BLACK = 0
2271 RED = 1
2272 GREEN = 2
2273 BLUE = 4
2274 PURPLE = RED|BLUE
2275
Ethan Furman65a5a472016-09-01 23:55:19 -07002276 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002277 RO = 0
2278 WO = 1
2279 RW = 2
2280 AC = 3
2281 CE = 1<<19
2282
Ethan Furman3515dcc2016-09-18 13:15:41 -07002283 def test_type(self):
2284 Perm = self.Perm
2285 Open = self.Open
2286 for f in Perm:
2287 self.assertTrue(isinstance(f, Perm))
2288 self.assertEqual(f, f.value)
2289 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2290 self.assertEqual(Perm.W | Perm.X, 3)
2291 for f in Open:
2292 self.assertTrue(isinstance(f, Open))
2293 self.assertEqual(f, f.value)
2294 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2295 self.assertEqual(Open.WO | Open.RW, 3)
2296
2297
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002298 def test_str(self):
2299 Perm = self.Perm
2300 self.assertEqual(str(Perm.R), 'Perm.R')
2301 self.assertEqual(str(Perm.W), 'Perm.W')
2302 self.assertEqual(str(Perm.X), 'Perm.X')
2303 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2304 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2305 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2306 self.assertEqual(str(Perm(0)), 'Perm.0')
2307 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002308 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2309 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2310 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2311 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002312 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002313 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2314 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2315 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002316
2317 Open = self.Open
2318 self.assertEqual(str(Open.RO), 'Open.RO')
2319 self.assertEqual(str(Open.WO), 'Open.WO')
2320 self.assertEqual(str(Open.AC), 'Open.AC')
2321 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2322 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2323 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002324 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2325 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2326 self.assertEqual(str(~Open.AC), 'Open.CE')
2327 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2328 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2329 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002330
2331 def test_repr(self):
2332 Perm = self.Perm
2333 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2334 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2335 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2336 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2337 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2338 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002339 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2340 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002341 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2342 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2343 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2344 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002345 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002346 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2347 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2348 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002349
2350 Open = self.Open
2351 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2352 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2353 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2354 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2355 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002356 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002357 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2358 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2359 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2360 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2361 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2362 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002363
2364 def test_or(self):
2365 Perm = self.Perm
2366 for i in Perm:
2367 for j in Perm:
2368 self.assertEqual(i | j, i.value | j.value)
2369 self.assertEqual((i | j).value, i.value | j.value)
2370 self.assertIs(type(i | j), Perm)
2371 for j in range(8):
2372 self.assertEqual(i | j, i.value | j)
2373 self.assertEqual((i | j).value, i.value | j)
2374 self.assertIs(type(i | j), Perm)
2375 self.assertEqual(j | i, j | i.value)
2376 self.assertEqual((j | i).value, j | i.value)
2377 self.assertIs(type(j | i), Perm)
2378 for i in Perm:
2379 self.assertIs(i | i, i)
2380 self.assertIs(i | 0, i)
2381 self.assertIs(0 | i, i)
2382 Open = self.Open
2383 self.assertIs(Open.RO | Open.CE, Open.CE)
2384
2385 def test_and(self):
2386 Perm = self.Perm
2387 RW = Perm.R | Perm.W
2388 RX = Perm.R | Perm.X
2389 WX = Perm.W | Perm.X
2390 RWX = Perm.R | Perm.W | Perm.X
2391 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2392 for i in values:
2393 for j in values:
2394 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2395 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2396 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2397 for j in range(8):
2398 self.assertEqual(i & j, i.value & j)
2399 self.assertEqual((i & j).value, i.value & j)
2400 self.assertIs(type(i & j), Perm)
2401 self.assertEqual(j & i, j & i.value)
2402 self.assertEqual((j & i).value, j & i.value)
2403 self.assertIs(type(j & i), Perm)
2404 for i in Perm:
2405 self.assertIs(i & i, i)
2406 self.assertIs(i & 7, i)
2407 self.assertIs(7 & i, i)
2408 Open = self.Open
2409 self.assertIs(Open.RO & Open.CE, Open.RO)
2410
2411 def test_xor(self):
2412 Perm = self.Perm
2413 for i in Perm:
2414 for j in Perm:
2415 self.assertEqual(i ^ j, i.value ^ j.value)
2416 self.assertEqual((i ^ j).value, i.value ^ j.value)
2417 self.assertIs(type(i ^ j), Perm)
2418 for j in range(8):
2419 self.assertEqual(i ^ j, i.value ^ j)
2420 self.assertEqual((i ^ j).value, i.value ^ j)
2421 self.assertIs(type(i ^ j), Perm)
2422 self.assertEqual(j ^ i, j ^ i.value)
2423 self.assertEqual((j ^ i).value, j ^ i.value)
2424 self.assertIs(type(j ^ i), Perm)
2425 for i in Perm:
2426 self.assertIs(i ^ 0, i)
2427 self.assertIs(0 ^ i, i)
2428 Open = self.Open
2429 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2430 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2431
2432 def test_invert(self):
2433 Perm = self.Perm
2434 RW = Perm.R | Perm.W
2435 RX = Perm.R | Perm.X
2436 WX = Perm.W | Perm.X
2437 RWX = Perm.R | Perm.W | Perm.X
2438 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2439 for i in values:
2440 self.assertEqual(~i, ~i.value)
2441 self.assertEqual((~i).value, ~i.value)
2442 self.assertIs(type(~i), Perm)
2443 self.assertEqual(~~i, i)
2444 for i in Perm:
2445 self.assertIs(~~i, i)
2446 Open = self.Open
2447 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2448 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2449
2450 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002451 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002452 lst = list(Perm)
2453 self.assertEqual(len(lst), len(Perm))
2454 self.assertEqual(len(Perm), 3, Perm)
2455 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2456 for i, n in enumerate('R W X'.split()):
2457 v = 1<<i
2458 e = Perm(v)
2459 self.assertEqual(e.value, v)
2460 self.assertEqual(type(e.value), int)
2461 self.assertEqual(e, v)
2462 self.assertEqual(e.name, n)
2463 self.assertIn(e, Perm)
2464 self.assertIs(type(e), Perm)
2465
2466 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002467 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002468 lst = list(Perm)
2469 self.assertEqual(len(lst), len(Perm))
2470 self.assertEqual(len(Perm), 3, Perm)
2471 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2472 for i, n in enumerate('R W X'.split()):
2473 v = 8<<i
2474 e = Perm(v)
2475 self.assertEqual(e.value, v)
2476 self.assertEqual(type(e.value), int)
2477 self.assertEqual(e, v)
2478 self.assertEqual(e.name, n)
2479 self.assertIn(e, Perm)
2480 self.assertIs(type(e), Perm)
2481
2482 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002483 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002484 lst = list(Perm)
2485 self.assertEqual(len(lst), len(Perm))
2486 self.assertEqual(len(Perm), 3, Perm)
2487 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2488 for i, n in enumerate('R W X'.split()):
2489 v = 1<<i
2490 e = Perm(v)
2491 self.assertEqual(e.value, v)
2492 self.assertEqual(type(e.value), int)
2493 self.assertEqual(e, v)
2494 self.assertEqual(e.name, n)
2495 self.assertIn(e, Perm)
2496 self.assertIs(type(e), Perm)
2497
2498 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002499 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002500 lst = list(Perm)
2501 self.assertEqual(len(lst), len(Perm))
2502 self.assertEqual(len(Perm), 3, Perm)
2503 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2504 for i, n in enumerate('R W X'.split()):
2505 v = 1<<(2*i+1)
2506 e = Perm(v)
2507 self.assertEqual(e.value, v)
2508 self.assertEqual(type(e.value), int)
2509 self.assertEqual(e, v)
2510 self.assertEqual(e.name, n)
2511 self.assertIn(e, Perm)
2512 self.assertIs(type(e), Perm)
2513
2514 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002515 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002516 lst = list(Perm)
2517 self.assertEqual(len(lst), len(Perm))
2518 self.assertEqual(len(Perm), 3, Perm)
2519 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2520 for i, n in enumerate('R W X'.split()):
2521 v = 1<<(2*i+1)
2522 e = Perm(v)
2523 self.assertEqual(e.value, v)
2524 self.assertEqual(type(e.value), int)
2525 self.assertEqual(e, v)
2526 self.assertEqual(e.name, n)
2527 self.assertIn(e, Perm)
2528 self.assertIs(type(e), Perm)
2529
2530
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002531 def test_programatic_function_from_empty_list(self):
2532 Perm = enum.IntFlag('Perm', [])
2533 lst = list(Perm)
2534 self.assertEqual(len(lst), len(Perm))
2535 self.assertEqual(len(Perm), 0, Perm)
2536 Thing = enum.Enum('Thing', [])
2537 lst = list(Thing)
2538 self.assertEqual(len(lst), len(Thing))
2539 self.assertEqual(len(Thing), 0, Thing)
2540
2541
2542 def test_programatic_function_from_empty_tuple(self):
2543 Perm = enum.IntFlag('Perm', ())
2544 lst = list(Perm)
2545 self.assertEqual(len(lst), len(Perm))
2546 self.assertEqual(len(Perm), 0, Perm)
2547 Thing = enum.Enum('Thing', ())
2548 self.assertEqual(len(lst), len(Thing))
2549 self.assertEqual(len(Thing), 0, Thing)
2550
Ethan Furman37151762018-04-11 18:56:25 -07002551 def test_contains(self):
2552 Color = self.Color
2553 Open = self.Open
2554 self.assertTrue(Color.GREEN in Color)
2555 self.assertTrue(Open.RW in Open)
2556 self.assertFalse(Color.GREEN in Open)
2557 self.assertFalse(Open.RW in Color)
2558 with self.assertWarns(DeprecationWarning):
2559 self.assertFalse('GREEN' in Color)
2560 with self.assertWarns(DeprecationWarning):
2561 self.assertFalse('RW' in Open)
2562 with self.assertWarns(DeprecationWarning):
2563 self.assertFalse(2 in Color)
2564 with self.assertWarns(DeprecationWarning):
2565 self.assertFalse(2 in Open)
2566
2567 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002568 Perm = self.Perm
2569 R, W, X = Perm
2570 RW = R | W
2571 RX = R | X
2572 WX = W | X
2573 RWX = R | W | X
2574 self.assertTrue(R in RW)
2575 self.assertTrue(R in RX)
2576 self.assertTrue(R in RWX)
2577 self.assertTrue(W in RW)
2578 self.assertTrue(W in WX)
2579 self.assertTrue(W in RWX)
2580 self.assertTrue(X in RX)
2581 self.assertTrue(X in WX)
2582 self.assertTrue(X in RWX)
2583 self.assertFalse(R in WX)
2584 self.assertFalse(W in RX)
2585 self.assertFalse(X in RW)
Ethan Furman37151762018-04-11 18:56:25 -07002586 with self.assertWarns(DeprecationWarning):
2587 self.assertFalse('swallow' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002588
Ethan Furman25d94bb2016-09-02 16:32:32 -07002589 def test_bool(self):
2590 Perm = self.Perm
2591 for f in Perm:
2592 self.assertTrue(f)
2593 Open = self.Open
2594 for f in Open:
2595 self.assertEqual(bool(f.value), bool(f))
2596
Ethan Furman0c076ca2018-09-21 22:26:32 -07002597 def test_multiple_mixin(self):
2598 class AllMixin:
2599 @classproperty
2600 def ALL(cls):
2601 members = list(cls)
2602 all_value = None
2603 if members:
2604 all_value = members[0]
2605 for member in members[1:]:
2606 all_value |= member
2607 cls.ALL = all_value
2608 return all_value
2609 class StrMixin:
2610 def __str__(self):
2611 return self._name_.lower()
2612 class Color(AllMixin, IntFlag):
2613 RED = auto()
2614 GREEN = auto()
2615 BLUE = auto()
2616 self.assertEqual(Color.RED.value, 1)
2617 self.assertEqual(Color.GREEN.value, 2)
2618 self.assertEqual(Color.BLUE.value, 4)
2619 self.assertEqual(Color.ALL.value, 7)
2620 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2621 class Color(AllMixin, StrMixin, IntFlag):
2622 RED = auto()
2623 GREEN = auto()
2624 BLUE = auto()
2625 self.assertEqual(Color.RED.value, 1)
2626 self.assertEqual(Color.GREEN.value, 2)
2627 self.assertEqual(Color.BLUE.value, 4)
2628 self.assertEqual(Color.ALL.value, 7)
2629 self.assertEqual(str(Color.BLUE), 'blue')
2630 class Color(StrMixin, AllMixin, IntFlag):
2631 RED = auto()
2632 GREEN = auto()
2633 BLUE = auto()
2634 self.assertEqual(Color.RED.value, 1)
2635 self.assertEqual(Color.GREEN.value, 2)
2636 self.assertEqual(Color.BLUE.value, 4)
2637 self.assertEqual(Color.ALL.value, 7)
2638 self.assertEqual(str(Color.BLUE), 'blue')
2639
Ethan Furman28cf6632017-01-24 12:12:06 -08002640 @support.reap_threads
2641 def test_unique_composite(self):
2642 # override __eq__ to be identity only
2643 class TestFlag(IntFlag):
2644 one = auto()
2645 two = auto()
2646 three = auto()
2647 four = auto()
2648 five = auto()
2649 six = auto()
2650 seven = auto()
2651 eight = auto()
2652 def __eq__(self, other):
2653 return self is other
2654 def __hash__(self):
2655 return hash(self._value_)
2656 # have multiple threads competing to complete the composite members
2657 seen = set()
2658 failed = False
2659 def cycle_enum():
2660 nonlocal failed
2661 try:
2662 for i in range(256):
2663 seen.add(TestFlag(i))
2664 except Exception:
2665 failed = True
2666 threads = [
2667 threading.Thread(target=cycle_enum)
2668 for _ in range(8)
2669 ]
2670 with support.start_threads(threads):
2671 pass
2672 # check that only 248 members were created
2673 self.assertFalse(
2674 failed,
2675 'at least one thread failed while creating composite members')
2676 self.assertEqual(256, len(seen), 'too many composite members created')
2677
2678
Ethan Furmanf24bb352013-07-18 17:05:39 -07002679class TestUnique(unittest.TestCase):
2680
2681 def test_unique_clean(self):
2682 @unique
2683 class Clean(Enum):
2684 one = 1
2685 two = 'dos'
2686 tres = 4.0
2687 @unique
2688 class Cleaner(IntEnum):
2689 single = 1
2690 double = 2
2691 triple = 3
2692
2693 def test_unique_dirty(self):
2694 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2695 @unique
2696 class Dirty(Enum):
2697 one = 1
2698 two = 'dos'
2699 tres = 1
2700 with self.assertRaisesRegex(
2701 ValueError,
2702 'double.*single.*turkey.*triple',
2703 ):
2704 @unique
2705 class Dirtier(IntEnum):
2706 single = 1
2707 double = 1
2708 triple = 3
2709 turkey = 3
2710
Ethan Furman3803ad42016-05-01 10:03:53 -07002711 def test_unique_with_name(self):
2712 @unique
2713 class Silly(Enum):
2714 one = 1
2715 two = 'dos'
2716 name = 3
2717 @unique
2718 class Sillier(IntEnum):
2719 single = 1
2720 name = 2
2721 triple = 3
2722 value = 4
2723
Ethan Furmanf24bb352013-07-18 17:05:39 -07002724
Ethan Furman0c076ca2018-09-21 22:26:32 -07002725
Ethan Furman3323da92015-04-11 09:39:59 -07002726expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002727Help on class Color in module %s:
2728
2729class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002730 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2731 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002732 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002733 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002734 | Method resolution order:
2735 | Color
2736 | enum.Enum
2737 | builtins.object
2738 |\x20\x20
2739 | Data and other attributes defined here:
2740 |\x20\x20
2741 | blue = <Color.blue: 3>
2742 |\x20\x20
2743 | green = <Color.green: 2>
2744 |\x20\x20
2745 | red = <Color.red: 1>
2746 |\x20\x20
2747 | ----------------------------------------------------------------------
2748 | Data descriptors inherited from enum.Enum:
2749 |\x20\x20
2750 | name
2751 | The name of the Enum member.
2752 |\x20\x20
2753 | value
2754 | The value of the Enum member.
2755 |\x20\x20
2756 | ----------------------------------------------------------------------
2757 | Data descriptors inherited from enum.EnumMeta:
2758 |\x20\x20
2759 | __members__
2760 | Returns a mapping of member name->value.
2761 |\x20\x20\x20\x20\x20\x20
2762 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002763 | is a read-only view of the internal mapping."""
2764
2765expected_help_output_without_docs = """\
2766Help on class Color in module %s:
2767
2768class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002769 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2770 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002771 | Method resolution order:
2772 | Color
2773 | enum.Enum
2774 | builtins.object
2775 |\x20\x20
2776 | Data and other attributes defined here:
2777 |\x20\x20
2778 | blue = <Color.blue: 3>
2779 |\x20\x20
2780 | green = <Color.green: 2>
2781 |\x20\x20
2782 | red = <Color.red: 1>
2783 |\x20\x20
2784 | ----------------------------------------------------------------------
2785 | Data descriptors inherited from enum.Enum:
2786 |\x20\x20
2787 | name
2788 |\x20\x20
2789 | value
2790 |\x20\x20
2791 | ----------------------------------------------------------------------
2792 | Data descriptors inherited from enum.EnumMeta:
2793 |\x20\x20
2794 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002795
2796class TestStdLib(unittest.TestCase):
2797
Ethan Furman48a724f2015-04-11 23:23:06 -07002798 maxDiff = None
2799
Ethan Furman5875d742013-10-21 20:45:55 -07002800 class Color(Enum):
2801 red = 1
2802 green = 2
2803 blue = 3
2804
2805 def test_pydoc(self):
2806 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002807 if StrEnum.__doc__ is None:
2808 expected_text = expected_help_output_without_docs % __name__
2809 else:
2810 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002811 output = StringIO()
2812 helper = pydoc.Helper(output=output)
2813 helper(self.Color)
2814 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002815 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002816
2817 def test_inspect_getmembers(self):
2818 values = dict((
2819 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002820 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002821 ('__members__', self.Color.__members__),
2822 ('__module__', __name__),
2823 ('blue', self.Color.blue),
2824 ('green', self.Color.green),
2825 ('name', Enum.__dict__['name']),
2826 ('red', self.Color.red),
2827 ('value', Enum.__dict__['value']),
2828 ))
2829 result = dict(inspect.getmembers(self.Color))
2830 self.assertEqual(values.keys(), result.keys())
2831 failed = False
2832 for k in values.keys():
2833 if result[k] != values[k]:
2834 print()
2835 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2836 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2837 failed = True
2838 if failed:
2839 self.fail("result does not equal expected, see print above")
2840
2841 def test_inspect_classify_class_attrs(self):
2842 # indirectly test __objclass__
2843 from inspect import Attribute
2844 values = [
2845 Attribute(name='__class__', kind='data',
2846 defining_class=object, object=EnumMeta),
2847 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002848 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002849 Attribute(name='__members__', kind='property',
2850 defining_class=EnumMeta, object=EnumMeta.__members__),
2851 Attribute(name='__module__', kind='data',
2852 defining_class=self.Color, object=__name__),
2853 Attribute(name='blue', kind='data',
2854 defining_class=self.Color, object=self.Color.blue),
2855 Attribute(name='green', kind='data',
2856 defining_class=self.Color, object=self.Color.green),
2857 Attribute(name='red', kind='data',
2858 defining_class=self.Color, object=self.Color.red),
2859 Attribute(name='name', kind='data',
2860 defining_class=Enum, object=Enum.__dict__['name']),
2861 Attribute(name='value', kind='data',
2862 defining_class=Enum, object=Enum.__dict__['value']),
2863 ]
2864 values.sort(key=lambda item: item.name)
2865 result = list(inspect.classify_class_attrs(self.Color))
2866 result.sort(key=lambda item: item.name)
2867 failed = False
2868 for v, r in zip(values, result):
2869 if r != v:
2870 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2871 failed = True
2872 if failed:
2873 self.fail("result does not equal expected, see print above")
2874
Martin Panter19e69c52015-11-14 12:46:42 +00002875
2876class MiscTestCase(unittest.TestCase):
2877 def test__all__(self):
2878 support.check__all__(self, enum)
2879
2880
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002881# These are unordered here on purpose to ensure that declaration order
2882# makes no difference.
2883CONVERT_TEST_NAME_D = 5
2884CONVERT_TEST_NAME_C = 5
2885CONVERT_TEST_NAME_B = 5
2886CONVERT_TEST_NAME_A = 5 # This one should sort first.
2887CONVERT_TEST_NAME_E = 5
2888CONVERT_TEST_NAME_F = 5
2889
2890class TestIntEnumConvert(unittest.TestCase):
2891 def test_convert_value_lookup_priority(self):
2892 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002893 'UnittestConvert',
2894 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002895 filter=lambda x: x.startswith('CONVERT_TEST_'))
2896 # We don't want the reverse lookup value to vary when there are
2897 # multiple possible names for a given value. It should always
2898 # report the first lexigraphical name in that case.
2899 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2900
2901 def test_convert(self):
2902 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002903 'UnittestConvert',
2904 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002905 filter=lambda x: x.startswith('CONVERT_TEST_'))
2906 # Ensure that test_type has all of the desired names and values.
2907 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2908 test_type.CONVERT_TEST_NAME_A)
2909 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2910 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2911 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2912 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2913 # Ensure that test_type only picked up names matching the filter.
2914 self.assertEqual([name for name in dir(test_type)
2915 if name[0:2] not in ('CO', '__')],
2916 [], msg='Names other than CONVERT_TEST_* found.')
2917
2918
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002919if __name__ == '__main__':
2920 unittest.main()