blob: 5d72d82cec27ffe53ee363b917886d9625e13d63 [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
Ethan Furman3064dbf2020-09-16 07:11:57 -07001012 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1013 class EvenMoreColor(Color, IntEnum):
1014 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001015
1016 def test_exclude_methods(self):
1017 class whatever(Enum):
1018 this = 'that'
1019 these = 'those'
1020 def really(self):
1021 return 'no, not %s' % self.value
1022 self.assertIsNot(type(whatever.really), whatever)
1023 self.assertEqual(whatever.this.really(), 'no, not that')
1024
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001025 def test_wrong_inheritance_order(self):
1026 with self.assertRaises(TypeError):
1027 class Wrong(Enum, str):
1028 NotHere = 'error before this point'
1029
1030 def test_intenum_transitivity(self):
1031 class number(IntEnum):
1032 one = 1
1033 two = 2
1034 three = 3
1035 class numero(IntEnum):
1036 uno = 1
1037 dos = 2
1038 tres = 3
1039 self.assertEqual(number.one, numero.uno)
1040 self.assertEqual(number.two, numero.dos)
1041 self.assertEqual(number.three, numero.tres)
1042
1043 def test_wrong_enum_in_call(self):
1044 class Monochrome(Enum):
1045 black = 0
1046 white = 1
1047 class Gender(Enum):
1048 male = 0
1049 female = 1
1050 self.assertRaises(ValueError, Monochrome, Gender.male)
1051
1052 def test_wrong_enum_in_mixed_call(self):
1053 class Monochrome(IntEnum):
1054 black = 0
1055 white = 1
1056 class Gender(Enum):
1057 male = 0
1058 female = 1
1059 self.assertRaises(ValueError, Monochrome, Gender.male)
1060
1061 def test_mixed_enum_in_call_1(self):
1062 class Monochrome(IntEnum):
1063 black = 0
1064 white = 1
1065 class Gender(IntEnum):
1066 male = 0
1067 female = 1
1068 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1069
1070 def test_mixed_enum_in_call_2(self):
1071 class Monochrome(Enum):
1072 black = 0
1073 white = 1
1074 class Gender(IntEnum):
1075 male = 0
1076 female = 1
1077 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1078
1079 def test_flufl_enum(self):
1080 class Fluflnum(Enum):
1081 def __int__(self):
1082 return int(self.value)
1083 class MailManOptions(Fluflnum):
1084 option1 = 1
1085 option2 = 2
1086 option3 = 3
1087 self.assertEqual(int(MailManOptions.option1), 1)
1088
Ethan Furman5e5a8232013-08-04 08:42:23 -07001089 def test_introspection(self):
1090 class Number(IntEnum):
1091 one = 100
1092 two = 200
1093 self.assertIs(Number.one._member_type_, int)
1094 self.assertIs(Number._member_type_, int)
1095 class String(str, Enum):
1096 yarn = 'soft'
1097 rope = 'rough'
1098 wire = 'hard'
1099 self.assertIs(String.yarn._member_type_, str)
1100 self.assertIs(String._member_type_, str)
1101 class Plain(Enum):
1102 vanilla = 'white'
1103 one = 1
1104 self.assertIs(Plain.vanilla._member_type_, object)
1105 self.assertIs(Plain._member_type_, object)
1106
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001107 def test_no_such_enum_member(self):
1108 class Color(Enum):
1109 red = 1
1110 green = 2
1111 blue = 3
1112 with self.assertRaises(ValueError):
1113 Color(4)
1114 with self.assertRaises(KeyError):
1115 Color['chartreuse']
1116
1117 def test_new_repr(self):
1118 class Color(Enum):
1119 red = 1
1120 green = 2
1121 blue = 3
1122 def __repr__(self):
1123 return "don't you just love shades of %s?" % self.name
1124 self.assertEqual(
1125 repr(Color.blue),
1126 "don't you just love shades of blue?",
1127 )
1128
1129 def test_inherited_repr(self):
1130 class MyEnum(Enum):
1131 def __repr__(self):
1132 return "My name is %s." % self.name
1133 class MyIntEnum(int, MyEnum):
1134 this = 1
1135 that = 2
1136 theother = 3
1137 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1138
1139 def test_multiple_mixin_mro(self):
1140 class auto_enum(type(Enum)):
1141 def __new__(metacls, cls, bases, classdict):
1142 temp = type(classdict)()
1143 names = set(classdict._member_names)
1144 i = 0
1145 for k in classdict._member_names:
1146 v = classdict[k]
1147 if v is Ellipsis:
1148 v = i
1149 else:
1150 i = v
1151 i += 1
1152 temp[k] = v
1153 for k, v in classdict.items():
1154 if k not in names:
1155 temp[k] = v
1156 return super(auto_enum, metacls).__new__(
1157 metacls, cls, bases, temp)
1158
1159 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1160 pass
1161
1162 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1163 pass
1164
1165 class TestAutoNumber(AutoNumberedEnum):
1166 a = ...
1167 b = 3
1168 c = ...
1169
1170 class TestAutoInt(AutoIntEnum):
1171 a = ...
1172 b = 3
1173 c = ...
1174
1175 def test_subclasses_with_getnewargs(self):
1176 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001177 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001178 def __new__(cls, *args):
1179 _args = args
1180 name, *args = args
1181 if len(args) == 0:
1182 raise TypeError("name and value must be specified")
1183 self = int.__new__(cls, *args)
1184 self._intname = name
1185 self._args = _args
1186 return self
1187 def __getnewargs__(self):
1188 return self._args
1189 @property
1190 def __name__(self):
1191 return self._intname
1192 def __repr__(self):
1193 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001194 return "{}({!r}, {})".format(
1195 type(self).__name__,
1196 self.__name__,
1197 int.__repr__(self),
1198 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001199 def __str__(self):
1200 # str() is unchanged, even if it relies on the repr() fallback
1201 base = int
1202 base_str = base.__str__
1203 if base_str.__objclass__ is object:
1204 return base.__repr__(self)
1205 return base_str(self)
1206 # for simplicity, we only define one operator that
1207 # propagates expressions
1208 def __add__(self, other):
1209 temp = int(self) + int( other)
1210 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1211 return NamedInt(
1212 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001213 temp,
1214 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001215 else:
1216 return temp
1217
1218 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001219 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001220 x = ('the-x', 1)
1221 y = ('the-y', 2)
1222
Ethan Furman2aa27322013-07-19 19:35:56 -07001223
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001224 self.assertIs(NEI.__new__, Enum.__new__)
1225 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1226 globals()['NamedInt'] = NamedInt
1227 globals()['NEI'] = NEI
1228 NI5 = NamedInt('test', 5)
1229 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001230 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001231 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001232 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001233 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001234
Ethan Furmanca1b7942014-02-08 11:36:27 -08001235 def test_subclasses_with_getnewargs_ex(self):
1236 class NamedInt(int):
1237 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1238 def __new__(cls, *args):
1239 _args = args
1240 name, *args = args
1241 if len(args) == 0:
1242 raise TypeError("name and value must be specified")
1243 self = int.__new__(cls, *args)
1244 self._intname = name
1245 self._args = _args
1246 return self
1247 def __getnewargs_ex__(self):
1248 return self._args, {}
1249 @property
1250 def __name__(self):
1251 return self._intname
1252 def __repr__(self):
1253 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001254 return "{}({!r}, {})".format(
1255 type(self).__name__,
1256 self.__name__,
1257 int.__repr__(self),
1258 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001259 def __str__(self):
1260 # str() is unchanged, even if it relies on the repr() fallback
1261 base = int
1262 base_str = base.__str__
1263 if base_str.__objclass__ is object:
1264 return base.__repr__(self)
1265 return base_str(self)
1266 # for simplicity, we only define one operator that
1267 # propagates expressions
1268 def __add__(self, other):
1269 temp = int(self) + int( other)
1270 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1271 return NamedInt(
1272 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001273 temp,
1274 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001275 else:
1276 return temp
1277
1278 class NEI(NamedInt, Enum):
1279 __qualname__ = 'NEI' # needed for pickle protocol 4
1280 x = ('the-x', 1)
1281 y = ('the-y', 2)
1282
1283
1284 self.assertIs(NEI.__new__, Enum.__new__)
1285 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1286 globals()['NamedInt'] = NamedInt
1287 globals()['NEI'] = NEI
1288 NI5 = NamedInt('test', 5)
1289 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001290 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001291 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001292 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001293 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001294
1295 def test_subclasses_with_reduce(self):
1296 class NamedInt(int):
1297 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1298 def __new__(cls, *args):
1299 _args = args
1300 name, *args = args
1301 if len(args) == 0:
1302 raise TypeError("name and value must be specified")
1303 self = int.__new__(cls, *args)
1304 self._intname = name
1305 self._args = _args
1306 return self
1307 def __reduce__(self):
1308 return self.__class__, self._args
1309 @property
1310 def __name__(self):
1311 return self._intname
1312 def __repr__(self):
1313 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001314 return "{}({!r}, {})".format(
1315 type(self).__name__,
1316 self.__name__,
1317 int.__repr__(self),
1318 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001319 def __str__(self):
1320 # str() is unchanged, even if it relies on the repr() fallback
1321 base = int
1322 base_str = base.__str__
1323 if base_str.__objclass__ is object:
1324 return base.__repr__(self)
1325 return base_str(self)
1326 # for simplicity, we only define one operator that
1327 # propagates expressions
1328 def __add__(self, other):
1329 temp = int(self) + int( other)
1330 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1331 return NamedInt(
1332 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001333 temp,
1334 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001335 else:
1336 return temp
1337
1338 class NEI(NamedInt, Enum):
1339 __qualname__ = 'NEI' # needed for pickle protocol 4
1340 x = ('the-x', 1)
1341 y = ('the-y', 2)
1342
1343
1344 self.assertIs(NEI.__new__, Enum.__new__)
1345 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1346 globals()['NamedInt'] = NamedInt
1347 globals()['NEI'] = NEI
1348 NI5 = NamedInt('test', 5)
1349 self.assertEqual(NI5, 5)
1350 test_pickle_dump_load(self.assertEqual, NI5, 5)
1351 self.assertEqual(NEI.y.value, 2)
1352 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001353 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354
1355 def test_subclasses_with_reduce_ex(self):
1356 class NamedInt(int):
1357 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1358 def __new__(cls, *args):
1359 _args = args
1360 name, *args = args
1361 if len(args) == 0:
1362 raise TypeError("name and value must be specified")
1363 self = int.__new__(cls, *args)
1364 self._intname = name
1365 self._args = _args
1366 return self
1367 def __reduce_ex__(self, proto):
1368 return self.__class__, self._args
1369 @property
1370 def __name__(self):
1371 return self._intname
1372 def __repr__(self):
1373 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001374 return "{}({!r}, {})".format(
1375 type(self).__name__,
1376 self.__name__,
1377 int.__repr__(self),
1378 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001379 def __str__(self):
1380 # str() is unchanged, even if it relies on the repr() fallback
1381 base = int
1382 base_str = base.__str__
1383 if base_str.__objclass__ is object:
1384 return base.__repr__(self)
1385 return base_str(self)
1386 # for simplicity, we only define one operator that
1387 # propagates expressions
1388 def __add__(self, other):
1389 temp = int(self) + int( other)
1390 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1391 return NamedInt(
1392 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001393 temp,
1394 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001395 else:
1396 return temp
1397
1398 class NEI(NamedInt, Enum):
1399 __qualname__ = 'NEI' # needed for pickle protocol 4
1400 x = ('the-x', 1)
1401 y = ('the-y', 2)
1402
Ethan Furmanca1b7942014-02-08 11:36:27 -08001403 self.assertIs(NEI.__new__, Enum.__new__)
1404 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1405 globals()['NamedInt'] = NamedInt
1406 globals()['NEI'] = NEI
1407 NI5 = NamedInt('test', 5)
1408 self.assertEqual(NI5, 5)
1409 test_pickle_dump_load(self.assertEqual, NI5, 5)
1410 self.assertEqual(NEI.y.value, 2)
1411 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001412 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001413
Ethan Furmandc870522014-02-18 12:37:12 -08001414 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001415 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001416 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001417 def __new__(cls, *args):
1418 _args = args
1419 name, *args = args
1420 if len(args) == 0:
1421 raise TypeError("name and value must be specified")
1422 self = int.__new__(cls, *args)
1423 self._intname = name
1424 self._args = _args
1425 return self
1426 @property
1427 def __name__(self):
1428 return self._intname
1429 def __repr__(self):
1430 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001431 return "{}({!r}, {})".format(
1432 type(self).__name__,
1433 self.__name__,
1434 int.__repr__(self),
1435 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 def __str__(self):
1437 # str() is unchanged, even if it relies on the repr() fallback
1438 base = int
1439 base_str = base.__str__
1440 if base_str.__objclass__ is object:
1441 return base.__repr__(self)
1442 return base_str(self)
1443 # for simplicity, we only define one operator that
1444 # propagates expressions
1445 def __add__(self, other):
1446 temp = int(self) + int( other)
1447 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1448 return NamedInt(
1449 '({0} + {1})'.format(self.__name__, other.__name__),
1450 temp )
1451 else:
1452 return temp
1453
1454 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001455 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 x = ('the-x', 1)
1457 y = ('the-y', 2)
1458
1459 self.assertIs(NEI.__new__, Enum.__new__)
1460 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1461 globals()['NamedInt'] = NamedInt
1462 globals()['NEI'] = NEI
1463 NI5 = NamedInt('test', 5)
1464 self.assertEqual(NI5, 5)
1465 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001466 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1467 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001468
Ethan Furmandc870522014-02-18 12:37:12 -08001469 def test_subclasses_without_direct_pickle_support_using_name(self):
1470 class NamedInt(int):
1471 __qualname__ = 'NamedInt'
1472 def __new__(cls, *args):
1473 _args = args
1474 name, *args = args
1475 if len(args) == 0:
1476 raise TypeError("name and value must be specified")
1477 self = int.__new__(cls, *args)
1478 self._intname = name
1479 self._args = _args
1480 return self
1481 @property
1482 def __name__(self):
1483 return self._intname
1484 def __repr__(self):
1485 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001486 return "{}({!r}, {})".format(
1487 type(self).__name__,
1488 self.__name__,
1489 int.__repr__(self),
1490 )
Ethan Furmandc870522014-02-18 12:37:12 -08001491 def __str__(self):
1492 # str() is unchanged, even if it relies on the repr() fallback
1493 base = int
1494 base_str = base.__str__
1495 if base_str.__objclass__ is object:
1496 return base.__repr__(self)
1497 return base_str(self)
1498 # for simplicity, we only define one operator that
1499 # propagates expressions
1500 def __add__(self, other):
1501 temp = int(self) + int( other)
1502 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1503 return NamedInt(
1504 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001505 temp,
1506 )
Ethan Furmandc870522014-02-18 12:37:12 -08001507 else:
1508 return temp
1509
1510 class NEI(NamedInt, Enum):
1511 __qualname__ = 'NEI'
1512 x = ('the-x', 1)
1513 y = ('the-y', 2)
1514 def __reduce_ex__(self, proto):
1515 return getattr, (self.__class__, self._name_)
1516
1517 self.assertIs(NEI.__new__, Enum.__new__)
1518 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1519 globals()['NamedInt'] = NamedInt
1520 globals()['NEI'] = NEI
1521 NI5 = NamedInt('test', 5)
1522 self.assertEqual(NI5, 5)
1523 self.assertEqual(NEI.y.value, 2)
1524 test_pickle_dump_load(self.assertIs, NEI.y)
1525 test_pickle_dump_load(self.assertIs, NEI)
1526
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001527 def test_tuple_subclass(self):
1528 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001529 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001530 first = (1, 'for the money')
1531 second = (2, 'for the show')
1532 third = (3, 'for the music')
1533 self.assertIs(type(SomeTuple.first), SomeTuple)
1534 self.assertIsInstance(SomeTuple.second, tuple)
1535 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1536 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001537 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001538
1539 def test_duplicate_values_give_unique_enum_items(self):
1540 class AutoNumber(Enum):
1541 first = ()
1542 second = ()
1543 third = ()
1544 def __new__(cls):
1545 value = len(cls.__members__) + 1
1546 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001547 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548 return obj
1549 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001550 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001551 self.assertEqual(
1552 list(AutoNumber),
1553 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1554 )
1555 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001556 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 self.assertIs(AutoNumber(1), AutoNumber.first)
1558
1559 def test_inherited_new_from_enhanced_enum(self):
1560 class AutoNumber(Enum):
1561 def __new__(cls):
1562 value = len(cls.__members__) + 1
1563 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001564 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001565 return obj
1566 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001567 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001568 class Color(AutoNumber):
1569 red = ()
1570 green = ()
1571 blue = ()
1572 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1573 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1574
1575 def test_inherited_new_from_mixed_enum(self):
1576 class AutoNumber(IntEnum):
1577 def __new__(cls):
1578 value = len(cls.__members__) + 1
1579 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001580 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001581 return obj
1582 class Color(AutoNumber):
1583 red = ()
1584 green = ()
1585 blue = ()
1586 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1587 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1588
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001589 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001590 class OrdinaryEnum(Enum):
1591 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001592 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1593 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001594
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001595 def test_ordered_mixin(self):
1596 class OrderedEnum(Enum):
1597 def __ge__(self, other):
1598 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001599 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001600 return NotImplemented
1601 def __gt__(self, other):
1602 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001603 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001604 return NotImplemented
1605 def __le__(self, other):
1606 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001607 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001608 return NotImplemented
1609 def __lt__(self, other):
1610 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001611 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001612 return NotImplemented
1613 class Grade(OrderedEnum):
1614 A = 5
1615 B = 4
1616 C = 3
1617 D = 2
1618 F = 1
1619 self.assertGreater(Grade.A, Grade.B)
1620 self.assertLessEqual(Grade.F, Grade.C)
1621 self.assertLess(Grade.D, Grade.A)
1622 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001623 self.assertEqual(Grade.B, Grade.B)
1624 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001625
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001626 def test_extending2(self):
1627 class Shade(Enum):
1628 def shade(self):
1629 print(self.name)
1630 class Color(Shade):
1631 red = 1
1632 green = 2
1633 blue = 3
1634 with self.assertRaises(TypeError):
1635 class MoreColor(Color):
1636 cyan = 4
1637 magenta = 5
1638 yellow = 6
1639
1640 def test_extending3(self):
1641 class Shade(Enum):
1642 def shade(self):
1643 return self.name
1644 class Color(Shade):
1645 def hex(self):
1646 return '%s hexlified!' % self.value
1647 class MoreColor(Color):
1648 cyan = 4
1649 magenta = 5
1650 yellow = 6
1651 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1652
orlnub1230fb9fad2018-09-12 20:28:53 +03001653 def test_subclass_duplicate_name(self):
1654 class Base(Enum):
1655 def test(self):
1656 pass
1657 class Test(Base):
1658 test = 1
1659 self.assertIs(type(Test.test), Test)
1660
1661 def test_subclass_duplicate_name_dynamic(self):
1662 from types import DynamicClassAttribute
1663 class Base(Enum):
1664 @DynamicClassAttribute
1665 def test(self):
1666 return 'dynamic'
1667 class Test(Base):
1668 test = 1
1669 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001670
1671 def test_no_duplicates(self):
1672 class UniqueEnum(Enum):
1673 def __init__(self, *args):
1674 cls = self.__class__
1675 if any(self.value == e.value for e in cls):
1676 a = self.name
1677 e = cls(self.value).name
1678 raise ValueError(
1679 "aliases not allowed in UniqueEnum: %r --> %r"
1680 % (a, e)
1681 )
1682 class Color(UniqueEnum):
1683 red = 1
1684 green = 2
1685 blue = 3
1686 with self.assertRaises(ValueError):
1687 class Color(UniqueEnum):
1688 red = 1
1689 green = 2
1690 blue = 3
1691 grene = 2
1692
1693 def test_init(self):
1694 class Planet(Enum):
1695 MERCURY = (3.303e+23, 2.4397e6)
1696 VENUS = (4.869e+24, 6.0518e6)
1697 EARTH = (5.976e+24, 6.37814e6)
1698 MARS = (6.421e+23, 3.3972e6)
1699 JUPITER = (1.9e+27, 7.1492e7)
1700 SATURN = (5.688e+26, 6.0268e7)
1701 URANUS = (8.686e+25, 2.5559e7)
1702 NEPTUNE = (1.024e+26, 2.4746e7)
1703 def __init__(self, mass, radius):
1704 self.mass = mass # in kilograms
1705 self.radius = radius # in meters
1706 @property
1707 def surface_gravity(self):
1708 # universal gravitational constant (m3 kg-1 s-2)
1709 G = 6.67300E-11
1710 return G * self.mass / (self.radius * self.radius)
1711 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1712 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1713
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001714 def test_ignore(self):
1715 class Period(timedelta, Enum):
1716 '''
1717 different lengths of time
1718 '''
1719 def __new__(cls, value, period):
1720 obj = timedelta.__new__(cls, value)
1721 obj._value_ = value
1722 obj.period = period
1723 return obj
1724 _ignore_ = 'Period i'
1725 Period = vars()
1726 for i in range(13):
1727 Period['month_%d' % i] = i*30, 'month'
1728 for i in range(53):
1729 Period['week_%d' % i] = i*7, 'week'
1730 for i in range(32):
1731 Period['day_%d' % i] = i, 'day'
1732 OneDay = day_1
1733 OneWeek = week_1
1734 OneMonth = month_1
1735 self.assertFalse(hasattr(Period, '_ignore_'))
1736 self.assertFalse(hasattr(Period, 'Period'))
1737 self.assertFalse(hasattr(Period, 'i'))
1738 self.assertTrue(isinstance(Period.day_1, timedelta))
1739 self.assertTrue(Period.month_1 is Period.day_30)
1740 self.assertTrue(Period.week_4 is Period.day_28)
1741
Ethan Furman2aa27322013-07-19 19:35:56 -07001742 def test_nonhash_value(self):
1743 class AutoNumberInAList(Enum):
1744 def __new__(cls):
1745 value = [len(cls.__members__) + 1]
1746 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001747 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001748 return obj
1749 class ColorInAList(AutoNumberInAList):
1750 red = ()
1751 green = ()
1752 blue = ()
1753 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001754 for enum, value in zip(ColorInAList, range(3)):
1755 value += 1
1756 self.assertEqual(enum.value, [value])
1757 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001758
Ethan Furmanb41803e2013-07-25 13:50:45 -07001759 def test_conflicting_types_resolved_in_new(self):
1760 class LabelledIntEnum(int, Enum):
1761 def __new__(cls, *args):
1762 value, label = args
1763 obj = int.__new__(cls, value)
1764 obj.label = label
1765 obj._value_ = value
1766 return obj
1767
1768 class LabelledList(LabelledIntEnum):
1769 unprocessed = (1, "Unprocessed")
1770 payment_complete = (2, "Payment Complete")
1771
1772 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1773 self.assertEqual(LabelledList.unprocessed, 1)
1774 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001775
Ethan Furmanc16595e2016-09-10 23:36:59 -07001776 def test_auto_number(self):
1777 class Color(Enum):
1778 red = auto()
1779 blue = auto()
1780 green = auto()
1781
1782 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1783 self.assertEqual(Color.red.value, 1)
1784 self.assertEqual(Color.blue.value, 2)
1785 self.assertEqual(Color.green.value, 3)
1786
1787 def test_auto_name(self):
1788 class Color(Enum):
1789 def _generate_next_value_(name, start, count, last):
1790 return name
1791 red = auto()
1792 blue = auto()
1793 green = auto()
1794
1795 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1796 self.assertEqual(Color.red.value, 'red')
1797 self.assertEqual(Color.blue.value, 'blue')
1798 self.assertEqual(Color.green.value, 'green')
1799
1800 def test_auto_name_inherit(self):
1801 class AutoNameEnum(Enum):
1802 def _generate_next_value_(name, start, count, last):
1803 return name
1804 class Color(AutoNameEnum):
1805 red = auto()
1806 blue = auto()
1807 green = auto()
1808
1809 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1810 self.assertEqual(Color.red.value, 'red')
1811 self.assertEqual(Color.blue.value, 'blue')
1812 self.assertEqual(Color.green.value, 'green')
1813
1814 def test_auto_garbage(self):
1815 class Color(Enum):
1816 red = 'red'
1817 blue = auto()
1818 self.assertEqual(Color.blue.value, 1)
1819
1820 def test_auto_garbage_corrected(self):
1821 class Color(Enum):
1822 red = 'red'
1823 blue = 2
1824 green = auto()
1825
1826 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1827 self.assertEqual(Color.red.value, 'red')
1828 self.assertEqual(Color.blue.value, 2)
1829 self.assertEqual(Color.green.value, 3)
1830
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001831 def test_auto_order(self):
1832 with self.assertRaises(TypeError):
1833 class Color(Enum):
1834 red = auto()
1835 green = auto()
1836 blue = auto()
1837 def _generate_next_value_(name, start, count, last):
1838 return name
1839
1840
Ethan Furman3515dcc2016-09-18 13:15:41 -07001841 def test_duplicate_auto(self):
1842 class Dupes(Enum):
1843 first = primero = auto()
1844 second = auto()
1845 third = auto()
1846 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1847
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001848 def test_default_missing(self):
1849 class Color(Enum):
1850 RED = 1
1851 GREEN = 2
1852 BLUE = 3
1853 try:
1854 Color(7)
1855 except ValueError as exc:
1856 self.assertTrue(exc.__context__ is None)
1857 else:
1858 raise Exception('Exception not raised.')
1859
Ethan Furman019f0a02018-09-12 11:43:34 -07001860 def test_missing(self):
1861 class Color(Enum):
1862 red = 1
1863 green = 2
1864 blue = 3
1865 @classmethod
1866 def _missing_(cls, item):
1867 if item == 'three':
1868 return cls.blue
1869 elif item == 'bad return':
1870 # trigger internal error
1871 return 5
1872 elif item == 'error out':
1873 raise ZeroDivisionError
1874 else:
1875 # trigger not found
1876 return None
1877 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001878 try:
1879 Color(7)
1880 except ValueError as exc:
1881 self.assertTrue(exc.__context__ is None)
1882 else:
1883 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001884 try:
1885 Color('bad return')
1886 except TypeError as exc:
1887 self.assertTrue(isinstance(exc.__context__, ValueError))
1888 else:
1889 raise Exception('Exception not raised.')
1890 try:
1891 Color('error out')
1892 except ZeroDivisionError as exc:
1893 self.assertTrue(isinstance(exc.__context__, ValueError))
1894 else:
1895 raise Exception('Exception not raised.')
1896
Ethan Furman5bdab642018-09-21 19:03:09 -07001897 def test_multiple_mixin(self):
1898 class MaxMixin:
1899 @classproperty
1900 def MAX(cls):
1901 max = len(cls)
1902 cls.MAX = max
1903 return max
1904 class StrMixin:
1905 def __str__(self):
1906 return self._name_.lower()
1907 class SomeEnum(Enum):
1908 def behavior(self):
1909 return 'booyah'
1910 class AnotherEnum(Enum):
1911 def behavior(self):
1912 return 'nuhuh!'
1913 def social(self):
1914 return "what's up?"
1915 class Color(MaxMixin, Enum):
1916 RED = auto()
1917 GREEN = auto()
1918 BLUE = auto()
1919 self.assertEqual(Color.RED.value, 1)
1920 self.assertEqual(Color.GREEN.value, 2)
1921 self.assertEqual(Color.BLUE.value, 3)
1922 self.assertEqual(Color.MAX, 3)
1923 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1924 class Color(MaxMixin, StrMixin, Enum):
1925 RED = auto()
1926 GREEN = auto()
1927 BLUE = auto()
1928 self.assertEqual(Color.RED.value, 1)
1929 self.assertEqual(Color.GREEN.value, 2)
1930 self.assertEqual(Color.BLUE.value, 3)
1931 self.assertEqual(Color.MAX, 3)
1932 self.assertEqual(str(Color.BLUE), 'blue')
1933 class Color(StrMixin, MaxMixin, Enum):
1934 RED = auto()
1935 GREEN = auto()
1936 BLUE = auto()
1937 self.assertEqual(Color.RED.value, 1)
1938 self.assertEqual(Color.GREEN.value, 2)
1939 self.assertEqual(Color.BLUE.value, 3)
1940 self.assertEqual(Color.MAX, 3)
1941 self.assertEqual(str(Color.BLUE), 'blue')
1942 class CoolColor(StrMixin, SomeEnum, Enum):
1943 RED = auto()
1944 GREEN = auto()
1945 BLUE = auto()
1946 self.assertEqual(CoolColor.RED.value, 1)
1947 self.assertEqual(CoolColor.GREEN.value, 2)
1948 self.assertEqual(CoolColor.BLUE.value, 3)
1949 self.assertEqual(str(CoolColor.BLUE), 'blue')
1950 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1951 class CoolerColor(StrMixin, AnotherEnum, Enum):
1952 RED = auto()
1953 GREEN = auto()
1954 BLUE = auto()
1955 self.assertEqual(CoolerColor.RED.value, 1)
1956 self.assertEqual(CoolerColor.GREEN.value, 2)
1957 self.assertEqual(CoolerColor.BLUE.value, 3)
1958 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1959 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1960 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1961 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1962 RED = auto()
1963 GREEN = auto()
1964 BLUE = auto()
1965 self.assertEqual(CoolestColor.RED.value, 1)
1966 self.assertEqual(CoolestColor.GREEN.value, 2)
1967 self.assertEqual(CoolestColor.BLUE.value, 3)
1968 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1969 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1970 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1971 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1972 RED = auto()
1973 GREEN = auto()
1974 BLUE = auto()
1975 self.assertEqual(ConfusedColor.RED.value, 1)
1976 self.assertEqual(ConfusedColor.GREEN.value, 2)
1977 self.assertEqual(ConfusedColor.BLUE.value, 3)
1978 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1979 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1980 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1981 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1982 RED = auto()
1983 GREEN = auto()
1984 BLUE = auto()
1985 self.assertEqual(ReformedColor.RED.value, 1)
1986 self.assertEqual(ReformedColor.GREEN.value, 2)
1987 self.assertEqual(ReformedColor.BLUE.value, 3)
1988 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1989 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1990 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1991 self.assertTrue(issubclass(ReformedColor, int))
1992
Ethan Furmancd453852018-10-05 23:29:36 -07001993 def test_multiple_inherited_mixin(self):
1994 class StrEnum(str, Enum):
1995 def __new__(cls, *args, **kwargs):
1996 for a in args:
1997 if not isinstance(a, str):
1998 raise TypeError("Enumeration '%s' (%s) is not"
1999 " a string" % (a, type(a).__name__))
2000 return str.__new__(cls, *args, **kwargs)
2001 @unique
2002 class Decision1(StrEnum):
2003 REVERT = "REVERT"
2004 REVERT_ALL = "REVERT_ALL"
2005 RETRY = "RETRY"
2006 class MyEnum(StrEnum):
2007 pass
2008 @unique
2009 class Decision2(MyEnum):
2010 REVERT = "REVERT"
2011 REVERT_ALL = "REVERT_ALL"
2012 RETRY = "RETRY"
2013
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002014 def test_empty_globals(self):
2015 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2016 # when using compile and exec because f_globals is empty
2017 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2018 code = compile(code, "<string>", "exec")
2019 global_ns = {}
2020 local_ls = {}
2021 exec(code, global_ns, local_ls)
2022
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002023
Ethan Furmane8e61272016-08-20 07:19:31 -07002024class TestOrder(unittest.TestCase):
2025
2026 def test_same_members(self):
2027 class Color(Enum):
2028 _order_ = 'red green blue'
2029 red = 1
2030 green = 2
2031 blue = 3
2032
2033 def test_same_members_with_aliases(self):
2034 class Color(Enum):
2035 _order_ = 'red green blue'
2036 red = 1
2037 green = 2
2038 blue = 3
2039 verde = green
2040
2041 def test_same_members_wrong_order(self):
2042 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2043 class Color(Enum):
2044 _order_ = 'red green blue'
2045 red = 1
2046 blue = 3
2047 green = 2
2048
2049 def test_order_has_extra_members(self):
2050 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2051 class Color(Enum):
2052 _order_ = 'red green blue purple'
2053 red = 1
2054 green = 2
2055 blue = 3
2056
2057 def test_order_has_extra_members_with_aliases(self):
2058 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2059 class Color(Enum):
2060 _order_ = 'red green blue purple'
2061 red = 1
2062 green = 2
2063 blue = 3
2064 verde = green
2065
2066 def test_enum_has_extra_members(self):
2067 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2068 class Color(Enum):
2069 _order_ = 'red green blue'
2070 red = 1
2071 green = 2
2072 blue = 3
2073 purple = 4
2074
2075 def test_enum_has_extra_members_with_aliases(self):
2076 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2077 class Color(Enum):
2078 _order_ = 'red green blue'
2079 red = 1
2080 green = 2
2081 blue = 3
2082 purple = 4
2083 verde = green
2084
2085
Ethan Furman65a5a472016-09-01 23:55:19 -07002086class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002087 """Tests of the Flags."""
2088
Ethan Furman65a5a472016-09-01 23:55:19 -07002089 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002090 R, W, X = 4, 2, 1
2091
Ethan Furman65a5a472016-09-01 23:55:19 -07002092 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002093 RO = 0
2094 WO = 1
2095 RW = 2
2096 AC = 3
2097 CE = 1<<19
2098
Rahul Jha94306522018-09-10 23:51:04 +05302099 class Color(Flag):
2100 BLACK = 0
2101 RED = 1
2102 GREEN = 2
2103 BLUE = 4
2104 PURPLE = RED|BLUE
2105
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002106 def test_str(self):
2107 Perm = self.Perm
2108 self.assertEqual(str(Perm.R), 'Perm.R')
2109 self.assertEqual(str(Perm.W), 'Perm.W')
2110 self.assertEqual(str(Perm.X), 'Perm.X')
2111 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2112 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2113 self.assertEqual(str(Perm(0)), 'Perm.0')
2114 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2115 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2116 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2117 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2118 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2119 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2120
2121 Open = self.Open
2122 self.assertEqual(str(Open.RO), 'Open.RO')
2123 self.assertEqual(str(Open.WO), 'Open.WO')
2124 self.assertEqual(str(Open.AC), 'Open.AC')
2125 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2126 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002127 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002128 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2129 self.assertEqual(str(~Open.AC), 'Open.CE')
2130 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2131 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2132
2133 def test_repr(self):
2134 Perm = self.Perm
2135 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2136 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2137 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2138 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2139 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002140 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002141 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2142 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2143 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2144 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002145 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002146 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2147
2148 Open = self.Open
2149 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2150 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2151 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2152 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2153 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002154 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002155 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2156 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2157 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2158 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2159
2160 def test_or(self):
2161 Perm = self.Perm
2162 for i in Perm:
2163 for j in Perm:
2164 self.assertEqual((i | j), Perm(i.value | j.value))
2165 self.assertEqual((i | j).value, i.value | j.value)
2166 self.assertIs(type(i | j), Perm)
2167 for i in Perm:
2168 self.assertIs(i | i, i)
2169 Open = self.Open
2170 self.assertIs(Open.RO | Open.CE, Open.CE)
2171
2172 def test_and(self):
2173 Perm = self.Perm
2174 RW = Perm.R | Perm.W
2175 RX = Perm.R | Perm.X
2176 WX = Perm.W | Perm.X
2177 RWX = Perm.R | Perm.W | Perm.X
2178 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2179 for i in values:
2180 for j in values:
2181 self.assertEqual((i & j).value, i.value & j.value)
2182 self.assertIs(type(i & j), Perm)
2183 for i in Perm:
2184 self.assertIs(i & i, i)
2185 self.assertIs(i & RWX, i)
2186 self.assertIs(RWX & i, i)
2187 Open = self.Open
2188 self.assertIs(Open.RO & Open.CE, Open.RO)
2189
2190 def test_xor(self):
2191 Perm = self.Perm
2192 for i in Perm:
2193 for j in Perm:
2194 self.assertEqual((i ^ j).value, i.value ^ j.value)
2195 self.assertIs(type(i ^ j), Perm)
2196 for i in Perm:
2197 self.assertIs(i ^ Perm(0), i)
2198 self.assertIs(Perm(0) ^ i, i)
2199 Open = self.Open
2200 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2201 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2202
2203 def test_invert(self):
2204 Perm = self.Perm
2205 RW = Perm.R | Perm.W
2206 RX = Perm.R | Perm.X
2207 WX = Perm.W | Perm.X
2208 RWX = Perm.R | Perm.W | Perm.X
2209 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2210 for i in values:
2211 self.assertIs(type(~i), Perm)
2212 self.assertEqual(~~i, i)
2213 for i in Perm:
2214 self.assertIs(~~i, i)
2215 Open = self.Open
2216 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2217 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2218
Ethan Furman25d94bb2016-09-02 16:32:32 -07002219 def test_bool(self):
2220 Perm = self.Perm
2221 for f in Perm:
2222 self.assertTrue(f)
2223 Open = self.Open
2224 for f in Open:
2225 self.assertEqual(bool(f.value), bool(f))
2226
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002227 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002228 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002229 lst = list(Perm)
2230 self.assertEqual(len(lst), len(Perm))
2231 self.assertEqual(len(Perm), 3, Perm)
2232 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2233 for i, n in enumerate('R W X'.split()):
2234 v = 1<<i
2235 e = Perm(v)
2236 self.assertEqual(e.value, v)
2237 self.assertEqual(type(e.value), int)
2238 self.assertEqual(e.name, n)
2239 self.assertIn(e, Perm)
2240 self.assertIs(type(e), Perm)
2241
2242 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002243 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002244 lst = list(Perm)
2245 self.assertEqual(len(lst), len(Perm))
2246 self.assertEqual(len(Perm), 3, Perm)
2247 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2248 for i, n in enumerate('R W X'.split()):
2249 v = 8<<i
2250 e = Perm(v)
2251 self.assertEqual(e.value, v)
2252 self.assertEqual(type(e.value), int)
2253 self.assertEqual(e.name, n)
2254 self.assertIn(e, Perm)
2255 self.assertIs(type(e), Perm)
2256
2257 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002258 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002259 lst = list(Perm)
2260 self.assertEqual(len(lst), len(Perm))
2261 self.assertEqual(len(Perm), 3, Perm)
2262 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2263 for i, n in enumerate('R W X'.split()):
2264 v = 1<<i
2265 e = Perm(v)
2266 self.assertEqual(e.value, v)
2267 self.assertEqual(type(e.value), int)
2268 self.assertEqual(e.name, n)
2269 self.assertIn(e, Perm)
2270 self.assertIs(type(e), Perm)
2271
2272 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002273 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002274 lst = list(Perm)
2275 self.assertEqual(len(lst), len(Perm))
2276 self.assertEqual(len(Perm), 3, Perm)
2277 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2278 for i, n in enumerate('R W X'.split()):
2279 v = 1<<(2*i+1)
2280 e = Perm(v)
2281 self.assertEqual(e.value, v)
2282 self.assertEqual(type(e.value), int)
2283 self.assertEqual(e.name, n)
2284 self.assertIn(e, Perm)
2285 self.assertIs(type(e), Perm)
2286
2287 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002288 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002289 lst = list(Perm)
2290 self.assertEqual(len(lst), len(Perm))
2291 self.assertEqual(len(Perm), 3, Perm)
2292 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2293 for i, n in enumerate('R W X'.split()):
2294 v = 1<<(2*i+1)
2295 e = Perm(v)
2296 self.assertEqual(e.value, v)
2297 self.assertEqual(type(e.value), int)
2298 self.assertEqual(e.name, n)
2299 self.assertIn(e, Perm)
2300 self.assertIs(type(e), Perm)
2301
Ethan Furman65a5a472016-09-01 23:55:19 -07002302 def test_pickle(self):
2303 if isinstance(FlagStooges, Exception):
2304 raise FlagStooges
2305 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2306 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002307
Rahul Jha94306522018-09-10 23:51:04 +05302308 def test_contains(self):
2309 Open = self.Open
2310 Color = self.Color
2311 self.assertFalse(Color.BLACK in Open)
2312 self.assertFalse(Open.RO in Color)
2313 with self.assertRaises(TypeError):
2314 'BLACK' in Color
2315 with self.assertRaises(TypeError):
2316 'RO' in Open
2317 with self.assertRaises(TypeError):
2318 1 in Color
2319 with self.assertRaises(TypeError):
2320 1 in Open
2321
2322 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002323 Perm = self.Perm
2324 R, W, X = Perm
2325 RW = R | W
2326 RX = R | X
2327 WX = W | X
2328 RWX = R | W | X
2329 self.assertTrue(R in RW)
2330 self.assertTrue(R in RX)
2331 self.assertTrue(R in RWX)
2332 self.assertTrue(W in RW)
2333 self.assertTrue(W in WX)
2334 self.assertTrue(W in RWX)
2335 self.assertTrue(X in RX)
2336 self.assertTrue(X in WX)
2337 self.assertTrue(X in RWX)
2338 self.assertFalse(R in WX)
2339 self.assertFalse(W in RX)
2340 self.assertFalse(X in RW)
2341
Ethan Furmanc16595e2016-09-10 23:36:59 -07002342 def test_auto_number(self):
2343 class Color(Flag):
2344 red = auto()
2345 blue = auto()
2346 green = auto()
2347
2348 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2349 self.assertEqual(Color.red.value, 1)
2350 self.assertEqual(Color.blue.value, 2)
2351 self.assertEqual(Color.green.value, 4)
2352
2353 def test_auto_number_garbage(self):
2354 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2355 class Color(Flag):
2356 red = 'not an int'
2357 blue = auto()
2358
Ethan Furman3515dcc2016-09-18 13:15:41 -07002359 def test_cascading_failure(self):
2360 class Bizarre(Flag):
2361 c = 3
2362 d = 4
2363 f = 6
2364 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002365 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2366 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2367 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2368 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2369 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2370 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2371 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002372
2373 def test_duplicate_auto(self):
2374 class Dupes(Enum):
2375 first = primero = auto()
2376 second = auto()
2377 third = auto()
2378 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2379
2380 def test_bizarre(self):
2381 class Bizarre(Flag):
2382 b = 3
2383 c = 4
2384 d = 6
2385 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2386
Ethan Furman5bdab642018-09-21 19:03:09 -07002387 def test_multiple_mixin(self):
2388 class AllMixin:
2389 @classproperty
2390 def ALL(cls):
2391 members = list(cls)
2392 all_value = None
2393 if members:
2394 all_value = members[0]
2395 for member in members[1:]:
2396 all_value |= member
2397 cls.ALL = all_value
2398 return all_value
2399 class StrMixin:
2400 def __str__(self):
2401 return self._name_.lower()
2402 class Color(AllMixin, Flag):
2403 RED = auto()
2404 GREEN = auto()
2405 BLUE = auto()
2406 self.assertEqual(Color.RED.value, 1)
2407 self.assertEqual(Color.GREEN.value, 2)
2408 self.assertEqual(Color.BLUE.value, 4)
2409 self.assertEqual(Color.ALL.value, 7)
2410 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2411 class Color(AllMixin, StrMixin, Flag):
2412 RED = auto()
2413 GREEN = auto()
2414 BLUE = auto()
2415 self.assertEqual(Color.RED.value, 1)
2416 self.assertEqual(Color.GREEN.value, 2)
2417 self.assertEqual(Color.BLUE.value, 4)
2418 self.assertEqual(Color.ALL.value, 7)
2419 self.assertEqual(str(Color.BLUE), 'blue')
2420 class Color(StrMixin, AllMixin, Flag):
2421 RED = auto()
2422 GREEN = auto()
2423 BLUE = auto()
2424 self.assertEqual(Color.RED.value, 1)
2425 self.assertEqual(Color.GREEN.value, 2)
2426 self.assertEqual(Color.BLUE.value, 4)
2427 self.assertEqual(Color.ALL.value, 7)
2428 self.assertEqual(str(Color.BLUE), 'blue')
2429
Hai Shie80697d2020-05-28 06:10:27 +08002430 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002431 def test_unique_composite(self):
2432 # override __eq__ to be identity only
2433 class TestFlag(Flag):
2434 one = auto()
2435 two = auto()
2436 three = auto()
2437 four = auto()
2438 five = auto()
2439 six = auto()
2440 seven = auto()
2441 eight = auto()
2442 def __eq__(self, other):
2443 return self is other
2444 def __hash__(self):
2445 return hash(self._value_)
2446 # have multiple threads competing to complete the composite members
2447 seen = set()
2448 failed = False
2449 def cycle_enum():
2450 nonlocal failed
2451 try:
2452 for i in range(256):
2453 seen.add(TestFlag(i))
2454 except Exception:
2455 failed = True
2456 threads = [
2457 threading.Thread(target=cycle_enum)
2458 for _ in range(8)
2459 ]
Hai Shie80697d2020-05-28 06:10:27 +08002460 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002461 pass
2462 # check that only 248 members were created
2463 self.assertFalse(
2464 failed,
2465 'at least one thread failed while creating composite members')
2466 self.assertEqual(256, len(seen), 'too many composite members created')
2467
Ethan Furmanc16595e2016-09-10 23:36:59 -07002468
Ethan Furman65a5a472016-09-01 23:55:19 -07002469class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002470 """Tests of the IntFlags."""
2471
Ethan Furman65a5a472016-09-01 23:55:19 -07002472 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002473 X = 1 << 0
2474 W = 1 << 1
2475 R = 1 << 2
2476
Ethan Furman65a5a472016-09-01 23:55:19 -07002477 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002478 RO = 0
2479 WO = 1
2480 RW = 2
2481 AC = 3
2482 CE = 1<<19
2483
Rahul Jha94306522018-09-10 23:51:04 +05302484 class Color(IntFlag):
2485 BLACK = 0
2486 RED = 1
2487 GREEN = 2
2488 BLUE = 4
2489 PURPLE = RED|BLUE
2490
Ethan Furman3515dcc2016-09-18 13:15:41 -07002491 def test_type(self):
2492 Perm = self.Perm
2493 Open = self.Open
2494 for f in Perm:
2495 self.assertTrue(isinstance(f, Perm))
2496 self.assertEqual(f, f.value)
2497 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2498 self.assertEqual(Perm.W | Perm.X, 3)
2499 for f in Open:
2500 self.assertTrue(isinstance(f, Open))
2501 self.assertEqual(f, f.value)
2502 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2503 self.assertEqual(Open.WO | Open.RW, 3)
2504
2505
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002506 def test_str(self):
2507 Perm = self.Perm
2508 self.assertEqual(str(Perm.R), 'Perm.R')
2509 self.assertEqual(str(Perm.W), 'Perm.W')
2510 self.assertEqual(str(Perm.X), 'Perm.X')
2511 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2512 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2513 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2514 self.assertEqual(str(Perm(0)), 'Perm.0')
2515 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002516 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2517 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2518 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2519 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002520 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002521 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2522 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2523 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002524
2525 Open = self.Open
2526 self.assertEqual(str(Open.RO), 'Open.RO')
2527 self.assertEqual(str(Open.WO), 'Open.WO')
2528 self.assertEqual(str(Open.AC), 'Open.AC')
2529 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2530 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2531 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002532 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2533 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2534 self.assertEqual(str(~Open.AC), 'Open.CE')
2535 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2536 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2537 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002538
2539 def test_repr(self):
2540 Perm = self.Perm
2541 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2542 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2543 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2544 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2545 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2546 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002547 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2548 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002549 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2550 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2551 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2552 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002553 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002554 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2555 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2556 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002557
2558 Open = self.Open
2559 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2560 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2561 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2562 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2563 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002564 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002565 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2566 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2567 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2568 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2569 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2570 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002571
2572 def test_or(self):
2573 Perm = self.Perm
2574 for i in Perm:
2575 for j in Perm:
2576 self.assertEqual(i | j, i.value | j.value)
2577 self.assertEqual((i | j).value, i.value | j.value)
2578 self.assertIs(type(i | j), Perm)
2579 for j in range(8):
2580 self.assertEqual(i | j, i.value | j)
2581 self.assertEqual((i | j).value, i.value | j)
2582 self.assertIs(type(i | j), Perm)
2583 self.assertEqual(j | i, j | i.value)
2584 self.assertEqual((j | i).value, j | i.value)
2585 self.assertIs(type(j | i), Perm)
2586 for i in Perm:
2587 self.assertIs(i | i, i)
2588 self.assertIs(i | 0, i)
2589 self.assertIs(0 | i, i)
2590 Open = self.Open
2591 self.assertIs(Open.RO | Open.CE, Open.CE)
2592
2593 def test_and(self):
2594 Perm = self.Perm
2595 RW = Perm.R | Perm.W
2596 RX = Perm.R | Perm.X
2597 WX = Perm.W | Perm.X
2598 RWX = Perm.R | Perm.W | Perm.X
2599 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2600 for i in values:
2601 for j in values:
2602 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2603 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2604 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2605 for j in range(8):
2606 self.assertEqual(i & j, i.value & j)
2607 self.assertEqual((i & j).value, i.value & j)
2608 self.assertIs(type(i & j), Perm)
2609 self.assertEqual(j & i, j & i.value)
2610 self.assertEqual((j & i).value, j & i.value)
2611 self.assertIs(type(j & i), Perm)
2612 for i in Perm:
2613 self.assertIs(i & i, i)
2614 self.assertIs(i & 7, i)
2615 self.assertIs(7 & i, i)
2616 Open = self.Open
2617 self.assertIs(Open.RO & Open.CE, Open.RO)
2618
2619 def test_xor(self):
2620 Perm = self.Perm
2621 for i in Perm:
2622 for j in Perm:
2623 self.assertEqual(i ^ j, i.value ^ j.value)
2624 self.assertEqual((i ^ j).value, i.value ^ j.value)
2625 self.assertIs(type(i ^ j), Perm)
2626 for j in range(8):
2627 self.assertEqual(i ^ j, i.value ^ j)
2628 self.assertEqual((i ^ j).value, i.value ^ j)
2629 self.assertIs(type(i ^ j), Perm)
2630 self.assertEqual(j ^ i, j ^ i.value)
2631 self.assertEqual((j ^ i).value, j ^ i.value)
2632 self.assertIs(type(j ^ i), Perm)
2633 for i in Perm:
2634 self.assertIs(i ^ 0, i)
2635 self.assertIs(0 ^ i, i)
2636 Open = self.Open
2637 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2638 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2639
2640 def test_invert(self):
2641 Perm = self.Perm
2642 RW = Perm.R | Perm.W
2643 RX = Perm.R | Perm.X
2644 WX = Perm.W | Perm.X
2645 RWX = Perm.R | Perm.W | Perm.X
2646 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2647 for i in values:
2648 self.assertEqual(~i, ~i.value)
2649 self.assertEqual((~i).value, ~i.value)
2650 self.assertIs(type(~i), Perm)
2651 self.assertEqual(~~i, i)
2652 for i in Perm:
2653 self.assertIs(~~i, i)
2654 Open = self.Open
2655 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2656 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2657
2658 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002659 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002660 lst = list(Perm)
2661 self.assertEqual(len(lst), len(Perm))
2662 self.assertEqual(len(Perm), 3, Perm)
2663 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2664 for i, n in enumerate('R W X'.split()):
2665 v = 1<<i
2666 e = Perm(v)
2667 self.assertEqual(e.value, v)
2668 self.assertEqual(type(e.value), int)
2669 self.assertEqual(e, v)
2670 self.assertEqual(e.name, n)
2671 self.assertIn(e, Perm)
2672 self.assertIs(type(e), Perm)
2673
2674 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002675 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002676 lst = list(Perm)
2677 self.assertEqual(len(lst), len(Perm))
2678 self.assertEqual(len(Perm), 3, Perm)
2679 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2680 for i, n in enumerate('R W X'.split()):
2681 v = 8<<i
2682 e = Perm(v)
2683 self.assertEqual(e.value, v)
2684 self.assertEqual(type(e.value), int)
2685 self.assertEqual(e, v)
2686 self.assertEqual(e.name, n)
2687 self.assertIn(e, Perm)
2688 self.assertIs(type(e), Perm)
2689
2690 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002691 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002692 lst = list(Perm)
2693 self.assertEqual(len(lst), len(Perm))
2694 self.assertEqual(len(Perm), 3, Perm)
2695 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2696 for i, n in enumerate('R W X'.split()):
2697 v = 1<<i
2698 e = Perm(v)
2699 self.assertEqual(e.value, v)
2700 self.assertEqual(type(e.value), int)
2701 self.assertEqual(e, v)
2702 self.assertEqual(e.name, n)
2703 self.assertIn(e, Perm)
2704 self.assertIs(type(e), Perm)
2705
2706 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002707 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002708 lst = list(Perm)
2709 self.assertEqual(len(lst), len(Perm))
2710 self.assertEqual(len(Perm), 3, Perm)
2711 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2712 for i, n in enumerate('R W X'.split()):
2713 v = 1<<(2*i+1)
2714 e = Perm(v)
2715 self.assertEqual(e.value, v)
2716 self.assertEqual(type(e.value), int)
2717 self.assertEqual(e, v)
2718 self.assertEqual(e.name, n)
2719 self.assertIn(e, Perm)
2720 self.assertIs(type(e), Perm)
2721
2722 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002723 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002724 lst = list(Perm)
2725 self.assertEqual(len(lst), len(Perm))
2726 self.assertEqual(len(Perm), 3, Perm)
2727 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2728 for i, n in enumerate('R W X'.split()):
2729 v = 1<<(2*i+1)
2730 e = Perm(v)
2731 self.assertEqual(e.value, v)
2732 self.assertEqual(type(e.value), int)
2733 self.assertEqual(e, v)
2734 self.assertEqual(e.name, n)
2735 self.assertIn(e, Perm)
2736 self.assertIs(type(e), Perm)
2737
2738
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002739 def test_programatic_function_from_empty_list(self):
2740 Perm = enum.IntFlag('Perm', [])
2741 lst = list(Perm)
2742 self.assertEqual(len(lst), len(Perm))
2743 self.assertEqual(len(Perm), 0, Perm)
2744 Thing = enum.Enum('Thing', [])
2745 lst = list(Thing)
2746 self.assertEqual(len(lst), len(Thing))
2747 self.assertEqual(len(Thing), 0, Thing)
2748
2749
2750 def test_programatic_function_from_empty_tuple(self):
2751 Perm = enum.IntFlag('Perm', ())
2752 lst = list(Perm)
2753 self.assertEqual(len(lst), len(Perm))
2754 self.assertEqual(len(Perm), 0, Perm)
2755 Thing = enum.Enum('Thing', ())
2756 self.assertEqual(len(lst), len(Thing))
2757 self.assertEqual(len(Thing), 0, Thing)
2758
Rahul Jha94306522018-09-10 23:51:04 +05302759 def test_contains(self):
2760 Open = self.Open
2761 Color = self.Color
2762 self.assertTrue(Color.GREEN in Color)
2763 self.assertTrue(Open.RW in Open)
2764 self.assertFalse(Color.GREEN in Open)
2765 self.assertFalse(Open.RW in Color)
2766 with self.assertRaises(TypeError):
2767 'GREEN' in Color
2768 with self.assertRaises(TypeError):
2769 'RW' in Open
2770 with self.assertRaises(TypeError):
2771 2 in Color
2772 with self.assertRaises(TypeError):
2773 2 in Open
2774
2775 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002776 Perm = self.Perm
2777 R, W, X = Perm
2778 RW = R | W
2779 RX = R | X
2780 WX = W | X
2781 RWX = R | W | X
2782 self.assertTrue(R in RW)
2783 self.assertTrue(R in RX)
2784 self.assertTrue(R in RWX)
2785 self.assertTrue(W in RW)
2786 self.assertTrue(W in WX)
2787 self.assertTrue(W in RWX)
2788 self.assertTrue(X in RX)
2789 self.assertTrue(X in WX)
2790 self.assertTrue(X in RWX)
2791 self.assertFalse(R in WX)
2792 self.assertFalse(W in RX)
2793 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302794 with self.assertRaises(TypeError):
2795 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002796
Ethan Furman25d94bb2016-09-02 16:32:32 -07002797 def test_bool(self):
2798 Perm = self.Perm
2799 for f in Perm:
2800 self.assertTrue(f)
2801 Open = self.Open
2802 for f in Open:
2803 self.assertEqual(bool(f.value), bool(f))
2804
Ethan Furman5bdab642018-09-21 19:03:09 -07002805 def test_multiple_mixin(self):
2806 class AllMixin:
2807 @classproperty
2808 def ALL(cls):
2809 members = list(cls)
2810 all_value = None
2811 if members:
2812 all_value = members[0]
2813 for member in members[1:]:
2814 all_value |= member
2815 cls.ALL = all_value
2816 return all_value
2817 class StrMixin:
2818 def __str__(self):
2819 return self._name_.lower()
2820 class Color(AllMixin, IntFlag):
2821 RED = auto()
2822 GREEN = auto()
2823 BLUE = auto()
2824 self.assertEqual(Color.RED.value, 1)
2825 self.assertEqual(Color.GREEN.value, 2)
2826 self.assertEqual(Color.BLUE.value, 4)
2827 self.assertEqual(Color.ALL.value, 7)
2828 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2829 class Color(AllMixin, StrMixin, IntFlag):
2830 RED = auto()
2831 GREEN = auto()
2832 BLUE = auto()
2833 self.assertEqual(Color.RED.value, 1)
2834 self.assertEqual(Color.GREEN.value, 2)
2835 self.assertEqual(Color.BLUE.value, 4)
2836 self.assertEqual(Color.ALL.value, 7)
2837 self.assertEqual(str(Color.BLUE), 'blue')
2838 class Color(StrMixin, AllMixin, IntFlag):
2839 RED = auto()
2840 GREEN = auto()
2841 BLUE = auto()
2842 self.assertEqual(Color.RED.value, 1)
2843 self.assertEqual(Color.GREEN.value, 2)
2844 self.assertEqual(Color.BLUE.value, 4)
2845 self.assertEqual(Color.ALL.value, 7)
2846 self.assertEqual(str(Color.BLUE), 'blue')
2847
Hai Shie80697d2020-05-28 06:10:27 +08002848 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002849 def test_unique_composite(self):
2850 # override __eq__ to be identity only
2851 class TestFlag(IntFlag):
2852 one = auto()
2853 two = auto()
2854 three = auto()
2855 four = auto()
2856 five = auto()
2857 six = auto()
2858 seven = auto()
2859 eight = auto()
2860 def __eq__(self, other):
2861 return self is other
2862 def __hash__(self):
2863 return hash(self._value_)
2864 # have multiple threads competing to complete the composite members
2865 seen = set()
2866 failed = False
2867 def cycle_enum():
2868 nonlocal failed
2869 try:
2870 for i in range(256):
2871 seen.add(TestFlag(i))
2872 except Exception:
2873 failed = True
2874 threads = [
2875 threading.Thread(target=cycle_enum)
2876 for _ in range(8)
2877 ]
Hai Shie80697d2020-05-28 06:10:27 +08002878 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002879 pass
2880 # check that only 248 members were created
2881 self.assertFalse(
2882 failed,
2883 'at least one thread failed while creating composite members')
2884 self.assertEqual(256, len(seen), 'too many composite members created')
2885
2886
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002887class TestEmptyAndNonLatinStrings(unittest.TestCase):
2888
2889 def test_empty_string(self):
2890 with self.assertRaises(ValueError):
2891 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2892
2893 def test_non_latin_character_string(self):
2894 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2895 item = getattr(greek_abc, '\u03B1')
2896 self.assertEqual(item.value, 1)
2897
2898 def test_non_latin_number_string(self):
2899 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2900 item = getattr(hebrew_123, '\u05D0')
2901 self.assertEqual(item.value, 1)
2902
2903
Ethan Furmanf24bb352013-07-18 17:05:39 -07002904class TestUnique(unittest.TestCase):
2905
2906 def test_unique_clean(self):
2907 @unique
2908 class Clean(Enum):
2909 one = 1
2910 two = 'dos'
2911 tres = 4.0
2912 @unique
2913 class Cleaner(IntEnum):
2914 single = 1
2915 double = 2
2916 triple = 3
2917
2918 def test_unique_dirty(self):
2919 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2920 @unique
2921 class Dirty(Enum):
2922 one = 1
2923 two = 'dos'
2924 tres = 1
2925 with self.assertRaisesRegex(
2926 ValueError,
2927 'double.*single.*turkey.*triple',
2928 ):
2929 @unique
2930 class Dirtier(IntEnum):
2931 single = 1
2932 double = 1
2933 triple = 3
2934 turkey = 3
2935
Ethan Furman3803ad42016-05-01 10:03:53 -07002936 def test_unique_with_name(self):
2937 @unique
2938 class Silly(Enum):
2939 one = 1
2940 two = 'dos'
2941 name = 3
2942 @unique
2943 class Sillier(IntEnum):
2944 single = 1
2945 name = 2
2946 triple = 3
2947 value = 4
2948
Ethan Furmanf24bb352013-07-18 17:05:39 -07002949
Ethan Furman5bdab642018-09-21 19:03:09 -07002950
Ethan Furman3323da92015-04-11 09:39:59 -07002951expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002952Help on class Color in module %s:
2953
2954class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002955 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2956 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002957 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002958 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002959 | Method resolution order:
2960 | Color
2961 | enum.Enum
2962 | builtins.object
2963 |\x20\x20
2964 | Data and other attributes defined here:
2965 |\x20\x20
2966 | blue = <Color.blue: 3>
2967 |\x20\x20
2968 | green = <Color.green: 2>
2969 |\x20\x20
2970 | red = <Color.red: 1>
2971 |\x20\x20
2972 | ----------------------------------------------------------------------
2973 | Data descriptors inherited from enum.Enum:
2974 |\x20\x20
2975 | name
2976 | The name of the Enum member.
2977 |\x20\x20
2978 | value
2979 | The value of the Enum member.
2980 |\x20\x20
2981 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002982 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002983 |\x20\x20
2984 | __members__
2985 | Returns a mapping of member name->value.
2986 |\x20\x20\x20\x20\x20\x20
2987 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002988 | is a read-only view of the internal mapping."""
2989
2990expected_help_output_without_docs = """\
2991Help on class Color in module %s:
2992
2993class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002994 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2995 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002996 | Method resolution order:
2997 | Color
2998 | enum.Enum
2999 | builtins.object
3000 |\x20\x20
3001 | Data and other attributes defined here:
3002 |\x20\x20
3003 | blue = <Color.blue: 3>
3004 |\x20\x20
3005 | green = <Color.green: 2>
3006 |\x20\x20
3007 | red = <Color.red: 1>
3008 |\x20\x20
3009 | ----------------------------------------------------------------------
3010 | Data descriptors inherited from enum.Enum:
3011 |\x20\x20
3012 | name
3013 |\x20\x20
3014 | value
3015 |\x20\x20
3016 | ----------------------------------------------------------------------
3017 | Data descriptors inherited from enum.EnumMeta:
3018 |\x20\x20
3019 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003020
3021class TestStdLib(unittest.TestCase):
3022
Ethan Furman48a724f2015-04-11 23:23:06 -07003023 maxDiff = None
3024
Ethan Furman5875d742013-10-21 20:45:55 -07003025 class Color(Enum):
3026 red = 1
3027 green = 2
3028 blue = 3
3029
3030 def test_pydoc(self):
3031 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003032 if StrEnum.__doc__ is None:
3033 expected_text = expected_help_output_without_docs % __name__
3034 else:
3035 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003036 output = StringIO()
3037 helper = pydoc.Helper(output=output)
3038 helper(self.Color)
3039 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003040 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003041
3042 def test_inspect_getmembers(self):
3043 values = dict((
3044 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003045 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003046 ('__members__', self.Color.__members__),
3047 ('__module__', __name__),
3048 ('blue', self.Color.blue),
3049 ('green', self.Color.green),
3050 ('name', Enum.__dict__['name']),
3051 ('red', self.Color.red),
3052 ('value', Enum.__dict__['value']),
3053 ))
3054 result = dict(inspect.getmembers(self.Color))
3055 self.assertEqual(values.keys(), result.keys())
3056 failed = False
3057 for k in values.keys():
3058 if result[k] != values[k]:
3059 print()
3060 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3061 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3062 failed = True
3063 if failed:
3064 self.fail("result does not equal expected, see print above")
3065
3066 def test_inspect_classify_class_attrs(self):
3067 # indirectly test __objclass__
3068 from inspect import Attribute
3069 values = [
3070 Attribute(name='__class__', kind='data',
3071 defining_class=object, object=EnumMeta),
3072 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003073 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003074 Attribute(name='__members__', kind='property',
3075 defining_class=EnumMeta, object=EnumMeta.__members__),
3076 Attribute(name='__module__', kind='data',
3077 defining_class=self.Color, object=__name__),
3078 Attribute(name='blue', kind='data',
3079 defining_class=self.Color, object=self.Color.blue),
3080 Attribute(name='green', kind='data',
3081 defining_class=self.Color, object=self.Color.green),
3082 Attribute(name='red', kind='data',
3083 defining_class=self.Color, object=self.Color.red),
3084 Attribute(name='name', kind='data',
3085 defining_class=Enum, object=Enum.__dict__['name']),
3086 Attribute(name='value', kind='data',
3087 defining_class=Enum, object=Enum.__dict__['value']),
3088 ]
3089 values.sort(key=lambda item: item.name)
3090 result = list(inspect.classify_class_attrs(self.Color))
3091 result.sort(key=lambda item: item.name)
3092 failed = False
3093 for v, r in zip(values, result):
3094 if r != v:
3095 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3096 failed = True
3097 if failed:
3098 self.fail("result does not equal expected, see print above")
3099
Martin Panter19e69c52015-11-14 12:46:42 +00003100
3101class MiscTestCase(unittest.TestCase):
3102 def test__all__(self):
3103 support.check__all__(self, enum)
3104
3105
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003106# These are unordered here on purpose to ensure that declaration order
3107# makes no difference.
3108CONVERT_TEST_NAME_D = 5
3109CONVERT_TEST_NAME_C = 5
3110CONVERT_TEST_NAME_B = 5
3111CONVERT_TEST_NAME_A = 5 # This one should sort first.
3112CONVERT_TEST_NAME_E = 5
3113CONVERT_TEST_NAME_F = 5
3114
3115class TestIntEnumConvert(unittest.TestCase):
3116 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003117 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003118 'UnittestConvert',
3119 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003120 filter=lambda x: x.startswith('CONVERT_TEST_'))
3121 # We don't want the reverse lookup value to vary when there are
3122 # multiple possible names for a given value. It should always
3123 # report the first lexigraphical name in that case.
3124 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3125
3126 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003127 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003128 'UnittestConvert',
3129 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003130 filter=lambda x: x.startswith('CONVERT_TEST_'))
3131 # Ensure that test_type has all of the desired names and values.
3132 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3133 test_type.CONVERT_TEST_NAME_A)
3134 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3135 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3136 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3137 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3138 # Ensure that test_type only picked up names matching the filter.
3139 self.assertEqual([name for name in dir(test_type)
3140 if name[0:2] not in ('CO', '__')],
3141 [], msg='Names other than CONVERT_TEST_* found.')
3142
orlnub1230fb9fad2018-09-12 20:28:53 +03003143 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3144 '_convert was deprecated in 3.8')
3145 def test_convert_warn(self):
3146 with self.assertWarns(DeprecationWarning):
3147 enum.IntEnum._convert(
3148 'UnittestConvert',
3149 ('test.test_enum', '__main__')[__name__=='__main__'],
3150 filter=lambda x: x.startswith('CONVERT_TEST_'))
3151
3152 @unittest.skipUnless(sys.version_info >= (3, 9),
3153 '_convert was removed in 3.9')
3154 def test_convert_raise(self):
3155 with self.assertRaises(AttributeError):
3156 enum.IntEnum._convert(
3157 'UnittestConvert',
3158 ('test.test_enum', '__main__')[__name__=='__main__'],
3159 filter=lambda x: x.startswith('CONVERT_TEST_'))
3160
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003161
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003162if __name__ == '__main__':
3163 unittest.main()