blob: 865edf1d9cfc67beecafb873800813f7e55f65cb [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07008from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000011from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030012from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080013from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080014from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080015
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016
17# for pickle tests
18try:
19 class Stooges(Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23except Exception as exc:
24 Stooges = exc
25
26try:
27 class IntStooges(int, Enum):
28 LARRY = 1
29 CURLY = 2
30 MOE = 3
31except Exception as exc:
32 IntStooges = exc
33
34try:
35 class FloatStooges(float, Enum):
36 LARRY = 1.39
37 CURLY = 2.72
38 MOE = 3.142596
39except Exception as exc:
40 FloatStooges = exc
41
Ethan Furman65a5a472016-09-01 23:55:19 -070042try:
43 class FlagStooges(Flag):
44 LARRY = 1
45 CURLY = 2
46 MOE = 3
47except Exception as exc:
48 FlagStooges = exc
49
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050# for pickle test and subclass tests
51try:
52 class StrEnum(str, Enum):
53 'accepts only string values'
54 class Name(StrEnum):
55 BDFL = 'Guido van Rossum'
56 FLUFL = 'Barry Warsaw'
57except Exception as exc:
58 Name = exc
59
60try:
61 Question = Enum('Question', 'who what when where why', module=__name__)
62except Exception as exc:
63 Question = exc
64
65try:
66 Answer = Enum('Answer', 'him this then there because')
67except Exception as exc:
68 Answer = exc
69
Ethan Furmanca1b7942014-02-08 11:36:27 -080070try:
71 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
72except Exception as exc:
73 Theory = exc
74
Ethan Furman6b3d64a2013-06-14 16:55:46 -070075# for doctests
76try:
77 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080078 TOMATO = 1
79 BANANA = 2
80 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081except Exception:
82 pass
83
Serhiy Storchakae50e7802015-03-31 16:56:49 +030084def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080085 if target is None:
86 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030087 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080088 assertion(loads(dumps(source, protocol=protocol)), target)
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_exception(assertion, exception, obj):
91 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080092 with assertion(exception):
93 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070094
95class TestHelpers(unittest.TestCase):
96 # _is_descriptor, _is_sunder, _is_dunder
97
98 def test_is_descriptor(self):
99 class foo:
100 pass
101 for attr in ('__get__','__set__','__delete__'):
102 obj = foo()
103 self.assertFalse(enum._is_descriptor(obj))
104 setattr(obj, attr, 1)
105 self.assertTrue(enum._is_descriptor(obj))
106
107 def test_is_sunder(self):
108 for s in ('_a_', '_aa_'):
109 self.assertTrue(enum._is_sunder(s))
110
111 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
112 '__', '___', '____', '_____',):
113 self.assertFalse(enum._is_sunder(s))
114
115 def test_is_dunder(self):
116 for s in ('__a__', '__aa__'):
117 self.assertTrue(enum._is_dunder(s))
118 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
119 '__', '___', '____', '_____',):
120 self.assertFalse(enum._is_dunder(s))
121
Ethan Furman5bdab642018-09-21 19:03:09 -0700122# for subclassing tests
123
124class classproperty:
125
126 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
127 self.fget = fget
128 self.fset = fset
129 self.fdel = fdel
130 if doc is None and fget is not None:
131 doc = fget.__doc__
132 self.__doc__ = doc
133
134 def __get__(self, instance, ownerclass):
135 return self.fget(ownerclass)
136
137
Ethan Furmanc16595e2016-09-10 23:36:59 -0700138# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700139
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700140class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800141
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700142 def setUp(self):
143 class Season(Enum):
144 SPRING = 1
145 SUMMER = 2
146 AUTUMN = 3
147 WINTER = 4
148 self.Season = Season
149
Ethan Furmanec15a822013-08-31 19:17:41 -0700150 class Konstants(float, Enum):
151 E = 2.7182818
152 PI = 3.1415926
153 TAU = 2 * PI
154 self.Konstants = Konstants
155
156 class Grades(IntEnum):
157 A = 5
158 B = 4
159 C = 3
160 D = 2
161 F = 0
162 self.Grades = Grades
163
164 class Directional(str, Enum):
165 EAST = 'east'
166 WEST = 'west'
167 NORTH = 'north'
168 SOUTH = 'south'
169 self.Directional = Directional
170
171 from datetime import date
172 class Holiday(date, Enum):
173 NEW_YEAR = 2013, 1, 1
174 IDES_OF_MARCH = 2013, 3, 15
175 self.Holiday = Holiday
176
Ethan Furman388a3922013-08-12 06:51:41 -0700177 def test_dir_on_class(self):
178 Season = self.Season
179 self.assertEqual(
180 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700181 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700182 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
183 )
184
185 def test_dir_on_item(self):
186 Season = self.Season
187 self.assertEqual(
188 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700189 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700190 )
191
Ethan Furmanc850f342013-09-15 16:59:35 -0700192 def test_dir_with_added_behavior(self):
193 class Test(Enum):
194 this = 'that'
195 these = 'those'
196 def wowser(self):
197 return ("Wowser! I'm %s!" % self.name)
198 self.assertEqual(
199 set(dir(Test)),
200 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
201 )
202 self.assertEqual(
203 set(dir(Test.this)),
204 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
205 )
206
Ethan Furman0ae550b2014-10-14 08:58:32 -0700207 def test_dir_on_sub_with_behavior_on_super(self):
208 # see issue22506
209 class SuperEnum(Enum):
210 def invisible(self):
211 return "did you see me?"
212 class SubEnum(SuperEnum):
213 sample = 5
214 self.assertEqual(
215 set(dir(SubEnum.sample)),
216 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
217 )
218
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219 def test_enum_in_enum_out(self):
220 Season = self.Season
221 self.assertIs(Season(Season.WINTER), Season.WINTER)
222
223 def test_enum_value(self):
224 Season = self.Season
225 self.assertEqual(Season.SPRING.value, 1)
226
227 def test_intenum_value(self):
228 self.assertEqual(IntStooges.CURLY.value, 2)
229
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700230 def test_enum(self):
231 Season = self.Season
232 lst = list(Season)
233 self.assertEqual(len(lst), len(Season))
234 self.assertEqual(len(Season), 4, Season)
235 self.assertEqual(
236 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
237
238 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
239 e = Season(i)
240 self.assertEqual(e, getattr(Season, season))
241 self.assertEqual(e.value, i)
242 self.assertNotEqual(e, i)
243 self.assertEqual(e.name, season)
244 self.assertIn(e, Season)
245 self.assertIs(type(e), Season)
246 self.assertIsInstance(e, Season)
247 self.assertEqual(str(e), 'Season.' + season)
248 self.assertEqual(
249 repr(e),
250 '<Season.{0}: {1}>'.format(season, i),
251 )
252
253 def test_value_name(self):
254 Season = self.Season
255 self.assertEqual(Season.SPRING.name, 'SPRING')
256 self.assertEqual(Season.SPRING.value, 1)
257 with self.assertRaises(AttributeError):
258 Season.SPRING.name = 'invierno'
259 with self.assertRaises(AttributeError):
260 Season.SPRING.value = 2
261
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700262 def test_changing_member(self):
263 Season = self.Season
264 with self.assertRaises(AttributeError):
265 Season.WINTER = 'really cold'
266
Ethan Furman64a99722013-09-22 16:18:19 -0700267 def test_attribute_deletion(self):
268 class Season(Enum):
269 SPRING = 1
270 SUMMER = 2
271 AUTUMN = 3
272 WINTER = 4
273
274 def spam(cls):
275 pass
276
277 self.assertTrue(hasattr(Season, 'spam'))
278 del Season.spam
279 self.assertFalse(hasattr(Season, 'spam'))
280
281 with self.assertRaises(AttributeError):
282 del Season.SPRING
283 with self.assertRaises(AttributeError):
284 del Season.DRY
285 with self.assertRaises(AttributeError):
286 del Season.SPRING.name
287
Ethan Furman5de67b12016-04-13 23:52:09 -0700288 def test_bool_of_class(self):
289 class Empty(Enum):
290 pass
291 self.assertTrue(bool(Empty))
292
293 def test_bool_of_member(self):
294 class Count(Enum):
295 zero = 0
296 one = 1
297 two = 2
298 for member in Count:
299 self.assertTrue(bool(member))
300
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700301 def test_invalid_names(self):
302 with self.assertRaises(ValueError):
303 class Wrong(Enum):
304 mro = 9
305 with self.assertRaises(ValueError):
306 class Wrong(Enum):
307 _create_= 11
308 with self.assertRaises(ValueError):
309 class Wrong(Enum):
310 _get_mixins_ = 9
311 with self.assertRaises(ValueError):
312 class Wrong(Enum):
313 _find_new_ = 1
314 with self.assertRaises(ValueError):
315 class Wrong(Enum):
316 _any_name_ = 9
317
Ethan Furman6db1fd52015-09-17 21:49:12 -0700318 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800319 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700320 class Logic(Enum):
321 true = True
322 false = False
323 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800324 self.assertTrue(Logic.false)
325 # unless overridden
326 class RealLogic(Enum):
327 true = True
328 false = False
329 def __bool__(self):
330 return bool(self._value_)
331 self.assertTrue(RealLogic.true)
332 self.assertFalse(RealLogic.false)
333 # mixed Enums depend on mixed-in type
334 class IntLogic(int, Enum):
335 true = 1
336 false = 0
337 self.assertTrue(IntLogic.true)
338 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700339
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700340 def test_contains(self):
341 Season = self.Season
342 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530343 with self.assertRaises(TypeError):
344 3 in Season
345 with self.assertRaises(TypeError):
346 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347
348 val = Season(3)
349 self.assertIn(val, Season)
350
351 class OtherEnum(Enum):
352 one = 1; two = 2
353 self.assertNotIn(OtherEnum.two, Season)
354
355 def test_comparisons(self):
356 Season = self.Season
357 with self.assertRaises(TypeError):
358 Season.SPRING < Season.WINTER
359 with self.assertRaises(TypeError):
360 Season.SPRING > 4
361
362 self.assertNotEqual(Season.SPRING, 1)
363
364 class Part(Enum):
365 SPRING = 1
366 CLIP = 2
367 BARREL = 3
368
369 self.assertNotEqual(Season.SPRING, Part.SPRING)
370 with self.assertRaises(TypeError):
371 Season.SPRING < Part.CLIP
372
373 def test_enum_duplicates(self):
374 class Season(Enum):
375 SPRING = 1
376 SUMMER = 2
377 AUTUMN = FALL = 3
378 WINTER = 4
379 ANOTHER_SPRING = 1
380 lst = list(Season)
381 self.assertEqual(
382 lst,
383 [Season.SPRING, Season.SUMMER,
384 Season.AUTUMN, Season.WINTER,
385 ])
386 self.assertIs(Season.FALL, Season.AUTUMN)
387 self.assertEqual(Season.FALL.value, 3)
388 self.assertEqual(Season.AUTUMN.value, 3)
389 self.assertIs(Season(3), Season.AUTUMN)
390 self.assertIs(Season(1), Season.SPRING)
391 self.assertEqual(Season.FALL.name, 'AUTUMN')
392 self.assertEqual(
393 [k for k,v in Season.__members__.items() if v.name != k],
394 ['FALL', 'ANOTHER_SPRING'],
395 )
396
Ethan Furman101e0742013-09-15 12:34:36 -0700397 def test_duplicate_name(self):
398 with self.assertRaises(TypeError):
399 class Color(Enum):
400 red = 1
401 green = 2
402 blue = 3
403 red = 4
404
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 def red(self):
411 return 'red'
412
413 with self.assertRaises(TypeError):
414 class Color(Enum):
415 @property
416 def red(self):
417 return 'redder'
418 red = 1
419 green = 2
420 blue = 3
421
Zackery Spytz2ec67522020-09-13 14:27:51 -0600422 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700423 with self.assertRaisesRegex(
424 ValueError,
425 '_sunder_ names, such as "_bad_", are reserved',
426 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600427 class Bad(Enum):
428 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700429
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700430 def test_enum_with_value_name(self):
431 class Huh(Enum):
432 name = 1
433 value = 2
434 self.assertEqual(
435 list(Huh),
436 [Huh.name, Huh.value],
437 )
438 self.assertIs(type(Huh.name), Huh)
439 self.assertEqual(Huh.name.name, 'name')
440 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700441
442 def test_format_enum(self):
443 Season = self.Season
444 self.assertEqual('{}'.format(Season.SPRING),
445 '{}'.format(str(Season.SPRING)))
446 self.assertEqual( '{:}'.format(Season.SPRING),
447 '{:}'.format(str(Season.SPRING)))
448 self.assertEqual('{:20}'.format(Season.SPRING),
449 '{:20}'.format(str(Season.SPRING)))
450 self.assertEqual('{:^20}'.format(Season.SPRING),
451 '{:^20}'.format(str(Season.SPRING)))
452 self.assertEqual('{:>20}'.format(Season.SPRING),
453 '{:>20}'.format(str(Season.SPRING)))
454 self.assertEqual('{:<20}'.format(Season.SPRING),
455 '{:<20}'.format(str(Season.SPRING)))
456
thatneat2f19e822019-07-04 11:28:37 -0700457 def test_str_override_enum(self):
458 class EnumWithStrOverrides(Enum):
459 one = auto()
460 two = auto()
461
462 def __str__(self):
463 return 'Str!'
464 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
465 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
466
467 def test_format_override_enum(self):
468 class EnumWithFormatOverride(Enum):
469 one = 1.0
470 two = 2.0
471 def __format__(self, spec):
472 return 'Format!!'
473 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
474 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
475
476 def test_str_and_format_override_enum(self):
477 class EnumWithStrFormatOverrides(Enum):
478 one = auto()
479 two = auto()
480 def __str__(self):
481 return 'Str!'
482 def __format__(self, spec):
483 return 'Format!'
484 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
485 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
486
487 def test_str_override_mixin(self):
488 class MixinEnumWithStrOverride(float, Enum):
489 one = 1.0
490 two = 2.0
491 def __str__(self):
492 return 'Overridden!'
493 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
494 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
495
496 def test_str_and_format_override_mixin(self):
497 class MixinWithStrFormatOverrides(float, Enum):
498 one = 1.0
499 two = 2.0
500 def __str__(self):
501 return 'Str!'
502 def __format__(self, spec):
503 return 'Format!'
504 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
505 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
506
507 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700508 class TestFloat(float, Enum):
509 one = 1.0
510 two = 2.0
511 def __format__(self, spec):
512 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700513 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700514 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
515
516 def assertFormatIsValue(self, spec, member):
517 self.assertEqual(spec.format(member), spec.format(member.value))
518
519 def test_format_enum_date(self):
520 Holiday = self.Holiday
521 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
522 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
523 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
524 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
525 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
526 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
527 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
528 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
529
530 def test_format_enum_float(self):
531 Konstants = self.Konstants
532 self.assertFormatIsValue('{}', Konstants.TAU)
533 self.assertFormatIsValue('{:}', Konstants.TAU)
534 self.assertFormatIsValue('{:20}', Konstants.TAU)
535 self.assertFormatIsValue('{:^20}', Konstants.TAU)
536 self.assertFormatIsValue('{:>20}', Konstants.TAU)
537 self.assertFormatIsValue('{:<20}', Konstants.TAU)
538 self.assertFormatIsValue('{:n}', Konstants.TAU)
539 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
540 self.assertFormatIsValue('{:f}', Konstants.TAU)
541
542 def test_format_enum_int(self):
543 Grades = self.Grades
544 self.assertFormatIsValue('{}', Grades.C)
545 self.assertFormatIsValue('{:}', Grades.C)
546 self.assertFormatIsValue('{:20}', Grades.C)
547 self.assertFormatIsValue('{:^20}', Grades.C)
548 self.assertFormatIsValue('{:>20}', Grades.C)
549 self.assertFormatIsValue('{:<20}', Grades.C)
550 self.assertFormatIsValue('{:+}', Grades.C)
551 self.assertFormatIsValue('{:08X}', Grades.C)
552 self.assertFormatIsValue('{:b}', Grades.C)
553
554 def test_format_enum_str(self):
555 Directional = self.Directional
556 self.assertFormatIsValue('{}', Directional.WEST)
557 self.assertFormatIsValue('{:}', Directional.WEST)
558 self.assertFormatIsValue('{:20}', Directional.WEST)
559 self.assertFormatIsValue('{:^20}', Directional.WEST)
560 self.assertFormatIsValue('{:>20}', Directional.WEST)
561 self.assertFormatIsValue('{:<20}', Directional.WEST)
562
Ethan Furman22415ad2020-09-15 16:28:25 -0700563 def test_object_str_override(self):
564 class Colors(Enum):
565 RED, GREEN, BLUE = 1, 2, 3
566 def __repr__(self):
567 return "test.%s" % (self._name_, )
568 __str__ = object.__str__
569 self.assertEqual(str(Colors.RED), 'test.RED')
570
Ethan Furmanbff01f32020-09-15 15:56:26 -0700571 def test_enum_str_override(self):
572 class MyStrEnum(Enum):
573 def __str__(self):
574 return 'MyStr'
575 class MyMethodEnum(Enum):
576 def hello(self):
577 return 'Hello! My name is %s' % self.name
578 class Test1Enum(MyMethodEnum, int, MyStrEnum):
579 One = 1
580 Two = 2
581 self.assertEqual(str(Test1Enum.One), 'MyStr')
582 #
583 class Test2Enum(MyStrEnum, MyMethodEnum):
584 One = 1
585 Two = 2
586 self.assertEqual(str(Test2Enum.One), 'MyStr')
587
588 def test_inherited_data_type(self):
589 class HexInt(int):
590 def __repr__(self):
591 return hex(self)
592 class MyEnum(HexInt, enum.Enum):
593 A = 1
594 B = 2
595 C = 3
596 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
597
598 def test_too_many_data_types(self):
599 with self.assertRaisesRegex(TypeError, 'too many data types'):
600 class Huh(str, int, Enum):
601 One = 1
602
603 class MyStr(str):
604 def hello(self):
605 return 'hello, %s' % self
606 class MyInt(int):
607 def repr(self):
608 return hex(self)
609 with self.assertRaisesRegex(TypeError, 'too many data types'):
610 class Huh(MyStr, MyInt, Enum):
611 One = 1
612
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700613 def test_hash(self):
614 Season = self.Season
615 dates = {}
616 dates[Season.WINTER] = '1225'
617 dates[Season.SPRING] = '0315'
618 dates[Season.SUMMER] = '0704'
619 dates[Season.AUTUMN] = '1031'
620 self.assertEqual(dates[Season.AUTUMN], '1031')
621
622 def test_intenum_from_scratch(self):
623 class phy(int, Enum):
624 pi = 3
625 tau = 2 * pi
626 self.assertTrue(phy.pi < phy.tau)
627
628 def test_intenum_inherited(self):
629 class IntEnum(int, Enum):
630 pass
631 class phy(IntEnum):
632 pi = 3
633 tau = 2 * pi
634 self.assertTrue(phy.pi < phy.tau)
635
636 def test_floatenum_from_scratch(self):
637 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700638 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700639 tau = 2 * pi
640 self.assertTrue(phy.pi < phy.tau)
641
642 def test_floatenum_inherited(self):
643 class FloatEnum(float, Enum):
644 pass
645 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700646 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700647 tau = 2 * pi
648 self.assertTrue(phy.pi < phy.tau)
649
650 def test_strenum_from_scratch(self):
651 class phy(str, Enum):
652 pi = 'Pi'
653 tau = 'Tau'
654 self.assertTrue(phy.pi < phy.tau)
655
656 def test_strenum_inherited(self):
657 class StrEnum(str, Enum):
658 pass
659 class phy(StrEnum):
660 pi = 'Pi'
661 tau = 'Tau'
662 self.assertTrue(phy.pi < phy.tau)
663
664
665 def test_intenum(self):
666 class WeekDay(IntEnum):
667 SUNDAY = 1
668 MONDAY = 2
669 TUESDAY = 3
670 WEDNESDAY = 4
671 THURSDAY = 5
672 FRIDAY = 6
673 SATURDAY = 7
674
675 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
676 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
677
678 lst = list(WeekDay)
679 self.assertEqual(len(lst), len(WeekDay))
680 self.assertEqual(len(WeekDay), 7)
681 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
682 target = target.split()
683 for i, weekday in enumerate(target, 1):
684 e = WeekDay(i)
685 self.assertEqual(e, i)
686 self.assertEqual(int(e), i)
687 self.assertEqual(e.name, weekday)
688 self.assertIn(e, WeekDay)
689 self.assertEqual(lst.index(e)+1, i)
690 self.assertTrue(0 < e < 8)
691 self.assertIs(type(e), WeekDay)
692 self.assertIsInstance(e, int)
693 self.assertIsInstance(e, Enum)
694
695 def test_intenum_duplicates(self):
696 class WeekDay(IntEnum):
697 SUNDAY = 1
698 MONDAY = 2
699 TUESDAY = TEUSDAY = 3
700 WEDNESDAY = 4
701 THURSDAY = 5
702 FRIDAY = 6
703 SATURDAY = 7
704 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
705 self.assertEqual(WeekDay(3).name, 'TUESDAY')
706 self.assertEqual([k for k,v in WeekDay.__members__.items()
707 if v.name != k], ['TEUSDAY', ])
708
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300709 def test_intenum_from_bytes(self):
710 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
711 with self.assertRaises(ValueError):
712 IntStooges.from_bytes(b'\x00\x05', 'big')
713
714 def test_floatenum_fromhex(self):
715 h = float.hex(FloatStooges.MOE.value)
716 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
717 h = float.hex(FloatStooges.MOE.value + 0.01)
718 with self.assertRaises(ValueError):
719 FloatStooges.fromhex(h)
720
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700721 def test_pickle_enum(self):
722 if isinstance(Stooges, Exception):
723 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800724 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
725 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700726
727 def test_pickle_int(self):
728 if isinstance(IntStooges, Exception):
729 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800730 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
731 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700732
733 def test_pickle_float(self):
734 if isinstance(FloatStooges, Exception):
735 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800736 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
737 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700738
739 def test_pickle_enum_function(self):
740 if isinstance(Answer, Exception):
741 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800742 test_pickle_dump_load(self.assertIs, Answer.him)
743 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700744
745 def test_pickle_enum_function_with_module(self):
746 if isinstance(Question, Exception):
747 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800748 test_pickle_dump_load(self.assertIs, Question.who)
749 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750
Ethan Furmanca1b7942014-02-08 11:36:27 -0800751 def test_enum_function_with_qualname(self):
752 if isinstance(Theory, Exception):
753 raise Theory
754 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
755
756 def test_class_nested_enum_and_pickle_protocol_four(self):
757 # would normally just have this directly in the class namespace
758 class NestedEnum(Enum):
759 twigs = 'common'
760 shiny = 'rare'
761
762 self.__class__.NestedEnum = NestedEnum
763 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300764 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800765
Ethan Furman24e837f2015-03-18 17:27:57 -0700766 def test_pickle_by_name(self):
767 class ReplaceGlobalInt(IntEnum):
768 ONE = 1
769 TWO = 2
770 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
771 for proto in range(HIGHEST_PROTOCOL):
772 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
773
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700774 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800775 BadPickle = Enum(
776 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700777 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800778 # now break BadPickle to test exception raising
779 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800780 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
781 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700782
783 def test_string_enum(self):
784 class SkillLevel(str, Enum):
785 master = 'what is the sound of one hand clapping?'
786 journeyman = 'why did the chicken cross the road?'
787 apprentice = 'knock, knock!'
788 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
789
790 def test_getattr_getitem(self):
791 class Period(Enum):
792 morning = 1
793 noon = 2
794 evening = 3
795 night = 4
796 self.assertIs(Period(2), Period.noon)
797 self.assertIs(getattr(Period, 'night'), Period.night)
798 self.assertIs(Period['morning'], Period.morning)
799
800 def test_getattr_dunder(self):
801 Season = self.Season
802 self.assertTrue(getattr(Season, '__eq__'))
803
804 def test_iteration_order(self):
805 class Season(Enum):
806 SUMMER = 2
807 WINTER = 4
808 AUTUMN = 3
809 SPRING = 1
810 self.assertEqual(
811 list(Season),
812 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
813 )
814
Ethan Furman2131a4a2013-09-14 18:11:24 -0700815 def test_reversed_iteration_order(self):
816 self.assertEqual(
817 list(reversed(self.Season)),
818 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
819 self.Season.SPRING]
820 )
821
Martin Pantereb995702016-07-28 01:11:04 +0000822 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700823 SummerMonth = Enum('SummerMonth', 'june july august')
824 lst = list(SummerMonth)
825 self.assertEqual(len(lst), len(SummerMonth))
826 self.assertEqual(len(SummerMonth), 3, SummerMonth)
827 self.assertEqual(
828 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
829 lst,
830 )
831 for i, month in enumerate('june july august'.split(), 1):
832 e = SummerMonth(i)
833 self.assertEqual(int(e.value), i)
834 self.assertNotEqual(e, i)
835 self.assertEqual(e.name, month)
836 self.assertIn(e, SummerMonth)
837 self.assertIs(type(e), SummerMonth)
838
Martin Pantereb995702016-07-28 01:11:04 +0000839 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700840 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
841 lst = list(SummerMonth)
842 self.assertEqual(len(lst), len(SummerMonth))
843 self.assertEqual(len(SummerMonth), 3, SummerMonth)
844 self.assertEqual(
845 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
846 lst,
847 )
848 for i, month in enumerate('june july august'.split(), 10):
849 e = SummerMonth(i)
850 self.assertEqual(int(e.value), i)
851 self.assertNotEqual(e, i)
852 self.assertEqual(e.name, month)
853 self.assertIn(e, SummerMonth)
854 self.assertIs(type(e), SummerMonth)
855
Martin Pantereb995702016-07-28 01:11:04 +0000856 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700857 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
858 lst = list(SummerMonth)
859 self.assertEqual(len(lst), len(SummerMonth))
860 self.assertEqual(len(SummerMonth), 3, SummerMonth)
861 self.assertEqual(
862 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
863 lst,
864 )
865 for i, month in enumerate('june july august'.split(), 1):
866 e = SummerMonth(i)
867 self.assertEqual(int(e.value), i)
868 self.assertNotEqual(e, i)
869 self.assertEqual(e.name, month)
870 self.assertIn(e, SummerMonth)
871 self.assertIs(type(e), SummerMonth)
872
Martin Pantereb995702016-07-28 01:11:04 +0000873 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700874 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
875 lst = list(SummerMonth)
876 self.assertEqual(len(lst), len(SummerMonth))
877 self.assertEqual(len(SummerMonth), 3, SummerMonth)
878 self.assertEqual(
879 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
880 lst,
881 )
882 for i, month in enumerate('june july august'.split(), 20):
883 e = SummerMonth(i)
884 self.assertEqual(int(e.value), i)
885 self.assertNotEqual(e, i)
886 self.assertEqual(e.name, month)
887 self.assertIn(e, SummerMonth)
888 self.assertIs(type(e), SummerMonth)
889
Martin Pantereb995702016-07-28 01:11:04 +0000890 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700891 SummerMonth = Enum(
892 'SummerMonth',
893 (('june', 1), ('july', 2), ('august', 3))
894 )
895 lst = list(SummerMonth)
896 self.assertEqual(len(lst), len(SummerMonth))
897 self.assertEqual(len(SummerMonth), 3, SummerMonth)
898 self.assertEqual(
899 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
900 lst,
901 )
902 for i, month in enumerate('june july august'.split(), 1):
903 e = SummerMonth(i)
904 self.assertEqual(int(e.value), i)
905 self.assertNotEqual(e, i)
906 self.assertEqual(e.name, month)
907 self.assertIn(e, SummerMonth)
908 self.assertIs(type(e), SummerMonth)
909
Martin Pantereb995702016-07-28 01:11:04 +0000910 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700911 SummerMonth = Enum(
912 'SummerMonth',
913 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
914 )
915 lst = list(SummerMonth)
916 self.assertEqual(len(lst), len(SummerMonth))
917 self.assertEqual(len(SummerMonth), 3, SummerMonth)
918 self.assertEqual(
919 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
920 lst,
921 )
922 for i, month in enumerate('june july august'.split(), 1):
923 e = SummerMonth(i)
924 self.assertEqual(int(e.value), i)
925 self.assertNotEqual(e, i)
926 self.assertEqual(e.name, month)
927 self.assertIn(e, SummerMonth)
928 self.assertIs(type(e), SummerMonth)
929
Martin Pantereb995702016-07-28 01:11:04 +0000930 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700931 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
932 lst = list(SummerMonth)
933 self.assertEqual(len(lst), len(SummerMonth))
934 self.assertEqual(len(SummerMonth), 3, SummerMonth)
935 self.assertEqual(
936 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
937 lst,
938 )
939 for i, month in enumerate('june july august'.split(), 1):
940 e = SummerMonth(i)
941 self.assertEqual(e, i)
942 self.assertEqual(e.name, month)
943 self.assertIn(e, SummerMonth)
944 self.assertIs(type(e), SummerMonth)
945
Martin Pantereb995702016-07-28 01:11:04 +0000946 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700947 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
948 lst = list(SummerMonth)
949 self.assertEqual(len(lst), len(SummerMonth))
950 self.assertEqual(len(SummerMonth), 3, SummerMonth)
951 self.assertEqual(
952 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
953 lst,
954 )
955 for i, month in enumerate('june july august'.split(), 30):
956 e = SummerMonth(i)
957 self.assertEqual(e, i)
958 self.assertEqual(e.name, month)
959 self.assertIn(e, SummerMonth)
960 self.assertIs(type(e), SummerMonth)
961
Martin Pantereb995702016-07-28 01:11:04 +0000962 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700963 SummerMonth = IntEnum('SummerMonth', 'june july august')
964 lst = list(SummerMonth)
965 self.assertEqual(len(lst), len(SummerMonth))
966 self.assertEqual(len(SummerMonth), 3, SummerMonth)
967 self.assertEqual(
968 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
969 lst,
970 )
971 for i, month in enumerate('june july august'.split(), 1):
972 e = SummerMonth(i)
973 self.assertEqual(e, i)
974 self.assertEqual(e.name, month)
975 self.assertIn(e, SummerMonth)
976 self.assertIs(type(e), SummerMonth)
977
Martin Pantereb995702016-07-28 01:11:04 +0000978 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700979 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
980 lst = list(SummerMonth)
981 self.assertEqual(len(lst), len(SummerMonth))
982 self.assertEqual(len(SummerMonth), 3, SummerMonth)
983 self.assertEqual(
984 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
985 lst,
986 )
987 for i, month in enumerate('june july august'.split(), 40):
988 e = SummerMonth(i)
989 self.assertEqual(e, i)
990 self.assertEqual(e.name, month)
991 self.assertIn(e, SummerMonth)
992 self.assertIs(type(e), SummerMonth)
993
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700994 def test_subclassing(self):
995 if isinstance(Name, Exception):
996 raise Name
997 self.assertEqual(Name.BDFL, 'Guido van Rossum')
998 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
999 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001000 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001001
1002 def test_extending(self):
1003 class Color(Enum):
1004 red = 1
1005 green = 2
1006 blue = 3
1007 with self.assertRaises(TypeError):
1008 class MoreColor(Color):
1009 cyan = 4
1010 magenta = 5
1011 yellow = 6
1012
1013 def test_exclude_methods(self):
1014 class whatever(Enum):
1015 this = 'that'
1016 these = 'those'
1017 def really(self):
1018 return 'no, not %s' % self.value
1019 self.assertIsNot(type(whatever.really), whatever)
1020 self.assertEqual(whatever.this.really(), 'no, not that')
1021
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001022 def test_wrong_inheritance_order(self):
1023 with self.assertRaises(TypeError):
1024 class Wrong(Enum, str):
1025 NotHere = 'error before this point'
1026
1027 def test_intenum_transitivity(self):
1028 class number(IntEnum):
1029 one = 1
1030 two = 2
1031 three = 3
1032 class numero(IntEnum):
1033 uno = 1
1034 dos = 2
1035 tres = 3
1036 self.assertEqual(number.one, numero.uno)
1037 self.assertEqual(number.two, numero.dos)
1038 self.assertEqual(number.three, numero.tres)
1039
1040 def test_wrong_enum_in_call(self):
1041 class Monochrome(Enum):
1042 black = 0
1043 white = 1
1044 class Gender(Enum):
1045 male = 0
1046 female = 1
1047 self.assertRaises(ValueError, Monochrome, Gender.male)
1048
1049 def test_wrong_enum_in_mixed_call(self):
1050 class Monochrome(IntEnum):
1051 black = 0
1052 white = 1
1053 class Gender(Enum):
1054 male = 0
1055 female = 1
1056 self.assertRaises(ValueError, Monochrome, Gender.male)
1057
1058 def test_mixed_enum_in_call_1(self):
1059 class Monochrome(IntEnum):
1060 black = 0
1061 white = 1
1062 class Gender(IntEnum):
1063 male = 0
1064 female = 1
1065 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1066
1067 def test_mixed_enum_in_call_2(self):
1068 class Monochrome(Enum):
1069 black = 0
1070 white = 1
1071 class Gender(IntEnum):
1072 male = 0
1073 female = 1
1074 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1075
1076 def test_flufl_enum(self):
1077 class Fluflnum(Enum):
1078 def __int__(self):
1079 return int(self.value)
1080 class MailManOptions(Fluflnum):
1081 option1 = 1
1082 option2 = 2
1083 option3 = 3
1084 self.assertEqual(int(MailManOptions.option1), 1)
1085
Ethan Furman5e5a8232013-08-04 08:42:23 -07001086 def test_introspection(self):
1087 class Number(IntEnum):
1088 one = 100
1089 two = 200
1090 self.assertIs(Number.one._member_type_, int)
1091 self.assertIs(Number._member_type_, int)
1092 class String(str, Enum):
1093 yarn = 'soft'
1094 rope = 'rough'
1095 wire = 'hard'
1096 self.assertIs(String.yarn._member_type_, str)
1097 self.assertIs(String._member_type_, str)
1098 class Plain(Enum):
1099 vanilla = 'white'
1100 one = 1
1101 self.assertIs(Plain.vanilla._member_type_, object)
1102 self.assertIs(Plain._member_type_, object)
1103
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001104 def test_no_such_enum_member(self):
1105 class Color(Enum):
1106 red = 1
1107 green = 2
1108 blue = 3
1109 with self.assertRaises(ValueError):
1110 Color(4)
1111 with self.assertRaises(KeyError):
1112 Color['chartreuse']
1113
1114 def test_new_repr(self):
1115 class Color(Enum):
1116 red = 1
1117 green = 2
1118 blue = 3
1119 def __repr__(self):
1120 return "don't you just love shades of %s?" % self.name
1121 self.assertEqual(
1122 repr(Color.blue),
1123 "don't you just love shades of blue?",
1124 )
1125
1126 def test_inherited_repr(self):
1127 class MyEnum(Enum):
1128 def __repr__(self):
1129 return "My name is %s." % self.name
1130 class MyIntEnum(int, MyEnum):
1131 this = 1
1132 that = 2
1133 theother = 3
1134 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1135
1136 def test_multiple_mixin_mro(self):
1137 class auto_enum(type(Enum)):
1138 def __new__(metacls, cls, bases, classdict):
1139 temp = type(classdict)()
1140 names = set(classdict._member_names)
1141 i = 0
1142 for k in classdict._member_names:
1143 v = classdict[k]
1144 if v is Ellipsis:
1145 v = i
1146 else:
1147 i = v
1148 i += 1
1149 temp[k] = v
1150 for k, v in classdict.items():
1151 if k not in names:
1152 temp[k] = v
1153 return super(auto_enum, metacls).__new__(
1154 metacls, cls, bases, temp)
1155
1156 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1157 pass
1158
1159 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1160 pass
1161
1162 class TestAutoNumber(AutoNumberedEnum):
1163 a = ...
1164 b = 3
1165 c = ...
1166
1167 class TestAutoInt(AutoIntEnum):
1168 a = ...
1169 b = 3
1170 c = ...
1171
1172 def test_subclasses_with_getnewargs(self):
1173 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001174 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001175 def __new__(cls, *args):
1176 _args = args
1177 name, *args = args
1178 if len(args) == 0:
1179 raise TypeError("name and value must be specified")
1180 self = int.__new__(cls, *args)
1181 self._intname = name
1182 self._args = _args
1183 return self
1184 def __getnewargs__(self):
1185 return self._args
1186 @property
1187 def __name__(self):
1188 return self._intname
1189 def __repr__(self):
1190 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001191 return "{}({!r}, {})".format(
1192 type(self).__name__,
1193 self.__name__,
1194 int.__repr__(self),
1195 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001196 def __str__(self):
1197 # str() is unchanged, even if it relies on the repr() fallback
1198 base = int
1199 base_str = base.__str__
1200 if base_str.__objclass__ is object:
1201 return base.__repr__(self)
1202 return base_str(self)
1203 # for simplicity, we only define one operator that
1204 # propagates expressions
1205 def __add__(self, other):
1206 temp = int(self) + int( other)
1207 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1208 return NamedInt(
1209 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001210 temp,
1211 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001212 else:
1213 return temp
1214
1215 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001216 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001217 x = ('the-x', 1)
1218 y = ('the-y', 2)
1219
Ethan Furman2aa27322013-07-19 19:35:56 -07001220
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001221 self.assertIs(NEI.__new__, Enum.__new__)
1222 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1223 globals()['NamedInt'] = NamedInt
1224 globals()['NEI'] = NEI
1225 NI5 = NamedInt('test', 5)
1226 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001227 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001228 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001229 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001230 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001231
Ethan Furmanca1b7942014-02-08 11:36:27 -08001232 def test_subclasses_with_getnewargs_ex(self):
1233 class NamedInt(int):
1234 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1235 def __new__(cls, *args):
1236 _args = args
1237 name, *args = args
1238 if len(args) == 0:
1239 raise TypeError("name and value must be specified")
1240 self = int.__new__(cls, *args)
1241 self._intname = name
1242 self._args = _args
1243 return self
1244 def __getnewargs_ex__(self):
1245 return self._args, {}
1246 @property
1247 def __name__(self):
1248 return self._intname
1249 def __repr__(self):
1250 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001251 return "{}({!r}, {})".format(
1252 type(self).__name__,
1253 self.__name__,
1254 int.__repr__(self),
1255 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001256 def __str__(self):
1257 # str() is unchanged, even if it relies on the repr() fallback
1258 base = int
1259 base_str = base.__str__
1260 if base_str.__objclass__ is object:
1261 return base.__repr__(self)
1262 return base_str(self)
1263 # for simplicity, we only define one operator that
1264 # propagates expressions
1265 def __add__(self, other):
1266 temp = int(self) + int( other)
1267 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1268 return NamedInt(
1269 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001270 temp,
1271 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001272 else:
1273 return temp
1274
1275 class NEI(NamedInt, Enum):
1276 __qualname__ = 'NEI' # needed for pickle protocol 4
1277 x = ('the-x', 1)
1278 y = ('the-y', 2)
1279
1280
1281 self.assertIs(NEI.__new__, Enum.__new__)
1282 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1283 globals()['NamedInt'] = NamedInt
1284 globals()['NEI'] = NEI
1285 NI5 = NamedInt('test', 5)
1286 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001287 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001288 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001289 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001290 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001291
1292 def test_subclasses_with_reduce(self):
1293 class NamedInt(int):
1294 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1295 def __new__(cls, *args):
1296 _args = args
1297 name, *args = args
1298 if len(args) == 0:
1299 raise TypeError("name and value must be specified")
1300 self = int.__new__(cls, *args)
1301 self._intname = name
1302 self._args = _args
1303 return self
1304 def __reduce__(self):
1305 return self.__class__, self._args
1306 @property
1307 def __name__(self):
1308 return self._intname
1309 def __repr__(self):
1310 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001311 return "{}({!r}, {})".format(
1312 type(self).__name__,
1313 self.__name__,
1314 int.__repr__(self),
1315 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001316 def __str__(self):
1317 # str() is unchanged, even if it relies on the repr() fallback
1318 base = int
1319 base_str = base.__str__
1320 if base_str.__objclass__ is object:
1321 return base.__repr__(self)
1322 return base_str(self)
1323 # for simplicity, we only define one operator that
1324 # propagates expressions
1325 def __add__(self, other):
1326 temp = int(self) + int( other)
1327 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1328 return NamedInt(
1329 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001330 temp,
1331 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001332 else:
1333 return temp
1334
1335 class NEI(NamedInt, Enum):
1336 __qualname__ = 'NEI' # needed for pickle protocol 4
1337 x = ('the-x', 1)
1338 y = ('the-y', 2)
1339
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 test_pickle_dump_load(self.assertEqual, NI5, 5)
1348 self.assertEqual(NEI.y.value, 2)
1349 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001350 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001351
1352 def test_subclasses_with_reduce_ex(self):
1353 class NamedInt(int):
1354 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1355 def __new__(cls, *args):
1356 _args = args
1357 name, *args = args
1358 if len(args) == 0:
1359 raise TypeError("name and value must be specified")
1360 self = int.__new__(cls, *args)
1361 self._intname = name
1362 self._args = _args
1363 return self
1364 def __reduce_ex__(self, proto):
1365 return self.__class__, self._args
1366 @property
1367 def __name__(self):
1368 return self._intname
1369 def __repr__(self):
1370 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001371 return "{}({!r}, {})".format(
1372 type(self).__name__,
1373 self.__name__,
1374 int.__repr__(self),
1375 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001376 def __str__(self):
1377 # str() is unchanged, even if it relies on the repr() fallback
1378 base = int
1379 base_str = base.__str__
1380 if base_str.__objclass__ is object:
1381 return base.__repr__(self)
1382 return base_str(self)
1383 # for simplicity, we only define one operator that
1384 # propagates expressions
1385 def __add__(self, other):
1386 temp = int(self) + int( other)
1387 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1388 return NamedInt(
1389 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001390 temp,
1391 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001392 else:
1393 return temp
1394
1395 class NEI(NamedInt, Enum):
1396 __qualname__ = 'NEI' # needed for pickle protocol 4
1397 x = ('the-x', 1)
1398 y = ('the-y', 2)
1399
Ethan Furmanca1b7942014-02-08 11:36:27 -08001400 self.assertIs(NEI.__new__, Enum.__new__)
1401 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1402 globals()['NamedInt'] = NamedInt
1403 globals()['NEI'] = NEI
1404 NI5 = NamedInt('test', 5)
1405 self.assertEqual(NI5, 5)
1406 test_pickle_dump_load(self.assertEqual, NI5, 5)
1407 self.assertEqual(NEI.y.value, 2)
1408 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001409 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001410
Ethan Furmandc870522014-02-18 12:37:12 -08001411 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001412 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001413 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001414 def __new__(cls, *args):
1415 _args = args
1416 name, *args = args
1417 if len(args) == 0:
1418 raise TypeError("name and value must be specified")
1419 self = int.__new__(cls, *args)
1420 self._intname = name
1421 self._args = _args
1422 return self
1423 @property
1424 def __name__(self):
1425 return self._intname
1426 def __repr__(self):
1427 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001428 return "{}({!r}, {})".format(
1429 type(self).__name__,
1430 self.__name__,
1431 int.__repr__(self),
1432 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001433 def __str__(self):
1434 # str() is unchanged, even if it relies on the repr() fallback
1435 base = int
1436 base_str = base.__str__
1437 if base_str.__objclass__ is object:
1438 return base.__repr__(self)
1439 return base_str(self)
1440 # for simplicity, we only define one operator that
1441 # propagates expressions
1442 def __add__(self, other):
1443 temp = int(self) + int( other)
1444 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1445 return NamedInt(
1446 '({0} + {1})'.format(self.__name__, other.__name__),
1447 temp )
1448 else:
1449 return temp
1450
1451 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001452 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001453 x = ('the-x', 1)
1454 y = ('the-y', 2)
1455
1456 self.assertIs(NEI.__new__, Enum.__new__)
1457 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1458 globals()['NamedInt'] = NamedInt
1459 globals()['NEI'] = NEI
1460 NI5 = NamedInt('test', 5)
1461 self.assertEqual(NI5, 5)
1462 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001463 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1464 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001465
Ethan Furmandc870522014-02-18 12:37:12 -08001466 def test_subclasses_without_direct_pickle_support_using_name(self):
1467 class NamedInt(int):
1468 __qualname__ = 'NamedInt'
1469 def __new__(cls, *args):
1470 _args = args
1471 name, *args = args
1472 if len(args) == 0:
1473 raise TypeError("name and value must be specified")
1474 self = int.__new__(cls, *args)
1475 self._intname = name
1476 self._args = _args
1477 return self
1478 @property
1479 def __name__(self):
1480 return self._intname
1481 def __repr__(self):
1482 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001483 return "{}({!r}, {})".format(
1484 type(self).__name__,
1485 self.__name__,
1486 int.__repr__(self),
1487 )
Ethan Furmandc870522014-02-18 12:37:12 -08001488 def __str__(self):
1489 # str() is unchanged, even if it relies on the repr() fallback
1490 base = int
1491 base_str = base.__str__
1492 if base_str.__objclass__ is object:
1493 return base.__repr__(self)
1494 return base_str(self)
1495 # for simplicity, we only define one operator that
1496 # propagates expressions
1497 def __add__(self, other):
1498 temp = int(self) + int( other)
1499 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1500 return NamedInt(
1501 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001502 temp,
1503 )
Ethan Furmandc870522014-02-18 12:37:12 -08001504 else:
1505 return temp
1506
1507 class NEI(NamedInt, Enum):
1508 __qualname__ = 'NEI'
1509 x = ('the-x', 1)
1510 y = ('the-y', 2)
1511 def __reduce_ex__(self, proto):
1512 return getattr, (self.__class__, self._name_)
1513
1514 self.assertIs(NEI.__new__, Enum.__new__)
1515 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1516 globals()['NamedInt'] = NamedInt
1517 globals()['NEI'] = NEI
1518 NI5 = NamedInt('test', 5)
1519 self.assertEqual(NI5, 5)
1520 self.assertEqual(NEI.y.value, 2)
1521 test_pickle_dump_load(self.assertIs, NEI.y)
1522 test_pickle_dump_load(self.assertIs, NEI)
1523
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001524 def test_tuple_subclass(self):
1525 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001526 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001527 first = (1, 'for the money')
1528 second = (2, 'for the show')
1529 third = (3, 'for the music')
1530 self.assertIs(type(SomeTuple.first), SomeTuple)
1531 self.assertIsInstance(SomeTuple.second, tuple)
1532 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1533 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001534 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001535
1536 def test_duplicate_values_give_unique_enum_items(self):
1537 class AutoNumber(Enum):
1538 first = ()
1539 second = ()
1540 third = ()
1541 def __new__(cls):
1542 value = len(cls.__members__) + 1
1543 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001544 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001545 return obj
1546 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001547 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548 self.assertEqual(
1549 list(AutoNumber),
1550 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1551 )
1552 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001553 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001554 self.assertIs(AutoNumber(1), AutoNumber.first)
1555
1556 def test_inherited_new_from_enhanced_enum(self):
1557 class AutoNumber(Enum):
1558 def __new__(cls):
1559 value = len(cls.__members__) + 1
1560 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001561 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001562 return obj
1563 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001564 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001565 class Color(AutoNumber):
1566 red = ()
1567 green = ()
1568 blue = ()
1569 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1570 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1571
1572 def test_inherited_new_from_mixed_enum(self):
1573 class AutoNumber(IntEnum):
1574 def __new__(cls):
1575 value = len(cls.__members__) + 1
1576 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001577 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001578 return obj
1579 class Color(AutoNumber):
1580 red = ()
1581 green = ()
1582 blue = ()
1583 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1584 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1585
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001586 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001587 class OrdinaryEnum(Enum):
1588 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001589 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1590 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001591
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001592 def test_ordered_mixin(self):
1593 class OrderedEnum(Enum):
1594 def __ge__(self, other):
1595 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001596 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001597 return NotImplemented
1598 def __gt__(self, other):
1599 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001600 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001601 return NotImplemented
1602 def __le__(self, other):
1603 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001604 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001605 return NotImplemented
1606 def __lt__(self, other):
1607 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001608 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001609 return NotImplemented
1610 class Grade(OrderedEnum):
1611 A = 5
1612 B = 4
1613 C = 3
1614 D = 2
1615 F = 1
1616 self.assertGreater(Grade.A, Grade.B)
1617 self.assertLessEqual(Grade.F, Grade.C)
1618 self.assertLess(Grade.D, Grade.A)
1619 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001620 self.assertEqual(Grade.B, Grade.B)
1621 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001622
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001623 def test_extending2(self):
1624 class Shade(Enum):
1625 def shade(self):
1626 print(self.name)
1627 class Color(Shade):
1628 red = 1
1629 green = 2
1630 blue = 3
1631 with self.assertRaises(TypeError):
1632 class MoreColor(Color):
1633 cyan = 4
1634 magenta = 5
1635 yellow = 6
1636
1637 def test_extending3(self):
1638 class Shade(Enum):
1639 def shade(self):
1640 return self.name
1641 class Color(Shade):
1642 def hex(self):
1643 return '%s hexlified!' % self.value
1644 class MoreColor(Color):
1645 cyan = 4
1646 magenta = 5
1647 yellow = 6
1648 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1649
orlnub1230fb9fad2018-09-12 20:28:53 +03001650 def test_subclass_duplicate_name(self):
1651 class Base(Enum):
1652 def test(self):
1653 pass
1654 class Test(Base):
1655 test = 1
1656 self.assertIs(type(Test.test), Test)
1657
1658 def test_subclass_duplicate_name_dynamic(self):
1659 from types import DynamicClassAttribute
1660 class Base(Enum):
1661 @DynamicClassAttribute
1662 def test(self):
1663 return 'dynamic'
1664 class Test(Base):
1665 test = 1
1666 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001667
1668 def test_no_duplicates(self):
1669 class UniqueEnum(Enum):
1670 def __init__(self, *args):
1671 cls = self.__class__
1672 if any(self.value == e.value for e in cls):
1673 a = self.name
1674 e = cls(self.value).name
1675 raise ValueError(
1676 "aliases not allowed in UniqueEnum: %r --> %r"
1677 % (a, e)
1678 )
1679 class Color(UniqueEnum):
1680 red = 1
1681 green = 2
1682 blue = 3
1683 with self.assertRaises(ValueError):
1684 class Color(UniqueEnum):
1685 red = 1
1686 green = 2
1687 blue = 3
1688 grene = 2
1689
1690 def test_init(self):
1691 class Planet(Enum):
1692 MERCURY = (3.303e+23, 2.4397e6)
1693 VENUS = (4.869e+24, 6.0518e6)
1694 EARTH = (5.976e+24, 6.37814e6)
1695 MARS = (6.421e+23, 3.3972e6)
1696 JUPITER = (1.9e+27, 7.1492e7)
1697 SATURN = (5.688e+26, 6.0268e7)
1698 URANUS = (8.686e+25, 2.5559e7)
1699 NEPTUNE = (1.024e+26, 2.4746e7)
1700 def __init__(self, mass, radius):
1701 self.mass = mass # in kilograms
1702 self.radius = radius # in meters
1703 @property
1704 def surface_gravity(self):
1705 # universal gravitational constant (m3 kg-1 s-2)
1706 G = 6.67300E-11
1707 return G * self.mass / (self.radius * self.radius)
1708 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1709 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1710
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001711 def test_ignore(self):
1712 class Period(timedelta, Enum):
1713 '''
1714 different lengths of time
1715 '''
1716 def __new__(cls, value, period):
1717 obj = timedelta.__new__(cls, value)
1718 obj._value_ = value
1719 obj.period = period
1720 return obj
1721 _ignore_ = 'Period i'
1722 Period = vars()
1723 for i in range(13):
1724 Period['month_%d' % i] = i*30, 'month'
1725 for i in range(53):
1726 Period['week_%d' % i] = i*7, 'week'
1727 for i in range(32):
1728 Period['day_%d' % i] = i, 'day'
1729 OneDay = day_1
1730 OneWeek = week_1
1731 OneMonth = month_1
1732 self.assertFalse(hasattr(Period, '_ignore_'))
1733 self.assertFalse(hasattr(Period, 'Period'))
1734 self.assertFalse(hasattr(Period, 'i'))
1735 self.assertTrue(isinstance(Period.day_1, timedelta))
1736 self.assertTrue(Period.month_1 is Period.day_30)
1737 self.assertTrue(Period.week_4 is Period.day_28)
1738
Ethan Furman2aa27322013-07-19 19:35:56 -07001739 def test_nonhash_value(self):
1740 class AutoNumberInAList(Enum):
1741 def __new__(cls):
1742 value = [len(cls.__members__) + 1]
1743 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001744 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001745 return obj
1746 class ColorInAList(AutoNumberInAList):
1747 red = ()
1748 green = ()
1749 blue = ()
1750 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001751 for enum, value in zip(ColorInAList, range(3)):
1752 value += 1
1753 self.assertEqual(enum.value, [value])
1754 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001755
Ethan Furmanb41803e2013-07-25 13:50:45 -07001756 def test_conflicting_types_resolved_in_new(self):
1757 class LabelledIntEnum(int, Enum):
1758 def __new__(cls, *args):
1759 value, label = args
1760 obj = int.__new__(cls, value)
1761 obj.label = label
1762 obj._value_ = value
1763 return obj
1764
1765 class LabelledList(LabelledIntEnum):
1766 unprocessed = (1, "Unprocessed")
1767 payment_complete = (2, "Payment Complete")
1768
1769 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1770 self.assertEqual(LabelledList.unprocessed, 1)
1771 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001772
Ethan Furmanc16595e2016-09-10 23:36:59 -07001773 def test_auto_number(self):
1774 class Color(Enum):
1775 red = auto()
1776 blue = auto()
1777 green = auto()
1778
1779 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1780 self.assertEqual(Color.red.value, 1)
1781 self.assertEqual(Color.blue.value, 2)
1782 self.assertEqual(Color.green.value, 3)
1783
1784 def test_auto_name(self):
1785 class Color(Enum):
1786 def _generate_next_value_(name, start, count, last):
1787 return name
1788 red = auto()
1789 blue = auto()
1790 green = auto()
1791
1792 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1793 self.assertEqual(Color.red.value, 'red')
1794 self.assertEqual(Color.blue.value, 'blue')
1795 self.assertEqual(Color.green.value, 'green')
1796
1797 def test_auto_name_inherit(self):
1798 class AutoNameEnum(Enum):
1799 def _generate_next_value_(name, start, count, last):
1800 return name
1801 class Color(AutoNameEnum):
1802 red = auto()
1803 blue = auto()
1804 green = auto()
1805
1806 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1807 self.assertEqual(Color.red.value, 'red')
1808 self.assertEqual(Color.blue.value, 'blue')
1809 self.assertEqual(Color.green.value, 'green')
1810
1811 def test_auto_garbage(self):
1812 class Color(Enum):
1813 red = 'red'
1814 blue = auto()
1815 self.assertEqual(Color.blue.value, 1)
1816
1817 def test_auto_garbage_corrected(self):
1818 class Color(Enum):
1819 red = 'red'
1820 blue = 2
1821 green = auto()
1822
1823 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1824 self.assertEqual(Color.red.value, 'red')
1825 self.assertEqual(Color.blue.value, 2)
1826 self.assertEqual(Color.green.value, 3)
1827
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001828 def test_auto_order(self):
1829 with self.assertRaises(TypeError):
1830 class Color(Enum):
1831 red = auto()
1832 green = auto()
1833 blue = auto()
1834 def _generate_next_value_(name, start, count, last):
1835 return name
1836
1837
Ethan Furman3515dcc2016-09-18 13:15:41 -07001838 def test_duplicate_auto(self):
1839 class Dupes(Enum):
1840 first = primero = auto()
1841 second = auto()
1842 third = auto()
1843 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1844
Ethan Furman019f0a02018-09-12 11:43:34 -07001845 def test_missing(self):
1846 class Color(Enum):
1847 red = 1
1848 green = 2
1849 blue = 3
1850 @classmethod
1851 def _missing_(cls, item):
1852 if item == 'three':
1853 return cls.blue
1854 elif item == 'bad return':
1855 # trigger internal error
1856 return 5
1857 elif item == 'error out':
1858 raise ZeroDivisionError
1859 else:
1860 # trigger not found
1861 return None
1862 self.assertIs(Color('three'), Color.blue)
1863 self.assertRaises(ValueError, Color, 7)
1864 try:
1865 Color('bad return')
1866 except TypeError as exc:
1867 self.assertTrue(isinstance(exc.__context__, ValueError))
1868 else:
1869 raise Exception('Exception not raised.')
1870 try:
1871 Color('error out')
1872 except ZeroDivisionError as exc:
1873 self.assertTrue(isinstance(exc.__context__, ValueError))
1874 else:
1875 raise Exception('Exception not raised.')
1876
Ethan Furman5bdab642018-09-21 19:03:09 -07001877 def test_multiple_mixin(self):
1878 class MaxMixin:
1879 @classproperty
1880 def MAX(cls):
1881 max = len(cls)
1882 cls.MAX = max
1883 return max
1884 class StrMixin:
1885 def __str__(self):
1886 return self._name_.lower()
1887 class SomeEnum(Enum):
1888 def behavior(self):
1889 return 'booyah'
1890 class AnotherEnum(Enum):
1891 def behavior(self):
1892 return 'nuhuh!'
1893 def social(self):
1894 return "what's up?"
1895 class Color(MaxMixin, Enum):
1896 RED = auto()
1897 GREEN = auto()
1898 BLUE = auto()
1899 self.assertEqual(Color.RED.value, 1)
1900 self.assertEqual(Color.GREEN.value, 2)
1901 self.assertEqual(Color.BLUE.value, 3)
1902 self.assertEqual(Color.MAX, 3)
1903 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1904 class Color(MaxMixin, StrMixin, Enum):
1905 RED = auto()
1906 GREEN = auto()
1907 BLUE = auto()
1908 self.assertEqual(Color.RED.value, 1)
1909 self.assertEqual(Color.GREEN.value, 2)
1910 self.assertEqual(Color.BLUE.value, 3)
1911 self.assertEqual(Color.MAX, 3)
1912 self.assertEqual(str(Color.BLUE), 'blue')
1913 class Color(StrMixin, MaxMixin, Enum):
1914 RED = auto()
1915 GREEN = auto()
1916 BLUE = auto()
1917 self.assertEqual(Color.RED.value, 1)
1918 self.assertEqual(Color.GREEN.value, 2)
1919 self.assertEqual(Color.BLUE.value, 3)
1920 self.assertEqual(Color.MAX, 3)
1921 self.assertEqual(str(Color.BLUE), 'blue')
1922 class CoolColor(StrMixin, SomeEnum, Enum):
1923 RED = auto()
1924 GREEN = auto()
1925 BLUE = auto()
1926 self.assertEqual(CoolColor.RED.value, 1)
1927 self.assertEqual(CoolColor.GREEN.value, 2)
1928 self.assertEqual(CoolColor.BLUE.value, 3)
1929 self.assertEqual(str(CoolColor.BLUE), 'blue')
1930 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1931 class CoolerColor(StrMixin, AnotherEnum, Enum):
1932 RED = auto()
1933 GREEN = auto()
1934 BLUE = auto()
1935 self.assertEqual(CoolerColor.RED.value, 1)
1936 self.assertEqual(CoolerColor.GREEN.value, 2)
1937 self.assertEqual(CoolerColor.BLUE.value, 3)
1938 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1939 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1940 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1941 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1942 RED = auto()
1943 GREEN = auto()
1944 BLUE = auto()
1945 self.assertEqual(CoolestColor.RED.value, 1)
1946 self.assertEqual(CoolestColor.GREEN.value, 2)
1947 self.assertEqual(CoolestColor.BLUE.value, 3)
1948 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1949 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1950 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1951 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1952 RED = auto()
1953 GREEN = auto()
1954 BLUE = auto()
1955 self.assertEqual(ConfusedColor.RED.value, 1)
1956 self.assertEqual(ConfusedColor.GREEN.value, 2)
1957 self.assertEqual(ConfusedColor.BLUE.value, 3)
1958 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1959 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1960 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1961 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1962 RED = auto()
1963 GREEN = auto()
1964 BLUE = auto()
1965 self.assertEqual(ReformedColor.RED.value, 1)
1966 self.assertEqual(ReformedColor.GREEN.value, 2)
1967 self.assertEqual(ReformedColor.BLUE.value, 3)
1968 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1969 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1970 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1971 self.assertTrue(issubclass(ReformedColor, int))
1972
Ethan Furmancd453852018-10-05 23:29:36 -07001973 def test_multiple_inherited_mixin(self):
1974 class StrEnum(str, Enum):
1975 def __new__(cls, *args, **kwargs):
1976 for a in args:
1977 if not isinstance(a, str):
1978 raise TypeError("Enumeration '%s' (%s) is not"
1979 " a string" % (a, type(a).__name__))
1980 return str.__new__(cls, *args, **kwargs)
1981 @unique
1982 class Decision1(StrEnum):
1983 REVERT = "REVERT"
1984 REVERT_ALL = "REVERT_ALL"
1985 RETRY = "RETRY"
1986 class MyEnum(StrEnum):
1987 pass
1988 @unique
1989 class Decision2(MyEnum):
1990 REVERT = "REVERT"
1991 REVERT_ALL = "REVERT_ALL"
1992 RETRY = "RETRY"
1993
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001994 def test_empty_globals(self):
1995 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1996 # when using compile and exec because f_globals is empty
1997 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1998 code = compile(code, "<string>", "exec")
1999 global_ns = {}
2000 local_ls = {}
2001 exec(code, global_ns, local_ls)
2002
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002003
Ethan Furmane8e61272016-08-20 07:19:31 -07002004class TestOrder(unittest.TestCase):
2005
2006 def test_same_members(self):
2007 class Color(Enum):
2008 _order_ = 'red green blue'
2009 red = 1
2010 green = 2
2011 blue = 3
2012
2013 def test_same_members_with_aliases(self):
2014 class Color(Enum):
2015 _order_ = 'red green blue'
2016 red = 1
2017 green = 2
2018 blue = 3
2019 verde = green
2020
2021 def test_same_members_wrong_order(self):
2022 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2023 class Color(Enum):
2024 _order_ = 'red green blue'
2025 red = 1
2026 blue = 3
2027 green = 2
2028
2029 def test_order_has_extra_members(self):
2030 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2031 class Color(Enum):
2032 _order_ = 'red green blue purple'
2033 red = 1
2034 green = 2
2035 blue = 3
2036
2037 def test_order_has_extra_members_with_aliases(self):
2038 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2039 class Color(Enum):
2040 _order_ = 'red green blue purple'
2041 red = 1
2042 green = 2
2043 blue = 3
2044 verde = green
2045
2046 def test_enum_has_extra_members(self):
2047 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2048 class Color(Enum):
2049 _order_ = 'red green blue'
2050 red = 1
2051 green = 2
2052 blue = 3
2053 purple = 4
2054
2055 def test_enum_has_extra_members_with_aliases(self):
2056 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2057 class Color(Enum):
2058 _order_ = 'red green blue'
2059 red = 1
2060 green = 2
2061 blue = 3
2062 purple = 4
2063 verde = green
2064
2065
Ethan Furman65a5a472016-09-01 23:55:19 -07002066class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002067 """Tests of the Flags."""
2068
Ethan Furman65a5a472016-09-01 23:55:19 -07002069 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002070 R, W, X = 4, 2, 1
2071
Ethan Furman65a5a472016-09-01 23:55:19 -07002072 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002073 RO = 0
2074 WO = 1
2075 RW = 2
2076 AC = 3
2077 CE = 1<<19
2078
Rahul Jha94306522018-09-10 23:51:04 +05302079 class Color(Flag):
2080 BLACK = 0
2081 RED = 1
2082 GREEN = 2
2083 BLUE = 4
2084 PURPLE = RED|BLUE
2085
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002086 def test_str(self):
2087 Perm = self.Perm
2088 self.assertEqual(str(Perm.R), 'Perm.R')
2089 self.assertEqual(str(Perm.W), 'Perm.W')
2090 self.assertEqual(str(Perm.X), 'Perm.X')
2091 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2092 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2093 self.assertEqual(str(Perm(0)), 'Perm.0')
2094 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2095 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2096 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2097 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2098 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2099 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2100
2101 Open = self.Open
2102 self.assertEqual(str(Open.RO), 'Open.RO')
2103 self.assertEqual(str(Open.WO), 'Open.WO')
2104 self.assertEqual(str(Open.AC), 'Open.AC')
2105 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2106 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002107 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002108 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2109 self.assertEqual(str(~Open.AC), 'Open.CE')
2110 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2111 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2112
2113 def test_repr(self):
2114 Perm = self.Perm
2115 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2116 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2117 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2118 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2119 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002120 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002121 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2122 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2123 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2124 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002125 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002126 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2127
2128 Open = self.Open
2129 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2130 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2131 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2132 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2133 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002134 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002135 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2136 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2137 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2138 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2139
2140 def test_or(self):
2141 Perm = self.Perm
2142 for i in Perm:
2143 for j in Perm:
2144 self.assertEqual((i | j), Perm(i.value | j.value))
2145 self.assertEqual((i | j).value, i.value | j.value)
2146 self.assertIs(type(i | j), Perm)
2147 for i in Perm:
2148 self.assertIs(i | i, i)
2149 Open = self.Open
2150 self.assertIs(Open.RO | Open.CE, Open.CE)
2151
2152 def test_and(self):
2153 Perm = self.Perm
2154 RW = Perm.R | Perm.W
2155 RX = Perm.R | Perm.X
2156 WX = Perm.W | Perm.X
2157 RWX = Perm.R | Perm.W | Perm.X
2158 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2159 for i in values:
2160 for j in values:
2161 self.assertEqual((i & j).value, i.value & j.value)
2162 self.assertIs(type(i & j), Perm)
2163 for i in Perm:
2164 self.assertIs(i & i, i)
2165 self.assertIs(i & RWX, i)
2166 self.assertIs(RWX & i, i)
2167 Open = self.Open
2168 self.assertIs(Open.RO & Open.CE, Open.RO)
2169
2170 def test_xor(self):
2171 Perm = self.Perm
2172 for i in Perm:
2173 for j in Perm:
2174 self.assertEqual((i ^ j).value, i.value ^ j.value)
2175 self.assertIs(type(i ^ j), Perm)
2176 for i in Perm:
2177 self.assertIs(i ^ Perm(0), i)
2178 self.assertIs(Perm(0) ^ i, i)
2179 Open = self.Open
2180 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2181 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2182
2183 def test_invert(self):
2184 Perm = self.Perm
2185 RW = Perm.R | Perm.W
2186 RX = Perm.R | Perm.X
2187 WX = Perm.W | Perm.X
2188 RWX = Perm.R | Perm.W | Perm.X
2189 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2190 for i in values:
2191 self.assertIs(type(~i), Perm)
2192 self.assertEqual(~~i, i)
2193 for i in Perm:
2194 self.assertIs(~~i, i)
2195 Open = self.Open
2196 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2197 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2198
Ethan Furman25d94bb2016-09-02 16:32:32 -07002199 def test_bool(self):
2200 Perm = self.Perm
2201 for f in Perm:
2202 self.assertTrue(f)
2203 Open = self.Open
2204 for f in Open:
2205 self.assertEqual(bool(f.value), bool(f))
2206
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002207 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002208 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002209 lst = list(Perm)
2210 self.assertEqual(len(lst), len(Perm))
2211 self.assertEqual(len(Perm), 3, Perm)
2212 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2213 for i, n in enumerate('R W X'.split()):
2214 v = 1<<i
2215 e = Perm(v)
2216 self.assertEqual(e.value, v)
2217 self.assertEqual(type(e.value), int)
2218 self.assertEqual(e.name, n)
2219 self.assertIn(e, Perm)
2220 self.assertIs(type(e), Perm)
2221
2222 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002223 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002224 lst = list(Perm)
2225 self.assertEqual(len(lst), len(Perm))
2226 self.assertEqual(len(Perm), 3, Perm)
2227 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2228 for i, n in enumerate('R W X'.split()):
2229 v = 8<<i
2230 e = Perm(v)
2231 self.assertEqual(e.value, v)
2232 self.assertEqual(type(e.value), int)
2233 self.assertEqual(e.name, n)
2234 self.assertIn(e, Perm)
2235 self.assertIs(type(e), Perm)
2236
2237 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002238 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002239 lst = list(Perm)
2240 self.assertEqual(len(lst), len(Perm))
2241 self.assertEqual(len(Perm), 3, Perm)
2242 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2243 for i, n in enumerate('R W X'.split()):
2244 v = 1<<i
2245 e = Perm(v)
2246 self.assertEqual(e.value, v)
2247 self.assertEqual(type(e.value), int)
2248 self.assertEqual(e.name, n)
2249 self.assertIn(e, Perm)
2250 self.assertIs(type(e), Perm)
2251
2252 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002253 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002254 lst = list(Perm)
2255 self.assertEqual(len(lst), len(Perm))
2256 self.assertEqual(len(Perm), 3, Perm)
2257 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2258 for i, n in enumerate('R W X'.split()):
2259 v = 1<<(2*i+1)
2260 e = Perm(v)
2261 self.assertEqual(e.value, v)
2262 self.assertEqual(type(e.value), int)
2263 self.assertEqual(e.name, n)
2264 self.assertIn(e, Perm)
2265 self.assertIs(type(e), Perm)
2266
2267 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002268 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002269 lst = list(Perm)
2270 self.assertEqual(len(lst), len(Perm))
2271 self.assertEqual(len(Perm), 3, Perm)
2272 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2273 for i, n in enumerate('R W X'.split()):
2274 v = 1<<(2*i+1)
2275 e = Perm(v)
2276 self.assertEqual(e.value, v)
2277 self.assertEqual(type(e.value), int)
2278 self.assertEqual(e.name, n)
2279 self.assertIn(e, Perm)
2280 self.assertIs(type(e), Perm)
2281
Ethan Furman65a5a472016-09-01 23:55:19 -07002282 def test_pickle(self):
2283 if isinstance(FlagStooges, Exception):
2284 raise FlagStooges
2285 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2286 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002287
Rahul Jha94306522018-09-10 23:51:04 +05302288 def test_contains(self):
2289 Open = self.Open
2290 Color = self.Color
2291 self.assertFalse(Color.BLACK in Open)
2292 self.assertFalse(Open.RO in Color)
2293 with self.assertRaises(TypeError):
2294 'BLACK' in Color
2295 with self.assertRaises(TypeError):
2296 'RO' in Open
2297 with self.assertRaises(TypeError):
2298 1 in Color
2299 with self.assertRaises(TypeError):
2300 1 in Open
2301
2302 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002303 Perm = self.Perm
2304 R, W, X = Perm
2305 RW = R | W
2306 RX = R | X
2307 WX = W | X
2308 RWX = R | W | X
2309 self.assertTrue(R in RW)
2310 self.assertTrue(R in RX)
2311 self.assertTrue(R in RWX)
2312 self.assertTrue(W in RW)
2313 self.assertTrue(W in WX)
2314 self.assertTrue(W in RWX)
2315 self.assertTrue(X in RX)
2316 self.assertTrue(X in WX)
2317 self.assertTrue(X in RWX)
2318 self.assertFalse(R in WX)
2319 self.assertFalse(W in RX)
2320 self.assertFalse(X in RW)
2321
Ethan Furmanc16595e2016-09-10 23:36:59 -07002322 def test_auto_number(self):
2323 class Color(Flag):
2324 red = auto()
2325 blue = auto()
2326 green = auto()
2327
2328 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2329 self.assertEqual(Color.red.value, 1)
2330 self.assertEqual(Color.blue.value, 2)
2331 self.assertEqual(Color.green.value, 4)
2332
2333 def test_auto_number_garbage(self):
2334 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2335 class Color(Flag):
2336 red = 'not an int'
2337 blue = auto()
2338
Ethan Furman3515dcc2016-09-18 13:15:41 -07002339 def test_cascading_failure(self):
2340 class Bizarre(Flag):
2341 c = 3
2342 d = 4
2343 f = 6
2344 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002345 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2346 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2347 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2348 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2349 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2350 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2351 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002352
2353 def test_duplicate_auto(self):
2354 class Dupes(Enum):
2355 first = primero = auto()
2356 second = auto()
2357 third = auto()
2358 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2359
2360 def test_bizarre(self):
2361 class Bizarre(Flag):
2362 b = 3
2363 c = 4
2364 d = 6
2365 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2366
Ethan Furman5bdab642018-09-21 19:03:09 -07002367 def test_multiple_mixin(self):
2368 class AllMixin:
2369 @classproperty
2370 def ALL(cls):
2371 members = list(cls)
2372 all_value = None
2373 if members:
2374 all_value = members[0]
2375 for member in members[1:]:
2376 all_value |= member
2377 cls.ALL = all_value
2378 return all_value
2379 class StrMixin:
2380 def __str__(self):
2381 return self._name_.lower()
2382 class Color(AllMixin, Flag):
2383 RED = auto()
2384 GREEN = auto()
2385 BLUE = auto()
2386 self.assertEqual(Color.RED.value, 1)
2387 self.assertEqual(Color.GREEN.value, 2)
2388 self.assertEqual(Color.BLUE.value, 4)
2389 self.assertEqual(Color.ALL.value, 7)
2390 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2391 class Color(AllMixin, StrMixin, Flag):
2392 RED = auto()
2393 GREEN = auto()
2394 BLUE = auto()
2395 self.assertEqual(Color.RED.value, 1)
2396 self.assertEqual(Color.GREEN.value, 2)
2397 self.assertEqual(Color.BLUE.value, 4)
2398 self.assertEqual(Color.ALL.value, 7)
2399 self.assertEqual(str(Color.BLUE), 'blue')
2400 class Color(StrMixin, AllMixin, Flag):
2401 RED = auto()
2402 GREEN = auto()
2403 BLUE = auto()
2404 self.assertEqual(Color.RED.value, 1)
2405 self.assertEqual(Color.GREEN.value, 2)
2406 self.assertEqual(Color.BLUE.value, 4)
2407 self.assertEqual(Color.ALL.value, 7)
2408 self.assertEqual(str(Color.BLUE), 'blue')
2409
Hai Shie80697d2020-05-28 06:10:27 +08002410 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002411 def test_unique_composite(self):
2412 # override __eq__ to be identity only
2413 class TestFlag(Flag):
2414 one = auto()
2415 two = auto()
2416 three = auto()
2417 four = auto()
2418 five = auto()
2419 six = auto()
2420 seven = auto()
2421 eight = auto()
2422 def __eq__(self, other):
2423 return self is other
2424 def __hash__(self):
2425 return hash(self._value_)
2426 # have multiple threads competing to complete the composite members
2427 seen = set()
2428 failed = False
2429 def cycle_enum():
2430 nonlocal failed
2431 try:
2432 for i in range(256):
2433 seen.add(TestFlag(i))
2434 except Exception:
2435 failed = True
2436 threads = [
2437 threading.Thread(target=cycle_enum)
2438 for _ in range(8)
2439 ]
Hai Shie80697d2020-05-28 06:10:27 +08002440 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002441 pass
2442 # check that only 248 members were created
2443 self.assertFalse(
2444 failed,
2445 'at least one thread failed while creating composite members')
2446 self.assertEqual(256, len(seen), 'too many composite members created')
2447
Ethan Furmanc16595e2016-09-10 23:36:59 -07002448
Ethan Furman65a5a472016-09-01 23:55:19 -07002449class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002450 """Tests of the IntFlags."""
2451
Ethan Furman65a5a472016-09-01 23:55:19 -07002452 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002453 X = 1 << 0
2454 W = 1 << 1
2455 R = 1 << 2
2456
Ethan Furman65a5a472016-09-01 23:55:19 -07002457 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002458 RO = 0
2459 WO = 1
2460 RW = 2
2461 AC = 3
2462 CE = 1<<19
2463
Rahul Jha94306522018-09-10 23:51:04 +05302464 class Color(IntFlag):
2465 BLACK = 0
2466 RED = 1
2467 GREEN = 2
2468 BLUE = 4
2469 PURPLE = RED|BLUE
2470
Ethan Furman3515dcc2016-09-18 13:15:41 -07002471 def test_type(self):
2472 Perm = self.Perm
2473 Open = self.Open
2474 for f in Perm:
2475 self.assertTrue(isinstance(f, Perm))
2476 self.assertEqual(f, f.value)
2477 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2478 self.assertEqual(Perm.W | Perm.X, 3)
2479 for f in Open:
2480 self.assertTrue(isinstance(f, Open))
2481 self.assertEqual(f, f.value)
2482 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2483 self.assertEqual(Open.WO | Open.RW, 3)
2484
2485
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002486 def test_str(self):
2487 Perm = self.Perm
2488 self.assertEqual(str(Perm.R), 'Perm.R')
2489 self.assertEqual(str(Perm.W), 'Perm.W')
2490 self.assertEqual(str(Perm.X), 'Perm.X')
2491 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2492 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2493 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2494 self.assertEqual(str(Perm(0)), 'Perm.0')
2495 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002496 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2497 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2498 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2499 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002500 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002501 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2502 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2503 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002504
2505 Open = self.Open
2506 self.assertEqual(str(Open.RO), 'Open.RO')
2507 self.assertEqual(str(Open.WO), 'Open.WO')
2508 self.assertEqual(str(Open.AC), 'Open.AC')
2509 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2510 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2511 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002512 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2513 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2514 self.assertEqual(str(~Open.AC), 'Open.CE')
2515 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2516 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2517 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002518
2519 def test_repr(self):
2520 Perm = self.Perm
2521 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2522 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2523 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2524 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2525 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2526 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002527 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2528 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002529 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2530 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2531 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2532 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002533 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002534 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2535 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2536 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002537
2538 Open = self.Open
2539 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2540 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2541 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2542 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2543 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002544 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002545 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2546 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2547 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2548 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2549 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2550 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002551
2552 def test_or(self):
2553 Perm = self.Perm
2554 for i in Perm:
2555 for j in Perm:
2556 self.assertEqual(i | j, i.value | j.value)
2557 self.assertEqual((i | j).value, i.value | j.value)
2558 self.assertIs(type(i | j), Perm)
2559 for j in range(8):
2560 self.assertEqual(i | j, i.value | j)
2561 self.assertEqual((i | j).value, i.value | j)
2562 self.assertIs(type(i | j), Perm)
2563 self.assertEqual(j | i, j | i.value)
2564 self.assertEqual((j | i).value, j | i.value)
2565 self.assertIs(type(j | i), Perm)
2566 for i in Perm:
2567 self.assertIs(i | i, i)
2568 self.assertIs(i | 0, i)
2569 self.assertIs(0 | i, i)
2570 Open = self.Open
2571 self.assertIs(Open.RO | Open.CE, Open.CE)
2572
2573 def test_and(self):
2574 Perm = self.Perm
2575 RW = Perm.R | Perm.W
2576 RX = Perm.R | Perm.X
2577 WX = Perm.W | Perm.X
2578 RWX = Perm.R | Perm.W | Perm.X
2579 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2580 for i in values:
2581 for j in values:
2582 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2583 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2584 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2585 for j in range(8):
2586 self.assertEqual(i & j, i.value & j)
2587 self.assertEqual((i & j).value, i.value & j)
2588 self.assertIs(type(i & j), Perm)
2589 self.assertEqual(j & i, j & i.value)
2590 self.assertEqual((j & i).value, j & i.value)
2591 self.assertIs(type(j & i), Perm)
2592 for i in Perm:
2593 self.assertIs(i & i, i)
2594 self.assertIs(i & 7, i)
2595 self.assertIs(7 & i, i)
2596 Open = self.Open
2597 self.assertIs(Open.RO & Open.CE, Open.RO)
2598
2599 def test_xor(self):
2600 Perm = self.Perm
2601 for i in Perm:
2602 for j in Perm:
2603 self.assertEqual(i ^ j, i.value ^ j.value)
2604 self.assertEqual((i ^ j).value, i.value ^ j.value)
2605 self.assertIs(type(i ^ j), Perm)
2606 for j in range(8):
2607 self.assertEqual(i ^ j, i.value ^ j)
2608 self.assertEqual((i ^ j).value, i.value ^ j)
2609 self.assertIs(type(i ^ j), Perm)
2610 self.assertEqual(j ^ i, j ^ i.value)
2611 self.assertEqual((j ^ i).value, j ^ i.value)
2612 self.assertIs(type(j ^ i), Perm)
2613 for i in Perm:
2614 self.assertIs(i ^ 0, i)
2615 self.assertIs(0 ^ i, i)
2616 Open = self.Open
2617 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2618 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2619
2620 def test_invert(self):
2621 Perm = self.Perm
2622 RW = Perm.R | Perm.W
2623 RX = Perm.R | Perm.X
2624 WX = Perm.W | Perm.X
2625 RWX = Perm.R | Perm.W | Perm.X
2626 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2627 for i in values:
2628 self.assertEqual(~i, ~i.value)
2629 self.assertEqual((~i).value, ~i.value)
2630 self.assertIs(type(~i), Perm)
2631 self.assertEqual(~~i, i)
2632 for i in Perm:
2633 self.assertIs(~~i, i)
2634 Open = self.Open
2635 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2636 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2637
2638 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002639 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002640 lst = list(Perm)
2641 self.assertEqual(len(lst), len(Perm))
2642 self.assertEqual(len(Perm), 3, Perm)
2643 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2644 for i, n in enumerate('R W X'.split()):
2645 v = 1<<i
2646 e = Perm(v)
2647 self.assertEqual(e.value, v)
2648 self.assertEqual(type(e.value), int)
2649 self.assertEqual(e, v)
2650 self.assertEqual(e.name, n)
2651 self.assertIn(e, Perm)
2652 self.assertIs(type(e), Perm)
2653
2654 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002655 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002656 lst = list(Perm)
2657 self.assertEqual(len(lst), len(Perm))
2658 self.assertEqual(len(Perm), 3, Perm)
2659 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2660 for i, n in enumerate('R W X'.split()):
2661 v = 8<<i
2662 e = Perm(v)
2663 self.assertEqual(e.value, v)
2664 self.assertEqual(type(e.value), int)
2665 self.assertEqual(e, v)
2666 self.assertEqual(e.name, n)
2667 self.assertIn(e, Perm)
2668 self.assertIs(type(e), Perm)
2669
2670 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002671 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002672 lst = list(Perm)
2673 self.assertEqual(len(lst), len(Perm))
2674 self.assertEqual(len(Perm), 3, Perm)
2675 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2676 for i, n in enumerate('R W X'.split()):
2677 v = 1<<i
2678 e = Perm(v)
2679 self.assertEqual(e.value, v)
2680 self.assertEqual(type(e.value), int)
2681 self.assertEqual(e, v)
2682 self.assertEqual(e.name, n)
2683 self.assertIn(e, Perm)
2684 self.assertIs(type(e), Perm)
2685
2686 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002687 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002688 lst = list(Perm)
2689 self.assertEqual(len(lst), len(Perm))
2690 self.assertEqual(len(Perm), 3, Perm)
2691 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2692 for i, n in enumerate('R W X'.split()):
2693 v = 1<<(2*i+1)
2694 e = Perm(v)
2695 self.assertEqual(e.value, v)
2696 self.assertEqual(type(e.value), int)
2697 self.assertEqual(e, v)
2698 self.assertEqual(e.name, n)
2699 self.assertIn(e, Perm)
2700 self.assertIs(type(e), Perm)
2701
2702 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002703 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002704 lst = list(Perm)
2705 self.assertEqual(len(lst), len(Perm))
2706 self.assertEqual(len(Perm), 3, Perm)
2707 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2708 for i, n in enumerate('R W X'.split()):
2709 v = 1<<(2*i+1)
2710 e = Perm(v)
2711 self.assertEqual(e.value, v)
2712 self.assertEqual(type(e.value), int)
2713 self.assertEqual(e, v)
2714 self.assertEqual(e.name, n)
2715 self.assertIn(e, Perm)
2716 self.assertIs(type(e), Perm)
2717
2718
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002719 def test_programatic_function_from_empty_list(self):
2720 Perm = enum.IntFlag('Perm', [])
2721 lst = list(Perm)
2722 self.assertEqual(len(lst), len(Perm))
2723 self.assertEqual(len(Perm), 0, Perm)
2724 Thing = enum.Enum('Thing', [])
2725 lst = list(Thing)
2726 self.assertEqual(len(lst), len(Thing))
2727 self.assertEqual(len(Thing), 0, Thing)
2728
2729
2730 def test_programatic_function_from_empty_tuple(self):
2731 Perm = enum.IntFlag('Perm', ())
2732 lst = list(Perm)
2733 self.assertEqual(len(lst), len(Perm))
2734 self.assertEqual(len(Perm), 0, Perm)
2735 Thing = enum.Enum('Thing', ())
2736 self.assertEqual(len(lst), len(Thing))
2737 self.assertEqual(len(Thing), 0, Thing)
2738
Rahul Jha94306522018-09-10 23:51:04 +05302739 def test_contains(self):
2740 Open = self.Open
2741 Color = self.Color
2742 self.assertTrue(Color.GREEN in Color)
2743 self.assertTrue(Open.RW in Open)
2744 self.assertFalse(Color.GREEN in Open)
2745 self.assertFalse(Open.RW in Color)
2746 with self.assertRaises(TypeError):
2747 'GREEN' in Color
2748 with self.assertRaises(TypeError):
2749 'RW' in Open
2750 with self.assertRaises(TypeError):
2751 2 in Color
2752 with self.assertRaises(TypeError):
2753 2 in Open
2754
2755 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002756 Perm = self.Perm
2757 R, W, X = Perm
2758 RW = R | W
2759 RX = R | X
2760 WX = W | X
2761 RWX = R | W | X
2762 self.assertTrue(R in RW)
2763 self.assertTrue(R in RX)
2764 self.assertTrue(R in RWX)
2765 self.assertTrue(W in RW)
2766 self.assertTrue(W in WX)
2767 self.assertTrue(W in RWX)
2768 self.assertTrue(X in RX)
2769 self.assertTrue(X in WX)
2770 self.assertTrue(X in RWX)
2771 self.assertFalse(R in WX)
2772 self.assertFalse(W in RX)
2773 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302774 with self.assertRaises(TypeError):
2775 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002776
Ethan Furman25d94bb2016-09-02 16:32:32 -07002777 def test_bool(self):
2778 Perm = self.Perm
2779 for f in Perm:
2780 self.assertTrue(f)
2781 Open = self.Open
2782 for f in Open:
2783 self.assertEqual(bool(f.value), bool(f))
2784
Ethan Furman5bdab642018-09-21 19:03:09 -07002785 def test_multiple_mixin(self):
2786 class AllMixin:
2787 @classproperty
2788 def ALL(cls):
2789 members = list(cls)
2790 all_value = None
2791 if members:
2792 all_value = members[0]
2793 for member in members[1:]:
2794 all_value |= member
2795 cls.ALL = all_value
2796 return all_value
2797 class StrMixin:
2798 def __str__(self):
2799 return self._name_.lower()
2800 class Color(AllMixin, IntFlag):
2801 RED = auto()
2802 GREEN = auto()
2803 BLUE = auto()
2804 self.assertEqual(Color.RED.value, 1)
2805 self.assertEqual(Color.GREEN.value, 2)
2806 self.assertEqual(Color.BLUE.value, 4)
2807 self.assertEqual(Color.ALL.value, 7)
2808 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2809 class Color(AllMixin, StrMixin, IntFlag):
2810 RED = auto()
2811 GREEN = auto()
2812 BLUE = auto()
2813 self.assertEqual(Color.RED.value, 1)
2814 self.assertEqual(Color.GREEN.value, 2)
2815 self.assertEqual(Color.BLUE.value, 4)
2816 self.assertEqual(Color.ALL.value, 7)
2817 self.assertEqual(str(Color.BLUE), 'blue')
2818 class Color(StrMixin, AllMixin, IntFlag):
2819 RED = auto()
2820 GREEN = auto()
2821 BLUE = auto()
2822 self.assertEqual(Color.RED.value, 1)
2823 self.assertEqual(Color.GREEN.value, 2)
2824 self.assertEqual(Color.BLUE.value, 4)
2825 self.assertEqual(Color.ALL.value, 7)
2826 self.assertEqual(str(Color.BLUE), 'blue')
2827
Hai Shie80697d2020-05-28 06:10:27 +08002828 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002829 def test_unique_composite(self):
2830 # override __eq__ to be identity only
2831 class TestFlag(IntFlag):
2832 one = auto()
2833 two = auto()
2834 three = auto()
2835 four = auto()
2836 five = auto()
2837 six = auto()
2838 seven = auto()
2839 eight = auto()
2840 def __eq__(self, other):
2841 return self is other
2842 def __hash__(self):
2843 return hash(self._value_)
2844 # have multiple threads competing to complete the composite members
2845 seen = set()
2846 failed = False
2847 def cycle_enum():
2848 nonlocal failed
2849 try:
2850 for i in range(256):
2851 seen.add(TestFlag(i))
2852 except Exception:
2853 failed = True
2854 threads = [
2855 threading.Thread(target=cycle_enum)
2856 for _ in range(8)
2857 ]
Hai Shie80697d2020-05-28 06:10:27 +08002858 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002859 pass
2860 # check that only 248 members were created
2861 self.assertFalse(
2862 failed,
2863 'at least one thread failed while creating composite members')
2864 self.assertEqual(256, len(seen), 'too many composite members created')
2865
2866
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002867class TestEmptyAndNonLatinStrings(unittest.TestCase):
2868
2869 def test_empty_string(self):
2870 with self.assertRaises(ValueError):
2871 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2872
2873 def test_non_latin_character_string(self):
2874 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2875 item = getattr(greek_abc, '\u03B1')
2876 self.assertEqual(item.value, 1)
2877
2878 def test_non_latin_number_string(self):
2879 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2880 item = getattr(hebrew_123, '\u05D0')
2881 self.assertEqual(item.value, 1)
2882
2883
Ethan Furmanf24bb352013-07-18 17:05:39 -07002884class TestUnique(unittest.TestCase):
2885
2886 def test_unique_clean(self):
2887 @unique
2888 class Clean(Enum):
2889 one = 1
2890 two = 'dos'
2891 tres = 4.0
2892 @unique
2893 class Cleaner(IntEnum):
2894 single = 1
2895 double = 2
2896 triple = 3
2897
2898 def test_unique_dirty(self):
2899 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2900 @unique
2901 class Dirty(Enum):
2902 one = 1
2903 two = 'dos'
2904 tres = 1
2905 with self.assertRaisesRegex(
2906 ValueError,
2907 'double.*single.*turkey.*triple',
2908 ):
2909 @unique
2910 class Dirtier(IntEnum):
2911 single = 1
2912 double = 1
2913 triple = 3
2914 turkey = 3
2915
Ethan Furman3803ad42016-05-01 10:03:53 -07002916 def test_unique_with_name(self):
2917 @unique
2918 class Silly(Enum):
2919 one = 1
2920 two = 'dos'
2921 name = 3
2922 @unique
2923 class Sillier(IntEnum):
2924 single = 1
2925 name = 2
2926 triple = 3
2927 value = 4
2928
Ethan Furmanf24bb352013-07-18 17:05:39 -07002929
Ethan Furman5bdab642018-09-21 19:03:09 -07002930
Ethan Furman3323da92015-04-11 09:39:59 -07002931expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002932Help on class Color in module %s:
2933
2934class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002935 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2936 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002937 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002938 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002939 | Method resolution order:
2940 | Color
2941 | enum.Enum
2942 | builtins.object
2943 |\x20\x20
2944 | Data and other attributes defined here:
2945 |\x20\x20
2946 | blue = <Color.blue: 3>
2947 |\x20\x20
2948 | green = <Color.green: 2>
2949 |\x20\x20
2950 | red = <Color.red: 1>
2951 |\x20\x20
2952 | ----------------------------------------------------------------------
2953 | Data descriptors inherited from enum.Enum:
2954 |\x20\x20
2955 | name
2956 | The name of the Enum member.
2957 |\x20\x20
2958 | value
2959 | The value of the Enum member.
2960 |\x20\x20
2961 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002962 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002963 |\x20\x20
2964 | __members__
2965 | Returns a mapping of member name->value.
2966 |\x20\x20\x20\x20\x20\x20
2967 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002968 | is a read-only view of the internal mapping."""
2969
2970expected_help_output_without_docs = """\
2971Help on class Color in module %s:
2972
2973class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002974 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2975 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002976 | Method resolution order:
2977 | Color
2978 | enum.Enum
2979 | builtins.object
2980 |\x20\x20
2981 | Data and other attributes defined here:
2982 |\x20\x20
2983 | blue = <Color.blue: 3>
2984 |\x20\x20
2985 | green = <Color.green: 2>
2986 |\x20\x20
2987 | red = <Color.red: 1>
2988 |\x20\x20
2989 | ----------------------------------------------------------------------
2990 | Data descriptors inherited from enum.Enum:
2991 |\x20\x20
2992 | name
2993 |\x20\x20
2994 | value
2995 |\x20\x20
2996 | ----------------------------------------------------------------------
2997 | Data descriptors inherited from enum.EnumMeta:
2998 |\x20\x20
2999 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003000
3001class TestStdLib(unittest.TestCase):
3002
Ethan Furman48a724f2015-04-11 23:23:06 -07003003 maxDiff = None
3004
Ethan Furman5875d742013-10-21 20:45:55 -07003005 class Color(Enum):
3006 red = 1
3007 green = 2
3008 blue = 3
3009
3010 def test_pydoc(self):
3011 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003012 if StrEnum.__doc__ is None:
3013 expected_text = expected_help_output_without_docs % __name__
3014 else:
3015 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003016 output = StringIO()
3017 helper = pydoc.Helper(output=output)
3018 helper(self.Color)
3019 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003020 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003021
3022 def test_inspect_getmembers(self):
3023 values = dict((
3024 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003025 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003026 ('__members__', self.Color.__members__),
3027 ('__module__', __name__),
3028 ('blue', self.Color.blue),
3029 ('green', self.Color.green),
3030 ('name', Enum.__dict__['name']),
3031 ('red', self.Color.red),
3032 ('value', Enum.__dict__['value']),
3033 ))
3034 result = dict(inspect.getmembers(self.Color))
3035 self.assertEqual(values.keys(), result.keys())
3036 failed = False
3037 for k in values.keys():
3038 if result[k] != values[k]:
3039 print()
3040 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3041 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3042 failed = True
3043 if failed:
3044 self.fail("result does not equal expected, see print above")
3045
3046 def test_inspect_classify_class_attrs(self):
3047 # indirectly test __objclass__
3048 from inspect import Attribute
3049 values = [
3050 Attribute(name='__class__', kind='data',
3051 defining_class=object, object=EnumMeta),
3052 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003053 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003054 Attribute(name='__members__', kind='property',
3055 defining_class=EnumMeta, object=EnumMeta.__members__),
3056 Attribute(name='__module__', kind='data',
3057 defining_class=self.Color, object=__name__),
3058 Attribute(name='blue', kind='data',
3059 defining_class=self.Color, object=self.Color.blue),
3060 Attribute(name='green', kind='data',
3061 defining_class=self.Color, object=self.Color.green),
3062 Attribute(name='red', kind='data',
3063 defining_class=self.Color, object=self.Color.red),
3064 Attribute(name='name', kind='data',
3065 defining_class=Enum, object=Enum.__dict__['name']),
3066 Attribute(name='value', kind='data',
3067 defining_class=Enum, object=Enum.__dict__['value']),
3068 ]
3069 values.sort(key=lambda item: item.name)
3070 result = list(inspect.classify_class_attrs(self.Color))
3071 result.sort(key=lambda item: item.name)
3072 failed = False
3073 for v, r in zip(values, result):
3074 if r != v:
3075 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3076 failed = True
3077 if failed:
3078 self.fail("result does not equal expected, see print above")
3079
Martin Panter19e69c52015-11-14 12:46:42 +00003080
3081class MiscTestCase(unittest.TestCase):
3082 def test__all__(self):
3083 support.check__all__(self, enum)
3084
3085
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003086# These are unordered here on purpose to ensure that declaration order
3087# makes no difference.
3088CONVERT_TEST_NAME_D = 5
3089CONVERT_TEST_NAME_C = 5
3090CONVERT_TEST_NAME_B = 5
3091CONVERT_TEST_NAME_A = 5 # This one should sort first.
3092CONVERT_TEST_NAME_E = 5
3093CONVERT_TEST_NAME_F = 5
3094
3095class TestIntEnumConvert(unittest.TestCase):
3096 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003097 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003098 'UnittestConvert',
3099 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003100 filter=lambda x: x.startswith('CONVERT_TEST_'))
3101 # We don't want the reverse lookup value to vary when there are
3102 # multiple possible names for a given value. It should always
3103 # report the first lexigraphical name in that case.
3104 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3105
3106 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003107 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003108 'UnittestConvert',
3109 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003110 filter=lambda x: x.startswith('CONVERT_TEST_'))
3111 # Ensure that test_type has all of the desired names and values.
3112 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3113 test_type.CONVERT_TEST_NAME_A)
3114 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3115 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3116 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3117 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3118 # Ensure that test_type only picked up names matching the filter.
3119 self.assertEqual([name for name in dir(test_type)
3120 if name[0:2] not in ('CO', '__')],
3121 [], msg='Names other than CONVERT_TEST_* found.')
3122
orlnub1230fb9fad2018-09-12 20:28:53 +03003123 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3124 '_convert was deprecated in 3.8')
3125 def test_convert_warn(self):
3126 with self.assertWarns(DeprecationWarning):
3127 enum.IntEnum._convert(
3128 'UnittestConvert',
3129 ('test.test_enum', '__main__')[__name__=='__main__'],
3130 filter=lambda x: x.startswith('CONVERT_TEST_'))
3131
3132 @unittest.skipUnless(sys.version_info >= (3, 9),
3133 '_convert was removed in 3.9')
3134 def test_convert_raise(self):
3135 with self.assertRaises(AttributeError):
3136 enum.IntEnum._convert(
3137 'UnittestConvert',
3138 ('test.test_enum', '__main__')[__name__=='__main__'],
3139 filter=lambda x: x.startswith('CONVERT_TEST_'))
3140
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003141
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003142if __name__ == '__main__':
3143 unittest.main()