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