blob: 60eabbe3d487442d45465aa6ac8dc2503141bb18 [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
Miss Islington (bot)453b3b02018-10-06 00:43:20 -07001816 def test_multiple_inherited_mixin(self):
1817 class StrEnum(str, Enum):
1818 def __new__(cls, *args, **kwargs):
1819 for a in args:
1820 if not isinstance(a, str):
1821 raise TypeError("Enumeration '%s' (%s) is not"
1822 " a string" % (a, type(a).__name__))
1823 return str.__new__(cls, *args, **kwargs)
1824 @unique
1825 class Decision1(StrEnum):
1826 REVERT = "REVERT"
1827 REVERT_ALL = "REVERT_ALL"
1828 RETRY = "RETRY"
1829 class MyEnum(StrEnum):
1830 pass
1831 @unique
1832 class Decision2(MyEnum):
1833 REVERT = "REVERT"
1834 REVERT_ALL = "REVERT_ALL"
1835 RETRY = "RETRY"
1836
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001837
Ethan Furmane8e61272016-08-20 07:19:31 -07001838class TestOrder(unittest.TestCase):
1839
1840 def test_same_members(self):
1841 class Color(Enum):
1842 _order_ = 'red green blue'
1843 red = 1
1844 green = 2
1845 blue = 3
1846
1847 def test_same_members_with_aliases(self):
1848 class Color(Enum):
1849 _order_ = 'red green blue'
1850 red = 1
1851 green = 2
1852 blue = 3
1853 verde = green
1854
1855 def test_same_members_wrong_order(self):
1856 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1857 class Color(Enum):
1858 _order_ = 'red green blue'
1859 red = 1
1860 blue = 3
1861 green = 2
1862
1863 def test_order_has_extra_members(self):
1864 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1865 class Color(Enum):
1866 _order_ = 'red green blue purple'
1867 red = 1
1868 green = 2
1869 blue = 3
1870
1871 def test_order_has_extra_members_with_aliases(self):
1872 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1873 class Color(Enum):
1874 _order_ = 'red green blue purple'
1875 red = 1
1876 green = 2
1877 blue = 3
1878 verde = green
1879
1880 def test_enum_has_extra_members(self):
1881 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1882 class Color(Enum):
1883 _order_ = 'red green blue'
1884 red = 1
1885 green = 2
1886 blue = 3
1887 purple = 4
1888
1889 def test_enum_has_extra_members_with_aliases(self):
1890 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1891 class Color(Enum):
1892 _order_ = 'red green blue'
1893 red = 1
1894 green = 2
1895 blue = 3
1896 purple = 4
1897 verde = green
1898
1899
Ethan Furman65a5a472016-09-01 23:55:19 -07001900class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001901 """Tests of the Flags."""
1902
Ethan Furman65a5a472016-09-01 23:55:19 -07001903 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001904 R, W, X = 4, 2, 1
1905
Ethan Furman37151762018-04-11 18:56:25 -07001906 class Color(Flag):
1907 BLACK = 0
1908 RED = 1
1909 GREEN = 2
1910 BLUE = 4
1911 PURPLE = RED|BLUE
1912
Ethan Furman65a5a472016-09-01 23:55:19 -07001913 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001914 RO = 0
1915 WO = 1
1916 RW = 2
1917 AC = 3
1918 CE = 1<<19
1919
1920 def test_str(self):
1921 Perm = self.Perm
1922 self.assertEqual(str(Perm.R), 'Perm.R')
1923 self.assertEqual(str(Perm.W), 'Perm.W')
1924 self.assertEqual(str(Perm.X), 'Perm.X')
1925 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1926 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1927 self.assertEqual(str(Perm(0)), 'Perm.0')
1928 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1929 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1930 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1931 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1932 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1933 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1934
1935 Open = self.Open
1936 self.assertEqual(str(Open.RO), 'Open.RO')
1937 self.assertEqual(str(Open.WO), 'Open.WO')
1938 self.assertEqual(str(Open.AC), 'Open.AC')
1939 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1940 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001941 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001942 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1943 self.assertEqual(str(~Open.AC), 'Open.CE')
1944 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1945 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1946
1947 def test_repr(self):
1948 Perm = self.Perm
1949 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1950 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1951 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1952 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1953 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001954 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001955 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1956 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1957 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1958 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001959 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001960 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1961
1962 Open = self.Open
1963 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1964 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1965 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1966 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1967 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001968 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001969 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1970 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1971 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1972 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1973
1974 def test_or(self):
1975 Perm = self.Perm
1976 for i in Perm:
1977 for j in Perm:
1978 self.assertEqual((i | j), Perm(i.value | j.value))
1979 self.assertEqual((i | j).value, i.value | j.value)
1980 self.assertIs(type(i | j), Perm)
1981 for i in Perm:
1982 self.assertIs(i | i, i)
1983 Open = self.Open
1984 self.assertIs(Open.RO | Open.CE, Open.CE)
1985
1986 def test_and(self):
1987 Perm = self.Perm
1988 RW = Perm.R | Perm.W
1989 RX = Perm.R | Perm.X
1990 WX = Perm.W | Perm.X
1991 RWX = Perm.R | Perm.W | Perm.X
1992 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1993 for i in values:
1994 for j in values:
1995 self.assertEqual((i & j).value, i.value & j.value)
1996 self.assertIs(type(i & j), Perm)
1997 for i in Perm:
1998 self.assertIs(i & i, i)
1999 self.assertIs(i & RWX, i)
2000 self.assertIs(RWX & i, i)
2001 Open = self.Open
2002 self.assertIs(Open.RO & Open.CE, Open.RO)
2003
2004 def test_xor(self):
2005 Perm = self.Perm
2006 for i in Perm:
2007 for j in Perm:
2008 self.assertEqual((i ^ j).value, i.value ^ j.value)
2009 self.assertIs(type(i ^ j), Perm)
2010 for i in Perm:
2011 self.assertIs(i ^ Perm(0), i)
2012 self.assertIs(Perm(0) ^ i, i)
2013 Open = self.Open
2014 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2015 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2016
2017 def test_invert(self):
2018 Perm = self.Perm
2019 RW = Perm.R | Perm.W
2020 RX = Perm.R | Perm.X
2021 WX = Perm.W | Perm.X
2022 RWX = Perm.R | Perm.W | Perm.X
2023 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2024 for i in values:
2025 self.assertIs(type(~i), Perm)
2026 self.assertEqual(~~i, i)
2027 for i in Perm:
2028 self.assertIs(~~i, i)
2029 Open = self.Open
2030 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2031 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2032
Ethan Furman25d94bb2016-09-02 16:32:32 -07002033 def test_bool(self):
2034 Perm = self.Perm
2035 for f in Perm:
2036 self.assertTrue(f)
2037 Open = self.Open
2038 for f in Open:
2039 self.assertEqual(bool(f.value), bool(f))
2040
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002041 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002042 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002043 lst = list(Perm)
2044 self.assertEqual(len(lst), len(Perm))
2045 self.assertEqual(len(Perm), 3, Perm)
2046 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2047 for i, n in enumerate('R W X'.split()):
2048 v = 1<<i
2049 e = Perm(v)
2050 self.assertEqual(e.value, v)
2051 self.assertEqual(type(e.value), int)
2052 self.assertEqual(e.name, n)
2053 self.assertIn(e, Perm)
2054 self.assertIs(type(e), Perm)
2055
2056 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002057 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002058 lst = list(Perm)
2059 self.assertEqual(len(lst), len(Perm))
2060 self.assertEqual(len(Perm), 3, Perm)
2061 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2062 for i, n in enumerate('R W X'.split()):
2063 v = 8<<i
2064 e = Perm(v)
2065 self.assertEqual(e.value, v)
2066 self.assertEqual(type(e.value), int)
2067 self.assertEqual(e.name, n)
2068 self.assertIn(e, Perm)
2069 self.assertIs(type(e), Perm)
2070
2071 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002072 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002073 lst = list(Perm)
2074 self.assertEqual(len(lst), len(Perm))
2075 self.assertEqual(len(Perm), 3, Perm)
2076 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2077 for i, n in enumerate('R W X'.split()):
2078 v = 1<<i
2079 e = Perm(v)
2080 self.assertEqual(e.value, v)
2081 self.assertEqual(type(e.value), int)
2082 self.assertEqual(e.name, n)
2083 self.assertIn(e, Perm)
2084 self.assertIs(type(e), Perm)
2085
2086 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002087 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002088 lst = list(Perm)
2089 self.assertEqual(len(lst), len(Perm))
2090 self.assertEqual(len(Perm), 3, Perm)
2091 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2092 for i, n in enumerate('R W X'.split()):
2093 v = 1<<(2*i+1)
2094 e = Perm(v)
2095 self.assertEqual(e.value, v)
2096 self.assertEqual(type(e.value), int)
2097 self.assertEqual(e.name, n)
2098 self.assertIn(e, Perm)
2099 self.assertIs(type(e), Perm)
2100
2101 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002102 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002103 lst = list(Perm)
2104 self.assertEqual(len(lst), len(Perm))
2105 self.assertEqual(len(Perm), 3, Perm)
2106 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2107 for i, n in enumerate('R W X'.split()):
2108 v = 1<<(2*i+1)
2109 e = Perm(v)
2110 self.assertEqual(e.value, v)
2111 self.assertEqual(type(e.value), int)
2112 self.assertEqual(e.name, n)
2113 self.assertIn(e, Perm)
2114 self.assertIs(type(e), Perm)
2115
Ethan Furman65a5a472016-09-01 23:55:19 -07002116 def test_pickle(self):
2117 if isinstance(FlagStooges, Exception):
2118 raise FlagStooges
2119 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2120 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002121
Ethan Furman37151762018-04-11 18:56:25 -07002122 def test_contains(self):
2123 Open = self.Open
2124 Color = self.Color
2125 self.assertFalse(Color.BLACK in Open)
2126 self.assertFalse(Open.RO in Color)
2127 with self.assertWarns(DeprecationWarning):
2128 self.assertFalse('BLACK' in Color)
2129 with self.assertWarns(DeprecationWarning):
2130 self.assertFalse('RO' in Open)
2131 with self.assertWarns(DeprecationWarning):
2132 self.assertFalse(1 in Color)
2133 with self.assertWarns(DeprecationWarning):
2134 self.assertFalse(1 in Open)
2135
2136 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002137 Perm = self.Perm
2138 R, W, X = Perm
2139 RW = R | W
2140 RX = R | X
2141 WX = W | X
2142 RWX = R | W | X
2143 self.assertTrue(R in RW)
2144 self.assertTrue(R in RX)
2145 self.assertTrue(R in RWX)
2146 self.assertTrue(W in RW)
2147 self.assertTrue(W in WX)
2148 self.assertTrue(W in RWX)
2149 self.assertTrue(X in RX)
2150 self.assertTrue(X in WX)
2151 self.assertTrue(X in RWX)
2152 self.assertFalse(R in WX)
2153 self.assertFalse(W in RX)
2154 self.assertFalse(X in RW)
2155
Ethan Furmanc16595e2016-09-10 23:36:59 -07002156 def test_auto_number(self):
2157 class Color(Flag):
2158 red = auto()
2159 blue = auto()
2160 green = auto()
2161
2162 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2163 self.assertEqual(Color.red.value, 1)
2164 self.assertEqual(Color.blue.value, 2)
2165 self.assertEqual(Color.green.value, 4)
2166
2167 def test_auto_number_garbage(self):
2168 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2169 class Color(Flag):
2170 red = 'not an int'
2171 blue = auto()
2172
Ethan Furman3515dcc2016-09-18 13:15:41 -07002173 def test_cascading_failure(self):
2174 class Bizarre(Flag):
2175 c = 3
2176 d = 4
2177 f = 6
2178 # Bizarre.c | Bizarre.d
2179 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2180 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2181 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2182 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2183 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2184 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2185
2186 def test_duplicate_auto(self):
2187 class Dupes(Enum):
2188 first = primero = auto()
2189 second = auto()
2190 third = auto()
2191 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2192
2193 def test_bizarre(self):
2194 class Bizarre(Flag):
2195 b = 3
2196 c = 4
2197 d = 6
2198 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2199
Ethan Furman0c076ca2018-09-21 22:26:32 -07002200 def test_multiple_mixin(self):
2201 class AllMixin:
2202 @classproperty
2203 def ALL(cls):
2204 members = list(cls)
2205 all_value = None
2206 if members:
2207 all_value = members[0]
2208 for member in members[1:]:
2209 all_value |= member
2210 cls.ALL = all_value
2211 return all_value
2212 class StrMixin:
2213 def __str__(self):
2214 return self._name_.lower()
2215 class Color(AllMixin, Flag):
2216 RED = auto()
2217 GREEN = auto()
2218 BLUE = auto()
2219 self.assertEqual(Color.RED.value, 1)
2220 self.assertEqual(Color.GREEN.value, 2)
2221 self.assertEqual(Color.BLUE.value, 4)
2222 self.assertEqual(Color.ALL.value, 7)
2223 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2224 class Color(AllMixin, StrMixin, Flag):
2225 RED = auto()
2226 GREEN = auto()
2227 BLUE = auto()
2228 self.assertEqual(Color.RED.value, 1)
2229 self.assertEqual(Color.GREEN.value, 2)
2230 self.assertEqual(Color.BLUE.value, 4)
2231 self.assertEqual(Color.ALL.value, 7)
2232 self.assertEqual(str(Color.BLUE), 'blue')
2233 class Color(StrMixin, AllMixin, Flag):
2234 RED = auto()
2235 GREEN = auto()
2236 BLUE = auto()
2237 self.assertEqual(Color.RED.value, 1)
2238 self.assertEqual(Color.GREEN.value, 2)
2239 self.assertEqual(Color.BLUE.value, 4)
2240 self.assertEqual(Color.ALL.value, 7)
2241 self.assertEqual(str(Color.BLUE), 'blue')
2242
Ethan Furman28cf6632017-01-24 12:12:06 -08002243 @support.reap_threads
2244 def test_unique_composite(self):
2245 # override __eq__ to be identity only
2246 class TestFlag(Flag):
2247 one = auto()
2248 two = auto()
2249 three = auto()
2250 four = auto()
2251 five = auto()
2252 six = auto()
2253 seven = auto()
2254 eight = auto()
2255 def __eq__(self, other):
2256 return self is other
2257 def __hash__(self):
2258 return hash(self._value_)
2259 # have multiple threads competing to complete the composite members
2260 seen = set()
2261 failed = False
2262 def cycle_enum():
2263 nonlocal failed
2264 try:
2265 for i in range(256):
2266 seen.add(TestFlag(i))
2267 except Exception:
2268 failed = True
2269 threads = [
2270 threading.Thread(target=cycle_enum)
2271 for _ in range(8)
2272 ]
2273 with support.start_threads(threads):
2274 pass
2275 # check that only 248 members were created
2276 self.assertFalse(
2277 failed,
2278 'at least one thread failed while creating composite members')
2279 self.assertEqual(256, len(seen), 'too many composite members created')
2280
Ethan Furmanc16595e2016-09-10 23:36:59 -07002281
Ethan Furman65a5a472016-09-01 23:55:19 -07002282class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002283 """Tests of the IntFlags."""
2284
Ethan Furman65a5a472016-09-01 23:55:19 -07002285 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002286 X = 1 << 0
2287 W = 1 << 1
2288 R = 1 << 2
2289
Ethan Furman37151762018-04-11 18:56:25 -07002290 class Color(IntFlag):
2291 BLACK = 0
2292 RED = 1
2293 GREEN = 2
2294 BLUE = 4
2295 PURPLE = RED|BLUE
2296
Ethan Furman65a5a472016-09-01 23:55:19 -07002297 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002298 RO = 0
2299 WO = 1
2300 RW = 2
2301 AC = 3
2302 CE = 1<<19
2303
Ethan Furman3515dcc2016-09-18 13:15:41 -07002304 def test_type(self):
2305 Perm = self.Perm
2306 Open = self.Open
2307 for f in Perm:
2308 self.assertTrue(isinstance(f, Perm))
2309 self.assertEqual(f, f.value)
2310 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2311 self.assertEqual(Perm.W | Perm.X, 3)
2312 for f in Open:
2313 self.assertTrue(isinstance(f, Open))
2314 self.assertEqual(f, f.value)
2315 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2316 self.assertEqual(Open.WO | Open.RW, 3)
2317
2318
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002319 def test_str(self):
2320 Perm = self.Perm
2321 self.assertEqual(str(Perm.R), 'Perm.R')
2322 self.assertEqual(str(Perm.W), 'Perm.W')
2323 self.assertEqual(str(Perm.X), 'Perm.X')
2324 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2325 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2326 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2327 self.assertEqual(str(Perm(0)), 'Perm.0')
2328 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002329 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2330 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2331 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2332 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002333 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002334 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2335 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2336 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002337
2338 Open = self.Open
2339 self.assertEqual(str(Open.RO), 'Open.RO')
2340 self.assertEqual(str(Open.WO), 'Open.WO')
2341 self.assertEqual(str(Open.AC), 'Open.AC')
2342 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2343 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2344 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002345 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2346 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2347 self.assertEqual(str(~Open.AC), 'Open.CE')
2348 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2349 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2350 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002351
2352 def test_repr(self):
2353 Perm = self.Perm
2354 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2355 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2356 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2357 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2358 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2359 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002360 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2361 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002362 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2363 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2364 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2365 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002366 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002367 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2368 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2369 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002370
2371 Open = self.Open
2372 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2373 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2374 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2375 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2376 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002377 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002378 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2379 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2380 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2381 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2382 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2383 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002384
2385 def test_or(self):
2386 Perm = self.Perm
2387 for i in Perm:
2388 for j in Perm:
2389 self.assertEqual(i | j, i.value | j.value)
2390 self.assertEqual((i | j).value, i.value | j.value)
2391 self.assertIs(type(i | j), Perm)
2392 for j in range(8):
2393 self.assertEqual(i | j, i.value | j)
2394 self.assertEqual((i | j).value, i.value | j)
2395 self.assertIs(type(i | j), Perm)
2396 self.assertEqual(j | i, j | i.value)
2397 self.assertEqual((j | i).value, j | i.value)
2398 self.assertIs(type(j | i), Perm)
2399 for i in Perm:
2400 self.assertIs(i | i, i)
2401 self.assertIs(i | 0, i)
2402 self.assertIs(0 | i, i)
2403 Open = self.Open
2404 self.assertIs(Open.RO | Open.CE, Open.CE)
2405
2406 def test_and(self):
2407 Perm = self.Perm
2408 RW = Perm.R | Perm.W
2409 RX = Perm.R | Perm.X
2410 WX = Perm.W | Perm.X
2411 RWX = Perm.R | Perm.W | Perm.X
2412 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2413 for i in values:
2414 for j in values:
2415 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2416 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2417 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
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 & i, i)
2427 self.assertIs(i & 7, i)
2428 self.assertIs(7 & i, i)
2429 Open = self.Open
2430 self.assertIs(Open.RO & Open.CE, Open.RO)
2431
2432 def test_xor(self):
2433 Perm = self.Perm
2434 for i in Perm:
2435 for j in Perm:
2436 self.assertEqual(i ^ j, i.value ^ j.value)
2437 self.assertEqual((i ^ j).value, i.value ^ j.value)
2438 self.assertIs(type(i ^ j), Perm)
2439 for j in range(8):
2440 self.assertEqual(i ^ j, i.value ^ j)
2441 self.assertEqual((i ^ j).value, i.value ^ j)
2442 self.assertIs(type(i ^ j), Perm)
2443 self.assertEqual(j ^ i, j ^ i.value)
2444 self.assertEqual((j ^ i).value, j ^ i.value)
2445 self.assertIs(type(j ^ i), Perm)
2446 for i in Perm:
2447 self.assertIs(i ^ 0, i)
2448 self.assertIs(0 ^ i, i)
2449 Open = self.Open
2450 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2451 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2452
2453 def test_invert(self):
2454 Perm = self.Perm
2455 RW = Perm.R | Perm.W
2456 RX = Perm.R | Perm.X
2457 WX = Perm.W | Perm.X
2458 RWX = Perm.R | Perm.W | Perm.X
2459 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2460 for i in values:
2461 self.assertEqual(~i, ~i.value)
2462 self.assertEqual((~i).value, ~i.value)
2463 self.assertIs(type(~i), Perm)
2464 self.assertEqual(~~i, i)
2465 for i in Perm:
2466 self.assertIs(~~i, i)
2467 Open = self.Open
2468 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2469 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2470
2471 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002472 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002473 lst = list(Perm)
2474 self.assertEqual(len(lst), len(Perm))
2475 self.assertEqual(len(Perm), 3, Perm)
2476 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2477 for i, n in enumerate('R W X'.split()):
2478 v = 1<<i
2479 e = Perm(v)
2480 self.assertEqual(e.value, v)
2481 self.assertEqual(type(e.value), int)
2482 self.assertEqual(e, v)
2483 self.assertEqual(e.name, n)
2484 self.assertIn(e, Perm)
2485 self.assertIs(type(e), Perm)
2486
2487 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002488 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002489 lst = list(Perm)
2490 self.assertEqual(len(lst), len(Perm))
2491 self.assertEqual(len(Perm), 3, Perm)
2492 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2493 for i, n in enumerate('R W X'.split()):
2494 v = 8<<i
2495 e = Perm(v)
2496 self.assertEqual(e.value, v)
2497 self.assertEqual(type(e.value), int)
2498 self.assertEqual(e, v)
2499 self.assertEqual(e.name, n)
2500 self.assertIn(e, Perm)
2501 self.assertIs(type(e), Perm)
2502
2503 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002504 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002505 lst = list(Perm)
2506 self.assertEqual(len(lst), len(Perm))
2507 self.assertEqual(len(Perm), 3, Perm)
2508 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2509 for i, n in enumerate('R W X'.split()):
2510 v = 1<<i
2511 e = Perm(v)
2512 self.assertEqual(e.value, v)
2513 self.assertEqual(type(e.value), int)
2514 self.assertEqual(e, v)
2515 self.assertEqual(e.name, n)
2516 self.assertIn(e, Perm)
2517 self.assertIs(type(e), Perm)
2518
2519 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002520 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002521 lst = list(Perm)
2522 self.assertEqual(len(lst), len(Perm))
2523 self.assertEqual(len(Perm), 3, Perm)
2524 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2525 for i, n in enumerate('R W X'.split()):
2526 v = 1<<(2*i+1)
2527 e = Perm(v)
2528 self.assertEqual(e.value, v)
2529 self.assertEqual(type(e.value), int)
2530 self.assertEqual(e, v)
2531 self.assertEqual(e.name, n)
2532 self.assertIn(e, Perm)
2533 self.assertIs(type(e), Perm)
2534
2535 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002536 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002537 lst = list(Perm)
2538 self.assertEqual(len(lst), len(Perm))
2539 self.assertEqual(len(Perm), 3, Perm)
2540 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2541 for i, n in enumerate('R W X'.split()):
2542 v = 1<<(2*i+1)
2543 e = Perm(v)
2544 self.assertEqual(e.value, v)
2545 self.assertEqual(type(e.value), int)
2546 self.assertEqual(e, v)
2547 self.assertEqual(e.name, n)
2548 self.assertIn(e, Perm)
2549 self.assertIs(type(e), Perm)
2550
2551
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002552 def test_programatic_function_from_empty_list(self):
2553 Perm = enum.IntFlag('Perm', [])
2554 lst = list(Perm)
2555 self.assertEqual(len(lst), len(Perm))
2556 self.assertEqual(len(Perm), 0, Perm)
2557 Thing = enum.Enum('Thing', [])
2558 lst = list(Thing)
2559 self.assertEqual(len(lst), len(Thing))
2560 self.assertEqual(len(Thing), 0, Thing)
2561
2562
2563 def test_programatic_function_from_empty_tuple(self):
2564 Perm = enum.IntFlag('Perm', ())
2565 lst = list(Perm)
2566 self.assertEqual(len(lst), len(Perm))
2567 self.assertEqual(len(Perm), 0, Perm)
2568 Thing = enum.Enum('Thing', ())
2569 self.assertEqual(len(lst), len(Thing))
2570 self.assertEqual(len(Thing), 0, Thing)
2571
Ethan Furman37151762018-04-11 18:56:25 -07002572 def test_contains(self):
2573 Color = self.Color
2574 Open = self.Open
2575 self.assertTrue(Color.GREEN in Color)
2576 self.assertTrue(Open.RW in Open)
2577 self.assertFalse(Color.GREEN in Open)
2578 self.assertFalse(Open.RW in Color)
2579 with self.assertWarns(DeprecationWarning):
2580 self.assertFalse('GREEN' in Color)
2581 with self.assertWarns(DeprecationWarning):
2582 self.assertFalse('RW' in Open)
2583 with self.assertWarns(DeprecationWarning):
2584 self.assertFalse(2 in Color)
2585 with self.assertWarns(DeprecationWarning):
2586 self.assertFalse(2 in Open)
2587
2588 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002589 Perm = self.Perm
2590 R, W, X = Perm
2591 RW = R | W
2592 RX = R | X
2593 WX = W | X
2594 RWX = R | W | X
2595 self.assertTrue(R in RW)
2596 self.assertTrue(R in RX)
2597 self.assertTrue(R in RWX)
2598 self.assertTrue(W in RW)
2599 self.assertTrue(W in WX)
2600 self.assertTrue(W in RWX)
2601 self.assertTrue(X in RX)
2602 self.assertTrue(X in WX)
2603 self.assertTrue(X in RWX)
2604 self.assertFalse(R in WX)
2605 self.assertFalse(W in RX)
2606 self.assertFalse(X in RW)
Ethan Furman37151762018-04-11 18:56:25 -07002607 with self.assertWarns(DeprecationWarning):
2608 self.assertFalse('swallow' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002609
Ethan Furman25d94bb2016-09-02 16:32:32 -07002610 def test_bool(self):
2611 Perm = self.Perm
2612 for f in Perm:
2613 self.assertTrue(f)
2614 Open = self.Open
2615 for f in Open:
2616 self.assertEqual(bool(f.value), bool(f))
2617
Ethan Furman0c076ca2018-09-21 22:26:32 -07002618 def test_multiple_mixin(self):
2619 class AllMixin:
2620 @classproperty
2621 def ALL(cls):
2622 members = list(cls)
2623 all_value = None
2624 if members:
2625 all_value = members[0]
2626 for member in members[1:]:
2627 all_value |= member
2628 cls.ALL = all_value
2629 return all_value
2630 class StrMixin:
2631 def __str__(self):
2632 return self._name_.lower()
2633 class Color(AllMixin, IntFlag):
2634 RED = auto()
2635 GREEN = auto()
2636 BLUE = auto()
2637 self.assertEqual(Color.RED.value, 1)
2638 self.assertEqual(Color.GREEN.value, 2)
2639 self.assertEqual(Color.BLUE.value, 4)
2640 self.assertEqual(Color.ALL.value, 7)
2641 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2642 class Color(AllMixin, StrMixin, IntFlag):
2643 RED = auto()
2644 GREEN = auto()
2645 BLUE = auto()
2646 self.assertEqual(Color.RED.value, 1)
2647 self.assertEqual(Color.GREEN.value, 2)
2648 self.assertEqual(Color.BLUE.value, 4)
2649 self.assertEqual(Color.ALL.value, 7)
2650 self.assertEqual(str(Color.BLUE), 'blue')
2651 class Color(StrMixin, AllMixin, IntFlag):
2652 RED = auto()
2653 GREEN = auto()
2654 BLUE = auto()
2655 self.assertEqual(Color.RED.value, 1)
2656 self.assertEqual(Color.GREEN.value, 2)
2657 self.assertEqual(Color.BLUE.value, 4)
2658 self.assertEqual(Color.ALL.value, 7)
2659 self.assertEqual(str(Color.BLUE), 'blue')
2660
Ethan Furman28cf6632017-01-24 12:12:06 -08002661 @support.reap_threads
2662 def test_unique_composite(self):
2663 # override __eq__ to be identity only
2664 class TestFlag(IntFlag):
2665 one = auto()
2666 two = auto()
2667 three = auto()
2668 four = auto()
2669 five = auto()
2670 six = auto()
2671 seven = auto()
2672 eight = auto()
2673 def __eq__(self, other):
2674 return self is other
2675 def __hash__(self):
2676 return hash(self._value_)
2677 # have multiple threads competing to complete the composite members
2678 seen = set()
2679 failed = False
2680 def cycle_enum():
2681 nonlocal failed
2682 try:
2683 for i in range(256):
2684 seen.add(TestFlag(i))
2685 except Exception:
2686 failed = True
2687 threads = [
2688 threading.Thread(target=cycle_enum)
2689 for _ in range(8)
2690 ]
2691 with support.start_threads(threads):
2692 pass
2693 # check that only 248 members were created
2694 self.assertFalse(
2695 failed,
2696 'at least one thread failed while creating composite members')
2697 self.assertEqual(256, len(seen), 'too many composite members created')
2698
2699
Ethan Furmanf24bb352013-07-18 17:05:39 -07002700class TestUnique(unittest.TestCase):
2701
2702 def test_unique_clean(self):
2703 @unique
2704 class Clean(Enum):
2705 one = 1
2706 two = 'dos'
2707 tres = 4.0
2708 @unique
2709 class Cleaner(IntEnum):
2710 single = 1
2711 double = 2
2712 triple = 3
2713
2714 def test_unique_dirty(self):
2715 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2716 @unique
2717 class Dirty(Enum):
2718 one = 1
2719 two = 'dos'
2720 tres = 1
2721 with self.assertRaisesRegex(
2722 ValueError,
2723 'double.*single.*turkey.*triple',
2724 ):
2725 @unique
2726 class Dirtier(IntEnum):
2727 single = 1
2728 double = 1
2729 triple = 3
2730 turkey = 3
2731
Ethan Furman3803ad42016-05-01 10:03:53 -07002732 def test_unique_with_name(self):
2733 @unique
2734 class Silly(Enum):
2735 one = 1
2736 two = 'dos'
2737 name = 3
2738 @unique
2739 class Sillier(IntEnum):
2740 single = 1
2741 name = 2
2742 triple = 3
2743 value = 4
2744
Ethan Furmanf24bb352013-07-18 17:05:39 -07002745
Ethan Furman0c076ca2018-09-21 22:26:32 -07002746
Ethan Furman3323da92015-04-11 09:39:59 -07002747expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002748Help on class Color in module %s:
2749
2750class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002751 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2752 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002753 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002754 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002755 | Method resolution order:
2756 | Color
2757 | enum.Enum
2758 | builtins.object
2759 |\x20\x20
2760 | Data and other attributes defined here:
2761 |\x20\x20
2762 | blue = <Color.blue: 3>
2763 |\x20\x20
2764 | green = <Color.green: 2>
2765 |\x20\x20
2766 | red = <Color.red: 1>
2767 |\x20\x20
2768 | ----------------------------------------------------------------------
2769 | Data descriptors inherited from enum.Enum:
2770 |\x20\x20
2771 | name
2772 | The name of the Enum member.
2773 |\x20\x20
2774 | value
2775 | The value of the Enum member.
2776 |\x20\x20
2777 | ----------------------------------------------------------------------
2778 | Data descriptors inherited from enum.EnumMeta:
2779 |\x20\x20
2780 | __members__
2781 | Returns a mapping of member name->value.
2782 |\x20\x20\x20\x20\x20\x20
2783 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002784 | is a read-only view of the internal mapping."""
2785
2786expected_help_output_without_docs = """\
2787Help on class Color in module %s:
2788
2789class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002790 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2791 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002792 | Method resolution order:
2793 | Color
2794 | enum.Enum
2795 | builtins.object
2796 |\x20\x20
2797 | Data and other attributes defined here:
2798 |\x20\x20
2799 | blue = <Color.blue: 3>
2800 |\x20\x20
2801 | green = <Color.green: 2>
2802 |\x20\x20
2803 | red = <Color.red: 1>
2804 |\x20\x20
2805 | ----------------------------------------------------------------------
2806 | Data descriptors inherited from enum.Enum:
2807 |\x20\x20
2808 | name
2809 |\x20\x20
2810 | value
2811 |\x20\x20
2812 | ----------------------------------------------------------------------
2813 | Data descriptors inherited from enum.EnumMeta:
2814 |\x20\x20
2815 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002816
2817class TestStdLib(unittest.TestCase):
2818
Ethan Furman48a724f2015-04-11 23:23:06 -07002819 maxDiff = None
2820
Ethan Furman5875d742013-10-21 20:45:55 -07002821 class Color(Enum):
2822 red = 1
2823 green = 2
2824 blue = 3
2825
2826 def test_pydoc(self):
2827 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002828 if StrEnum.__doc__ is None:
2829 expected_text = expected_help_output_without_docs % __name__
2830 else:
2831 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002832 output = StringIO()
2833 helper = pydoc.Helper(output=output)
2834 helper(self.Color)
2835 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002836 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002837
2838 def test_inspect_getmembers(self):
2839 values = dict((
2840 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002841 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002842 ('__members__', self.Color.__members__),
2843 ('__module__', __name__),
2844 ('blue', self.Color.blue),
2845 ('green', self.Color.green),
2846 ('name', Enum.__dict__['name']),
2847 ('red', self.Color.red),
2848 ('value', Enum.__dict__['value']),
2849 ))
2850 result = dict(inspect.getmembers(self.Color))
2851 self.assertEqual(values.keys(), result.keys())
2852 failed = False
2853 for k in values.keys():
2854 if result[k] != values[k]:
2855 print()
2856 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2857 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2858 failed = True
2859 if failed:
2860 self.fail("result does not equal expected, see print above")
2861
2862 def test_inspect_classify_class_attrs(self):
2863 # indirectly test __objclass__
2864 from inspect import Attribute
2865 values = [
2866 Attribute(name='__class__', kind='data',
2867 defining_class=object, object=EnumMeta),
2868 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002869 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002870 Attribute(name='__members__', kind='property',
2871 defining_class=EnumMeta, object=EnumMeta.__members__),
2872 Attribute(name='__module__', kind='data',
2873 defining_class=self.Color, object=__name__),
2874 Attribute(name='blue', kind='data',
2875 defining_class=self.Color, object=self.Color.blue),
2876 Attribute(name='green', kind='data',
2877 defining_class=self.Color, object=self.Color.green),
2878 Attribute(name='red', kind='data',
2879 defining_class=self.Color, object=self.Color.red),
2880 Attribute(name='name', kind='data',
2881 defining_class=Enum, object=Enum.__dict__['name']),
2882 Attribute(name='value', kind='data',
2883 defining_class=Enum, object=Enum.__dict__['value']),
2884 ]
2885 values.sort(key=lambda item: item.name)
2886 result = list(inspect.classify_class_attrs(self.Color))
2887 result.sort(key=lambda item: item.name)
2888 failed = False
2889 for v, r in zip(values, result):
2890 if r != v:
2891 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2892 failed = True
2893 if failed:
2894 self.fail("result does not equal expected, see print above")
2895
Martin Panter19e69c52015-11-14 12:46:42 +00002896
2897class MiscTestCase(unittest.TestCase):
2898 def test__all__(self):
2899 support.check__all__(self, enum)
2900
2901
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002902# These are unordered here on purpose to ensure that declaration order
2903# makes no difference.
2904CONVERT_TEST_NAME_D = 5
2905CONVERT_TEST_NAME_C = 5
2906CONVERT_TEST_NAME_B = 5
2907CONVERT_TEST_NAME_A = 5 # This one should sort first.
2908CONVERT_TEST_NAME_E = 5
2909CONVERT_TEST_NAME_F = 5
2910
2911class TestIntEnumConvert(unittest.TestCase):
2912 def test_convert_value_lookup_priority(self):
2913 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002914 'UnittestConvert',
2915 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002916 filter=lambda x: x.startswith('CONVERT_TEST_'))
2917 # We don't want the reverse lookup value to vary when there are
2918 # multiple possible names for a given value. It should always
2919 # report the first lexigraphical name in that case.
2920 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2921
2922 def test_convert(self):
2923 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002924 'UnittestConvert',
2925 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002926 filter=lambda x: x.startswith('CONVERT_TEST_'))
2927 # Ensure that test_type has all of the desired names and values.
2928 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2929 test_type.CONVERT_TEST_NAME_A)
2930 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2931 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2932 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2933 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2934 # Ensure that test_type only picked up names matching the filter.
2935 self.assertEqual([name for name in dir(test_type)
2936 if name[0:2] not in ('CO', '__')],
2937 [], msg='Names other than CONVERT_TEST_* found.')
2938
2939
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002940if __name__ == '__main__':
2941 unittest.main()