blob: 59789fb7bcc5fdea0fa0f6ff3ca659086c1923e4 [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
Ethan Furmanfc23a942020-09-16 12:37:54 -07001840 def test_auto_order_wierd(self):
1841 weird_auto = auto()
1842 weird_auto.value = 'pathological case'
1843 class Color(Enum):
1844 red = weird_auto
1845 def _generate_next_value_(name, start, count, last):
1846 return name
1847 blue = auto()
1848 self.assertEqual(list(Color), [Color.red, Color.blue])
1849 self.assertEqual(Color.red.value, 'pathological case')
1850 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001851
Ethan Furman3515dcc2016-09-18 13:15:41 -07001852 def test_duplicate_auto(self):
1853 class Dupes(Enum):
1854 first = primero = auto()
1855 second = auto()
1856 third = auto()
1857 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1858
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001859 def test_default_missing(self):
1860 class Color(Enum):
1861 RED = 1
1862 GREEN = 2
1863 BLUE = 3
1864 try:
1865 Color(7)
1866 except ValueError as exc:
1867 self.assertTrue(exc.__context__ is None)
1868 else:
1869 raise Exception('Exception not raised.')
1870
Ethan Furman019f0a02018-09-12 11:43:34 -07001871 def test_missing(self):
1872 class Color(Enum):
1873 red = 1
1874 green = 2
1875 blue = 3
1876 @classmethod
1877 def _missing_(cls, item):
1878 if item == 'three':
1879 return cls.blue
1880 elif item == 'bad return':
1881 # trigger internal error
1882 return 5
1883 elif item == 'error out':
1884 raise ZeroDivisionError
1885 else:
1886 # trigger not found
1887 return None
1888 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001889 try:
1890 Color(7)
1891 except ValueError as exc:
1892 self.assertTrue(exc.__context__ is None)
1893 else:
1894 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001895 try:
1896 Color('bad return')
1897 except TypeError as exc:
1898 self.assertTrue(isinstance(exc.__context__, ValueError))
1899 else:
1900 raise Exception('Exception not raised.')
1901 try:
1902 Color('error out')
1903 except ZeroDivisionError as exc:
1904 self.assertTrue(isinstance(exc.__context__, ValueError))
1905 else:
1906 raise Exception('Exception not raised.')
1907
Ethan Furman5bdab642018-09-21 19:03:09 -07001908 def test_multiple_mixin(self):
1909 class MaxMixin:
1910 @classproperty
1911 def MAX(cls):
1912 max = len(cls)
1913 cls.MAX = max
1914 return max
1915 class StrMixin:
1916 def __str__(self):
1917 return self._name_.lower()
1918 class SomeEnum(Enum):
1919 def behavior(self):
1920 return 'booyah'
1921 class AnotherEnum(Enum):
1922 def behavior(self):
1923 return 'nuhuh!'
1924 def social(self):
1925 return "what's up?"
1926 class Color(MaxMixin, Enum):
1927 RED = auto()
1928 GREEN = auto()
1929 BLUE = auto()
1930 self.assertEqual(Color.RED.value, 1)
1931 self.assertEqual(Color.GREEN.value, 2)
1932 self.assertEqual(Color.BLUE.value, 3)
1933 self.assertEqual(Color.MAX, 3)
1934 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1935 class Color(MaxMixin, StrMixin, Enum):
1936 RED = auto()
1937 GREEN = auto()
1938 BLUE = auto()
1939 self.assertEqual(Color.RED.value, 1)
1940 self.assertEqual(Color.GREEN.value, 2)
1941 self.assertEqual(Color.BLUE.value, 3)
1942 self.assertEqual(Color.MAX, 3)
1943 self.assertEqual(str(Color.BLUE), 'blue')
1944 class Color(StrMixin, MaxMixin, Enum):
1945 RED = auto()
1946 GREEN = auto()
1947 BLUE = auto()
1948 self.assertEqual(Color.RED.value, 1)
1949 self.assertEqual(Color.GREEN.value, 2)
1950 self.assertEqual(Color.BLUE.value, 3)
1951 self.assertEqual(Color.MAX, 3)
1952 self.assertEqual(str(Color.BLUE), 'blue')
1953 class CoolColor(StrMixin, SomeEnum, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(CoolColor.RED.value, 1)
1958 self.assertEqual(CoolColor.GREEN.value, 2)
1959 self.assertEqual(CoolColor.BLUE.value, 3)
1960 self.assertEqual(str(CoolColor.BLUE), 'blue')
1961 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1962 class CoolerColor(StrMixin, AnotherEnum, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(CoolerColor.RED.value, 1)
1967 self.assertEqual(CoolerColor.GREEN.value, 2)
1968 self.assertEqual(CoolerColor.BLUE.value, 3)
1969 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1970 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1971 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1972 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1973 RED = auto()
1974 GREEN = auto()
1975 BLUE = auto()
1976 self.assertEqual(CoolestColor.RED.value, 1)
1977 self.assertEqual(CoolestColor.GREEN.value, 2)
1978 self.assertEqual(CoolestColor.BLUE.value, 3)
1979 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1980 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1981 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1982 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1983 RED = auto()
1984 GREEN = auto()
1985 BLUE = auto()
1986 self.assertEqual(ConfusedColor.RED.value, 1)
1987 self.assertEqual(ConfusedColor.GREEN.value, 2)
1988 self.assertEqual(ConfusedColor.BLUE.value, 3)
1989 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1990 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1991 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1992 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1993 RED = auto()
1994 GREEN = auto()
1995 BLUE = auto()
1996 self.assertEqual(ReformedColor.RED.value, 1)
1997 self.assertEqual(ReformedColor.GREEN.value, 2)
1998 self.assertEqual(ReformedColor.BLUE.value, 3)
1999 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2000 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2001 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2002 self.assertTrue(issubclass(ReformedColor, int))
2003
Ethan Furmancd453852018-10-05 23:29:36 -07002004 def test_multiple_inherited_mixin(self):
2005 class StrEnum(str, Enum):
2006 def __new__(cls, *args, **kwargs):
2007 for a in args:
2008 if not isinstance(a, str):
2009 raise TypeError("Enumeration '%s' (%s) is not"
2010 " a string" % (a, type(a).__name__))
2011 return str.__new__(cls, *args, **kwargs)
2012 @unique
2013 class Decision1(StrEnum):
2014 REVERT = "REVERT"
2015 REVERT_ALL = "REVERT_ALL"
2016 RETRY = "RETRY"
2017 class MyEnum(StrEnum):
2018 pass
2019 @unique
2020 class Decision2(MyEnum):
2021 REVERT = "REVERT"
2022 REVERT_ALL = "REVERT_ALL"
2023 RETRY = "RETRY"
2024
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002025 def test_empty_globals(self):
2026 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2027 # when using compile and exec because f_globals is empty
2028 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2029 code = compile(code, "<string>", "exec")
2030 global_ns = {}
2031 local_ls = {}
2032 exec(code, global_ns, local_ls)
2033
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002034
Ethan Furmane8e61272016-08-20 07:19:31 -07002035class TestOrder(unittest.TestCase):
2036
2037 def test_same_members(self):
2038 class Color(Enum):
2039 _order_ = 'red green blue'
2040 red = 1
2041 green = 2
2042 blue = 3
2043
2044 def test_same_members_with_aliases(self):
2045 class Color(Enum):
2046 _order_ = 'red green blue'
2047 red = 1
2048 green = 2
2049 blue = 3
2050 verde = green
2051
2052 def test_same_members_wrong_order(self):
2053 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2054 class Color(Enum):
2055 _order_ = 'red green blue'
2056 red = 1
2057 blue = 3
2058 green = 2
2059
2060 def test_order_has_extra_members(self):
2061 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2062 class Color(Enum):
2063 _order_ = 'red green blue purple'
2064 red = 1
2065 green = 2
2066 blue = 3
2067
2068 def test_order_has_extra_members_with_aliases(self):
2069 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2070 class Color(Enum):
2071 _order_ = 'red green blue purple'
2072 red = 1
2073 green = 2
2074 blue = 3
2075 verde = green
2076
2077 def test_enum_has_extra_members(self):
2078 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2079 class Color(Enum):
2080 _order_ = 'red green blue'
2081 red = 1
2082 green = 2
2083 blue = 3
2084 purple = 4
2085
2086 def test_enum_has_extra_members_with_aliases(self):
2087 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2088 class Color(Enum):
2089 _order_ = 'red green blue'
2090 red = 1
2091 green = 2
2092 blue = 3
2093 purple = 4
2094 verde = green
2095
2096
Ethan Furman65a5a472016-09-01 23:55:19 -07002097class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002098 """Tests of the Flags."""
2099
Ethan Furman65a5a472016-09-01 23:55:19 -07002100 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002101 R, W, X = 4, 2, 1
2102
Ethan Furman65a5a472016-09-01 23:55:19 -07002103 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002104 RO = 0
2105 WO = 1
2106 RW = 2
2107 AC = 3
2108 CE = 1<<19
2109
Rahul Jha94306522018-09-10 23:51:04 +05302110 class Color(Flag):
2111 BLACK = 0
2112 RED = 1
2113 GREEN = 2
2114 BLUE = 4
2115 PURPLE = RED|BLUE
2116
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002117 def test_str(self):
2118 Perm = self.Perm
2119 self.assertEqual(str(Perm.R), 'Perm.R')
2120 self.assertEqual(str(Perm.W), 'Perm.W')
2121 self.assertEqual(str(Perm.X), 'Perm.X')
2122 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2123 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2124 self.assertEqual(str(Perm(0)), 'Perm.0')
2125 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2126 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2127 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2128 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2129 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2130 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2131
2132 Open = self.Open
2133 self.assertEqual(str(Open.RO), 'Open.RO')
2134 self.assertEqual(str(Open.WO), 'Open.WO')
2135 self.assertEqual(str(Open.AC), 'Open.AC')
2136 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2137 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002138 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002139 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2140 self.assertEqual(str(~Open.AC), 'Open.CE')
2141 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2142 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2143
2144 def test_repr(self):
2145 Perm = self.Perm
2146 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2147 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2148 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2149 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2150 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002151 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002152 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2153 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2154 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2155 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002156 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002157 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2158
2159 Open = self.Open
2160 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2161 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2162 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2163 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2164 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002165 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002166 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2167 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2168 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2169 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2170
2171 def test_or(self):
2172 Perm = self.Perm
2173 for i in Perm:
2174 for j in Perm:
2175 self.assertEqual((i | j), Perm(i.value | j.value))
2176 self.assertEqual((i | j).value, i.value | j.value)
2177 self.assertIs(type(i | j), Perm)
2178 for i in Perm:
2179 self.assertIs(i | i, i)
2180 Open = self.Open
2181 self.assertIs(Open.RO | Open.CE, Open.CE)
2182
2183 def test_and(self):
2184 Perm = self.Perm
2185 RW = Perm.R | Perm.W
2186 RX = Perm.R | Perm.X
2187 WX = Perm.W | Perm.X
2188 RWX = Perm.R | Perm.W | Perm.X
2189 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2190 for i in values:
2191 for j in values:
2192 self.assertEqual((i & j).value, i.value & j.value)
2193 self.assertIs(type(i & j), Perm)
2194 for i in Perm:
2195 self.assertIs(i & i, i)
2196 self.assertIs(i & RWX, i)
2197 self.assertIs(RWX & i, i)
2198 Open = self.Open
2199 self.assertIs(Open.RO & Open.CE, Open.RO)
2200
2201 def test_xor(self):
2202 Perm = self.Perm
2203 for i in Perm:
2204 for j in Perm:
2205 self.assertEqual((i ^ j).value, i.value ^ j.value)
2206 self.assertIs(type(i ^ j), Perm)
2207 for i in Perm:
2208 self.assertIs(i ^ Perm(0), i)
2209 self.assertIs(Perm(0) ^ i, i)
2210 Open = self.Open
2211 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2212 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2213
2214 def test_invert(self):
2215 Perm = self.Perm
2216 RW = Perm.R | Perm.W
2217 RX = Perm.R | Perm.X
2218 WX = Perm.W | Perm.X
2219 RWX = Perm.R | Perm.W | Perm.X
2220 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2221 for i in values:
2222 self.assertIs(type(~i), Perm)
2223 self.assertEqual(~~i, i)
2224 for i in Perm:
2225 self.assertIs(~~i, i)
2226 Open = self.Open
2227 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2228 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2229
Ethan Furman25d94bb2016-09-02 16:32:32 -07002230 def test_bool(self):
2231 Perm = self.Perm
2232 for f in Perm:
2233 self.assertTrue(f)
2234 Open = self.Open
2235 for f in Open:
2236 self.assertEqual(bool(f.value), bool(f))
2237
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002238 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002239 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002240 lst = list(Perm)
2241 self.assertEqual(len(lst), len(Perm))
2242 self.assertEqual(len(Perm), 3, Perm)
2243 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2244 for i, n in enumerate('R W X'.split()):
2245 v = 1<<i
2246 e = Perm(v)
2247 self.assertEqual(e.value, v)
2248 self.assertEqual(type(e.value), int)
2249 self.assertEqual(e.name, n)
2250 self.assertIn(e, Perm)
2251 self.assertIs(type(e), Perm)
2252
2253 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002254 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002255 lst = list(Perm)
2256 self.assertEqual(len(lst), len(Perm))
2257 self.assertEqual(len(Perm), 3, Perm)
2258 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2259 for i, n in enumerate('R W X'.split()):
2260 v = 8<<i
2261 e = Perm(v)
2262 self.assertEqual(e.value, v)
2263 self.assertEqual(type(e.value), int)
2264 self.assertEqual(e.name, n)
2265 self.assertIn(e, Perm)
2266 self.assertIs(type(e), Perm)
2267
2268 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002269 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002270 lst = list(Perm)
2271 self.assertEqual(len(lst), len(Perm))
2272 self.assertEqual(len(Perm), 3, Perm)
2273 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2274 for i, n in enumerate('R W X'.split()):
2275 v = 1<<i
2276 e = Perm(v)
2277 self.assertEqual(e.value, v)
2278 self.assertEqual(type(e.value), int)
2279 self.assertEqual(e.name, n)
2280 self.assertIn(e, Perm)
2281 self.assertIs(type(e), Perm)
2282
2283 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002284 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002285 lst = list(Perm)
2286 self.assertEqual(len(lst), len(Perm))
2287 self.assertEqual(len(Perm), 3, Perm)
2288 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2289 for i, n in enumerate('R W X'.split()):
2290 v = 1<<(2*i+1)
2291 e = Perm(v)
2292 self.assertEqual(e.value, v)
2293 self.assertEqual(type(e.value), int)
2294 self.assertEqual(e.name, n)
2295 self.assertIn(e, Perm)
2296 self.assertIs(type(e), Perm)
2297
2298 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002299 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002300 lst = list(Perm)
2301 self.assertEqual(len(lst), len(Perm))
2302 self.assertEqual(len(Perm), 3, Perm)
2303 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2304 for i, n in enumerate('R W X'.split()):
2305 v = 1<<(2*i+1)
2306 e = Perm(v)
2307 self.assertEqual(e.value, v)
2308 self.assertEqual(type(e.value), int)
2309 self.assertEqual(e.name, n)
2310 self.assertIn(e, Perm)
2311 self.assertIs(type(e), Perm)
2312
Ethan Furman65a5a472016-09-01 23:55:19 -07002313 def test_pickle(self):
2314 if isinstance(FlagStooges, Exception):
2315 raise FlagStooges
2316 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2317 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002318
Rahul Jha94306522018-09-10 23:51:04 +05302319 def test_contains(self):
2320 Open = self.Open
2321 Color = self.Color
2322 self.assertFalse(Color.BLACK in Open)
2323 self.assertFalse(Open.RO in Color)
2324 with self.assertRaises(TypeError):
2325 'BLACK' in Color
2326 with self.assertRaises(TypeError):
2327 'RO' in Open
2328 with self.assertRaises(TypeError):
2329 1 in Color
2330 with self.assertRaises(TypeError):
2331 1 in Open
2332
2333 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002334 Perm = self.Perm
2335 R, W, X = Perm
2336 RW = R | W
2337 RX = R | X
2338 WX = W | X
2339 RWX = R | W | X
2340 self.assertTrue(R in RW)
2341 self.assertTrue(R in RX)
2342 self.assertTrue(R in RWX)
2343 self.assertTrue(W in RW)
2344 self.assertTrue(W in WX)
2345 self.assertTrue(W in RWX)
2346 self.assertTrue(X in RX)
2347 self.assertTrue(X in WX)
2348 self.assertTrue(X in RWX)
2349 self.assertFalse(R in WX)
2350 self.assertFalse(W in RX)
2351 self.assertFalse(X in RW)
2352
Ethan Furman7219e272020-09-16 13:01:00 -07002353 def test_member_iter(self):
2354 Color = self.Color
2355 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2356 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2357 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2358
Ethan Furmanc16595e2016-09-10 23:36:59 -07002359 def test_auto_number(self):
2360 class Color(Flag):
2361 red = auto()
2362 blue = auto()
2363 green = auto()
2364
2365 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2366 self.assertEqual(Color.red.value, 1)
2367 self.assertEqual(Color.blue.value, 2)
2368 self.assertEqual(Color.green.value, 4)
2369
2370 def test_auto_number_garbage(self):
2371 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2372 class Color(Flag):
2373 red = 'not an int'
2374 blue = auto()
2375
Ethan Furman3515dcc2016-09-18 13:15:41 -07002376 def test_cascading_failure(self):
2377 class Bizarre(Flag):
2378 c = 3
2379 d = 4
2380 f = 6
2381 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002382 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2383 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2384 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2385 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2386 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2387 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2388 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002389
2390 def test_duplicate_auto(self):
2391 class Dupes(Enum):
2392 first = primero = auto()
2393 second = auto()
2394 third = auto()
2395 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2396
2397 def test_bizarre(self):
2398 class Bizarre(Flag):
2399 b = 3
2400 c = 4
2401 d = 6
2402 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2403
Ethan Furman5bdab642018-09-21 19:03:09 -07002404 def test_multiple_mixin(self):
2405 class AllMixin:
2406 @classproperty
2407 def ALL(cls):
2408 members = list(cls)
2409 all_value = None
2410 if members:
2411 all_value = members[0]
2412 for member in members[1:]:
2413 all_value |= member
2414 cls.ALL = all_value
2415 return all_value
2416 class StrMixin:
2417 def __str__(self):
2418 return self._name_.lower()
2419 class Color(AllMixin, Flag):
2420 RED = auto()
2421 GREEN = auto()
2422 BLUE = auto()
2423 self.assertEqual(Color.RED.value, 1)
2424 self.assertEqual(Color.GREEN.value, 2)
2425 self.assertEqual(Color.BLUE.value, 4)
2426 self.assertEqual(Color.ALL.value, 7)
2427 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2428 class Color(AllMixin, StrMixin, Flag):
2429 RED = auto()
2430 GREEN = auto()
2431 BLUE = auto()
2432 self.assertEqual(Color.RED.value, 1)
2433 self.assertEqual(Color.GREEN.value, 2)
2434 self.assertEqual(Color.BLUE.value, 4)
2435 self.assertEqual(Color.ALL.value, 7)
2436 self.assertEqual(str(Color.BLUE), 'blue')
2437 class Color(StrMixin, AllMixin, Flag):
2438 RED = auto()
2439 GREEN = auto()
2440 BLUE = auto()
2441 self.assertEqual(Color.RED.value, 1)
2442 self.assertEqual(Color.GREEN.value, 2)
2443 self.assertEqual(Color.BLUE.value, 4)
2444 self.assertEqual(Color.ALL.value, 7)
2445 self.assertEqual(str(Color.BLUE), 'blue')
2446
Hai Shie80697d2020-05-28 06:10:27 +08002447 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002448 def test_unique_composite(self):
2449 # override __eq__ to be identity only
2450 class TestFlag(Flag):
2451 one = auto()
2452 two = auto()
2453 three = auto()
2454 four = auto()
2455 five = auto()
2456 six = auto()
2457 seven = auto()
2458 eight = auto()
2459 def __eq__(self, other):
2460 return self is other
2461 def __hash__(self):
2462 return hash(self._value_)
2463 # have multiple threads competing to complete the composite members
2464 seen = set()
2465 failed = False
2466 def cycle_enum():
2467 nonlocal failed
2468 try:
2469 for i in range(256):
2470 seen.add(TestFlag(i))
2471 except Exception:
2472 failed = True
2473 threads = [
2474 threading.Thread(target=cycle_enum)
2475 for _ in range(8)
2476 ]
Hai Shie80697d2020-05-28 06:10:27 +08002477 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002478 pass
2479 # check that only 248 members were created
2480 self.assertFalse(
2481 failed,
2482 'at least one thread failed while creating composite members')
2483 self.assertEqual(256, len(seen), 'too many composite members created')
2484
Ethan Furmanc16595e2016-09-10 23:36:59 -07002485
Ethan Furman65a5a472016-09-01 23:55:19 -07002486class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002487 """Tests of the IntFlags."""
2488
Ethan Furman65a5a472016-09-01 23:55:19 -07002489 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002490 X = 1 << 0
2491 W = 1 << 1
2492 R = 1 << 2
2493
Ethan Furman65a5a472016-09-01 23:55:19 -07002494 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002495 RO = 0
2496 WO = 1
2497 RW = 2
2498 AC = 3
2499 CE = 1<<19
2500
Rahul Jha94306522018-09-10 23:51:04 +05302501 class Color(IntFlag):
2502 BLACK = 0
2503 RED = 1
2504 GREEN = 2
2505 BLUE = 4
2506 PURPLE = RED|BLUE
2507
Ethan Furman3515dcc2016-09-18 13:15:41 -07002508 def test_type(self):
2509 Perm = self.Perm
2510 Open = self.Open
2511 for f in Perm:
2512 self.assertTrue(isinstance(f, Perm))
2513 self.assertEqual(f, f.value)
2514 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2515 self.assertEqual(Perm.W | Perm.X, 3)
2516 for f in Open:
2517 self.assertTrue(isinstance(f, Open))
2518 self.assertEqual(f, f.value)
2519 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2520 self.assertEqual(Open.WO | Open.RW, 3)
2521
2522
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002523 def test_str(self):
2524 Perm = self.Perm
2525 self.assertEqual(str(Perm.R), 'Perm.R')
2526 self.assertEqual(str(Perm.W), 'Perm.W')
2527 self.assertEqual(str(Perm.X), 'Perm.X')
2528 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2529 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2530 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2531 self.assertEqual(str(Perm(0)), 'Perm.0')
2532 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002533 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2534 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2535 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2536 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002537 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002538 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2539 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2540 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002541
2542 Open = self.Open
2543 self.assertEqual(str(Open.RO), 'Open.RO')
2544 self.assertEqual(str(Open.WO), 'Open.WO')
2545 self.assertEqual(str(Open.AC), 'Open.AC')
2546 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2547 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2548 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002549 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2550 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2551 self.assertEqual(str(~Open.AC), 'Open.CE')
2552 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2553 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2554 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002555
2556 def test_repr(self):
2557 Perm = self.Perm
2558 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2559 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2560 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2561 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2562 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2563 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002564 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2565 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002566 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2567 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2568 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2569 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002570 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002571 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2572 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2573 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002574
2575 Open = self.Open
2576 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2577 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2578 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2579 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2580 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002581 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002582 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2583 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2584 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2585 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2586 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2587 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002588
2589 def test_or(self):
2590 Perm = self.Perm
2591 for i in Perm:
2592 for j in Perm:
2593 self.assertEqual(i | j, i.value | j.value)
2594 self.assertEqual((i | j).value, i.value | j.value)
2595 self.assertIs(type(i | j), Perm)
2596 for j in range(8):
2597 self.assertEqual(i | j, i.value | j)
2598 self.assertEqual((i | j).value, i.value | j)
2599 self.assertIs(type(i | j), Perm)
2600 self.assertEqual(j | i, j | i.value)
2601 self.assertEqual((j | i).value, j | i.value)
2602 self.assertIs(type(j | i), Perm)
2603 for i in Perm:
2604 self.assertIs(i | i, i)
2605 self.assertIs(i | 0, i)
2606 self.assertIs(0 | i, i)
2607 Open = self.Open
2608 self.assertIs(Open.RO | Open.CE, Open.CE)
2609
2610 def test_and(self):
2611 Perm = self.Perm
2612 RW = Perm.R | Perm.W
2613 RX = Perm.R | Perm.X
2614 WX = Perm.W | Perm.X
2615 RWX = Perm.R | Perm.W | Perm.X
2616 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2617 for i in values:
2618 for j in values:
2619 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2620 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2621 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2622 for j in range(8):
2623 self.assertEqual(i & j, i.value & j)
2624 self.assertEqual((i & j).value, i.value & j)
2625 self.assertIs(type(i & j), Perm)
2626 self.assertEqual(j & i, j & i.value)
2627 self.assertEqual((j & i).value, j & i.value)
2628 self.assertIs(type(j & i), Perm)
2629 for i in Perm:
2630 self.assertIs(i & i, i)
2631 self.assertIs(i & 7, i)
2632 self.assertIs(7 & i, i)
2633 Open = self.Open
2634 self.assertIs(Open.RO & Open.CE, Open.RO)
2635
2636 def test_xor(self):
2637 Perm = self.Perm
2638 for i in Perm:
2639 for j in Perm:
2640 self.assertEqual(i ^ j, i.value ^ j.value)
2641 self.assertEqual((i ^ j).value, i.value ^ j.value)
2642 self.assertIs(type(i ^ j), Perm)
2643 for j in range(8):
2644 self.assertEqual(i ^ j, i.value ^ j)
2645 self.assertEqual((i ^ j).value, i.value ^ j)
2646 self.assertIs(type(i ^ j), Perm)
2647 self.assertEqual(j ^ i, j ^ i.value)
2648 self.assertEqual((j ^ i).value, j ^ i.value)
2649 self.assertIs(type(j ^ i), Perm)
2650 for i in Perm:
2651 self.assertIs(i ^ 0, i)
2652 self.assertIs(0 ^ i, i)
2653 Open = self.Open
2654 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2655 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2656
2657 def test_invert(self):
2658 Perm = self.Perm
2659 RW = Perm.R | Perm.W
2660 RX = Perm.R | Perm.X
2661 WX = Perm.W | Perm.X
2662 RWX = Perm.R | Perm.W | Perm.X
2663 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2664 for i in values:
2665 self.assertEqual(~i, ~i.value)
2666 self.assertEqual((~i).value, ~i.value)
2667 self.assertIs(type(~i), Perm)
2668 self.assertEqual(~~i, i)
2669 for i in Perm:
2670 self.assertIs(~~i, i)
2671 Open = self.Open
2672 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2673 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2674
2675 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002676 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002677 lst = list(Perm)
2678 self.assertEqual(len(lst), len(Perm))
2679 self.assertEqual(len(Perm), 3, Perm)
2680 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2681 for i, n in enumerate('R W X'.split()):
2682 v = 1<<i
2683 e = Perm(v)
2684 self.assertEqual(e.value, v)
2685 self.assertEqual(type(e.value), int)
2686 self.assertEqual(e, v)
2687 self.assertEqual(e.name, n)
2688 self.assertIn(e, Perm)
2689 self.assertIs(type(e), Perm)
2690
2691 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002692 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002693 lst = list(Perm)
2694 self.assertEqual(len(lst), len(Perm))
2695 self.assertEqual(len(Perm), 3, Perm)
2696 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2697 for i, n in enumerate('R W X'.split()):
2698 v = 8<<i
2699 e = Perm(v)
2700 self.assertEqual(e.value, v)
2701 self.assertEqual(type(e.value), int)
2702 self.assertEqual(e, v)
2703 self.assertEqual(e.name, n)
2704 self.assertIn(e, Perm)
2705 self.assertIs(type(e), Perm)
2706
2707 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002708 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002709 lst = list(Perm)
2710 self.assertEqual(len(lst), len(Perm))
2711 self.assertEqual(len(Perm), 3, Perm)
2712 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2713 for i, n in enumerate('R W X'.split()):
2714 v = 1<<i
2715 e = Perm(v)
2716 self.assertEqual(e.value, v)
2717 self.assertEqual(type(e.value), int)
2718 self.assertEqual(e, v)
2719 self.assertEqual(e.name, n)
2720 self.assertIn(e, Perm)
2721 self.assertIs(type(e), Perm)
2722
2723 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002724 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002725 lst = list(Perm)
2726 self.assertEqual(len(lst), len(Perm))
2727 self.assertEqual(len(Perm), 3, Perm)
2728 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2729 for i, n in enumerate('R W X'.split()):
2730 v = 1<<(2*i+1)
2731 e = Perm(v)
2732 self.assertEqual(e.value, v)
2733 self.assertEqual(type(e.value), int)
2734 self.assertEqual(e, v)
2735 self.assertEqual(e.name, n)
2736 self.assertIn(e, Perm)
2737 self.assertIs(type(e), Perm)
2738
2739 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002740 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002741 lst = list(Perm)
2742 self.assertEqual(len(lst), len(Perm))
2743 self.assertEqual(len(Perm), 3, Perm)
2744 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2745 for i, n in enumerate('R W X'.split()):
2746 v = 1<<(2*i+1)
2747 e = Perm(v)
2748 self.assertEqual(e.value, v)
2749 self.assertEqual(type(e.value), int)
2750 self.assertEqual(e, v)
2751 self.assertEqual(e.name, n)
2752 self.assertIn(e, Perm)
2753 self.assertIs(type(e), Perm)
2754
2755
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002756 def test_programatic_function_from_empty_list(self):
2757 Perm = enum.IntFlag('Perm', [])
2758 lst = list(Perm)
2759 self.assertEqual(len(lst), len(Perm))
2760 self.assertEqual(len(Perm), 0, Perm)
2761 Thing = enum.Enum('Thing', [])
2762 lst = list(Thing)
2763 self.assertEqual(len(lst), len(Thing))
2764 self.assertEqual(len(Thing), 0, Thing)
2765
2766
2767 def test_programatic_function_from_empty_tuple(self):
2768 Perm = enum.IntFlag('Perm', ())
2769 lst = list(Perm)
2770 self.assertEqual(len(lst), len(Perm))
2771 self.assertEqual(len(Perm), 0, Perm)
2772 Thing = enum.Enum('Thing', ())
2773 self.assertEqual(len(lst), len(Thing))
2774 self.assertEqual(len(Thing), 0, Thing)
2775
Rahul Jha94306522018-09-10 23:51:04 +05302776 def test_contains(self):
2777 Open = self.Open
2778 Color = self.Color
2779 self.assertTrue(Color.GREEN in Color)
2780 self.assertTrue(Open.RW in Open)
2781 self.assertFalse(Color.GREEN in Open)
2782 self.assertFalse(Open.RW in Color)
2783 with self.assertRaises(TypeError):
2784 'GREEN' in Color
2785 with self.assertRaises(TypeError):
2786 'RW' in Open
2787 with self.assertRaises(TypeError):
2788 2 in Color
2789 with self.assertRaises(TypeError):
2790 2 in Open
2791
2792 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002793 Perm = self.Perm
2794 R, W, X = Perm
2795 RW = R | W
2796 RX = R | X
2797 WX = W | X
2798 RWX = R | W | X
2799 self.assertTrue(R in RW)
2800 self.assertTrue(R in RX)
2801 self.assertTrue(R in RWX)
2802 self.assertTrue(W in RW)
2803 self.assertTrue(W in WX)
2804 self.assertTrue(W in RWX)
2805 self.assertTrue(X in RX)
2806 self.assertTrue(X in WX)
2807 self.assertTrue(X in RWX)
2808 self.assertFalse(R in WX)
2809 self.assertFalse(W in RX)
2810 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302811 with self.assertRaises(TypeError):
2812 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002813
Ethan Furman7219e272020-09-16 13:01:00 -07002814 def test_member_iter(self):
2815 Color = self.Color
2816 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2817 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2818 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2819
Ethan Furman25d94bb2016-09-02 16:32:32 -07002820 def test_bool(self):
2821 Perm = self.Perm
2822 for f in Perm:
2823 self.assertTrue(f)
2824 Open = self.Open
2825 for f in Open:
2826 self.assertEqual(bool(f.value), bool(f))
2827
Ethan Furman5bdab642018-09-21 19:03:09 -07002828 def test_multiple_mixin(self):
2829 class AllMixin:
2830 @classproperty
2831 def ALL(cls):
2832 members = list(cls)
2833 all_value = None
2834 if members:
2835 all_value = members[0]
2836 for member in members[1:]:
2837 all_value |= member
2838 cls.ALL = all_value
2839 return all_value
2840 class StrMixin:
2841 def __str__(self):
2842 return self._name_.lower()
2843 class Color(AllMixin, IntFlag):
2844 RED = auto()
2845 GREEN = auto()
2846 BLUE = auto()
2847 self.assertEqual(Color.RED.value, 1)
2848 self.assertEqual(Color.GREEN.value, 2)
2849 self.assertEqual(Color.BLUE.value, 4)
2850 self.assertEqual(Color.ALL.value, 7)
2851 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2852 class Color(AllMixin, StrMixin, IntFlag):
2853 RED = auto()
2854 GREEN = auto()
2855 BLUE = auto()
2856 self.assertEqual(Color.RED.value, 1)
2857 self.assertEqual(Color.GREEN.value, 2)
2858 self.assertEqual(Color.BLUE.value, 4)
2859 self.assertEqual(Color.ALL.value, 7)
2860 self.assertEqual(str(Color.BLUE), 'blue')
2861 class Color(StrMixin, AllMixin, IntFlag):
2862 RED = auto()
2863 GREEN = auto()
2864 BLUE = auto()
2865 self.assertEqual(Color.RED.value, 1)
2866 self.assertEqual(Color.GREEN.value, 2)
2867 self.assertEqual(Color.BLUE.value, 4)
2868 self.assertEqual(Color.ALL.value, 7)
2869 self.assertEqual(str(Color.BLUE), 'blue')
2870
Hai Shie80697d2020-05-28 06:10:27 +08002871 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002872 def test_unique_composite(self):
2873 # override __eq__ to be identity only
2874 class TestFlag(IntFlag):
2875 one = auto()
2876 two = auto()
2877 three = auto()
2878 four = auto()
2879 five = auto()
2880 six = auto()
2881 seven = auto()
2882 eight = auto()
2883 def __eq__(self, other):
2884 return self is other
2885 def __hash__(self):
2886 return hash(self._value_)
2887 # have multiple threads competing to complete the composite members
2888 seen = set()
2889 failed = False
2890 def cycle_enum():
2891 nonlocal failed
2892 try:
2893 for i in range(256):
2894 seen.add(TestFlag(i))
2895 except Exception:
2896 failed = True
2897 threads = [
2898 threading.Thread(target=cycle_enum)
2899 for _ in range(8)
2900 ]
Hai Shie80697d2020-05-28 06:10:27 +08002901 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002902 pass
2903 # check that only 248 members were created
2904 self.assertFalse(
2905 failed,
2906 'at least one thread failed while creating composite members')
2907 self.assertEqual(256, len(seen), 'too many composite members created')
2908
2909
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002910class TestEmptyAndNonLatinStrings(unittest.TestCase):
2911
2912 def test_empty_string(self):
2913 with self.assertRaises(ValueError):
2914 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2915
2916 def test_non_latin_character_string(self):
2917 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2918 item = getattr(greek_abc, '\u03B1')
2919 self.assertEqual(item.value, 1)
2920
2921 def test_non_latin_number_string(self):
2922 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2923 item = getattr(hebrew_123, '\u05D0')
2924 self.assertEqual(item.value, 1)
2925
2926
Ethan Furmanf24bb352013-07-18 17:05:39 -07002927class TestUnique(unittest.TestCase):
2928
2929 def test_unique_clean(self):
2930 @unique
2931 class Clean(Enum):
2932 one = 1
2933 two = 'dos'
2934 tres = 4.0
2935 @unique
2936 class Cleaner(IntEnum):
2937 single = 1
2938 double = 2
2939 triple = 3
2940
2941 def test_unique_dirty(self):
2942 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2943 @unique
2944 class Dirty(Enum):
2945 one = 1
2946 two = 'dos'
2947 tres = 1
2948 with self.assertRaisesRegex(
2949 ValueError,
2950 'double.*single.*turkey.*triple',
2951 ):
2952 @unique
2953 class Dirtier(IntEnum):
2954 single = 1
2955 double = 1
2956 triple = 3
2957 turkey = 3
2958
Ethan Furman3803ad42016-05-01 10:03:53 -07002959 def test_unique_with_name(self):
2960 @unique
2961 class Silly(Enum):
2962 one = 1
2963 two = 'dos'
2964 name = 3
2965 @unique
2966 class Sillier(IntEnum):
2967 single = 1
2968 name = 2
2969 triple = 3
2970 value = 4
2971
Ethan Furmanf24bb352013-07-18 17:05:39 -07002972
Ethan Furman5bdab642018-09-21 19:03:09 -07002973
Ethan Furman3323da92015-04-11 09:39:59 -07002974expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002975Help on class Color in module %s:
2976
2977class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002978 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2979 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002980 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002981 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002982 | Method resolution order:
2983 | Color
2984 | enum.Enum
2985 | builtins.object
2986 |\x20\x20
2987 | Data and other attributes defined here:
2988 |\x20\x20
2989 | blue = <Color.blue: 3>
2990 |\x20\x20
2991 | green = <Color.green: 2>
2992 |\x20\x20
2993 | red = <Color.red: 1>
2994 |\x20\x20
2995 | ----------------------------------------------------------------------
2996 | Data descriptors inherited from enum.Enum:
2997 |\x20\x20
2998 | name
2999 | The name of the Enum member.
3000 |\x20\x20
3001 | value
3002 | The value of the Enum member.
3003 |\x20\x20
3004 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003005 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003006 |\x20\x20
3007 | __members__
3008 | Returns a mapping of member name->value.
3009 |\x20\x20\x20\x20\x20\x20
3010 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003011 | is a read-only view of the internal mapping."""
3012
3013expected_help_output_without_docs = """\
3014Help on class Color in module %s:
3015
3016class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003017 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3018 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003019 | Method resolution order:
3020 | Color
3021 | enum.Enum
3022 | builtins.object
3023 |\x20\x20
3024 | Data and other attributes defined here:
3025 |\x20\x20
3026 | blue = <Color.blue: 3>
3027 |\x20\x20
3028 | green = <Color.green: 2>
3029 |\x20\x20
3030 | red = <Color.red: 1>
3031 |\x20\x20
3032 | ----------------------------------------------------------------------
3033 | Data descriptors inherited from enum.Enum:
3034 |\x20\x20
3035 | name
3036 |\x20\x20
3037 | value
3038 |\x20\x20
3039 | ----------------------------------------------------------------------
3040 | Data descriptors inherited from enum.EnumMeta:
3041 |\x20\x20
3042 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003043
3044class TestStdLib(unittest.TestCase):
3045
Ethan Furman48a724f2015-04-11 23:23:06 -07003046 maxDiff = None
3047
Ethan Furman5875d742013-10-21 20:45:55 -07003048 class Color(Enum):
3049 red = 1
3050 green = 2
3051 blue = 3
3052
3053 def test_pydoc(self):
3054 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003055 if StrEnum.__doc__ is None:
3056 expected_text = expected_help_output_without_docs % __name__
3057 else:
3058 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003059 output = StringIO()
3060 helper = pydoc.Helper(output=output)
3061 helper(self.Color)
3062 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003063 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003064
3065 def test_inspect_getmembers(self):
3066 values = dict((
3067 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003068 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003069 ('__members__', self.Color.__members__),
3070 ('__module__', __name__),
3071 ('blue', self.Color.blue),
3072 ('green', self.Color.green),
3073 ('name', Enum.__dict__['name']),
3074 ('red', self.Color.red),
3075 ('value', Enum.__dict__['value']),
3076 ))
3077 result = dict(inspect.getmembers(self.Color))
3078 self.assertEqual(values.keys(), result.keys())
3079 failed = False
3080 for k in values.keys():
3081 if result[k] != values[k]:
3082 print()
3083 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3084 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3085 failed = True
3086 if failed:
3087 self.fail("result does not equal expected, see print above")
3088
3089 def test_inspect_classify_class_attrs(self):
3090 # indirectly test __objclass__
3091 from inspect import Attribute
3092 values = [
3093 Attribute(name='__class__', kind='data',
3094 defining_class=object, object=EnumMeta),
3095 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003096 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003097 Attribute(name='__members__', kind='property',
3098 defining_class=EnumMeta, object=EnumMeta.__members__),
3099 Attribute(name='__module__', kind='data',
3100 defining_class=self.Color, object=__name__),
3101 Attribute(name='blue', kind='data',
3102 defining_class=self.Color, object=self.Color.blue),
3103 Attribute(name='green', kind='data',
3104 defining_class=self.Color, object=self.Color.green),
3105 Attribute(name='red', kind='data',
3106 defining_class=self.Color, object=self.Color.red),
3107 Attribute(name='name', kind='data',
3108 defining_class=Enum, object=Enum.__dict__['name']),
3109 Attribute(name='value', kind='data',
3110 defining_class=Enum, object=Enum.__dict__['value']),
3111 ]
3112 values.sort(key=lambda item: item.name)
3113 result = list(inspect.classify_class_attrs(self.Color))
3114 result.sort(key=lambda item: item.name)
3115 failed = False
3116 for v, r in zip(values, result):
3117 if r != v:
3118 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3119 failed = True
3120 if failed:
3121 self.fail("result does not equal expected, see print above")
3122
Martin Panter19e69c52015-11-14 12:46:42 +00003123
3124class MiscTestCase(unittest.TestCase):
3125 def test__all__(self):
3126 support.check__all__(self, enum)
3127
3128
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003129# These are unordered here on purpose to ensure that declaration order
3130# makes no difference.
3131CONVERT_TEST_NAME_D = 5
3132CONVERT_TEST_NAME_C = 5
3133CONVERT_TEST_NAME_B = 5
3134CONVERT_TEST_NAME_A = 5 # This one should sort first.
3135CONVERT_TEST_NAME_E = 5
3136CONVERT_TEST_NAME_F = 5
3137
3138class TestIntEnumConvert(unittest.TestCase):
3139 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003140 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003141 'UnittestConvert',
3142 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003143 filter=lambda x: x.startswith('CONVERT_TEST_'))
3144 # We don't want the reverse lookup value to vary when there are
3145 # multiple possible names for a given value. It should always
3146 # report the first lexigraphical name in that case.
3147 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3148
3149 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003150 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003151 'UnittestConvert',
3152 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003153 filter=lambda x: x.startswith('CONVERT_TEST_'))
3154 # Ensure that test_type has all of the desired names and values.
3155 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3156 test_type.CONVERT_TEST_NAME_A)
3157 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3158 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3159 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3160 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3161 # Ensure that test_type only picked up names matching the filter.
3162 self.assertEqual([name for name in dir(test_type)
3163 if name[0:2] not in ('CO', '__')],
3164 [], msg='Names other than CONVERT_TEST_* found.')
3165
orlnub1230fb9fad2018-09-12 20:28:53 +03003166 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3167 '_convert was deprecated in 3.8')
3168 def test_convert_warn(self):
3169 with self.assertWarns(DeprecationWarning):
3170 enum.IntEnum._convert(
3171 'UnittestConvert',
3172 ('test.test_enum', '__main__')[__name__=='__main__'],
3173 filter=lambda x: x.startswith('CONVERT_TEST_'))
3174
3175 @unittest.skipUnless(sys.version_info >= (3, 9),
3176 '_convert was removed in 3.9')
3177 def test_convert_raise(self):
3178 with self.assertRaises(AttributeError):
3179 enum.IntEnum._convert(
3180 'UnittestConvert',
3181 ('test.test_enum', '__main__')[__name__=='__main__'],
3182 filter=lambda x: x.startswith('CONVERT_TEST_'))
3183
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003184
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003185if __name__ == '__main__':
3186 unittest.main()