blob: 9a7882b8a9c6fef1d22c8d70db1dbeeb6c05cd98 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002import doctest
Ethan Furman5875d742013-10-21 20:45:55 -07003import inspect
Ethan Furman01faf452021-01-26 12:52:52 -08004import os
Ethan Furman5875d742013-10-21 20:45:55 -07005import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03006import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02008import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07009from collections import OrderedDict
Ethan Furmanb7751062021-03-30 21:17:26 -070010from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
Ethan Furmana02cb472021-04-21 10:20:44 -070011from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
Ethan Furman74964862021-06-10 07:24:20 -070012from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS
Ethan Furman5875d742013-10-21 20:45:55 -070013from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080014from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000015from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030016from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080017from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080018from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080019
Ethan Furman6bd92882021-04-27 13:05:08 -070020python_version = sys.version_info[:2]
21
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080022def load_tests(loader, tests, ignore):
23 tests.addTests(doctest.DocTestSuite(enum))
Ethan Furman44e580f2021-03-03 09:54:30 -080024 if os.path.exists('Doc/library/enum.rst'):
Ethan Furman01faf452021-01-26 12:52:52 -080025 tests.addTests(doctest.DocFileSuite(
26 '../../Doc/library/enum.rst',
27 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
28 ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080029 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070030
31# for pickle tests
32try:
33 class Stooges(Enum):
34 LARRY = 1
35 CURLY = 2
36 MOE = 3
37except Exception as exc:
38 Stooges = exc
39
40try:
41 class IntStooges(int, Enum):
42 LARRY = 1
43 CURLY = 2
44 MOE = 3
45except Exception as exc:
46 IntStooges = exc
47
48try:
49 class FloatStooges(float, Enum):
50 LARRY = 1.39
51 CURLY = 2.72
52 MOE = 3.142596
53except Exception as exc:
54 FloatStooges = exc
55
Ethan Furman65a5a472016-09-01 23:55:19 -070056try:
57 class FlagStooges(Flag):
58 LARRY = 1
59 CURLY = 2
60 MOE = 3
61except Exception as exc:
62 FlagStooges = exc
63
Ethan Furman6b3d64a2013-06-14 16:55:46 -070064# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070065class Name(StrEnum):
66 BDFL = 'Guido van Rossum'
67 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070068
69try:
70 Question = Enum('Question', 'who what when where why', module=__name__)
71except Exception as exc:
72 Question = exc
73
74try:
75 Answer = Enum('Answer', 'him this then there because')
76except Exception as exc:
77 Answer = exc
78
Ethan Furmanca1b7942014-02-08 11:36:27 -080079try:
80 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
81except Exception as exc:
82 Theory = exc
83
Ethan Furman6b3d64a2013-06-14 16:55:46 -070084# for doctests
85try:
86 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080087 TOMATO = 1
88 BANANA = 2
89 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070090except Exception:
91 pass
92
Serhiy Storchakae50e7802015-03-31 16:56:49 +030093def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080094 if target is None:
95 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030096 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080097 assertion(loads(dumps(source, protocol=protocol)), target)
98
Serhiy Storchakae50e7802015-03-31 16:56:49 +030099def test_pickle_exception(assertion, exception, obj):
100 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800101 with assertion(exception):
102 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -0700103
104class TestHelpers(unittest.TestCase):
105 # _is_descriptor, _is_sunder, _is_dunder
106
107 def test_is_descriptor(self):
108 class foo:
109 pass
110 for attr in ('__get__','__set__','__delete__'):
111 obj = foo()
112 self.assertFalse(enum._is_descriptor(obj))
113 setattr(obj, attr, 1)
114 self.assertTrue(enum._is_descriptor(obj))
115
116 def test_is_sunder(self):
117 for s in ('_a_', '_aa_'):
118 self.assertTrue(enum._is_sunder(s))
119
120 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
121 '__', '___', '____', '_____',):
122 self.assertFalse(enum._is_sunder(s))
123
124 def test_is_dunder(self):
125 for s in ('__a__', '__aa__'):
126 self.assertTrue(enum._is_dunder(s))
127 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
128 '__', '___', '____', '_____',):
129 self.assertFalse(enum._is_dunder(s))
130
Ethan Furman5bdab642018-09-21 19:03:09 -0700131# for subclassing tests
132
133class classproperty:
134
135 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
136 self.fget = fget
137 self.fset = fset
138 self.fdel = fdel
139 if doc is None and fget is not None:
140 doc = fget.__doc__
141 self.__doc__ = doc
142
143 def __get__(self, instance, ownerclass):
144 return self.fget(ownerclass)
145
146
Ethan Furmanc16595e2016-09-10 23:36:59 -0700147# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700148
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700149class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800150
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700151 def setUp(self):
152 class Season(Enum):
153 SPRING = 1
154 SUMMER = 2
155 AUTUMN = 3
156 WINTER = 4
157 self.Season = Season
158
Ethan Furmanec15a822013-08-31 19:17:41 -0700159 class Konstants(float, Enum):
160 E = 2.7182818
161 PI = 3.1415926
162 TAU = 2 * PI
163 self.Konstants = Konstants
164
165 class Grades(IntEnum):
166 A = 5
167 B = 4
168 C = 3
169 D = 2
170 F = 0
171 self.Grades = Grades
172
173 class Directional(str, Enum):
174 EAST = 'east'
175 WEST = 'west'
176 NORTH = 'north'
177 SOUTH = 'south'
178 self.Directional = Directional
179
180 from datetime import date
181 class Holiday(date, Enum):
182 NEW_YEAR = 2013, 1, 1
183 IDES_OF_MARCH = 2013, 3, 15
184 self.Holiday = Holiday
185
Ethan Furman388a3922013-08-12 06:51:41 -0700186 def test_dir_on_class(self):
187 Season = self.Season
188 self.assertEqual(
189 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700190 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700191 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
192 )
193
194 def test_dir_on_item(self):
195 Season = self.Season
196 self.assertEqual(
197 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700198 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700199 )
200
Ethan Furmanc850f342013-09-15 16:59:35 -0700201 def test_dir_with_added_behavior(self):
202 class Test(Enum):
203 this = 'that'
204 these = 'those'
205 def wowser(self):
206 return ("Wowser! I'm %s!" % self.name)
207 self.assertEqual(
208 set(dir(Test)),
209 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
210 )
211 self.assertEqual(
212 set(dir(Test.this)),
213 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
214 )
215
Ethan Furman0ae550b2014-10-14 08:58:32 -0700216 def test_dir_on_sub_with_behavior_on_super(self):
217 # see issue22506
218 class SuperEnum(Enum):
219 def invisible(self):
220 return "did you see me?"
221 class SubEnum(SuperEnum):
222 sample = 5
223 self.assertEqual(
224 set(dir(SubEnum.sample)),
225 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
226 )
227
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200228 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
229 # see issue40084
230 class SuperEnum(IntEnum):
231 def __new__(cls, value, description=""):
232 obj = int.__new__(cls, value)
233 obj._value_ = value
234 obj.description = description
235 return obj
236 class SubEnum(SuperEnum):
237 sample = 5
238 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
239
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700240 def test_enum_in_enum_out(self):
241 Season = self.Season
242 self.assertIs(Season(Season.WINTER), Season.WINTER)
243
244 def test_enum_value(self):
245 Season = self.Season
246 self.assertEqual(Season.SPRING.value, 1)
247
248 def test_intenum_value(self):
249 self.assertEqual(IntStooges.CURLY.value, 2)
250
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700251 def test_enum(self):
252 Season = self.Season
253 lst = list(Season)
254 self.assertEqual(len(lst), len(Season))
255 self.assertEqual(len(Season), 4, Season)
256 self.assertEqual(
257 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
258
259 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
260 e = Season(i)
261 self.assertEqual(e, getattr(Season, season))
262 self.assertEqual(e.value, i)
263 self.assertNotEqual(e, i)
264 self.assertEqual(e.name, season)
265 self.assertIn(e, Season)
266 self.assertIs(type(e), Season)
267 self.assertIsInstance(e, Season)
Ethan Furmanb7751062021-03-30 21:17:26 -0700268 self.assertEqual(str(e), season)
269 self.assertEqual(repr(e), 'Season.{0}'.format(season))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700270
271 def test_value_name(self):
272 Season = self.Season
273 self.assertEqual(Season.SPRING.name, 'SPRING')
274 self.assertEqual(Season.SPRING.value, 1)
275 with self.assertRaises(AttributeError):
276 Season.SPRING.name = 'invierno'
277 with self.assertRaises(AttributeError):
278 Season.SPRING.value = 2
279
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700280 def test_changing_member(self):
281 Season = self.Season
282 with self.assertRaises(AttributeError):
283 Season.WINTER = 'really cold'
284
Ethan Furman64a99722013-09-22 16:18:19 -0700285 def test_attribute_deletion(self):
286 class Season(Enum):
287 SPRING = 1
288 SUMMER = 2
289 AUTUMN = 3
290 WINTER = 4
291
292 def spam(cls):
293 pass
294
295 self.assertTrue(hasattr(Season, 'spam'))
296 del Season.spam
297 self.assertFalse(hasattr(Season, 'spam'))
298
299 with self.assertRaises(AttributeError):
300 del Season.SPRING
301 with self.assertRaises(AttributeError):
302 del Season.DRY
303 with self.assertRaises(AttributeError):
304 del Season.SPRING.name
305
Ethan Furman5de67b12016-04-13 23:52:09 -0700306 def test_bool_of_class(self):
307 class Empty(Enum):
308 pass
309 self.assertTrue(bool(Empty))
310
311 def test_bool_of_member(self):
312 class Count(Enum):
313 zero = 0
314 one = 1
315 two = 2
316 for member in Count:
317 self.assertTrue(bool(member))
318
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700319 def test_invalid_names(self):
320 with self.assertRaises(ValueError):
321 class Wrong(Enum):
322 mro = 9
323 with self.assertRaises(ValueError):
324 class Wrong(Enum):
325 _create_= 11
326 with self.assertRaises(ValueError):
327 class Wrong(Enum):
328 _get_mixins_ = 9
329 with self.assertRaises(ValueError):
330 class Wrong(Enum):
331 _find_new_ = 1
332 with self.assertRaises(ValueError):
333 class Wrong(Enum):
334 _any_name_ = 9
335
Ethan Furman6db1fd52015-09-17 21:49:12 -0700336 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800337 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700338 class Logic(Enum):
339 true = True
340 false = False
341 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800342 self.assertTrue(Logic.false)
343 # unless overridden
344 class RealLogic(Enum):
345 true = True
346 false = False
347 def __bool__(self):
348 return bool(self._value_)
349 self.assertTrue(RealLogic.true)
350 self.assertFalse(RealLogic.false)
351 # mixed Enums depend on mixed-in type
352 class IntLogic(int, Enum):
353 true = 1
354 false = 0
355 self.assertTrue(IntLogic.true)
356 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700357
Ethan Furman6bd92882021-04-27 13:05:08 -0700358 @unittest.skipIf(
359 python_version >= (3, 12),
360 '__contains__ now returns True/False for all inputs',
361 )
362 def test_contains_er(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700363 Season = self.Season
364 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530365 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -0700366 with self.assertWarns(DeprecationWarning):
367 3 in Season
Rahul Jha94306522018-09-10 23:51:04 +0530368 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -0700369 with self.assertWarns(DeprecationWarning):
370 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700371 val = Season(3)
372 self.assertIn(val, Season)
Ethan Furman6bd92882021-04-27 13:05:08 -0700373 #
374 class OtherEnum(Enum):
375 one = 1; two = 2
376 self.assertNotIn(OtherEnum.two, Season)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700377
Ethan Furman6bd92882021-04-27 13:05:08 -0700378 @unittest.skipIf(
379 python_version < (3, 12),
380 '__contains__ only works with enum memmbers before 3.12',
381 )
382 def test_contains_tf(self):
383 Season = self.Season
384 self.assertIn(Season.AUTUMN, Season)
385 self.assertTrue(3 in Season)
386 self.assertFalse('AUTUMN' in Season)
387 val = Season(3)
388 self.assertIn(val, Season)
389 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700390 class OtherEnum(Enum):
391 one = 1; two = 2
392 self.assertNotIn(OtherEnum.two, Season)
393
394 def test_comparisons(self):
395 Season = self.Season
396 with self.assertRaises(TypeError):
397 Season.SPRING < Season.WINTER
398 with self.assertRaises(TypeError):
399 Season.SPRING > 4
400
401 self.assertNotEqual(Season.SPRING, 1)
402
403 class Part(Enum):
404 SPRING = 1
405 CLIP = 2
406 BARREL = 3
407
408 self.assertNotEqual(Season.SPRING, Part.SPRING)
409 with self.assertRaises(TypeError):
410 Season.SPRING < Part.CLIP
411
412 def test_enum_duplicates(self):
413 class Season(Enum):
414 SPRING = 1
415 SUMMER = 2
416 AUTUMN = FALL = 3
417 WINTER = 4
418 ANOTHER_SPRING = 1
419 lst = list(Season)
420 self.assertEqual(
421 lst,
422 [Season.SPRING, Season.SUMMER,
423 Season.AUTUMN, Season.WINTER,
424 ])
425 self.assertIs(Season.FALL, Season.AUTUMN)
426 self.assertEqual(Season.FALL.value, 3)
427 self.assertEqual(Season.AUTUMN.value, 3)
428 self.assertIs(Season(3), Season.AUTUMN)
429 self.assertIs(Season(1), Season.SPRING)
430 self.assertEqual(Season.FALL.name, 'AUTUMN')
431 self.assertEqual(
432 [k for k,v in Season.__members__.items() if v.name != k],
433 ['FALL', 'ANOTHER_SPRING'],
434 )
435
Ethan Furman101e0742013-09-15 12:34:36 -0700436 def test_duplicate_name(self):
437 with self.assertRaises(TypeError):
438 class Color(Enum):
439 red = 1
440 green = 2
441 blue = 3
442 red = 4
443
444 with self.assertRaises(TypeError):
445 class Color(Enum):
446 red = 1
447 green = 2
448 blue = 3
449 def red(self):
450 return 'red'
451
452 with self.assertRaises(TypeError):
453 class Color(Enum):
454 @property
455 def red(self):
456 return 'redder'
457 red = 1
458 green = 2
459 blue = 3
460
Zackery Spytz2ec67522020-09-13 14:27:51 -0600461 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700462 with self.assertRaisesRegex(
463 ValueError,
Ethan Furmanb7751062021-03-30 21:17:26 -0700464 '_sunder_ names, such as ._bad_., are reserved',
Ethan Furman5a565b32020-09-15 12:27:06 -0700465 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600466 class Bad(Enum):
467 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700468
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700469 def test_enum_with_value_name(self):
470 class Huh(Enum):
471 name = 1
472 value = 2
473 self.assertEqual(
474 list(Huh),
475 [Huh.name, Huh.value],
476 )
477 self.assertIs(type(Huh.name), Huh)
478 self.assertEqual(Huh.name.name, 'name')
479 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700480
481 def test_format_enum(self):
482 Season = self.Season
483 self.assertEqual('{}'.format(Season.SPRING),
484 '{}'.format(str(Season.SPRING)))
485 self.assertEqual( '{:}'.format(Season.SPRING),
486 '{:}'.format(str(Season.SPRING)))
487 self.assertEqual('{:20}'.format(Season.SPRING),
488 '{:20}'.format(str(Season.SPRING)))
489 self.assertEqual('{:^20}'.format(Season.SPRING),
490 '{:^20}'.format(str(Season.SPRING)))
491 self.assertEqual('{:>20}'.format(Season.SPRING),
492 '{:>20}'.format(str(Season.SPRING)))
493 self.assertEqual('{:<20}'.format(Season.SPRING),
494 '{:<20}'.format(str(Season.SPRING)))
495
thatneat2f19e822019-07-04 11:28:37 -0700496 def test_str_override_enum(self):
497 class EnumWithStrOverrides(Enum):
498 one = auto()
499 two = auto()
500
501 def __str__(self):
502 return 'Str!'
503 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
504 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
505
506 def test_format_override_enum(self):
507 class EnumWithFormatOverride(Enum):
508 one = 1.0
509 two = 2.0
510 def __format__(self, spec):
511 return 'Format!!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700512 self.assertEqual(str(EnumWithFormatOverride.one), 'one')
thatneat2f19e822019-07-04 11:28:37 -0700513 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
514
515 def test_str_and_format_override_enum(self):
516 class EnumWithStrFormatOverrides(Enum):
517 one = auto()
518 two = auto()
519 def __str__(self):
520 return 'Str!'
521 def __format__(self, spec):
522 return 'Format!'
523 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
524 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
525
526 def test_str_override_mixin(self):
527 class MixinEnumWithStrOverride(float, Enum):
528 one = 1.0
529 two = 2.0
530 def __str__(self):
531 return 'Overridden!'
532 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
533 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
534
535 def test_str_and_format_override_mixin(self):
536 class MixinWithStrFormatOverrides(float, Enum):
537 one = 1.0
538 two = 2.0
539 def __str__(self):
540 return 'Str!'
541 def __format__(self, spec):
542 return 'Format!'
543 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
544 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
545
546 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700547 class TestFloat(float, Enum):
548 one = 1.0
549 two = 2.0
550 def __format__(self, spec):
551 return 'TestFloat success!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700552 self.assertEqual(str(TestFloat.one), 'one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700553 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
554
Ethan Furman6bd92882021-04-27 13:05:08 -0700555 @unittest.skipIf(
556 python_version < (3, 12),
557 'mixin-format is still using member.value',
558 )
559 def test_mixin_format_warning(self):
560 with self.assertWarns(DeprecationWarning):
561 self.assertEqual(f'{self.Grades.B}', 'Grades.B')
562
563 @unittest.skipIf(
564 python_version >= (3, 12),
Ethan Furman5987b8c2021-04-26 22:42:57 -0700565 'mixin-format now uses member instead of member.value',
566 )
567 def test_mixin_format_warning(self):
568 with self.assertWarns(DeprecationWarning):
569 self.assertEqual(f'{self.Grades.B}', '4')
570
Ethan Furmanec15a822013-08-31 19:17:41 -0700571 def assertFormatIsValue(self, spec, member):
Ethan Furman6bd92882021-04-27 13:05:08 -0700572 if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
573 with self.assertWarns(DeprecationWarning):
574 self.assertEqual(spec.format(member), spec.format(member.value))
575 else:
576 self.assertEqual(spec.format(member), spec.format(member.value))
Ethan Furmanec15a822013-08-31 19:17:41 -0700577
578 def test_format_enum_date(self):
579 Holiday = self.Holiday
580 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
581 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
582 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
583 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
584 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
585 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
586 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
587 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
588
589 def test_format_enum_float(self):
590 Konstants = self.Konstants
591 self.assertFormatIsValue('{}', Konstants.TAU)
592 self.assertFormatIsValue('{:}', Konstants.TAU)
593 self.assertFormatIsValue('{:20}', Konstants.TAU)
594 self.assertFormatIsValue('{:^20}', Konstants.TAU)
595 self.assertFormatIsValue('{:>20}', Konstants.TAU)
596 self.assertFormatIsValue('{:<20}', Konstants.TAU)
597 self.assertFormatIsValue('{:n}', Konstants.TAU)
598 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
599 self.assertFormatIsValue('{:f}', Konstants.TAU)
600
601 def test_format_enum_int(self):
602 Grades = self.Grades
603 self.assertFormatIsValue('{}', Grades.C)
604 self.assertFormatIsValue('{:}', Grades.C)
605 self.assertFormatIsValue('{:20}', Grades.C)
606 self.assertFormatIsValue('{:^20}', Grades.C)
607 self.assertFormatIsValue('{:>20}', Grades.C)
608 self.assertFormatIsValue('{:<20}', Grades.C)
609 self.assertFormatIsValue('{:+}', Grades.C)
610 self.assertFormatIsValue('{:08X}', Grades.C)
611 self.assertFormatIsValue('{:b}', Grades.C)
612
613 def test_format_enum_str(self):
614 Directional = self.Directional
615 self.assertFormatIsValue('{}', Directional.WEST)
616 self.assertFormatIsValue('{:}', Directional.WEST)
617 self.assertFormatIsValue('{:20}', Directional.WEST)
618 self.assertFormatIsValue('{:^20}', Directional.WEST)
619 self.assertFormatIsValue('{:>20}', Directional.WEST)
620 self.assertFormatIsValue('{:<20}', Directional.WEST)
621
Ethan Furman22415ad2020-09-15 16:28:25 -0700622 def test_object_str_override(self):
623 class Colors(Enum):
624 RED, GREEN, BLUE = 1, 2, 3
625 def __repr__(self):
626 return "test.%s" % (self._name_, )
627 __str__ = object.__str__
628 self.assertEqual(str(Colors.RED), 'test.RED')
629
Ethan Furmanbff01f32020-09-15 15:56:26 -0700630 def test_enum_str_override(self):
631 class MyStrEnum(Enum):
632 def __str__(self):
633 return 'MyStr'
634 class MyMethodEnum(Enum):
635 def hello(self):
636 return 'Hello! My name is %s' % self.name
637 class Test1Enum(MyMethodEnum, int, MyStrEnum):
638 One = 1
639 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800640 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700641 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800642 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700643 #
644 class Test2Enum(MyStrEnum, MyMethodEnum):
645 One = 1
646 Two = 2
647 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800648 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700649
650 def test_inherited_data_type(self):
651 class HexInt(int):
652 def __repr__(self):
653 return hex(self)
654 class MyEnum(HexInt, enum.Enum):
655 A = 1
656 B = 2
657 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700658 def __repr__(self):
659 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700660 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
661
662 def test_too_many_data_types(self):
663 with self.assertRaisesRegex(TypeError, 'too many data types'):
664 class Huh(str, int, Enum):
665 One = 1
666
667 class MyStr(str):
668 def hello(self):
669 return 'hello, %s' % self
670 class MyInt(int):
671 def repr(self):
672 return hex(self)
673 with self.assertRaisesRegex(TypeError, 'too many data types'):
674 class Huh(MyStr, MyInt, Enum):
675 One = 1
676
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700677 def test_hash(self):
678 Season = self.Season
679 dates = {}
680 dates[Season.WINTER] = '1225'
681 dates[Season.SPRING] = '0315'
682 dates[Season.SUMMER] = '0704'
683 dates[Season.AUTUMN] = '1031'
684 self.assertEqual(dates[Season.AUTUMN], '1031')
685
686 def test_intenum_from_scratch(self):
687 class phy(int, Enum):
688 pi = 3
689 tau = 2 * pi
690 self.assertTrue(phy.pi < phy.tau)
691
692 def test_intenum_inherited(self):
693 class IntEnum(int, Enum):
694 pass
695 class phy(IntEnum):
696 pi = 3
697 tau = 2 * pi
698 self.assertTrue(phy.pi < phy.tau)
699
700 def test_floatenum_from_scratch(self):
701 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700702 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700703 tau = 2 * pi
704 self.assertTrue(phy.pi < phy.tau)
705
706 def test_floatenum_inherited(self):
707 class FloatEnum(float, Enum):
708 pass
709 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700710 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700711 tau = 2 * pi
712 self.assertTrue(phy.pi < phy.tau)
713
714 def test_strenum_from_scratch(self):
715 class phy(str, Enum):
716 pi = 'Pi'
717 tau = 'Tau'
718 self.assertTrue(phy.pi < phy.tau)
719
Ethan Furman0063ff42020-09-21 17:23:13 -0700720 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700721 class phy(StrEnum):
722 pi = 'Pi'
723 tau = 'Tau'
724 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700725 self.assertEqual(phy.pi.upper(), 'PI')
726 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700727
728 def test_intenum(self):
729 class WeekDay(IntEnum):
730 SUNDAY = 1
731 MONDAY = 2
732 TUESDAY = 3
733 WEDNESDAY = 4
734 THURSDAY = 5
735 FRIDAY = 6
736 SATURDAY = 7
737
738 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
739 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
740
741 lst = list(WeekDay)
742 self.assertEqual(len(lst), len(WeekDay))
743 self.assertEqual(len(WeekDay), 7)
744 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
745 target = target.split()
746 for i, weekday in enumerate(target, 1):
747 e = WeekDay(i)
748 self.assertEqual(e, i)
749 self.assertEqual(int(e), i)
750 self.assertEqual(e.name, weekday)
751 self.assertIn(e, WeekDay)
752 self.assertEqual(lst.index(e)+1, i)
753 self.assertTrue(0 < e < 8)
754 self.assertIs(type(e), WeekDay)
755 self.assertIsInstance(e, int)
756 self.assertIsInstance(e, Enum)
757
758 def test_intenum_duplicates(self):
759 class WeekDay(IntEnum):
760 SUNDAY = 1
761 MONDAY = 2
762 TUESDAY = TEUSDAY = 3
763 WEDNESDAY = 4
764 THURSDAY = 5
765 FRIDAY = 6
766 SATURDAY = 7
767 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
768 self.assertEqual(WeekDay(3).name, 'TUESDAY')
769 self.assertEqual([k for k,v in WeekDay.__members__.items()
770 if v.name != k], ['TEUSDAY', ])
771
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300772 def test_intenum_from_bytes(self):
773 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
774 with self.assertRaises(ValueError):
775 IntStooges.from_bytes(b'\x00\x05', 'big')
776
777 def test_floatenum_fromhex(self):
778 h = float.hex(FloatStooges.MOE.value)
779 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
780 h = float.hex(FloatStooges.MOE.value + 0.01)
781 with self.assertRaises(ValueError):
782 FloatStooges.fromhex(h)
783
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700784 def test_pickle_enum(self):
785 if isinstance(Stooges, Exception):
786 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800787 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
788 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700789
790 def test_pickle_int(self):
791 if isinstance(IntStooges, Exception):
792 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800793 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
794 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700795
796 def test_pickle_float(self):
797 if isinstance(FloatStooges, Exception):
798 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800799 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
800 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700801
802 def test_pickle_enum_function(self):
803 if isinstance(Answer, Exception):
804 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800805 test_pickle_dump_load(self.assertIs, Answer.him)
806 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700807
808 def test_pickle_enum_function_with_module(self):
809 if isinstance(Question, Exception):
810 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800811 test_pickle_dump_load(self.assertIs, Question.who)
812 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700813
Ethan Furmanca1b7942014-02-08 11:36:27 -0800814 def test_enum_function_with_qualname(self):
815 if isinstance(Theory, Exception):
816 raise Theory
817 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
818
819 def test_class_nested_enum_and_pickle_protocol_four(self):
820 # would normally just have this directly in the class namespace
821 class NestedEnum(Enum):
822 twigs = 'common'
823 shiny = 'rare'
824
825 self.__class__.NestedEnum = NestedEnum
826 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300827 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800828
Ethan Furman24e837f2015-03-18 17:27:57 -0700829 def test_pickle_by_name(self):
830 class ReplaceGlobalInt(IntEnum):
831 ONE = 1
832 TWO = 2
Miss Islington (bot)b6131322021-06-10 16:37:27 -0700833 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700834 for proto in range(HIGHEST_PROTOCOL):
835 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
836
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700837 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800838 BadPickle = Enum(
839 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700840 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800841 # now break BadPickle to test exception raising
842 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800843 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
844 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700845
846 def test_string_enum(self):
847 class SkillLevel(str, Enum):
848 master = 'what is the sound of one hand clapping?'
849 journeyman = 'why did the chicken cross the road?'
850 apprentice = 'knock, knock!'
851 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
852
853 def test_getattr_getitem(self):
854 class Period(Enum):
855 morning = 1
856 noon = 2
857 evening = 3
858 night = 4
859 self.assertIs(Period(2), Period.noon)
860 self.assertIs(getattr(Period, 'night'), Period.night)
861 self.assertIs(Period['morning'], Period.morning)
862
863 def test_getattr_dunder(self):
864 Season = self.Season
865 self.assertTrue(getattr(Season, '__eq__'))
866
867 def test_iteration_order(self):
868 class Season(Enum):
869 SUMMER = 2
870 WINTER = 4
871 AUTUMN = 3
872 SPRING = 1
873 self.assertEqual(
874 list(Season),
875 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
876 )
877
Ethan Furman2131a4a2013-09-14 18:11:24 -0700878 def test_reversed_iteration_order(self):
879 self.assertEqual(
880 list(reversed(self.Season)),
881 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
882 self.Season.SPRING]
883 )
884
Martin Pantereb995702016-07-28 01:11:04 +0000885 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700886 SummerMonth = Enum('SummerMonth', 'june july august')
887 lst = list(SummerMonth)
888 self.assertEqual(len(lst), len(SummerMonth))
889 self.assertEqual(len(SummerMonth), 3, SummerMonth)
890 self.assertEqual(
891 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
892 lst,
893 )
894 for i, month in enumerate('june july august'.split(), 1):
895 e = SummerMonth(i)
896 self.assertEqual(int(e.value), i)
897 self.assertNotEqual(e, i)
898 self.assertEqual(e.name, month)
899 self.assertIn(e, SummerMonth)
900 self.assertIs(type(e), SummerMonth)
901
Martin Pantereb995702016-07-28 01:11:04 +0000902 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700903 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
904 lst = list(SummerMonth)
905 self.assertEqual(len(lst), len(SummerMonth))
906 self.assertEqual(len(SummerMonth), 3, SummerMonth)
907 self.assertEqual(
908 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
909 lst,
910 )
911 for i, month in enumerate('june july august'.split(), 10):
912 e = SummerMonth(i)
913 self.assertEqual(int(e.value), i)
914 self.assertNotEqual(e, i)
915 self.assertEqual(e.name, month)
916 self.assertIn(e, SummerMonth)
917 self.assertIs(type(e), SummerMonth)
918
Martin Pantereb995702016-07-28 01:11:04 +0000919 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700920 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
921 lst = list(SummerMonth)
922 self.assertEqual(len(lst), len(SummerMonth))
923 self.assertEqual(len(SummerMonth), 3, SummerMonth)
924 self.assertEqual(
925 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
926 lst,
927 )
928 for i, month in enumerate('june july august'.split(), 1):
929 e = SummerMonth(i)
930 self.assertEqual(int(e.value), i)
931 self.assertNotEqual(e, i)
932 self.assertEqual(e.name, month)
933 self.assertIn(e, SummerMonth)
934 self.assertIs(type(e), SummerMonth)
935
Martin Pantereb995702016-07-28 01:11:04 +0000936 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700937 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
938 lst = list(SummerMonth)
939 self.assertEqual(len(lst), len(SummerMonth))
940 self.assertEqual(len(SummerMonth), 3, SummerMonth)
941 self.assertEqual(
942 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
943 lst,
944 )
945 for i, month in enumerate('june july august'.split(), 20):
946 e = SummerMonth(i)
947 self.assertEqual(int(e.value), i)
948 self.assertNotEqual(e, i)
949 self.assertEqual(e.name, month)
950 self.assertIn(e, SummerMonth)
951 self.assertIs(type(e), SummerMonth)
952
Martin Pantereb995702016-07-28 01:11:04 +0000953 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700954 SummerMonth = Enum(
955 'SummerMonth',
956 (('june', 1), ('july', 2), ('august', 3))
957 )
958 lst = list(SummerMonth)
959 self.assertEqual(len(lst), len(SummerMonth))
960 self.assertEqual(len(SummerMonth), 3, SummerMonth)
961 self.assertEqual(
962 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
963 lst,
964 )
965 for i, month in enumerate('june july august'.split(), 1):
966 e = SummerMonth(i)
967 self.assertEqual(int(e.value), i)
968 self.assertNotEqual(e, i)
969 self.assertEqual(e.name, month)
970 self.assertIn(e, SummerMonth)
971 self.assertIs(type(e), SummerMonth)
972
Martin Pantereb995702016-07-28 01:11:04 +0000973 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700974 SummerMonth = Enum(
975 'SummerMonth',
976 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
977 )
978 lst = list(SummerMonth)
979 self.assertEqual(len(lst), len(SummerMonth))
980 self.assertEqual(len(SummerMonth), 3, SummerMonth)
981 self.assertEqual(
982 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
983 lst,
984 )
985 for i, month in enumerate('june july august'.split(), 1):
986 e = SummerMonth(i)
987 self.assertEqual(int(e.value), i)
988 self.assertNotEqual(e, i)
989 self.assertEqual(e.name, month)
990 self.assertIn(e, SummerMonth)
991 self.assertIs(type(e), SummerMonth)
992
Martin Pantereb995702016-07-28 01:11:04 +0000993 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700994 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
995 lst = list(SummerMonth)
996 self.assertEqual(len(lst), len(SummerMonth))
997 self.assertEqual(len(SummerMonth), 3, SummerMonth)
998 self.assertEqual(
999 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1000 lst,
1001 )
1002 for i, month in enumerate('june july august'.split(), 1):
1003 e = SummerMonth(i)
1004 self.assertEqual(e, i)
1005 self.assertEqual(e.name, month)
1006 self.assertIn(e, SummerMonth)
1007 self.assertIs(type(e), SummerMonth)
1008
Martin Pantereb995702016-07-28 01:11:04 +00001009 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001010 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1011 lst = list(SummerMonth)
1012 self.assertEqual(len(lst), len(SummerMonth))
1013 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1014 self.assertEqual(
1015 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1016 lst,
1017 )
1018 for i, month in enumerate('june july august'.split(), 30):
1019 e = SummerMonth(i)
1020 self.assertEqual(e, i)
1021 self.assertEqual(e.name, month)
1022 self.assertIn(e, SummerMonth)
1023 self.assertIs(type(e), SummerMonth)
1024
Martin Pantereb995702016-07-28 01:11:04 +00001025 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001026 SummerMonth = IntEnum('SummerMonth', 'june july august')
1027 lst = list(SummerMonth)
1028 self.assertEqual(len(lst), len(SummerMonth))
1029 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1030 self.assertEqual(
1031 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1032 lst,
1033 )
1034 for i, month in enumerate('june july august'.split(), 1):
1035 e = SummerMonth(i)
1036 self.assertEqual(e, i)
1037 self.assertEqual(e.name, month)
1038 self.assertIn(e, SummerMonth)
1039 self.assertIs(type(e), SummerMonth)
1040
Martin Pantereb995702016-07-28 01:11:04 +00001041 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001042 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1043 lst = list(SummerMonth)
1044 self.assertEqual(len(lst), len(SummerMonth))
1045 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1046 self.assertEqual(
1047 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1048 lst,
1049 )
1050 for i, month in enumerate('june july august'.split(), 40):
1051 e = SummerMonth(i)
1052 self.assertEqual(e, i)
1053 self.assertEqual(e.name, month)
1054 self.assertIn(e, SummerMonth)
1055 self.assertIs(type(e), SummerMonth)
1056
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001057 def test_subclassing(self):
1058 if isinstance(Name, Exception):
1059 raise Name
1060 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1061 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1062 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001063 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001064
1065 def test_extending(self):
1066 class Color(Enum):
1067 red = 1
1068 green = 2
1069 blue = 3
1070 with self.assertRaises(TypeError):
1071 class MoreColor(Color):
1072 cyan = 4
1073 magenta = 5
1074 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001075 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1076 class EvenMoreColor(Color, IntEnum):
1077 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001078
1079 def test_exclude_methods(self):
1080 class whatever(Enum):
1081 this = 'that'
1082 these = 'those'
1083 def really(self):
1084 return 'no, not %s' % self.value
1085 self.assertIsNot(type(whatever.really), whatever)
1086 self.assertEqual(whatever.this.really(), 'no, not that')
1087
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001088 def test_wrong_inheritance_order(self):
1089 with self.assertRaises(TypeError):
1090 class Wrong(Enum, str):
1091 NotHere = 'error before this point'
1092
1093 def test_intenum_transitivity(self):
1094 class number(IntEnum):
1095 one = 1
1096 two = 2
1097 three = 3
1098 class numero(IntEnum):
1099 uno = 1
1100 dos = 2
1101 tres = 3
1102 self.assertEqual(number.one, numero.uno)
1103 self.assertEqual(number.two, numero.dos)
1104 self.assertEqual(number.three, numero.tres)
1105
1106 def test_wrong_enum_in_call(self):
1107 class Monochrome(Enum):
1108 black = 0
1109 white = 1
1110 class Gender(Enum):
1111 male = 0
1112 female = 1
1113 self.assertRaises(ValueError, Monochrome, Gender.male)
1114
1115 def test_wrong_enum_in_mixed_call(self):
1116 class Monochrome(IntEnum):
1117 black = 0
1118 white = 1
1119 class Gender(Enum):
1120 male = 0
1121 female = 1
1122 self.assertRaises(ValueError, Monochrome, Gender.male)
1123
1124 def test_mixed_enum_in_call_1(self):
1125 class Monochrome(IntEnum):
1126 black = 0
1127 white = 1
1128 class Gender(IntEnum):
1129 male = 0
1130 female = 1
1131 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1132
1133 def test_mixed_enum_in_call_2(self):
1134 class Monochrome(Enum):
1135 black = 0
1136 white = 1
1137 class Gender(IntEnum):
1138 male = 0
1139 female = 1
1140 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1141
1142 def test_flufl_enum(self):
1143 class Fluflnum(Enum):
1144 def __int__(self):
1145 return int(self.value)
1146 class MailManOptions(Fluflnum):
1147 option1 = 1
1148 option2 = 2
1149 option3 = 3
1150 self.assertEqual(int(MailManOptions.option1), 1)
1151
Ethan Furman5e5a8232013-08-04 08:42:23 -07001152 def test_introspection(self):
1153 class Number(IntEnum):
1154 one = 100
1155 two = 200
1156 self.assertIs(Number.one._member_type_, int)
1157 self.assertIs(Number._member_type_, int)
1158 class String(str, Enum):
1159 yarn = 'soft'
1160 rope = 'rough'
1161 wire = 'hard'
1162 self.assertIs(String.yarn._member_type_, str)
1163 self.assertIs(String._member_type_, str)
1164 class Plain(Enum):
1165 vanilla = 'white'
1166 one = 1
1167 self.assertIs(Plain.vanilla._member_type_, object)
1168 self.assertIs(Plain._member_type_, object)
1169
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001170 def test_no_such_enum_member(self):
1171 class Color(Enum):
1172 red = 1
1173 green = 2
1174 blue = 3
1175 with self.assertRaises(ValueError):
1176 Color(4)
1177 with self.assertRaises(KeyError):
1178 Color['chartreuse']
1179
1180 def test_new_repr(self):
1181 class Color(Enum):
1182 red = 1
1183 green = 2
1184 blue = 3
1185 def __repr__(self):
1186 return "don't you just love shades of %s?" % self.name
1187 self.assertEqual(
1188 repr(Color.blue),
1189 "don't you just love shades of blue?",
1190 )
1191
1192 def test_inherited_repr(self):
1193 class MyEnum(Enum):
1194 def __repr__(self):
1195 return "My name is %s." % self.name
1196 class MyIntEnum(int, MyEnum):
1197 this = 1
1198 that = 2
1199 theother = 3
1200 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1201
1202 def test_multiple_mixin_mro(self):
1203 class auto_enum(type(Enum)):
1204 def __new__(metacls, cls, bases, classdict):
1205 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001206 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001207 names = set(classdict._member_names)
1208 i = 0
1209 for k in classdict._member_names:
1210 v = classdict[k]
1211 if v is Ellipsis:
1212 v = i
1213 else:
1214 i = v
1215 i += 1
1216 temp[k] = v
1217 for k, v in classdict.items():
1218 if k not in names:
1219 temp[k] = v
1220 return super(auto_enum, metacls).__new__(
1221 metacls, cls, bases, temp)
1222
1223 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1224 pass
1225
1226 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1227 pass
1228
1229 class TestAutoNumber(AutoNumberedEnum):
1230 a = ...
1231 b = 3
1232 c = ...
1233
1234 class TestAutoInt(AutoIntEnum):
1235 a = ...
1236 b = 3
1237 c = ...
1238
1239 def test_subclasses_with_getnewargs(self):
1240 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001241 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001242 def __new__(cls, *args):
1243 _args = args
1244 name, *args = args
1245 if len(args) == 0:
1246 raise TypeError("name and value must be specified")
1247 self = int.__new__(cls, *args)
1248 self._intname = name
1249 self._args = _args
1250 return self
1251 def __getnewargs__(self):
1252 return self._args
1253 @property
1254 def __name__(self):
1255 return self._intname
1256 def __repr__(self):
1257 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001258 return "{}({!r}, {})".format(
1259 type(self).__name__,
1260 self.__name__,
1261 int.__repr__(self),
1262 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001263 def __str__(self):
1264 # str() is unchanged, even if it relies on the repr() fallback
1265 base = int
1266 base_str = base.__str__
1267 if base_str.__objclass__ is object:
1268 return base.__repr__(self)
1269 return base_str(self)
1270 # for simplicity, we only define one operator that
1271 # propagates expressions
1272 def __add__(self, other):
1273 temp = int(self) + int( other)
1274 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1275 return NamedInt(
1276 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001277 temp,
1278 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001279 else:
1280 return temp
1281
1282 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001283 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001284 x = ('the-x', 1)
1285 y = ('the-y', 2)
1286
Ethan Furman2aa27322013-07-19 19:35:56 -07001287
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001288 self.assertIs(NEI.__new__, Enum.__new__)
1289 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1290 globals()['NamedInt'] = NamedInt
1291 globals()['NEI'] = NEI
1292 NI5 = NamedInt('test', 5)
1293 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001294 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001295 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001296 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001297 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001298
Ethan Furmanca1b7942014-02-08 11:36:27 -08001299 def test_subclasses_with_getnewargs_ex(self):
1300 class NamedInt(int):
1301 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1302 def __new__(cls, *args):
1303 _args = args
1304 name, *args = args
1305 if len(args) == 0:
1306 raise TypeError("name and value must be specified")
1307 self = int.__new__(cls, *args)
1308 self._intname = name
1309 self._args = _args
1310 return self
1311 def __getnewargs_ex__(self):
1312 return self._args, {}
1313 @property
1314 def __name__(self):
1315 return self._intname
1316 def __repr__(self):
1317 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001318 return "{}({!r}, {})".format(
1319 type(self).__name__,
1320 self.__name__,
1321 int.__repr__(self),
1322 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001323 def __str__(self):
1324 # str() is unchanged, even if it relies on the repr() fallback
1325 base = int
1326 base_str = base.__str__
1327 if base_str.__objclass__ is object:
1328 return base.__repr__(self)
1329 return base_str(self)
1330 # for simplicity, we only define one operator that
1331 # propagates expressions
1332 def __add__(self, other):
1333 temp = int(self) + int( other)
1334 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1335 return NamedInt(
1336 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001337 temp,
1338 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001339 else:
1340 return temp
1341
1342 class NEI(NamedInt, Enum):
1343 __qualname__ = 'NEI' # needed for pickle protocol 4
1344 x = ('the-x', 1)
1345 y = ('the-y', 2)
1346
1347
1348 self.assertIs(NEI.__new__, Enum.__new__)
1349 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1350 globals()['NamedInt'] = NamedInt
1351 globals()['NEI'] = NEI
1352 NI5 = NamedInt('test', 5)
1353 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001354 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001355 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001356 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001357 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001358
1359 def test_subclasses_with_reduce(self):
1360 class NamedInt(int):
1361 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1362 def __new__(cls, *args):
1363 _args = args
1364 name, *args = args
1365 if len(args) == 0:
1366 raise TypeError("name and value must be specified")
1367 self = int.__new__(cls, *args)
1368 self._intname = name
1369 self._args = _args
1370 return self
1371 def __reduce__(self):
1372 return self.__class__, self._args
1373 @property
1374 def __name__(self):
1375 return self._intname
1376 def __repr__(self):
1377 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001378 return "{}({!r}, {})".format(
1379 type(self).__name__,
1380 self.__name__,
1381 int.__repr__(self),
1382 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001383 def __str__(self):
1384 # str() is unchanged, even if it relies on the repr() fallback
1385 base = int
1386 base_str = base.__str__
1387 if base_str.__objclass__ is object:
1388 return base.__repr__(self)
1389 return base_str(self)
1390 # for simplicity, we only define one operator that
1391 # propagates expressions
1392 def __add__(self, other):
1393 temp = int(self) + int( other)
1394 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1395 return NamedInt(
1396 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001397 temp,
1398 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001399 else:
1400 return temp
1401
1402 class NEI(NamedInt, Enum):
1403 __qualname__ = 'NEI' # needed for pickle protocol 4
1404 x = ('the-x', 1)
1405 y = ('the-y', 2)
1406
1407
1408 self.assertIs(NEI.__new__, Enum.__new__)
1409 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1410 globals()['NamedInt'] = NamedInt
1411 globals()['NEI'] = NEI
1412 NI5 = NamedInt('test', 5)
1413 self.assertEqual(NI5, 5)
1414 test_pickle_dump_load(self.assertEqual, NI5, 5)
1415 self.assertEqual(NEI.y.value, 2)
1416 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001417 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001418
1419 def test_subclasses_with_reduce_ex(self):
1420 class NamedInt(int):
1421 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1422 def __new__(cls, *args):
1423 _args = args
1424 name, *args = args
1425 if len(args) == 0:
1426 raise TypeError("name and value must be specified")
1427 self = int.__new__(cls, *args)
1428 self._intname = name
1429 self._args = _args
1430 return self
1431 def __reduce_ex__(self, proto):
1432 return self.__class__, self._args
1433 @property
1434 def __name__(self):
1435 return self._intname
1436 def __repr__(self):
1437 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001438 return "{}({!r}, {})".format(
1439 type(self).__name__,
1440 self.__name__,
1441 int.__repr__(self),
1442 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001443 def __str__(self):
1444 # str() is unchanged, even if it relies on the repr() fallback
1445 base = int
1446 base_str = base.__str__
1447 if base_str.__objclass__ is object:
1448 return base.__repr__(self)
1449 return base_str(self)
1450 # for simplicity, we only define one operator that
1451 # propagates expressions
1452 def __add__(self, other):
1453 temp = int(self) + int( other)
1454 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1455 return NamedInt(
1456 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001457 temp,
1458 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001459 else:
1460 return temp
1461
1462 class NEI(NamedInt, Enum):
1463 __qualname__ = 'NEI' # needed for pickle protocol 4
1464 x = ('the-x', 1)
1465 y = ('the-y', 2)
1466
Ethan Furmanca1b7942014-02-08 11:36:27 -08001467 self.assertIs(NEI.__new__, Enum.__new__)
1468 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1469 globals()['NamedInt'] = NamedInt
1470 globals()['NEI'] = NEI
1471 NI5 = NamedInt('test', 5)
1472 self.assertEqual(NI5, 5)
1473 test_pickle_dump_load(self.assertEqual, NI5, 5)
1474 self.assertEqual(NEI.y.value, 2)
1475 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001476 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001477
Ethan Furmandc870522014-02-18 12:37:12 -08001478 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001479 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001480 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001481 def __new__(cls, *args):
1482 _args = args
1483 name, *args = args
1484 if len(args) == 0:
1485 raise TypeError("name and value must be specified")
1486 self = int.__new__(cls, *args)
1487 self._intname = name
1488 self._args = _args
1489 return self
1490 @property
1491 def __name__(self):
1492 return self._intname
1493 def __repr__(self):
1494 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001495 return "{}({!r}, {})".format(
1496 type(self).__name__,
1497 self.__name__,
1498 int.__repr__(self),
1499 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001500 def __str__(self):
1501 # str() is unchanged, even if it relies on the repr() fallback
1502 base = int
1503 base_str = base.__str__
1504 if base_str.__objclass__ is object:
1505 return base.__repr__(self)
1506 return base_str(self)
1507 # for simplicity, we only define one operator that
1508 # propagates expressions
1509 def __add__(self, other):
1510 temp = int(self) + int( other)
1511 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1512 return NamedInt(
1513 '({0} + {1})'.format(self.__name__, other.__name__),
1514 temp )
1515 else:
1516 return temp
1517
1518 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001519 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001520 x = ('the-x', 1)
1521 y = ('the-y', 2)
1522
1523 self.assertIs(NEI.__new__, Enum.__new__)
1524 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1525 globals()['NamedInt'] = NamedInt
1526 globals()['NEI'] = NEI
1527 NI5 = NamedInt('test', 5)
1528 self.assertEqual(NI5, 5)
1529 self.assertEqual(NEI.y.value, 2)
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001530 test_pickle_dump_load(self.assertIs, NEI.y)
1531 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001532
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001533 def test_subclasses_with_direct_pickle_support(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001534 class NamedInt(int):
1535 __qualname__ = 'NamedInt'
1536 def __new__(cls, *args):
1537 _args = args
1538 name, *args = args
1539 if len(args) == 0:
1540 raise TypeError("name and value must be specified")
1541 self = int.__new__(cls, *args)
1542 self._intname = name
1543 self._args = _args
1544 return self
1545 @property
1546 def __name__(self):
1547 return self._intname
1548 def __repr__(self):
1549 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001550 return "{}({!r}, {})".format(
1551 type(self).__name__,
1552 self.__name__,
1553 int.__repr__(self),
1554 )
Ethan Furmandc870522014-02-18 12:37:12 -08001555 def __str__(self):
1556 # str() is unchanged, even if it relies on the repr() fallback
1557 base = int
1558 base_str = base.__str__
1559 if base_str.__objclass__ is object:
1560 return base.__repr__(self)
1561 return base_str(self)
1562 # for simplicity, we only define one operator that
1563 # propagates expressions
1564 def __add__(self, other):
1565 temp = int(self) + int( other)
1566 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1567 return NamedInt(
1568 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001569 temp,
1570 )
Ethan Furmandc870522014-02-18 12:37:12 -08001571 else:
1572 return temp
1573
1574 class NEI(NamedInt, Enum):
1575 __qualname__ = 'NEI'
1576 x = ('the-x', 1)
1577 y = ('the-y', 2)
1578 def __reduce_ex__(self, proto):
1579 return getattr, (self.__class__, self._name_)
1580
1581 self.assertIs(NEI.__new__, Enum.__new__)
1582 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1583 globals()['NamedInt'] = NamedInt
1584 globals()['NEI'] = NEI
1585 NI5 = NamedInt('test', 5)
1586 self.assertEqual(NI5, 5)
1587 self.assertEqual(NEI.y.value, 2)
1588 test_pickle_dump_load(self.assertIs, NEI.y)
1589 test_pickle_dump_load(self.assertIs, NEI)
1590
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001591 def test_tuple_subclass(self):
1592 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001593 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001594 first = (1, 'for the money')
1595 second = (2, 'for the show')
1596 third = (3, 'for the music')
1597 self.assertIs(type(SomeTuple.first), SomeTuple)
1598 self.assertIsInstance(SomeTuple.second, tuple)
1599 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1600 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001601 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001602
1603 def test_duplicate_values_give_unique_enum_items(self):
1604 class AutoNumber(Enum):
1605 first = ()
1606 second = ()
1607 third = ()
1608 def __new__(cls):
1609 value = len(cls.__members__) + 1
1610 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001611 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001612 return obj
1613 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001614 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001615 self.assertEqual(
1616 list(AutoNumber),
1617 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1618 )
1619 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001620 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001621 self.assertIs(AutoNumber(1), AutoNumber.first)
1622
1623 def test_inherited_new_from_enhanced_enum(self):
1624 class AutoNumber(Enum):
1625 def __new__(cls):
1626 value = len(cls.__members__) + 1
1627 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001628 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001629 return obj
1630 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001631 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001632 class Color(AutoNumber):
1633 red = ()
1634 green = ()
1635 blue = ()
1636 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1637 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1638
1639 def test_inherited_new_from_mixed_enum(self):
1640 class AutoNumber(IntEnum):
1641 def __new__(cls):
1642 value = len(cls.__members__) + 1
1643 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001644 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001645 return obj
1646 class Color(AutoNumber):
1647 red = ()
1648 green = ()
1649 blue = ()
1650 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1651 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1652
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001653 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001654 class OrdinaryEnum(Enum):
1655 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001656 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1657 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001658
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001659 def test_ordered_mixin(self):
1660 class OrderedEnum(Enum):
1661 def __ge__(self, other):
1662 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001663 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001664 return NotImplemented
1665 def __gt__(self, other):
1666 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001667 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001668 return NotImplemented
1669 def __le__(self, other):
1670 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001671 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001672 return NotImplemented
1673 def __lt__(self, other):
1674 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001675 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001676 return NotImplemented
1677 class Grade(OrderedEnum):
1678 A = 5
1679 B = 4
1680 C = 3
1681 D = 2
1682 F = 1
1683 self.assertGreater(Grade.A, Grade.B)
1684 self.assertLessEqual(Grade.F, Grade.C)
1685 self.assertLess(Grade.D, Grade.A)
1686 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001687 self.assertEqual(Grade.B, Grade.B)
1688 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001689
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001690 def test_extending2(self):
1691 class Shade(Enum):
1692 def shade(self):
1693 print(self.name)
1694 class Color(Shade):
1695 red = 1
1696 green = 2
1697 blue = 3
1698 with self.assertRaises(TypeError):
1699 class MoreColor(Color):
1700 cyan = 4
1701 magenta = 5
1702 yellow = 6
1703
1704 def test_extending3(self):
1705 class Shade(Enum):
1706 def shade(self):
1707 return self.name
1708 class Color(Shade):
1709 def hex(self):
1710 return '%s hexlified!' % self.value
1711 class MoreColor(Color):
1712 cyan = 4
1713 magenta = 5
1714 yellow = 6
1715 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1716
orlnub1230fb9fad2018-09-12 20:28:53 +03001717 def test_subclass_duplicate_name(self):
1718 class Base(Enum):
1719 def test(self):
1720 pass
1721 class Test(Base):
1722 test = 1
1723 self.assertIs(type(Test.test), Test)
1724
1725 def test_subclass_duplicate_name_dynamic(self):
1726 from types import DynamicClassAttribute
1727 class Base(Enum):
1728 @DynamicClassAttribute
1729 def test(self):
1730 return 'dynamic'
1731 class Test(Base):
1732 test = 1
1733 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001734 class Base2(Enum):
1735 @enum.property
1736 def flash(self):
1737 return 'flashy dynamic'
1738 class Test(Base2):
1739 flash = 1
1740 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001741
1742 def test_no_duplicates(self):
1743 class UniqueEnum(Enum):
1744 def __init__(self, *args):
1745 cls = self.__class__
1746 if any(self.value == e.value for e in cls):
1747 a = self.name
1748 e = cls(self.value).name
1749 raise ValueError(
1750 "aliases not allowed in UniqueEnum: %r --> %r"
1751 % (a, e)
1752 )
1753 class Color(UniqueEnum):
1754 red = 1
1755 green = 2
1756 blue = 3
1757 with self.assertRaises(ValueError):
1758 class Color(UniqueEnum):
1759 red = 1
1760 green = 2
1761 blue = 3
1762 grene = 2
1763
1764 def test_init(self):
1765 class Planet(Enum):
1766 MERCURY = (3.303e+23, 2.4397e6)
1767 VENUS = (4.869e+24, 6.0518e6)
1768 EARTH = (5.976e+24, 6.37814e6)
1769 MARS = (6.421e+23, 3.3972e6)
1770 JUPITER = (1.9e+27, 7.1492e7)
1771 SATURN = (5.688e+26, 6.0268e7)
1772 URANUS = (8.686e+25, 2.5559e7)
1773 NEPTUNE = (1.024e+26, 2.4746e7)
1774 def __init__(self, mass, radius):
1775 self.mass = mass # in kilograms
1776 self.radius = radius # in meters
1777 @property
1778 def surface_gravity(self):
1779 # universal gravitational constant (m3 kg-1 s-2)
1780 G = 6.67300E-11
1781 return G * self.mass / (self.radius * self.radius)
1782 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1783 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1784
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001785 def test_ignore(self):
1786 class Period(timedelta, Enum):
1787 '''
1788 different lengths of time
1789 '''
1790 def __new__(cls, value, period):
1791 obj = timedelta.__new__(cls, value)
1792 obj._value_ = value
1793 obj.period = period
1794 return obj
1795 _ignore_ = 'Period i'
1796 Period = vars()
1797 for i in range(13):
1798 Period['month_%d' % i] = i*30, 'month'
1799 for i in range(53):
1800 Period['week_%d' % i] = i*7, 'week'
1801 for i in range(32):
1802 Period['day_%d' % i] = i, 'day'
1803 OneDay = day_1
1804 OneWeek = week_1
1805 OneMonth = month_1
1806 self.assertFalse(hasattr(Period, '_ignore_'))
1807 self.assertFalse(hasattr(Period, 'Period'))
1808 self.assertFalse(hasattr(Period, 'i'))
1809 self.assertTrue(isinstance(Period.day_1, timedelta))
1810 self.assertTrue(Period.month_1 is Period.day_30)
1811 self.assertTrue(Period.week_4 is Period.day_28)
1812
Ethan Furman2aa27322013-07-19 19:35:56 -07001813 def test_nonhash_value(self):
1814 class AutoNumberInAList(Enum):
1815 def __new__(cls):
1816 value = [len(cls.__members__) + 1]
1817 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001818 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001819 return obj
1820 class ColorInAList(AutoNumberInAList):
1821 red = ()
1822 green = ()
1823 blue = ()
1824 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001825 for enum, value in zip(ColorInAList, range(3)):
1826 value += 1
1827 self.assertEqual(enum.value, [value])
1828 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001829
Ethan Furmanb41803e2013-07-25 13:50:45 -07001830 def test_conflicting_types_resolved_in_new(self):
1831 class LabelledIntEnum(int, Enum):
1832 def __new__(cls, *args):
1833 value, label = args
1834 obj = int.__new__(cls, value)
1835 obj.label = label
1836 obj._value_ = value
1837 return obj
1838
1839 class LabelledList(LabelledIntEnum):
1840 unprocessed = (1, "Unprocessed")
1841 payment_complete = (2, "Payment Complete")
1842
1843 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1844 self.assertEqual(LabelledList.unprocessed, 1)
1845 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001846
Ethan Furmanc16595e2016-09-10 23:36:59 -07001847 def test_auto_number(self):
1848 class Color(Enum):
1849 red = auto()
1850 blue = auto()
1851 green = auto()
1852
1853 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1854 self.assertEqual(Color.red.value, 1)
1855 self.assertEqual(Color.blue.value, 2)
1856 self.assertEqual(Color.green.value, 3)
1857
1858 def test_auto_name(self):
1859 class Color(Enum):
1860 def _generate_next_value_(name, start, count, last):
1861 return name
1862 red = auto()
1863 blue = auto()
1864 green = auto()
1865
1866 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1867 self.assertEqual(Color.red.value, 'red')
1868 self.assertEqual(Color.blue.value, 'blue')
1869 self.assertEqual(Color.green.value, 'green')
1870
1871 def test_auto_name_inherit(self):
1872 class AutoNameEnum(Enum):
1873 def _generate_next_value_(name, start, count, last):
1874 return name
1875 class Color(AutoNameEnum):
1876 red = auto()
1877 blue = auto()
1878 green = auto()
1879
1880 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1881 self.assertEqual(Color.red.value, 'red')
1882 self.assertEqual(Color.blue.value, 'blue')
1883 self.assertEqual(Color.green.value, 'green')
1884
1885 def test_auto_garbage(self):
1886 class Color(Enum):
1887 red = 'red'
1888 blue = auto()
1889 self.assertEqual(Color.blue.value, 1)
1890
1891 def test_auto_garbage_corrected(self):
1892 class Color(Enum):
1893 red = 'red'
1894 blue = 2
1895 green = auto()
1896
1897 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1898 self.assertEqual(Color.red.value, 'red')
1899 self.assertEqual(Color.blue.value, 2)
1900 self.assertEqual(Color.green.value, 3)
1901
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001902 def test_auto_order(self):
1903 with self.assertRaises(TypeError):
1904 class Color(Enum):
1905 red = auto()
1906 green = auto()
1907 blue = auto()
1908 def _generate_next_value_(name, start, count, last):
1909 return name
1910
Ethan Furmanfc23a942020-09-16 12:37:54 -07001911 def test_auto_order_wierd(self):
1912 weird_auto = auto()
1913 weird_auto.value = 'pathological case'
1914 class Color(Enum):
1915 red = weird_auto
1916 def _generate_next_value_(name, start, count, last):
1917 return name
1918 blue = auto()
1919 self.assertEqual(list(Color), [Color.red, Color.blue])
1920 self.assertEqual(Color.red.value, 'pathological case')
1921 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001922
Ethan Furman3515dcc2016-09-18 13:15:41 -07001923 def test_duplicate_auto(self):
1924 class Dupes(Enum):
1925 first = primero = auto()
1926 second = auto()
1927 third = auto()
1928 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1929
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001930 def test_default_missing(self):
1931 class Color(Enum):
1932 RED = 1
1933 GREEN = 2
1934 BLUE = 3
1935 try:
1936 Color(7)
1937 except ValueError as exc:
1938 self.assertTrue(exc.__context__ is None)
1939 else:
1940 raise Exception('Exception not raised.')
1941
Ethan Furman019f0a02018-09-12 11:43:34 -07001942 def test_missing(self):
1943 class Color(Enum):
1944 red = 1
1945 green = 2
1946 blue = 3
1947 @classmethod
1948 def _missing_(cls, item):
1949 if item == 'three':
1950 return cls.blue
1951 elif item == 'bad return':
1952 # trigger internal error
1953 return 5
1954 elif item == 'error out':
1955 raise ZeroDivisionError
1956 else:
1957 # trigger not found
1958 return None
1959 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001960 try:
1961 Color(7)
1962 except ValueError as exc:
1963 self.assertTrue(exc.__context__ is None)
1964 else:
1965 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001966 try:
1967 Color('bad return')
1968 except TypeError as exc:
1969 self.assertTrue(isinstance(exc.__context__, ValueError))
1970 else:
1971 raise Exception('Exception not raised.')
1972 try:
1973 Color('error out')
1974 except ZeroDivisionError as exc:
1975 self.assertTrue(isinstance(exc.__context__, ValueError))
1976 else:
1977 raise Exception('Exception not raised.')
1978
Ethan Furman8c14f5a2021-04-12 08:51:20 -07001979 def test_missing_exceptions_reset(self):
1980 import weakref
1981 #
1982 class TestEnum(enum.Enum):
1983 VAL1 = 'val1'
1984 VAL2 = 'val2'
1985 #
1986 class Class1:
1987 def __init__(self):
1988 # Gracefully handle an exception of our own making
1989 try:
1990 raise ValueError()
1991 except ValueError:
1992 pass
1993 #
1994 class Class2:
1995 def __init__(self):
1996 # Gracefully handle an exception of Enum's making
1997 try:
1998 TestEnum('invalid_value')
1999 except ValueError:
2000 pass
2001 # No strong refs here so these are free to die.
2002 class_1_ref = weakref.ref(Class1())
2003 class_2_ref = weakref.ref(Class2())
2004 #
2005 # The exception raised by Enum creates a reference loop and thus
2006 # Class2 instances will stick around until the next gargage collection
2007 # cycle, unlike Class1.
2008 self.assertIs(class_1_ref(), None)
2009 self.assertIs(class_2_ref(), None)
2010
Ethan Furman5bdab642018-09-21 19:03:09 -07002011 def test_multiple_mixin(self):
2012 class MaxMixin:
2013 @classproperty
2014 def MAX(cls):
2015 max = len(cls)
2016 cls.MAX = max
2017 return max
2018 class StrMixin:
2019 def __str__(self):
2020 return self._name_.lower()
2021 class SomeEnum(Enum):
2022 def behavior(self):
2023 return 'booyah'
2024 class AnotherEnum(Enum):
2025 def behavior(self):
2026 return 'nuhuh!'
2027 def social(self):
2028 return "what's up?"
2029 class Color(MaxMixin, Enum):
2030 RED = auto()
2031 GREEN = auto()
2032 BLUE = auto()
2033 self.assertEqual(Color.RED.value, 1)
2034 self.assertEqual(Color.GREEN.value, 2)
2035 self.assertEqual(Color.BLUE.value, 3)
2036 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002037 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002038 class Color(MaxMixin, StrMixin, Enum):
2039 RED = auto()
2040 GREEN = auto()
2041 BLUE = auto()
2042 self.assertEqual(Color.RED.value, 1)
2043 self.assertEqual(Color.GREEN.value, 2)
2044 self.assertEqual(Color.BLUE.value, 3)
2045 self.assertEqual(Color.MAX, 3)
2046 self.assertEqual(str(Color.BLUE), 'blue')
2047 class Color(StrMixin, MaxMixin, Enum):
2048 RED = auto()
2049 GREEN = auto()
2050 BLUE = auto()
2051 self.assertEqual(Color.RED.value, 1)
2052 self.assertEqual(Color.GREEN.value, 2)
2053 self.assertEqual(Color.BLUE.value, 3)
2054 self.assertEqual(Color.MAX, 3)
2055 self.assertEqual(str(Color.BLUE), 'blue')
2056 class CoolColor(StrMixin, SomeEnum, Enum):
2057 RED = auto()
2058 GREEN = auto()
2059 BLUE = auto()
2060 self.assertEqual(CoolColor.RED.value, 1)
2061 self.assertEqual(CoolColor.GREEN.value, 2)
2062 self.assertEqual(CoolColor.BLUE.value, 3)
2063 self.assertEqual(str(CoolColor.BLUE), 'blue')
2064 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2065 class CoolerColor(StrMixin, AnotherEnum, Enum):
2066 RED = auto()
2067 GREEN = auto()
2068 BLUE = auto()
2069 self.assertEqual(CoolerColor.RED.value, 1)
2070 self.assertEqual(CoolerColor.GREEN.value, 2)
2071 self.assertEqual(CoolerColor.BLUE.value, 3)
2072 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2073 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2074 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2075 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2076 RED = auto()
2077 GREEN = auto()
2078 BLUE = auto()
2079 self.assertEqual(CoolestColor.RED.value, 1)
2080 self.assertEqual(CoolestColor.GREEN.value, 2)
2081 self.assertEqual(CoolestColor.BLUE.value, 3)
2082 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2083 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2084 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2085 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2086 RED = auto()
2087 GREEN = auto()
2088 BLUE = auto()
2089 self.assertEqual(ConfusedColor.RED.value, 1)
2090 self.assertEqual(ConfusedColor.GREEN.value, 2)
2091 self.assertEqual(ConfusedColor.BLUE.value, 3)
2092 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2093 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2094 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2095 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2096 RED = auto()
2097 GREEN = auto()
2098 BLUE = auto()
2099 self.assertEqual(ReformedColor.RED.value, 1)
2100 self.assertEqual(ReformedColor.GREEN.value, 2)
2101 self.assertEqual(ReformedColor.BLUE.value, 3)
2102 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2103 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2104 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2105 self.assertTrue(issubclass(ReformedColor, int))
2106
Ethan Furmancd453852018-10-05 23:29:36 -07002107 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002108 @unique
2109 class Decision1(StrEnum):
2110 REVERT = "REVERT"
2111 REVERT_ALL = "REVERT_ALL"
2112 RETRY = "RETRY"
2113 class MyEnum(StrEnum):
2114 pass
2115 @unique
2116 class Decision2(MyEnum):
2117 REVERT = "REVERT"
2118 REVERT_ALL = "REVERT_ALL"
2119 RETRY = "RETRY"
2120
Ethan Furmanc2667362020-12-07 00:17:31 -08002121 def test_multiple_mixin_inherited(self):
2122 class MyInt(int):
2123 def __new__(cls, value):
2124 return super().__new__(cls, value)
2125
2126 class HexMixin:
2127 def __repr__(self):
2128 return hex(self)
2129
2130 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2131 pass
2132
2133 class Foo(MyIntEnum):
2134 TEST = 1
2135 self.assertTrue(isinstance(Foo.TEST, MyInt))
2136 self.assertEqual(repr(Foo.TEST), "0x1")
2137
2138 class Fee(MyIntEnum):
2139 TEST = 1
2140 def __new__(cls, value):
2141 value += 1
2142 member = int.__new__(cls, value)
2143 member._value_ = value
2144 return member
2145 self.assertEqual(Fee.TEST, 2)
2146
Miss Islington (bot)01286012021-06-10 15:01:03 -07002147 def test_miltuple_mixin_with_common_data_type(self):
2148 class CaseInsensitiveStrEnum(str, Enum):
2149 @classmethod
2150 def _missing_(cls, value):
2151 for member in cls._member_map_.values():
2152 if member._value_.lower() == value.lower():
2153 return member
2154 return super()._missing_(value)
2155 #
2156 class LenientStrEnum(str, Enum):
2157 def __init__(self, *args):
2158 self._valid = True
2159 @classmethod
2160 def _missing_(cls, value):
2161 # encountered an unknown value!
2162 # Luckily I'm a LenientStrEnum, so I won't crash just yet.
2163 # You might want to add a new case though.
2164 unknown = cls._member_type_.__new__(cls, value)
2165 unknown._valid = False
2166 unknown._name_ = value.upper()
2167 unknown._value_ = value
2168 cls._member_map_[value] = unknown
2169 return unknown
2170 @property
2171 def valid(self):
2172 return self._valid
2173 #
2174 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2175 ACTIVE = "active"
2176 PENDING = "pending"
2177 TERMINATED = "terminated"
2178 #
2179 JS = JobStatus
2180 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2181 self.assertEqual(JS.ACTIVE, 'active')
2182 self.assertEqual(JS.ACTIVE.value, 'active')
2183 self.assertIs(JS('Active'), JS.ACTIVE)
2184 self.assertTrue(JS.ACTIVE.valid)
2185 missing = JS('missing')
2186 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2187 self.assertEqual(JS.ACTIVE, 'active')
2188 self.assertEqual(JS.ACTIVE.value, 'active')
2189 self.assertIs(JS('Active'), JS.ACTIVE)
2190 self.assertTrue(JS.ACTIVE.valid)
2191 self.assertTrue(isinstance(missing, JS))
2192 self.assertFalse(missing.valid)
2193
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002194 def test_empty_globals(self):
2195 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2196 # when using compile and exec because f_globals is empty
2197 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2198 code = compile(code, "<string>", "exec")
2199 global_ns = {}
2200 local_ls = {}
2201 exec(code, global_ns, local_ls)
2202
Ethan Furman0063ff42020-09-21 17:23:13 -07002203 def test_strenum(self):
2204 class GoodStrEnum(StrEnum):
2205 one = '1'
2206 two = '2'
2207 three = b'3', 'ascii'
2208 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002209 self.assertEqual(GoodStrEnum.one, '1')
2210 self.assertEqual(str(GoodStrEnum.one), '1')
2211 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2212 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2213 #
2214 class DumbMixin:
2215 def __str__(self):
2216 return "don't do this"
2217 class DumbStrEnum(DumbMixin, StrEnum):
2218 five = '5'
2219 six = '6'
2220 seven = '7'
2221 self.assertEqual(DumbStrEnum.seven, '7')
2222 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2223 #
2224 class EnumMixin(Enum):
2225 def hello(self):
2226 print('hello from %s' % (self, ))
2227 class HelloEnum(EnumMixin, StrEnum):
2228 eight = '8'
2229 self.assertEqual(HelloEnum.eight, '8')
2230 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2231 #
2232 class GoodbyeMixin:
2233 def goodbye(self):
2234 print('%s wishes you a fond farewell')
2235 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2236 nine = '9'
2237 self.assertEqual(GoodbyeEnum.nine, '9')
2238 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2239 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002240 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2241 class FirstFailedStrEnum(StrEnum):
2242 one = 1
2243 two = '2'
2244 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2245 class SecondFailedStrEnum(StrEnum):
2246 one = '1'
2247 two = 2,
2248 three = '3'
2249 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2250 class ThirdFailedStrEnum(StrEnum):
2251 one = '1'
2252 two = 2
2253 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2254 class ThirdFailedStrEnum(StrEnum):
2255 one = '1'
2256 two = b'2', sys.getdefaultencoding
2257 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2258 class ThirdFailedStrEnum(StrEnum):
2259 one = '1'
2260 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002261
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002262 def test_missing_value_error(self):
2263 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2264 class Combined(str, Enum):
2265 #
2266 def __new__(cls, value, sequence):
2267 enum = str.__new__(cls, value)
2268 if '(' in value:
2269 fis_name, segment = value.split('(', 1)
2270 segment = segment.strip(' )')
2271 else:
2272 fis_name = value
2273 segment = None
2274 enum.fis_name = fis_name
2275 enum.segment = segment
2276 enum.sequence = sequence
2277 return enum
2278 #
2279 def __repr__(self):
2280 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2281 #
2282 key_type = 'An$(1,2)', 0
2283 company_id = 'An$(3,2)', 1
2284 code = 'An$(5,1)', 2
2285 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002286
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002287 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002288 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002289 'private variables are now normal attributes',
2290 )
2291 def test_warning_for_private_variables(self):
2292 with self.assertWarns(DeprecationWarning):
2293 class Private(Enum):
2294 __corporal = 'Radar'
2295 self.assertEqual(Private._Private__corporal.value, 'Radar')
2296 try:
2297 with self.assertWarns(DeprecationWarning):
2298 class Private(Enum):
2299 __major_ = 'Hoolihan'
2300 except ValueError:
2301 pass
2302
2303 def test_private_variable_is_normal_attribute(self):
2304 class Private(Enum):
2305 __corporal = 'Radar'
2306 __major_ = 'Hoolihan'
2307 self.assertEqual(Private._Private__corporal, 'Radar')
2308 self.assertEqual(Private._Private__major_, 'Hoolihan')
2309
Ethan Furmand65b9032021-02-08 17:32:38 -08002310 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002311 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002312 'member-member access now raises an exception',
2313 )
2314 def test_warning_for_member_from_member_access(self):
2315 with self.assertWarns(DeprecationWarning):
2316 class Di(Enum):
2317 YES = 1
2318 NO = 0
2319 nope = Di.YES.NO
2320 self.assertIs(Di.NO, nope)
2321
2322 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002323 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002324 'member-member access currently issues a warning',
2325 )
2326 def test_exception_for_member_from_member_access(self):
2327 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2328 class Di(Enum):
2329 YES = 1
2330 NO = 0
2331 nope = Di.YES.NO
2332
Ethan Furmanefb13be2020-12-10 12:20:06 -08002333 def test_strenum_auto(self):
2334 class Strings(StrEnum):
2335 ONE = auto()
2336 TWO = auto()
2337 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2338
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002339
Ethan Furmana6582872020-12-10 13:07:00 -08002340 def test_dynamic_members_with_static_methods(self):
2341 #
2342 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2343 class Foo(Enum):
2344 vars().update({
2345 k: v
2346 for k, v in foo_defines.items()
2347 if k.startswith('FOO_')
2348 })
2349 def upper(self):
2350 return self.value.upper()
2351 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2352 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2353 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2354 #
2355 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2356 class FooBar(Enum):
2357 vars().update({
2358 k: v
2359 for k, v in foo_defines.items()
2360 if k.startswith('FOO_')
2361 },
2362 **{'FOO_CAT': 'small'},
2363 )
2364 def upper(self):
2365 return self.value.upper()
2366
2367
Ethan Furmane8e61272016-08-20 07:19:31 -07002368class TestOrder(unittest.TestCase):
2369
2370 def test_same_members(self):
2371 class Color(Enum):
2372 _order_ = 'red green blue'
2373 red = 1
2374 green = 2
2375 blue = 3
2376
2377 def test_same_members_with_aliases(self):
2378 class Color(Enum):
2379 _order_ = 'red green blue'
2380 red = 1
2381 green = 2
2382 blue = 3
2383 verde = green
2384
2385 def test_same_members_wrong_order(self):
2386 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2387 class Color(Enum):
2388 _order_ = 'red green blue'
2389 red = 1
2390 blue = 3
2391 green = 2
2392
2393 def test_order_has_extra_members(self):
2394 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2395 class Color(Enum):
2396 _order_ = 'red green blue purple'
2397 red = 1
2398 green = 2
2399 blue = 3
2400
2401 def test_order_has_extra_members_with_aliases(self):
2402 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2403 class Color(Enum):
2404 _order_ = 'red green blue purple'
2405 red = 1
2406 green = 2
2407 blue = 3
2408 verde = green
2409
2410 def test_enum_has_extra_members(self):
2411 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2412 class Color(Enum):
2413 _order_ = 'red green blue'
2414 red = 1
2415 green = 2
2416 blue = 3
2417 purple = 4
2418
2419 def test_enum_has_extra_members_with_aliases(self):
2420 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2421 class Color(Enum):
2422 _order_ = 'red green blue'
2423 red = 1
2424 green = 2
2425 blue = 3
2426 purple = 4
2427 verde = green
2428
2429
Ethan Furman65a5a472016-09-01 23:55:19 -07002430class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002431 """Tests of the Flags."""
2432
Ethan Furman65a5a472016-09-01 23:55:19 -07002433 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002434 R, W, X = 4, 2, 1
2435
Ethan Furman65a5a472016-09-01 23:55:19 -07002436 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002437 RO = 0
2438 WO = 1
2439 RW = 2
2440 AC = 3
2441 CE = 1<<19
2442
Rahul Jha94306522018-09-10 23:51:04 +05302443 class Color(Flag):
2444 BLACK = 0
2445 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002446 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302447 GREEN = 2
2448 BLUE = 4
2449 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002450 WHITE = RED|GREEN|BLUE
2451 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302452
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002453 def test_str(self):
2454 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002455 self.assertEqual(str(Perm.R), 'R')
2456 self.assertEqual(str(Perm.W), 'W')
2457 self.assertEqual(str(Perm.X), 'X')
2458 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2459 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002460 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002461 self.assertEqual(str(~Perm.R), 'W|X')
2462 self.assertEqual(str(~Perm.W), 'R|X')
2463 self.assertEqual(str(~Perm.X), 'R|W')
2464 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002465 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002466 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002467
2468 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002469 self.assertEqual(str(Open.RO), 'RO')
2470 self.assertEqual(str(Open.WO), 'WO')
2471 self.assertEqual(str(Open.AC), 'AC')
2472 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2473 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2474 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2475 self.assertEqual(str(~Open.WO), 'RW|CE')
2476 self.assertEqual(str(~Open.AC), 'CE')
2477 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2478 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002479
2480 def test_repr(self):
2481 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002482 self.assertEqual(repr(Perm.R), 'Perm.R')
2483 self.assertEqual(repr(Perm.W), 'Perm.W')
2484 self.assertEqual(repr(Perm.X), 'Perm.X')
2485 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2486 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2487 self.assertEqual(repr(Perm(0)), '0x0')
2488 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2489 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2490 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2491 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2492 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2493 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002494
2495 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002496 self.assertEqual(repr(Open.RO), 'Open.RO')
2497 self.assertEqual(repr(Open.WO), 'Open.WO')
2498 self.assertEqual(repr(Open.AC), 'Open.AC')
2499 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2500 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2501 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2502 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2503 self.assertEqual(repr(~Open.AC), 'Open.CE')
2504 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2505 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002506
Ethan Furman37440ee2020-12-08 11:14:10 -08002507 def test_format(self):
2508 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002509 self.assertEqual(format(Perm.R, ''), 'R')
2510 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002511
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002512 def test_or(self):
2513 Perm = self.Perm
2514 for i in Perm:
2515 for j in Perm:
2516 self.assertEqual((i | j), Perm(i.value | j.value))
2517 self.assertEqual((i | j).value, i.value | j.value)
2518 self.assertIs(type(i | j), Perm)
2519 for i in Perm:
2520 self.assertIs(i | i, i)
2521 Open = self.Open
2522 self.assertIs(Open.RO | Open.CE, Open.CE)
2523
2524 def test_and(self):
2525 Perm = self.Perm
2526 RW = Perm.R | Perm.W
2527 RX = Perm.R | Perm.X
2528 WX = Perm.W | Perm.X
2529 RWX = Perm.R | Perm.W | Perm.X
2530 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2531 for i in values:
2532 for j in values:
2533 self.assertEqual((i & j).value, i.value & j.value)
2534 self.assertIs(type(i & j), Perm)
2535 for i in Perm:
2536 self.assertIs(i & i, i)
2537 self.assertIs(i & RWX, i)
2538 self.assertIs(RWX & i, i)
2539 Open = self.Open
2540 self.assertIs(Open.RO & Open.CE, Open.RO)
2541
2542 def test_xor(self):
2543 Perm = self.Perm
2544 for i in Perm:
2545 for j in Perm:
2546 self.assertEqual((i ^ j).value, i.value ^ j.value)
2547 self.assertIs(type(i ^ j), Perm)
2548 for i in Perm:
2549 self.assertIs(i ^ Perm(0), i)
2550 self.assertIs(Perm(0) ^ i, i)
2551 Open = self.Open
2552 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2553 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2554
2555 def test_invert(self):
2556 Perm = self.Perm
2557 RW = Perm.R | Perm.W
2558 RX = Perm.R | Perm.X
2559 WX = Perm.W | Perm.X
2560 RWX = Perm.R | Perm.W | Perm.X
2561 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2562 for i in values:
2563 self.assertIs(type(~i), Perm)
2564 self.assertEqual(~~i, i)
2565 for i in Perm:
2566 self.assertIs(~~i, i)
2567 Open = self.Open
2568 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2569 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2570
Ethan Furman25d94bb2016-09-02 16:32:32 -07002571 def test_bool(self):
2572 Perm = self.Perm
2573 for f in Perm:
2574 self.assertTrue(f)
2575 Open = self.Open
2576 for f in Open:
2577 self.assertEqual(bool(f.value), bool(f))
2578
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002579 def test_boundary(self):
2580 self.assertIs(enum.Flag._boundary_, STRICT)
2581 class Iron(Flag, boundary=STRICT):
2582 ONE = 1
2583 TWO = 2
2584 EIGHT = 8
2585 self.assertIs(Iron._boundary_, STRICT)
2586 #
2587 class Water(Flag, boundary=CONFORM):
2588 ONE = 1
2589 TWO = 2
2590 EIGHT = 8
2591 self.assertIs(Water._boundary_, CONFORM)
2592 #
2593 class Space(Flag, boundary=EJECT):
2594 ONE = 1
2595 TWO = 2
2596 EIGHT = 8
2597 self.assertIs(Space._boundary_, EJECT)
2598 #
2599 class Bizarre(Flag, boundary=KEEP):
2600 b = 3
2601 c = 4
2602 d = 6
2603 #
2604 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002605 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002606 self.assertIs(Water(7), Water.ONE|Water.TWO)
2607 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002608 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002609 self.assertEqual(Space(7), 7)
2610 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002611 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002612 self.assertEqual(list(Bizarre), [Bizarre.c])
2613 self.assertIs(Bizarre(3), Bizarre.b)
2614 self.assertIs(Bizarre(6), Bizarre.d)
2615
2616 def test_iter(self):
2617 Color = self.Color
2618 Open = self.Open
2619 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2620 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2621
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002622 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002623 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002624 lst = list(Perm)
2625 self.assertEqual(len(lst), len(Perm))
2626 self.assertEqual(len(Perm), 3, Perm)
2627 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2628 for i, n in enumerate('R W X'.split()):
2629 v = 1<<i
2630 e = Perm(v)
2631 self.assertEqual(e.value, v)
2632 self.assertEqual(type(e.value), int)
2633 self.assertEqual(e.name, n)
2634 self.assertIn(e, Perm)
2635 self.assertIs(type(e), Perm)
2636
2637 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002638 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002639 lst = list(Perm)
2640 self.assertEqual(len(lst), len(Perm))
2641 self.assertEqual(len(Perm), 3, Perm)
2642 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2643 for i, n in enumerate('R W X'.split()):
2644 v = 8<<i
2645 e = Perm(v)
2646 self.assertEqual(e.value, v)
2647 self.assertEqual(type(e.value), int)
2648 self.assertEqual(e.name, n)
2649 self.assertIn(e, Perm)
2650 self.assertIs(type(e), Perm)
2651
2652 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002653 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002654 lst = list(Perm)
2655 self.assertEqual(len(lst), len(Perm))
2656 self.assertEqual(len(Perm), 3, Perm)
2657 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2658 for i, n in enumerate('R W X'.split()):
2659 v = 1<<i
2660 e = Perm(v)
2661 self.assertEqual(e.value, v)
2662 self.assertEqual(type(e.value), int)
2663 self.assertEqual(e.name, n)
2664 self.assertIn(e, Perm)
2665 self.assertIs(type(e), Perm)
2666
2667 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002668 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002669 lst = list(Perm)
2670 self.assertEqual(len(lst), len(Perm))
2671 self.assertEqual(len(Perm), 3, Perm)
2672 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2673 for i, n in enumerate('R W X'.split()):
2674 v = 1<<(2*i+1)
2675 e = Perm(v)
2676 self.assertEqual(e.value, v)
2677 self.assertEqual(type(e.value), int)
2678 self.assertEqual(e.name, n)
2679 self.assertIn(e, Perm)
2680 self.assertIs(type(e), Perm)
2681
2682 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002683 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002684 lst = list(Perm)
2685 self.assertEqual(len(lst), len(Perm))
2686 self.assertEqual(len(Perm), 3, Perm)
2687 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2688 for i, n in enumerate('R W X'.split()):
2689 v = 1<<(2*i+1)
2690 e = Perm(v)
2691 self.assertEqual(e.value, v)
2692 self.assertEqual(type(e.value), int)
2693 self.assertEqual(e.name, n)
2694 self.assertIn(e, Perm)
2695 self.assertIs(type(e), Perm)
2696
Ethan Furman65a5a472016-09-01 23:55:19 -07002697 def test_pickle(self):
2698 if isinstance(FlagStooges, Exception):
2699 raise FlagStooges
2700 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2701 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002702
Ethan Furman6bd92882021-04-27 13:05:08 -07002703 @unittest.skipIf(
2704 python_version >= (3, 12),
2705 '__contains__ now returns True/False for all inputs',
2706 )
2707 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302708 Open = self.Open
2709 Color = self.Color
2710 self.assertFalse(Color.BLACK in Open)
2711 self.assertFalse(Open.RO in Color)
2712 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002713 with self.assertWarns(DeprecationWarning):
2714 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302715 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002716 with self.assertWarns(DeprecationWarning):
2717 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302718 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002719 with self.assertWarns(DeprecationWarning):
2720 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302721 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002722 with self.assertWarns(DeprecationWarning):
2723 1 in Open
2724
2725 @unittest.skipIf(
2726 python_version < (3, 12),
2727 '__contains__ only works with enum memmbers before 3.12',
2728 )
2729 def test_contains_tf(self):
2730 Open = self.Open
2731 Color = self.Color
2732 self.assertFalse(Color.BLACK in Open)
2733 self.assertFalse(Open.RO in Color)
2734 self.assertFalse('BLACK' in Color)
2735 self.assertFalse('RO' in Open)
2736 self.assertTrue(1 in Color)
2737 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302738
2739 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002740 Perm = self.Perm
2741 R, W, X = Perm
2742 RW = R | W
2743 RX = R | X
2744 WX = W | X
2745 RWX = R | W | X
2746 self.assertTrue(R in RW)
2747 self.assertTrue(R in RX)
2748 self.assertTrue(R in RWX)
2749 self.assertTrue(W in RW)
2750 self.assertTrue(W in WX)
2751 self.assertTrue(W in RWX)
2752 self.assertTrue(X in RX)
2753 self.assertTrue(X in WX)
2754 self.assertTrue(X in RWX)
2755 self.assertFalse(R in WX)
2756 self.assertFalse(W in RX)
2757 self.assertFalse(X in RW)
2758
Ethan Furman7219e272020-09-16 13:01:00 -07002759 def test_member_iter(self):
2760 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002761 self.assertEqual(list(Color.BLACK), [])
2762 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002763 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2764 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002765 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2766 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2767
2768 def test_member_length(self):
2769 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2770 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2771 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2772 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2773
2774 def test_number_reset_and_order_cleanup(self):
2775 class Confused(Flag):
2776 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2777 ONE = auto()
2778 TWO = auto()
2779 FOUR = auto()
2780 DOS = 2
2781 EIGHT = auto()
2782 SIXTEEN = auto()
2783 self.assertEqual(
2784 list(Confused),
2785 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2786 self.assertIs(Confused.TWO, Confused.DOS)
2787 self.assertEqual(Confused.DOS._value_, 2)
2788 self.assertEqual(Confused.EIGHT._value_, 8)
2789 self.assertEqual(Confused.SIXTEEN._value_, 16)
2790
2791 def test_aliases(self):
2792 Color = self.Color
2793 self.assertEqual(Color(1).name, 'RED')
2794 self.assertEqual(Color['ROJO'].name, 'RED')
2795 self.assertEqual(Color(7).name, 'WHITE')
2796 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2797 self.assertIs(Color.BLANCO, Color.WHITE)
2798 Open = self.Open
2799 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002800
Ethan Furmanc16595e2016-09-10 23:36:59 -07002801 def test_auto_number(self):
2802 class Color(Flag):
2803 red = auto()
2804 blue = auto()
2805 green = auto()
2806
2807 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2808 self.assertEqual(Color.red.value, 1)
2809 self.assertEqual(Color.blue.value, 2)
2810 self.assertEqual(Color.green.value, 4)
2811
2812 def test_auto_number_garbage(self):
2813 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2814 class Color(Flag):
2815 red = 'not an int'
2816 blue = auto()
2817
Ethan Furman3515dcc2016-09-18 13:15:41 -07002818 def test_duplicate_auto(self):
2819 class Dupes(Enum):
2820 first = primero = auto()
2821 second = auto()
2822 third = auto()
2823 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2824
Ethan Furman5bdab642018-09-21 19:03:09 -07002825 def test_multiple_mixin(self):
2826 class AllMixin:
2827 @classproperty
2828 def ALL(cls):
2829 members = list(cls)
2830 all_value = None
2831 if members:
2832 all_value = members[0]
2833 for member in members[1:]:
2834 all_value |= member
2835 cls.ALL = all_value
2836 return all_value
2837 class StrMixin:
2838 def __str__(self):
2839 return self._name_.lower()
2840 class Color(AllMixin, Flag):
2841 RED = auto()
2842 GREEN = auto()
2843 BLUE = auto()
2844 self.assertEqual(Color.RED.value, 1)
2845 self.assertEqual(Color.GREEN.value, 2)
2846 self.assertEqual(Color.BLUE.value, 4)
2847 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002848 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002849 class Color(AllMixin, StrMixin, Flag):
2850 RED = auto()
2851 GREEN = auto()
2852 BLUE = auto()
2853 self.assertEqual(Color.RED.value, 1)
2854 self.assertEqual(Color.GREEN.value, 2)
2855 self.assertEqual(Color.BLUE.value, 4)
2856 self.assertEqual(Color.ALL.value, 7)
2857 self.assertEqual(str(Color.BLUE), 'blue')
2858 class Color(StrMixin, AllMixin, Flag):
2859 RED = auto()
2860 GREEN = auto()
2861 BLUE = auto()
2862 self.assertEqual(Color.RED.value, 1)
2863 self.assertEqual(Color.GREEN.value, 2)
2864 self.assertEqual(Color.BLUE.value, 4)
2865 self.assertEqual(Color.ALL.value, 7)
2866 self.assertEqual(str(Color.BLUE), 'blue')
2867
Hai Shie80697d2020-05-28 06:10:27 +08002868 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002869 def test_unique_composite(self):
2870 # override __eq__ to be identity only
2871 class TestFlag(Flag):
2872 one = auto()
2873 two = auto()
2874 three = auto()
2875 four = auto()
2876 five = auto()
2877 six = auto()
2878 seven = auto()
2879 eight = auto()
2880 def __eq__(self, other):
2881 return self is other
2882 def __hash__(self):
2883 return hash(self._value_)
2884 # have multiple threads competing to complete the composite members
2885 seen = set()
2886 failed = False
2887 def cycle_enum():
2888 nonlocal failed
2889 try:
2890 for i in range(256):
2891 seen.add(TestFlag(i))
2892 except Exception:
2893 failed = True
2894 threads = [
2895 threading.Thread(target=cycle_enum)
2896 for _ in range(8)
2897 ]
Hai Shie80697d2020-05-28 06:10:27 +08002898 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002899 pass
2900 # check that only 248 members were created
2901 self.assertFalse(
2902 failed,
2903 'at least one thread failed while creating composite members')
2904 self.assertEqual(256, len(seen), 'too many composite members created')
2905
Ethan Furman6bd94de2020-12-09 16:41:22 -08002906 def test_init_subclass(self):
2907 class MyEnum(Flag):
2908 def __init_subclass__(cls, **kwds):
2909 super().__init_subclass__(**kwds)
2910 self.assertFalse(cls.__dict__.get('_test', False))
2911 cls._test1 = 'MyEnum'
2912 #
2913 class TheirEnum(MyEnum):
2914 def __init_subclass__(cls, **kwds):
2915 super(TheirEnum, cls).__init_subclass__(**kwds)
2916 cls._test2 = 'TheirEnum'
2917 class WhoseEnum(TheirEnum):
2918 def __init_subclass__(cls, **kwds):
2919 pass
2920 class NoEnum(WhoseEnum):
2921 ONE = 1
2922 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2923 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2924 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2925 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2926 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2927 #
2928 class OurEnum(MyEnum):
2929 def __init_subclass__(cls, **kwds):
2930 cls._test2 = 'OurEnum'
2931 class WhereEnum(OurEnum):
2932 def __init_subclass__(cls, **kwds):
2933 pass
2934 class NeverEnum(WhereEnum):
2935 ONE = 1
2936 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2937 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2938 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2939 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2940 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2941
Ethan Furmanc16595e2016-09-10 23:36:59 -07002942
Ethan Furman65a5a472016-09-01 23:55:19 -07002943class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002944 """Tests of the IntFlags."""
2945
Ethan Furman65a5a472016-09-01 23:55:19 -07002946 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002947 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002948 W = 1 << 1
2949 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002950
Ethan Furman65a5a472016-09-01 23:55:19 -07002951 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002952 RO = 0
2953 WO = 1
2954 RW = 2
2955 AC = 3
2956 CE = 1<<19
2957
Rahul Jha94306522018-09-10 23:51:04 +05302958 class Color(IntFlag):
2959 BLACK = 0
2960 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002961 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302962 GREEN = 2
2963 BLUE = 4
2964 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002965 WHITE = RED|GREEN|BLUE
2966 BLANCO = RED|GREEN|BLUE
2967
2968 class Skip(IntFlag):
2969 FIRST = 1
2970 SECOND = 2
2971 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302972
Ethan Furman3515dcc2016-09-18 13:15:41 -07002973 def test_type(self):
2974 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002975 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002976 Open = self.Open
2977 for f in Perm:
2978 self.assertTrue(isinstance(f, Perm))
2979 self.assertEqual(f, f.value)
2980 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2981 self.assertEqual(Perm.W | Perm.X, 3)
2982 for f in Open:
2983 self.assertTrue(isinstance(f, Open))
2984 self.assertEqual(f, f.value)
2985 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2986 self.assertEqual(Open.WO | Open.RW, 3)
2987
2988
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002989 def test_str(self):
2990 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002991 self.assertEqual(str(Perm.R), 'R')
2992 self.assertEqual(str(Perm.W), 'W')
2993 self.assertEqual(str(Perm.X), 'X')
2994 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2995 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002996 self.assertEqual(str(Perm.R | 8), '12')
2997 self.assertEqual(str(Perm(0)), 'Perm(0)')
2998 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002999 self.assertEqual(str(~Perm.R), 'W|X')
3000 self.assertEqual(str(~Perm.W), 'R|X')
3001 self.assertEqual(str(~Perm.X), 'R|W')
3002 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003003 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3004 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003005 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003006 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003007
3008 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003009 self.assertEqual(str(Open.RO), 'RO')
3010 self.assertEqual(str(Open.WO), 'WO')
3011 self.assertEqual(str(Open.AC), 'AC')
3012 self.assertEqual(str(Open.RO | Open.CE), 'CE')
3013 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003014 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003015 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3016 self.assertEqual(str(~Open.WO), 'RW|CE')
3017 self.assertEqual(str(~Open.AC), 'CE')
3018 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3019 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003020 self.assertEqual(str(Open(~4)), '-5')
3021
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003022 def test_repr(self):
3023 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003024 self.assertEqual(repr(Perm.R), 'Perm.R')
3025 self.assertEqual(repr(Perm.W), 'Perm.W')
3026 self.assertEqual(repr(Perm.X), 'Perm.X')
3027 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3028 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003029 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07003030 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003031 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003032 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3033 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3034 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3035 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3036 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003037 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003038 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003039 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003040
3041 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003042 self.assertEqual(repr(Open.RO), 'Open.RO')
3043 self.assertEqual(repr(Open.WO), 'Open.WO')
3044 self.assertEqual(repr(Open.AC), 'Open.AC')
3045 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3046 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003047 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003048 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3049 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3050 self.assertEqual(repr(~Open.AC), 'Open.CE')
3051 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3052 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003053 self.assertEqual(repr(Open(~4)), '-5')
3054
Ethan Furman6bd92882021-04-27 13:05:08 -07003055 @unittest.skipUnless(
3056 python_version < (3, 12),
3057 'mixin-format now uses member instead of member.value',
3058 )
Ethan Furman37440ee2020-12-08 11:14:10 -08003059 def test_format(self):
Ethan Furman6bd92882021-04-27 13:05:08 -07003060 with self.assertWarns(DeprecationWarning):
3061 Perm = self.Perm
3062 self.assertEqual(format(Perm.R, ''), '4')
3063 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08003064
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003065 def test_or(self):
3066 Perm = self.Perm
3067 for i in Perm:
3068 for j in Perm:
3069 self.assertEqual(i | j, i.value | j.value)
3070 self.assertEqual((i | j).value, i.value | j.value)
3071 self.assertIs(type(i | j), Perm)
3072 for j in range(8):
3073 self.assertEqual(i | j, i.value | j)
3074 self.assertEqual((i | j).value, i.value | j)
3075 self.assertIs(type(i | j), Perm)
3076 self.assertEqual(j | i, j | i.value)
3077 self.assertEqual((j | i).value, j | i.value)
3078 self.assertIs(type(j | i), Perm)
3079 for i in Perm:
3080 self.assertIs(i | i, i)
3081 self.assertIs(i | 0, i)
3082 self.assertIs(0 | i, i)
3083 Open = self.Open
3084 self.assertIs(Open.RO | Open.CE, Open.CE)
3085
3086 def test_and(self):
3087 Perm = self.Perm
3088 RW = Perm.R | Perm.W
3089 RX = Perm.R | Perm.X
3090 WX = Perm.W | Perm.X
3091 RWX = Perm.R | Perm.W | Perm.X
3092 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3093 for i in values:
3094 for j in values:
3095 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3096 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3097 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3098 for j in range(8):
3099 self.assertEqual(i & j, i.value & j)
3100 self.assertEqual((i & j).value, i.value & j)
3101 self.assertIs(type(i & j), Perm)
3102 self.assertEqual(j & i, j & i.value)
3103 self.assertEqual((j & i).value, j & i.value)
3104 self.assertIs(type(j & i), Perm)
3105 for i in Perm:
3106 self.assertIs(i & i, i)
3107 self.assertIs(i & 7, i)
3108 self.assertIs(7 & i, i)
3109 Open = self.Open
3110 self.assertIs(Open.RO & Open.CE, Open.RO)
3111
3112 def test_xor(self):
3113 Perm = self.Perm
3114 for i in Perm:
3115 for j in Perm:
3116 self.assertEqual(i ^ j, i.value ^ j.value)
3117 self.assertEqual((i ^ j).value, i.value ^ j.value)
3118 self.assertIs(type(i ^ j), Perm)
3119 for j in range(8):
3120 self.assertEqual(i ^ j, i.value ^ j)
3121 self.assertEqual((i ^ j).value, i.value ^ j)
3122 self.assertIs(type(i ^ j), Perm)
3123 self.assertEqual(j ^ i, j ^ i.value)
3124 self.assertEqual((j ^ i).value, j ^ i.value)
3125 self.assertIs(type(j ^ i), Perm)
3126 for i in Perm:
3127 self.assertIs(i ^ 0, i)
3128 self.assertIs(0 ^ i, i)
3129 Open = self.Open
3130 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3131 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3132
3133 def test_invert(self):
3134 Perm = self.Perm
3135 RW = Perm.R | Perm.W
3136 RX = Perm.R | Perm.X
3137 WX = Perm.W | Perm.X
3138 RWX = Perm.R | Perm.W | Perm.X
3139 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3140 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003141 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003142 self.assertIs(type(~i), Perm)
3143 self.assertEqual(~~i, i)
3144 for i in Perm:
3145 self.assertIs(~~i, i)
3146 Open = self.Open
3147 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3148 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3149
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003150 def test_boundary(self):
3151 self.assertIs(enum.IntFlag._boundary_, EJECT)
3152 class Iron(IntFlag, boundary=STRICT):
3153 ONE = 1
3154 TWO = 2
3155 EIGHT = 8
3156 self.assertIs(Iron._boundary_, STRICT)
3157 #
3158 class Water(IntFlag, boundary=CONFORM):
3159 ONE = 1
3160 TWO = 2
3161 EIGHT = 8
3162 self.assertIs(Water._boundary_, CONFORM)
3163 #
3164 class Space(IntFlag, boundary=EJECT):
3165 ONE = 1
3166 TWO = 2
3167 EIGHT = 8
3168 self.assertIs(Space._boundary_, EJECT)
3169 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003170 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003171 class Bizarre(IntFlag, boundary=KEEP):
3172 b = 3
3173 c = 4
3174 d = 6
3175 #
3176 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003177 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003178 self.assertIs(Water(7), Water.ONE|Water.TWO)
3179 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003180 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003181 self.assertEqual(Space(7), 7)
3182 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003183 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003184 self.assertEqual(list(Bizarre), [Bizarre.c])
3185 self.assertIs(Bizarre(3), Bizarre.b)
3186 self.assertIs(Bizarre(6), Bizarre.d)
3187
3188 def test_iter(self):
3189 Color = self.Color
3190 Open = self.Open
3191 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3192 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3193
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003194 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003195 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003196 lst = list(Perm)
3197 self.assertEqual(len(lst), len(Perm))
3198 self.assertEqual(len(Perm), 3, Perm)
3199 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3200 for i, n in enumerate('R W X'.split()):
3201 v = 1<<i
3202 e = Perm(v)
3203 self.assertEqual(e.value, v)
3204 self.assertEqual(type(e.value), int)
3205 self.assertEqual(e, v)
3206 self.assertEqual(e.name, n)
3207 self.assertIn(e, Perm)
3208 self.assertIs(type(e), Perm)
3209
3210 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003211 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003212 lst = list(Perm)
3213 self.assertEqual(len(lst), len(Perm))
3214 self.assertEqual(len(Perm), 3, Perm)
3215 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3216 for i, n in enumerate('R W X'.split()):
3217 v = 8<<i
3218 e = Perm(v)
3219 self.assertEqual(e.value, v)
3220 self.assertEqual(type(e.value), int)
3221 self.assertEqual(e, v)
3222 self.assertEqual(e.name, n)
3223 self.assertIn(e, Perm)
3224 self.assertIs(type(e), Perm)
3225
3226 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003227 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003228 lst = list(Perm)
3229 self.assertEqual(len(lst), len(Perm))
3230 self.assertEqual(len(Perm), 3, Perm)
3231 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3232 for i, n in enumerate('R W X'.split()):
3233 v = 1<<i
3234 e = Perm(v)
3235 self.assertEqual(e.value, v)
3236 self.assertEqual(type(e.value), int)
3237 self.assertEqual(e, v)
3238 self.assertEqual(e.name, n)
3239 self.assertIn(e, Perm)
3240 self.assertIs(type(e), Perm)
3241
3242 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003243 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003244 lst = list(Perm)
3245 self.assertEqual(len(lst), len(Perm))
3246 self.assertEqual(len(Perm), 3, Perm)
3247 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3248 for i, n in enumerate('R W X'.split()):
3249 v = 1<<(2*i+1)
3250 e = Perm(v)
3251 self.assertEqual(e.value, v)
3252 self.assertEqual(type(e.value), int)
3253 self.assertEqual(e, v)
3254 self.assertEqual(e.name, n)
3255 self.assertIn(e, Perm)
3256 self.assertIs(type(e), Perm)
3257
3258 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003259 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003260 lst = list(Perm)
3261 self.assertEqual(len(lst), len(Perm))
3262 self.assertEqual(len(Perm), 3, Perm)
3263 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3264 for i, n in enumerate('R W X'.split()):
3265 v = 1<<(2*i+1)
3266 e = Perm(v)
3267 self.assertEqual(e.value, v)
3268 self.assertEqual(type(e.value), int)
3269 self.assertEqual(e, v)
3270 self.assertEqual(e.name, n)
3271 self.assertIn(e, Perm)
3272 self.assertIs(type(e), Perm)
3273
3274
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003275 def test_programatic_function_from_empty_list(self):
3276 Perm = enum.IntFlag('Perm', [])
3277 lst = list(Perm)
3278 self.assertEqual(len(lst), len(Perm))
3279 self.assertEqual(len(Perm), 0, Perm)
3280 Thing = enum.Enum('Thing', [])
3281 lst = list(Thing)
3282 self.assertEqual(len(lst), len(Thing))
3283 self.assertEqual(len(Thing), 0, Thing)
3284
3285
3286 def test_programatic_function_from_empty_tuple(self):
3287 Perm = enum.IntFlag('Perm', ())
3288 lst = list(Perm)
3289 self.assertEqual(len(lst), len(Perm))
3290 self.assertEqual(len(Perm), 0, Perm)
3291 Thing = enum.Enum('Thing', ())
3292 self.assertEqual(len(lst), len(Thing))
3293 self.assertEqual(len(Thing), 0, Thing)
3294
Ethan Furman6bd92882021-04-27 13:05:08 -07003295 @unittest.skipIf(
3296 python_version >= (3, 12),
3297 '__contains__ now returns True/False for all inputs',
3298 )
3299 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303300 Open = self.Open
3301 Color = self.Color
3302 self.assertTrue(Color.GREEN in Color)
3303 self.assertTrue(Open.RW in Open)
3304 self.assertFalse(Color.GREEN in Open)
3305 self.assertFalse(Open.RW in Color)
3306 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003307 with self.assertWarns(DeprecationWarning):
3308 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303309 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003310 with self.assertWarns(DeprecationWarning):
3311 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05303312 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003313 with self.assertWarns(DeprecationWarning):
3314 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05303315 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003316 with self.assertWarns(DeprecationWarning):
3317 2 in Open
3318
3319 @unittest.skipIf(
3320 python_version < (3, 12),
3321 '__contains__ only works with enum memmbers before 3.12',
3322 )
3323 def test_contains_tf(self):
3324 Open = self.Open
3325 Color = self.Color
3326 self.assertTrue(Color.GREEN in Color)
3327 self.assertTrue(Open.RW in Open)
3328 self.assertTrue(Color.GREEN in Open)
3329 self.assertTrue(Open.RW in Color)
3330 self.assertFalse('GREEN' in Color)
3331 self.assertFalse('RW' in Open)
3332 self.assertTrue(2 in Color)
3333 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303334
3335 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003336 Perm = self.Perm
3337 R, W, X = Perm
3338 RW = R | W
3339 RX = R | X
3340 WX = W | X
3341 RWX = R | W | X
3342 self.assertTrue(R in RW)
3343 self.assertTrue(R in RX)
3344 self.assertTrue(R in RWX)
3345 self.assertTrue(W in RW)
3346 self.assertTrue(W in WX)
3347 self.assertTrue(W in RWX)
3348 self.assertTrue(X in RX)
3349 self.assertTrue(X in WX)
3350 self.assertTrue(X in RWX)
3351 self.assertFalse(R in WX)
3352 self.assertFalse(W in RX)
3353 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303354 with self.assertRaises(TypeError):
3355 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003356
Ethan Furman7219e272020-09-16 13:01:00 -07003357 def test_member_iter(self):
3358 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003359 self.assertEqual(list(Color.BLACK), [])
3360 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003361 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3362 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003363 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3364
3365 def test_member_length(self):
3366 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3367 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3368 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3369 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3370
3371 def test_aliases(self):
3372 Color = self.Color
3373 self.assertEqual(Color(1).name, 'RED')
3374 self.assertEqual(Color['ROJO'].name, 'RED')
3375 self.assertEqual(Color(7).name, 'WHITE')
3376 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3377 self.assertIs(Color.BLANCO, Color.WHITE)
3378 Open = self.Open
3379 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003380
Ethan Furman25d94bb2016-09-02 16:32:32 -07003381 def test_bool(self):
3382 Perm = self.Perm
3383 for f in Perm:
3384 self.assertTrue(f)
3385 Open = self.Open
3386 for f in Open:
3387 self.assertEqual(bool(f.value), bool(f))
3388
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003389
Ethan Furman5bdab642018-09-21 19:03:09 -07003390 def test_multiple_mixin(self):
3391 class AllMixin:
3392 @classproperty
3393 def ALL(cls):
3394 members = list(cls)
3395 all_value = None
3396 if members:
3397 all_value = members[0]
3398 for member in members[1:]:
3399 all_value |= member
3400 cls.ALL = all_value
3401 return all_value
3402 class StrMixin:
3403 def __str__(self):
3404 return self._name_.lower()
3405 class Color(AllMixin, IntFlag):
3406 RED = auto()
3407 GREEN = auto()
3408 BLUE = auto()
3409 self.assertEqual(Color.RED.value, 1)
3410 self.assertEqual(Color.GREEN.value, 2)
3411 self.assertEqual(Color.BLUE.value, 4)
3412 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003413 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003414 class Color(AllMixin, StrMixin, IntFlag):
3415 RED = auto()
3416 GREEN = auto()
3417 BLUE = auto()
3418 self.assertEqual(Color.RED.value, 1)
3419 self.assertEqual(Color.GREEN.value, 2)
3420 self.assertEqual(Color.BLUE.value, 4)
3421 self.assertEqual(Color.ALL.value, 7)
3422 self.assertEqual(str(Color.BLUE), 'blue')
3423 class Color(StrMixin, AllMixin, IntFlag):
3424 RED = auto()
3425 GREEN = auto()
3426 BLUE = auto()
3427 self.assertEqual(Color.RED.value, 1)
3428 self.assertEqual(Color.GREEN.value, 2)
3429 self.assertEqual(Color.BLUE.value, 4)
3430 self.assertEqual(Color.ALL.value, 7)
3431 self.assertEqual(str(Color.BLUE), 'blue')
3432
Hai Shie80697d2020-05-28 06:10:27 +08003433 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003434 def test_unique_composite(self):
3435 # override __eq__ to be identity only
3436 class TestFlag(IntFlag):
3437 one = auto()
3438 two = auto()
3439 three = auto()
3440 four = auto()
3441 five = auto()
3442 six = auto()
3443 seven = auto()
3444 eight = auto()
3445 def __eq__(self, other):
3446 return self is other
3447 def __hash__(self):
3448 return hash(self._value_)
3449 # have multiple threads competing to complete the composite members
3450 seen = set()
3451 failed = False
3452 def cycle_enum():
3453 nonlocal failed
3454 try:
3455 for i in range(256):
3456 seen.add(TestFlag(i))
3457 except Exception:
3458 failed = True
3459 threads = [
3460 threading.Thread(target=cycle_enum)
3461 for _ in range(8)
3462 ]
Hai Shie80697d2020-05-28 06:10:27 +08003463 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003464 pass
3465 # check that only 248 members were created
3466 self.assertFalse(
3467 failed,
3468 'at least one thread failed while creating composite members')
3469 self.assertEqual(256, len(seen), 'too many composite members created')
3470
3471
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003472class TestEmptyAndNonLatinStrings(unittest.TestCase):
3473
3474 def test_empty_string(self):
3475 with self.assertRaises(ValueError):
3476 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3477
3478 def test_non_latin_character_string(self):
3479 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3480 item = getattr(greek_abc, '\u03B1')
3481 self.assertEqual(item.value, 1)
3482
3483 def test_non_latin_number_string(self):
3484 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3485 item = getattr(hebrew_123, '\u05D0')
3486 self.assertEqual(item.value, 1)
3487
3488
Ethan Furmanf24bb352013-07-18 17:05:39 -07003489class TestUnique(unittest.TestCase):
3490
3491 def test_unique_clean(self):
3492 @unique
3493 class Clean(Enum):
3494 one = 1
3495 two = 'dos'
3496 tres = 4.0
Ethan Furman74964862021-06-10 07:24:20 -07003497 #
Ethan Furmanf24bb352013-07-18 17:05:39 -07003498 @unique
3499 class Cleaner(IntEnum):
3500 single = 1
3501 double = 2
3502 triple = 3
3503
3504 def test_unique_dirty(self):
3505 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3506 @unique
3507 class Dirty(Enum):
3508 one = 1
3509 two = 'dos'
3510 tres = 1
3511 with self.assertRaisesRegex(
3512 ValueError,
3513 'double.*single.*turkey.*triple',
3514 ):
3515 @unique
3516 class Dirtier(IntEnum):
3517 single = 1
3518 double = 1
3519 triple = 3
3520 turkey = 3
3521
Ethan Furman3803ad42016-05-01 10:03:53 -07003522 def test_unique_with_name(self):
Ethan Furman74964862021-06-10 07:24:20 -07003523 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003524 class Silly(Enum):
3525 one = 1
3526 two = 'dos'
3527 name = 3
Ethan Furman74964862021-06-10 07:24:20 -07003528 #
3529 @verify(UNIQUE)
3530 class Sillier(IntEnum):
3531 single = 1
3532 name = 2
3533 triple = 3
3534 value = 4
3535
3536class TestVerify(unittest.TestCase):
3537
3538 def test_continuous(self):
3539 @verify(CONTINUOUS)
3540 class Auto(Enum):
3541 FIRST = auto()
3542 SECOND = auto()
3543 THIRD = auto()
3544 FORTH = auto()
3545 #
3546 @verify(CONTINUOUS)
3547 class Manual(Enum):
3548 FIRST = 3
3549 SECOND = 4
3550 THIRD = 5
3551 FORTH = 6
3552 #
3553 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
3554 @verify(CONTINUOUS)
3555 class Missing(Enum):
3556 FIRST = 3
3557 SECOND = 4
3558 THIRD = 11
3559 FORTH = 13
3560 #
3561 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
3562 @verify(CONTINUOUS)
3563 class Incomplete(Flag):
3564 FIRST = 4
3565 SECOND = 8
3566 THIRD = 16
3567 FORTH = 64
3568 #
3569 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
3570 @verify(CONTINUOUS)
3571 class StillIncomplete(Flag):
3572 FIRST = 4
3573 SECOND = 8
3574 THIRD = 11
3575 FORTH = 32
3576
3577
3578 def test_composite(self):
3579 class Bizarre(Flag):
3580 b = 3
3581 c = 4
3582 d = 6
3583 self.assertEqual(list(Bizarre), [Bizarre.c])
3584 self.assertEqual(Bizarre.b.value, 3)
3585 self.assertEqual(Bizarre.c.value, 4)
3586 self.assertEqual(Bizarre.d.value, 6)
3587 with self.assertRaisesRegex(
3588 ValueError,
3589 "invalid Flag 'Bizarre': 'b' is missing named flags for values 1, 2; 'd' is missing a named flag for value 2",
3590 ):
3591 @verify(NAMED_FLAGS)
3592 class Bizarre(Flag):
3593 b = 3
3594 c = 4
3595 d = 6
3596 #
3597 class Bizarre(IntFlag):
3598 b = 3
3599 c = 4
3600 d = 6
3601 self.assertEqual(list(Bizarre), [Bizarre.c])
3602 self.assertEqual(Bizarre.b.value, 3)
3603 self.assertEqual(Bizarre.c.value, 4)
3604 self.assertEqual(Bizarre.d.value, 6)
3605 with self.assertRaisesRegex(
3606 ValueError,
3607 "invalid Flag 'Bizarre': 'b' is missing named flags for values 1, 2; 'd' is missing a named flag for value 2",
3608 ):
3609 @verify(NAMED_FLAGS)
3610 class Bizarre(IntFlag):
3611 b = 3
3612 c = 4
3613 d = 6
3614
3615 def test_unique_clean(self):
3616 @verify(UNIQUE)
3617 class Clean(Enum):
3618 one = 1
3619 two = 'dos'
3620 tres = 4.0
3621 #
3622 @verify(UNIQUE)
3623 class Cleaner(IntEnum):
3624 single = 1
3625 double = 2
3626 triple = 3
3627
3628 def test_unique_dirty(self):
3629 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3630 @verify(UNIQUE)
3631 class Dirty(Enum):
3632 one = 1
3633 two = 'dos'
3634 tres = 1
3635 with self.assertRaisesRegex(
3636 ValueError,
3637 'double.*single.*turkey.*triple',
3638 ):
3639 @verify(UNIQUE)
3640 class Dirtier(IntEnum):
3641 single = 1
3642 double = 1
3643 triple = 3
3644 turkey = 3
3645
3646 def test_unique_with_name(self):
3647 @verify(UNIQUE)
3648 class Silly(Enum):
3649 one = 1
3650 two = 'dos'
3651 name = 3
3652 #
3653 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003654 class Sillier(IntEnum):
3655 single = 1
3656 name = 2
3657 triple = 3
3658 value = 4
3659
Ethan Furmanec099732021-04-15 06:58:33 -07003660class TestHelpers(unittest.TestCase):
3661
3662 sunder_names = '_bad_', '_good_', '_what_ho_'
3663 dunder_names = '__mal__', '__bien__', '__que_que__'
3664 private_names = '_MyEnum__private', '_MyEnum__still_private'
3665 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3666 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3667
3668 def test_sunder(self):
3669 for name in self.sunder_names + self.private_and_sunder_names:
3670 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3671 for name in self.dunder_names + self.private_names + self.random_names:
3672 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3673
3674 def test_dunder(self):
3675 for name in self.dunder_names:
3676 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3677 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3678 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3679
3680 def test_is_private(self):
3681 for name in self.private_names + self.private_and_sunder_names:
3682 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3683 for name in self.sunder_names + self.dunder_names + self.random_names:
3684 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003685
Ethan Furmanb7751062021-03-30 21:17:26 -07003686class TestEnumTypeSubclassing(unittest.TestCase):
3687 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003688
Ethan Furman3323da92015-04-11 09:39:59 -07003689expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003690Help on class Color in module %s:
3691
3692class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003693 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003694 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003695 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003696 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003697 | Method resolution order:
3698 | Color
3699 | enum.Enum
3700 | builtins.object
3701 |\x20\x20
3702 | Data and other attributes defined here:
3703 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003704 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003705 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003706 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003707 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003708 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003709 |\x20\x20
3710 | ----------------------------------------------------------------------
3711 | Data descriptors inherited from enum.Enum:
3712 |\x20\x20
3713 | name
3714 | The name of the Enum member.
3715 |\x20\x20
3716 | value
3717 | The value of the Enum member.
3718 |\x20\x20
3719 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003720 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003721 |\x20\x20
3722 | __members__
3723 | Returns a mapping of member name->value.
3724 |\x20\x20\x20\x20\x20\x20
3725 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003726 | is a read-only view of the internal mapping."""
3727
3728expected_help_output_without_docs = """\
3729Help on class Color in module %s:
3730
3731class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003732 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3733 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003734 | Method resolution order:
3735 | Color
3736 | enum.Enum
3737 | builtins.object
3738 |\x20\x20
3739 | Data and other attributes defined here:
3740 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003741 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003742 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003743 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003744 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003745 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003746 |\x20\x20
3747 | ----------------------------------------------------------------------
3748 | Data descriptors inherited from enum.Enum:
3749 |\x20\x20
3750 | name
3751 |\x20\x20
3752 | value
3753 |\x20\x20
3754 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003755 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003756 |\x20\x20
3757 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003758
3759class TestStdLib(unittest.TestCase):
3760
Ethan Furman48a724f2015-04-11 23:23:06 -07003761 maxDiff = None
3762
Ethan Furman5875d742013-10-21 20:45:55 -07003763 class Color(Enum):
3764 red = 1
3765 green = 2
3766 blue = 3
3767
3768 def test_pydoc(self):
3769 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003770 if StrEnum.__doc__ is None:
3771 expected_text = expected_help_output_without_docs % __name__
3772 else:
3773 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003774 output = StringIO()
3775 helper = pydoc.Helper(output=output)
3776 helper(self.Color)
3777 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003778 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003779
3780 def test_inspect_getmembers(self):
3781 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003782 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003783 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003784 ('__members__', self.Color.__members__),
3785 ('__module__', __name__),
3786 ('blue', self.Color.blue),
3787 ('green', self.Color.green),
3788 ('name', Enum.__dict__['name']),
3789 ('red', self.Color.red),
3790 ('value', Enum.__dict__['value']),
3791 ))
3792 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003793 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003794 failed = False
3795 for k in values.keys():
3796 if result[k] != values[k]:
3797 print()
3798 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3799 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3800 failed = True
3801 if failed:
3802 self.fail("result does not equal expected, see print above")
3803
3804 def test_inspect_classify_class_attrs(self):
3805 # indirectly test __objclass__
3806 from inspect import Attribute
3807 values = [
3808 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003809 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003810 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003811 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003812 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003813 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003814 Attribute(name='__module__', kind='data',
3815 defining_class=self.Color, object=__name__),
3816 Attribute(name='blue', kind='data',
3817 defining_class=self.Color, object=self.Color.blue),
3818 Attribute(name='green', kind='data',
3819 defining_class=self.Color, object=self.Color.green),
3820 Attribute(name='red', kind='data',
3821 defining_class=self.Color, object=self.Color.red),
3822 Attribute(name='name', kind='data',
3823 defining_class=Enum, object=Enum.__dict__['name']),
3824 Attribute(name='value', kind='data',
3825 defining_class=Enum, object=Enum.__dict__['value']),
3826 ]
3827 values.sort(key=lambda item: item.name)
3828 result = list(inspect.classify_class_attrs(self.Color))
3829 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003830 self.assertEqual(
3831 len(values), len(result),
3832 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3833 )
Ethan Furman5875d742013-10-21 20:45:55 -07003834 failed = False
3835 for v, r in zip(values, result):
3836 if r != v:
3837 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3838 failed = True
3839 if failed:
3840 self.fail("result does not equal expected, see print above")
3841
Ethan Furmana02cb472021-04-21 10:20:44 -07003842 def test_test_simple_enum(self):
3843 @_simple_enum(Enum)
3844 class SimpleColor:
3845 RED = 1
3846 GREEN = 2
3847 BLUE = 3
3848 class CheckedColor(Enum):
3849 RED = 1
3850 GREEN = 2
3851 BLUE = 3
3852 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3853 SimpleColor.GREEN._value_ = 9
3854 self.assertRaisesRegex(
3855 TypeError, "enum mismatch",
3856 _test_simple_enum, CheckedColor, SimpleColor,
3857 )
3858 class CheckedMissing(IntFlag, boundary=KEEP):
3859 SIXTY_FOUR = 64
3860 ONE_TWENTY_EIGHT = 128
3861 TWENTY_FORTY_EIGHT = 2048
3862 ALL = 2048 + 128 + 64 + 12
3863 CM = CheckedMissing
3864 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3865 #
3866 @_simple_enum(IntFlag, boundary=KEEP)
3867 class Missing:
3868 SIXTY_FOUR = 64
3869 ONE_TWENTY_EIGHT = 128
3870 TWENTY_FORTY_EIGHT = 2048
3871 ALL = 2048 + 128 + 64 + 12
3872 M = Missing
3873 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3874 #
3875 _test_simple_enum(CheckedMissing, Missing)
3876
Martin Panter19e69c52015-11-14 12:46:42 +00003877
3878class MiscTestCase(unittest.TestCase):
3879 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003880 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003881
3882
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003883# These are unordered here on purpose to ensure that declaration order
3884# makes no difference.
3885CONVERT_TEST_NAME_D = 5
3886CONVERT_TEST_NAME_C = 5
3887CONVERT_TEST_NAME_B = 5
3888CONVERT_TEST_NAME_A = 5 # This one should sort first.
3889CONVERT_TEST_NAME_E = 5
3890CONVERT_TEST_NAME_F = 5
3891
Ethan Furmana02cb472021-04-21 10:20:44 -07003892CONVERT_STRING_TEST_NAME_D = 5
3893CONVERT_STRING_TEST_NAME_C = 5
3894CONVERT_STRING_TEST_NAME_B = 5
3895CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3896CONVERT_STRING_TEST_NAME_E = 5
3897CONVERT_STRING_TEST_NAME_F = 5
3898
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003899class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003900 def setUp(self):
3901 # Reset the module-level test variables to their original integer
3902 # values, otherwise the already created enum values get converted
3903 # instead.
3904 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3905 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3906 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3907
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003908 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003909 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003910 'UnittestConvert',
3911 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003912 filter=lambda x: x.startswith('CONVERT_TEST_'))
3913 # We don't want the reverse lookup value to vary when there are
3914 # multiple possible names for a given value. It should always
3915 # report the first lexigraphical name in that case.
3916 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3917
3918 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003919 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003920 'UnittestConvert',
3921 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003922 filter=lambda x: x.startswith('CONVERT_TEST_'))
3923 # Ensure that test_type has all of the desired names and values.
3924 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3925 test_type.CONVERT_TEST_NAME_A)
3926 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3927 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3928 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3929 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3930 # Ensure that test_type only picked up names matching the filter.
3931 self.assertEqual([name for name in dir(test_type)
3932 if name[0:2] not in ('CO', '__')],
3933 [], msg='Names other than CONVERT_TEST_* found.')
3934
Ethan Furman6bd92882021-04-27 13:05:08 -07003935 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003936 '_convert was deprecated in 3.8')
3937 def test_convert_warn(self):
3938 with self.assertWarns(DeprecationWarning):
3939 enum.IntEnum._convert(
3940 'UnittestConvert',
3941 ('test.test_enum', '__main__')[__name__=='__main__'],
3942 filter=lambda x: x.startswith('CONVERT_TEST_'))
3943
Ethan Furman6bd92882021-04-27 13:05:08 -07003944 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003945 '_convert was removed in 3.9')
3946 def test_convert_raise(self):
3947 with self.assertRaises(AttributeError):
3948 enum.IntEnum._convert(
3949 'UnittestConvert',
3950 ('test.test_enum', '__main__')[__name__=='__main__'],
3951 filter=lambda x: x.startswith('CONVERT_TEST_'))
3952
Ethan Furman6bd92882021-04-27 13:05:08 -07003953 @unittest.skipUnless(
3954 python_version < (3, 12),
3955 'mixin-format now uses member instead of member.value',
3956 )
Ethan Furmanb7751062021-03-30 21:17:26 -07003957 def test_convert_repr_and_str(self):
3958 module = ('test.test_enum', '__main__')[__name__=='__main__']
3959 test_type = enum.IntEnum._convert_(
3960 'UnittestConvert',
3961 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003962 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3963 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3964 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman6bd92882021-04-27 13:05:08 -07003965 with self.assertWarns(DeprecationWarning):
3966 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003967
3968# global names for StrEnum._convert_ test
3969CONVERT_STR_TEST_2 = 'goodbye'
3970CONVERT_STR_TEST_1 = 'hello'
3971
3972class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003973 def setUp(self):
3974 global CONVERT_STR_TEST_1
3975 global CONVERT_STR_TEST_2
3976 CONVERT_STR_TEST_2 = 'goodbye'
3977 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07003978
3979 def test_convert(self):
3980 test_type = enum.StrEnum._convert_(
3981 'UnittestConvert',
3982 ('test.test_enum', '__main__')[__name__=='__main__'],
3983 filter=lambda x: x.startswith('CONVERT_STR_'))
3984 # Ensure that test_type has all of the desired names and values.
3985 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3986 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3987 # Ensure that test_type only picked up names matching the filter.
3988 self.assertEqual([name for name in dir(test_type)
3989 if name[0:2] not in ('CO', '__')],
3990 [], msg='Names other than CONVERT_STR_* found.')
3991
3992 def test_convert_repr_and_str(self):
3993 module = ('test.test_enum', '__main__')[__name__=='__main__']
3994 test_type = enum.StrEnum._convert_(
3995 'UnittestConvert',
3996 module,
3997 filter=lambda x: x.startswith('CONVERT_STR_'))
3998 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3999 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
4000 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
4001
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004002
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004003if __name__ == '__main__':
4004 unittest.main()