blob: ceb0da8c77ba3c80ae2951656e6878bc7df62dac [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):
Miss Islington (bot)01286012021-06-10 15:01:03 -07002161 unknown = cls._member_type_.__new__(cls, value)
2162 unknown._valid = False
2163 unknown._name_ = value.upper()
2164 unknown._value_ = value
2165 cls._member_map_[value] = unknown
2166 return unknown
2167 @property
2168 def valid(self):
2169 return self._valid
2170 #
2171 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2172 ACTIVE = "active"
2173 PENDING = "pending"
2174 TERMINATED = "terminated"
2175 #
2176 JS = JobStatus
2177 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2178 self.assertEqual(JS.ACTIVE, 'active')
2179 self.assertEqual(JS.ACTIVE.value, 'active')
2180 self.assertIs(JS('Active'), JS.ACTIVE)
2181 self.assertTrue(JS.ACTIVE.valid)
2182 missing = JS('missing')
2183 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2184 self.assertEqual(JS.ACTIVE, 'active')
2185 self.assertEqual(JS.ACTIVE.value, 'active')
2186 self.assertIs(JS('Active'), JS.ACTIVE)
2187 self.assertTrue(JS.ACTIVE.valid)
2188 self.assertTrue(isinstance(missing, JS))
2189 self.assertFalse(missing.valid)
2190
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002191 def test_empty_globals(self):
2192 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2193 # when using compile and exec because f_globals is empty
2194 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2195 code = compile(code, "<string>", "exec")
2196 global_ns = {}
2197 local_ls = {}
2198 exec(code, global_ns, local_ls)
2199
Ethan Furman0063ff42020-09-21 17:23:13 -07002200 def test_strenum(self):
2201 class GoodStrEnum(StrEnum):
2202 one = '1'
2203 two = '2'
2204 three = b'3', 'ascii'
2205 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002206 self.assertEqual(GoodStrEnum.one, '1')
2207 self.assertEqual(str(GoodStrEnum.one), '1')
2208 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2209 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2210 #
2211 class DumbMixin:
2212 def __str__(self):
2213 return "don't do this"
2214 class DumbStrEnum(DumbMixin, StrEnum):
2215 five = '5'
2216 six = '6'
2217 seven = '7'
2218 self.assertEqual(DumbStrEnum.seven, '7')
2219 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2220 #
2221 class EnumMixin(Enum):
2222 def hello(self):
2223 print('hello from %s' % (self, ))
2224 class HelloEnum(EnumMixin, StrEnum):
2225 eight = '8'
2226 self.assertEqual(HelloEnum.eight, '8')
2227 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2228 #
2229 class GoodbyeMixin:
2230 def goodbye(self):
2231 print('%s wishes you a fond farewell')
2232 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2233 nine = '9'
2234 self.assertEqual(GoodbyeEnum.nine, '9')
2235 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2236 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002237 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2238 class FirstFailedStrEnum(StrEnum):
2239 one = 1
2240 two = '2'
2241 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2242 class SecondFailedStrEnum(StrEnum):
2243 one = '1'
2244 two = 2,
2245 three = '3'
2246 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2247 class ThirdFailedStrEnum(StrEnum):
2248 one = '1'
2249 two = 2
2250 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2251 class ThirdFailedStrEnum(StrEnum):
2252 one = '1'
2253 two = b'2', sys.getdefaultencoding
2254 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2255 class ThirdFailedStrEnum(StrEnum):
2256 one = '1'
2257 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002258
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002259 def test_missing_value_error(self):
2260 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2261 class Combined(str, Enum):
2262 #
2263 def __new__(cls, value, sequence):
2264 enum = str.__new__(cls, value)
2265 if '(' in value:
2266 fis_name, segment = value.split('(', 1)
2267 segment = segment.strip(' )')
2268 else:
2269 fis_name = value
2270 segment = None
2271 enum.fis_name = fis_name
2272 enum.segment = segment
2273 enum.sequence = sequence
2274 return enum
2275 #
2276 def __repr__(self):
2277 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2278 #
2279 key_type = 'An$(1,2)', 0
2280 company_id = 'An$(3,2)', 1
2281 code = 'An$(5,1)', 2
2282 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002283
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002284 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002285 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002286 'private variables are now normal attributes',
2287 )
2288 def test_warning_for_private_variables(self):
2289 with self.assertWarns(DeprecationWarning):
2290 class Private(Enum):
2291 __corporal = 'Radar'
2292 self.assertEqual(Private._Private__corporal.value, 'Radar')
2293 try:
2294 with self.assertWarns(DeprecationWarning):
2295 class Private(Enum):
2296 __major_ = 'Hoolihan'
2297 except ValueError:
2298 pass
2299
2300 def test_private_variable_is_normal_attribute(self):
2301 class Private(Enum):
2302 __corporal = 'Radar'
2303 __major_ = 'Hoolihan'
2304 self.assertEqual(Private._Private__corporal, 'Radar')
2305 self.assertEqual(Private._Private__major_, 'Hoolihan')
2306
Ethan Furmand65b9032021-02-08 17:32:38 -08002307 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002308 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002309 'member-member access now raises an exception',
2310 )
2311 def test_warning_for_member_from_member_access(self):
2312 with self.assertWarns(DeprecationWarning):
2313 class Di(Enum):
2314 YES = 1
2315 NO = 0
2316 nope = Di.YES.NO
2317 self.assertIs(Di.NO, nope)
2318
2319 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002320 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002321 'member-member access currently issues a warning',
2322 )
2323 def test_exception_for_member_from_member_access(self):
2324 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2325 class Di(Enum):
2326 YES = 1
2327 NO = 0
2328 nope = Di.YES.NO
2329
Ethan Furmanefb13be2020-12-10 12:20:06 -08002330 def test_strenum_auto(self):
2331 class Strings(StrEnum):
2332 ONE = auto()
2333 TWO = auto()
2334 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2335
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002336
Ethan Furmana6582872020-12-10 13:07:00 -08002337 def test_dynamic_members_with_static_methods(self):
2338 #
2339 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2340 class Foo(Enum):
2341 vars().update({
2342 k: v
2343 for k, v in foo_defines.items()
2344 if k.startswith('FOO_')
2345 })
2346 def upper(self):
2347 return self.value.upper()
2348 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2349 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2350 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2351 #
2352 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2353 class FooBar(Enum):
2354 vars().update({
2355 k: v
2356 for k, v in foo_defines.items()
2357 if k.startswith('FOO_')
2358 },
2359 **{'FOO_CAT': 'small'},
2360 )
2361 def upper(self):
2362 return self.value.upper()
2363
2364
Ethan Furmane8e61272016-08-20 07:19:31 -07002365class TestOrder(unittest.TestCase):
2366
2367 def test_same_members(self):
2368 class Color(Enum):
2369 _order_ = 'red green blue'
2370 red = 1
2371 green = 2
2372 blue = 3
2373
2374 def test_same_members_with_aliases(self):
2375 class Color(Enum):
2376 _order_ = 'red green blue'
2377 red = 1
2378 green = 2
2379 blue = 3
2380 verde = green
2381
2382 def test_same_members_wrong_order(self):
2383 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2384 class Color(Enum):
2385 _order_ = 'red green blue'
2386 red = 1
2387 blue = 3
2388 green = 2
2389
2390 def test_order_has_extra_members(self):
2391 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2392 class Color(Enum):
2393 _order_ = 'red green blue purple'
2394 red = 1
2395 green = 2
2396 blue = 3
2397
2398 def test_order_has_extra_members_with_aliases(self):
2399 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2400 class Color(Enum):
2401 _order_ = 'red green blue purple'
2402 red = 1
2403 green = 2
2404 blue = 3
2405 verde = green
2406
2407 def test_enum_has_extra_members(self):
2408 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2409 class Color(Enum):
2410 _order_ = 'red green blue'
2411 red = 1
2412 green = 2
2413 blue = 3
2414 purple = 4
2415
2416 def test_enum_has_extra_members_with_aliases(self):
2417 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2418 class Color(Enum):
2419 _order_ = 'red green blue'
2420 red = 1
2421 green = 2
2422 blue = 3
2423 purple = 4
2424 verde = green
2425
2426
Ethan Furman65a5a472016-09-01 23:55:19 -07002427class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002428 """Tests of the Flags."""
2429
Ethan Furman65a5a472016-09-01 23:55:19 -07002430 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002431 R, W, X = 4, 2, 1
2432
Ethan Furman65a5a472016-09-01 23:55:19 -07002433 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002434 RO = 0
2435 WO = 1
2436 RW = 2
2437 AC = 3
2438 CE = 1<<19
2439
Rahul Jha94306522018-09-10 23:51:04 +05302440 class Color(Flag):
2441 BLACK = 0
2442 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002443 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302444 GREEN = 2
2445 BLUE = 4
2446 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002447 WHITE = RED|GREEN|BLUE
2448 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302449
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002450 def test_str(self):
2451 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002452 self.assertEqual(str(Perm.R), 'R')
2453 self.assertEqual(str(Perm.W), 'W')
2454 self.assertEqual(str(Perm.X), 'X')
2455 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2456 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002457 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002458 self.assertEqual(str(~Perm.R), 'W|X')
2459 self.assertEqual(str(~Perm.W), 'R|X')
2460 self.assertEqual(str(~Perm.X), 'R|W')
2461 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002462 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002463 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002464
2465 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002466 self.assertEqual(str(Open.RO), 'RO')
2467 self.assertEqual(str(Open.WO), 'WO')
2468 self.assertEqual(str(Open.AC), 'AC')
2469 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2470 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2471 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2472 self.assertEqual(str(~Open.WO), 'RW|CE')
2473 self.assertEqual(str(~Open.AC), 'CE')
2474 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2475 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002476
2477 def test_repr(self):
2478 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002479 self.assertEqual(repr(Perm.R), 'Perm.R')
2480 self.assertEqual(repr(Perm.W), 'Perm.W')
2481 self.assertEqual(repr(Perm.X), 'Perm.X')
2482 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2483 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2484 self.assertEqual(repr(Perm(0)), '0x0')
2485 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2486 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2487 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2488 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2489 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2490 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002491
2492 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002493 self.assertEqual(repr(Open.RO), 'Open.RO')
2494 self.assertEqual(repr(Open.WO), 'Open.WO')
2495 self.assertEqual(repr(Open.AC), 'Open.AC')
2496 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2497 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2498 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2499 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2500 self.assertEqual(repr(~Open.AC), 'Open.CE')
2501 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2502 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002503
Ethan Furman37440ee2020-12-08 11:14:10 -08002504 def test_format(self):
2505 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002506 self.assertEqual(format(Perm.R, ''), 'R')
2507 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002508
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002509 def test_or(self):
2510 Perm = self.Perm
2511 for i in Perm:
2512 for j in Perm:
2513 self.assertEqual((i | j), Perm(i.value | j.value))
2514 self.assertEqual((i | j).value, i.value | j.value)
2515 self.assertIs(type(i | j), Perm)
2516 for i in Perm:
2517 self.assertIs(i | i, i)
2518 Open = self.Open
2519 self.assertIs(Open.RO | Open.CE, Open.CE)
2520
2521 def test_and(self):
2522 Perm = self.Perm
2523 RW = Perm.R | Perm.W
2524 RX = Perm.R | Perm.X
2525 WX = Perm.W | Perm.X
2526 RWX = Perm.R | Perm.W | Perm.X
2527 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2528 for i in values:
2529 for j in values:
2530 self.assertEqual((i & j).value, i.value & j.value)
2531 self.assertIs(type(i & j), Perm)
2532 for i in Perm:
2533 self.assertIs(i & i, i)
2534 self.assertIs(i & RWX, i)
2535 self.assertIs(RWX & i, i)
2536 Open = self.Open
2537 self.assertIs(Open.RO & Open.CE, Open.RO)
2538
2539 def test_xor(self):
2540 Perm = self.Perm
2541 for i in Perm:
2542 for j in Perm:
2543 self.assertEqual((i ^ j).value, i.value ^ j.value)
2544 self.assertIs(type(i ^ j), Perm)
2545 for i in Perm:
2546 self.assertIs(i ^ Perm(0), i)
2547 self.assertIs(Perm(0) ^ i, i)
2548 Open = self.Open
2549 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2550 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2551
2552 def test_invert(self):
2553 Perm = self.Perm
2554 RW = Perm.R | Perm.W
2555 RX = Perm.R | Perm.X
2556 WX = Perm.W | Perm.X
2557 RWX = Perm.R | Perm.W | Perm.X
2558 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2559 for i in values:
2560 self.assertIs(type(~i), Perm)
2561 self.assertEqual(~~i, i)
2562 for i in Perm:
2563 self.assertIs(~~i, i)
2564 Open = self.Open
2565 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2566 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2567
Ethan Furman25d94bb2016-09-02 16:32:32 -07002568 def test_bool(self):
2569 Perm = self.Perm
2570 for f in Perm:
2571 self.assertTrue(f)
2572 Open = self.Open
2573 for f in Open:
2574 self.assertEqual(bool(f.value), bool(f))
2575
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002576 def test_boundary(self):
2577 self.assertIs(enum.Flag._boundary_, STRICT)
2578 class Iron(Flag, boundary=STRICT):
2579 ONE = 1
2580 TWO = 2
2581 EIGHT = 8
2582 self.assertIs(Iron._boundary_, STRICT)
2583 #
2584 class Water(Flag, boundary=CONFORM):
2585 ONE = 1
2586 TWO = 2
2587 EIGHT = 8
2588 self.assertIs(Water._boundary_, CONFORM)
2589 #
2590 class Space(Flag, boundary=EJECT):
2591 ONE = 1
2592 TWO = 2
2593 EIGHT = 8
2594 self.assertIs(Space._boundary_, EJECT)
2595 #
2596 class Bizarre(Flag, boundary=KEEP):
2597 b = 3
2598 c = 4
2599 d = 6
2600 #
2601 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002602 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002603 self.assertIs(Water(7), Water.ONE|Water.TWO)
2604 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002605 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002606 self.assertEqual(Space(7), 7)
2607 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002608 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002609 self.assertEqual(list(Bizarre), [Bizarre.c])
2610 self.assertIs(Bizarre(3), Bizarre.b)
2611 self.assertIs(Bizarre(6), Bizarre.d)
2612
2613 def test_iter(self):
2614 Color = self.Color
2615 Open = self.Open
2616 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2617 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2618
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002619 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002620 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002621 lst = list(Perm)
2622 self.assertEqual(len(lst), len(Perm))
2623 self.assertEqual(len(Perm), 3, Perm)
2624 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2625 for i, n in enumerate('R W X'.split()):
2626 v = 1<<i
2627 e = Perm(v)
2628 self.assertEqual(e.value, v)
2629 self.assertEqual(type(e.value), int)
2630 self.assertEqual(e.name, n)
2631 self.assertIn(e, Perm)
2632 self.assertIs(type(e), Perm)
2633
2634 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002635 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002636 lst = list(Perm)
2637 self.assertEqual(len(lst), len(Perm))
2638 self.assertEqual(len(Perm), 3, Perm)
2639 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2640 for i, n in enumerate('R W X'.split()):
2641 v = 8<<i
2642 e = Perm(v)
2643 self.assertEqual(e.value, v)
2644 self.assertEqual(type(e.value), int)
2645 self.assertEqual(e.name, n)
2646 self.assertIn(e, Perm)
2647 self.assertIs(type(e), Perm)
2648
2649 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002650 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002651 lst = list(Perm)
2652 self.assertEqual(len(lst), len(Perm))
2653 self.assertEqual(len(Perm), 3, Perm)
2654 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2655 for i, n in enumerate('R W X'.split()):
2656 v = 1<<i
2657 e = Perm(v)
2658 self.assertEqual(e.value, v)
2659 self.assertEqual(type(e.value), int)
2660 self.assertEqual(e.name, n)
2661 self.assertIn(e, Perm)
2662 self.assertIs(type(e), Perm)
2663
2664 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002665 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002666 lst = list(Perm)
2667 self.assertEqual(len(lst), len(Perm))
2668 self.assertEqual(len(Perm), 3, Perm)
2669 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2670 for i, n in enumerate('R W X'.split()):
2671 v = 1<<(2*i+1)
2672 e = Perm(v)
2673 self.assertEqual(e.value, v)
2674 self.assertEqual(type(e.value), int)
2675 self.assertEqual(e.name, n)
2676 self.assertIn(e, Perm)
2677 self.assertIs(type(e), Perm)
2678
2679 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002680 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002681 lst = list(Perm)
2682 self.assertEqual(len(lst), len(Perm))
2683 self.assertEqual(len(Perm), 3, Perm)
2684 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2685 for i, n in enumerate('R W X'.split()):
2686 v = 1<<(2*i+1)
2687 e = Perm(v)
2688 self.assertEqual(e.value, v)
2689 self.assertEqual(type(e.value), int)
2690 self.assertEqual(e.name, n)
2691 self.assertIn(e, Perm)
2692 self.assertIs(type(e), Perm)
2693
Ethan Furman65a5a472016-09-01 23:55:19 -07002694 def test_pickle(self):
2695 if isinstance(FlagStooges, Exception):
2696 raise FlagStooges
2697 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2698 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002699
Ethan Furman6bd92882021-04-27 13:05:08 -07002700 @unittest.skipIf(
2701 python_version >= (3, 12),
2702 '__contains__ now returns True/False for all inputs',
2703 )
2704 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302705 Open = self.Open
2706 Color = self.Color
2707 self.assertFalse(Color.BLACK in Open)
2708 self.assertFalse(Open.RO in Color)
2709 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002710 with self.assertWarns(DeprecationWarning):
2711 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302712 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002713 with self.assertWarns(DeprecationWarning):
2714 'RO' in Open
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 1 in Color
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 Open
2721
2722 @unittest.skipIf(
2723 python_version < (3, 12),
2724 '__contains__ only works with enum memmbers before 3.12',
2725 )
2726 def test_contains_tf(self):
2727 Open = self.Open
2728 Color = self.Color
2729 self.assertFalse(Color.BLACK in Open)
2730 self.assertFalse(Open.RO in Color)
2731 self.assertFalse('BLACK' in Color)
2732 self.assertFalse('RO' in Open)
2733 self.assertTrue(1 in Color)
2734 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302735
2736 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002737 Perm = self.Perm
2738 R, W, X = Perm
2739 RW = R | W
2740 RX = R | X
2741 WX = W | X
2742 RWX = R | W | X
2743 self.assertTrue(R in RW)
2744 self.assertTrue(R in RX)
2745 self.assertTrue(R in RWX)
2746 self.assertTrue(W in RW)
2747 self.assertTrue(W in WX)
2748 self.assertTrue(W in RWX)
2749 self.assertTrue(X in RX)
2750 self.assertTrue(X in WX)
2751 self.assertTrue(X in RWX)
2752 self.assertFalse(R in WX)
2753 self.assertFalse(W in RX)
2754 self.assertFalse(X in RW)
2755
Ethan Furman7219e272020-09-16 13:01:00 -07002756 def test_member_iter(self):
2757 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002758 self.assertEqual(list(Color.BLACK), [])
2759 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002760 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2761 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002762 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2763 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2764
2765 def test_member_length(self):
2766 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2767 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2768 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2769 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2770
2771 def test_number_reset_and_order_cleanup(self):
2772 class Confused(Flag):
2773 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2774 ONE = auto()
2775 TWO = auto()
2776 FOUR = auto()
2777 DOS = 2
2778 EIGHT = auto()
2779 SIXTEEN = auto()
2780 self.assertEqual(
2781 list(Confused),
2782 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2783 self.assertIs(Confused.TWO, Confused.DOS)
2784 self.assertEqual(Confused.DOS._value_, 2)
2785 self.assertEqual(Confused.EIGHT._value_, 8)
2786 self.assertEqual(Confused.SIXTEEN._value_, 16)
2787
2788 def test_aliases(self):
2789 Color = self.Color
2790 self.assertEqual(Color(1).name, 'RED')
2791 self.assertEqual(Color['ROJO'].name, 'RED')
2792 self.assertEqual(Color(7).name, 'WHITE')
2793 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2794 self.assertIs(Color.BLANCO, Color.WHITE)
2795 Open = self.Open
2796 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002797
Ethan Furmanc16595e2016-09-10 23:36:59 -07002798 def test_auto_number(self):
2799 class Color(Flag):
2800 red = auto()
2801 blue = auto()
2802 green = auto()
2803
2804 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2805 self.assertEqual(Color.red.value, 1)
2806 self.assertEqual(Color.blue.value, 2)
2807 self.assertEqual(Color.green.value, 4)
2808
2809 def test_auto_number_garbage(self):
2810 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2811 class Color(Flag):
2812 red = 'not an int'
2813 blue = auto()
2814
Ethan Furman3515dcc2016-09-18 13:15:41 -07002815 def test_duplicate_auto(self):
2816 class Dupes(Enum):
2817 first = primero = auto()
2818 second = auto()
2819 third = auto()
2820 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2821
Ethan Furman5bdab642018-09-21 19:03:09 -07002822 def test_multiple_mixin(self):
2823 class AllMixin:
2824 @classproperty
2825 def ALL(cls):
2826 members = list(cls)
2827 all_value = None
2828 if members:
2829 all_value = members[0]
2830 for member in members[1:]:
2831 all_value |= member
2832 cls.ALL = all_value
2833 return all_value
2834 class StrMixin:
2835 def __str__(self):
2836 return self._name_.lower()
2837 class Color(AllMixin, Flag):
2838 RED = auto()
2839 GREEN = auto()
2840 BLUE = auto()
2841 self.assertEqual(Color.RED.value, 1)
2842 self.assertEqual(Color.GREEN.value, 2)
2843 self.assertEqual(Color.BLUE.value, 4)
2844 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002845 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002846 class Color(AllMixin, StrMixin, Flag):
2847 RED = auto()
2848 GREEN = auto()
2849 BLUE = auto()
2850 self.assertEqual(Color.RED.value, 1)
2851 self.assertEqual(Color.GREEN.value, 2)
2852 self.assertEqual(Color.BLUE.value, 4)
2853 self.assertEqual(Color.ALL.value, 7)
2854 self.assertEqual(str(Color.BLUE), 'blue')
2855 class Color(StrMixin, AllMixin, Flag):
2856 RED = auto()
2857 GREEN = auto()
2858 BLUE = auto()
2859 self.assertEqual(Color.RED.value, 1)
2860 self.assertEqual(Color.GREEN.value, 2)
2861 self.assertEqual(Color.BLUE.value, 4)
2862 self.assertEqual(Color.ALL.value, 7)
2863 self.assertEqual(str(Color.BLUE), 'blue')
2864
Hai Shie80697d2020-05-28 06:10:27 +08002865 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002866 def test_unique_composite(self):
2867 # override __eq__ to be identity only
2868 class TestFlag(Flag):
2869 one = auto()
2870 two = auto()
2871 three = auto()
2872 four = auto()
2873 five = auto()
2874 six = auto()
2875 seven = auto()
2876 eight = auto()
2877 def __eq__(self, other):
2878 return self is other
2879 def __hash__(self):
2880 return hash(self._value_)
2881 # have multiple threads competing to complete the composite members
2882 seen = set()
2883 failed = False
2884 def cycle_enum():
2885 nonlocal failed
2886 try:
2887 for i in range(256):
2888 seen.add(TestFlag(i))
2889 except Exception:
2890 failed = True
2891 threads = [
2892 threading.Thread(target=cycle_enum)
2893 for _ in range(8)
2894 ]
Hai Shie80697d2020-05-28 06:10:27 +08002895 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002896 pass
2897 # check that only 248 members were created
2898 self.assertFalse(
2899 failed,
2900 'at least one thread failed while creating composite members')
2901 self.assertEqual(256, len(seen), 'too many composite members created')
2902
Ethan Furman6bd94de2020-12-09 16:41:22 -08002903 def test_init_subclass(self):
2904 class MyEnum(Flag):
2905 def __init_subclass__(cls, **kwds):
2906 super().__init_subclass__(**kwds)
2907 self.assertFalse(cls.__dict__.get('_test', False))
2908 cls._test1 = 'MyEnum'
2909 #
2910 class TheirEnum(MyEnum):
2911 def __init_subclass__(cls, **kwds):
2912 super(TheirEnum, cls).__init_subclass__(**kwds)
2913 cls._test2 = 'TheirEnum'
2914 class WhoseEnum(TheirEnum):
2915 def __init_subclass__(cls, **kwds):
2916 pass
2917 class NoEnum(WhoseEnum):
2918 ONE = 1
2919 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2920 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2921 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2922 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2923 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2924 #
2925 class OurEnum(MyEnum):
2926 def __init_subclass__(cls, **kwds):
2927 cls._test2 = 'OurEnum'
2928 class WhereEnum(OurEnum):
2929 def __init_subclass__(cls, **kwds):
2930 pass
2931 class NeverEnum(WhereEnum):
2932 ONE = 1
2933 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2934 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2935 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2936 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2937 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2938
Ethan Furmanc16595e2016-09-10 23:36:59 -07002939
Ethan Furman65a5a472016-09-01 23:55:19 -07002940class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002941 """Tests of the IntFlags."""
2942
Ethan Furman65a5a472016-09-01 23:55:19 -07002943 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002944 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002945 W = 1 << 1
2946 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002947
Ethan Furman65a5a472016-09-01 23:55:19 -07002948 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002949 RO = 0
2950 WO = 1
2951 RW = 2
2952 AC = 3
2953 CE = 1<<19
2954
Rahul Jha94306522018-09-10 23:51:04 +05302955 class Color(IntFlag):
2956 BLACK = 0
2957 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002958 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302959 GREEN = 2
2960 BLUE = 4
2961 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002962 WHITE = RED|GREEN|BLUE
2963 BLANCO = RED|GREEN|BLUE
2964
2965 class Skip(IntFlag):
2966 FIRST = 1
2967 SECOND = 2
2968 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302969
Ethan Furman3515dcc2016-09-18 13:15:41 -07002970 def test_type(self):
2971 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002972 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002973 Open = self.Open
2974 for f in Perm:
2975 self.assertTrue(isinstance(f, Perm))
2976 self.assertEqual(f, f.value)
2977 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2978 self.assertEqual(Perm.W | Perm.X, 3)
2979 for f in Open:
2980 self.assertTrue(isinstance(f, Open))
2981 self.assertEqual(f, f.value)
2982 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2983 self.assertEqual(Open.WO | Open.RW, 3)
2984
2985
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002986 def test_str(self):
2987 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002988 self.assertEqual(str(Perm.R), 'R')
2989 self.assertEqual(str(Perm.W), 'W')
2990 self.assertEqual(str(Perm.X), 'X')
2991 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2992 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002993 self.assertEqual(str(Perm.R | 8), '12')
2994 self.assertEqual(str(Perm(0)), 'Perm(0)')
2995 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002996 self.assertEqual(str(~Perm.R), 'W|X')
2997 self.assertEqual(str(~Perm.W), 'R|X')
2998 self.assertEqual(str(~Perm.X), 'R|W')
2999 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003000 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3001 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003002 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003003 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003004
3005 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003006 self.assertEqual(str(Open.RO), 'RO')
3007 self.assertEqual(str(Open.WO), 'WO')
3008 self.assertEqual(str(Open.AC), 'AC')
3009 self.assertEqual(str(Open.RO | Open.CE), 'CE')
3010 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003011 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003012 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3013 self.assertEqual(str(~Open.WO), 'RW|CE')
3014 self.assertEqual(str(~Open.AC), 'CE')
3015 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3016 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003017 self.assertEqual(str(Open(~4)), '-5')
3018
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003019 def test_repr(self):
3020 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003021 self.assertEqual(repr(Perm.R), 'Perm.R')
3022 self.assertEqual(repr(Perm.W), 'Perm.W')
3023 self.assertEqual(repr(Perm.X), 'Perm.X')
3024 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3025 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003026 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07003027 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003028 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003029 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3030 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3031 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3032 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3033 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003034 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003035 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003036 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003037
3038 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003039 self.assertEqual(repr(Open.RO), 'Open.RO')
3040 self.assertEqual(repr(Open.WO), 'Open.WO')
3041 self.assertEqual(repr(Open.AC), 'Open.AC')
3042 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3043 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003044 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003045 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3046 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3047 self.assertEqual(repr(~Open.AC), 'Open.CE')
3048 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3049 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003050 self.assertEqual(repr(Open(~4)), '-5')
3051
Ethan Furman6bd92882021-04-27 13:05:08 -07003052 @unittest.skipUnless(
3053 python_version < (3, 12),
3054 'mixin-format now uses member instead of member.value',
3055 )
Ethan Furman37440ee2020-12-08 11:14:10 -08003056 def test_format(self):
Ethan Furman6bd92882021-04-27 13:05:08 -07003057 with self.assertWarns(DeprecationWarning):
3058 Perm = self.Perm
3059 self.assertEqual(format(Perm.R, ''), '4')
3060 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08003061
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003062 def test_or(self):
3063 Perm = self.Perm
3064 for i in Perm:
3065 for j in Perm:
3066 self.assertEqual(i | j, i.value | j.value)
3067 self.assertEqual((i | j).value, i.value | j.value)
3068 self.assertIs(type(i | j), Perm)
3069 for j in range(8):
3070 self.assertEqual(i | j, i.value | j)
3071 self.assertEqual((i | j).value, i.value | j)
3072 self.assertIs(type(i | j), Perm)
3073 self.assertEqual(j | i, j | i.value)
3074 self.assertEqual((j | i).value, j | i.value)
3075 self.assertIs(type(j | i), Perm)
3076 for i in Perm:
3077 self.assertIs(i | i, i)
3078 self.assertIs(i | 0, i)
3079 self.assertIs(0 | i, i)
3080 Open = self.Open
3081 self.assertIs(Open.RO | Open.CE, Open.CE)
3082
3083 def test_and(self):
3084 Perm = self.Perm
3085 RW = Perm.R | Perm.W
3086 RX = Perm.R | Perm.X
3087 WX = Perm.W | Perm.X
3088 RWX = Perm.R | Perm.W | Perm.X
3089 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3090 for i in values:
3091 for j in values:
3092 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3093 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3094 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3095 for j in range(8):
3096 self.assertEqual(i & j, i.value & j)
3097 self.assertEqual((i & j).value, i.value & j)
3098 self.assertIs(type(i & j), Perm)
3099 self.assertEqual(j & i, j & i.value)
3100 self.assertEqual((j & i).value, j & i.value)
3101 self.assertIs(type(j & i), Perm)
3102 for i in Perm:
3103 self.assertIs(i & i, i)
3104 self.assertIs(i & 7, i)
3105 self.assertIs(7 & i, i)
3106 Open = self.Open
3107 self.assertIs(Open.RO & Open.CE, Open.RO)
3108
3109 def test_xor(self):
3110 Perm = self.Perm
3111 for i in Perm:
3112 for j in Perm:
3113 self.assertEqual(i ^ j, i.value ^ j.value)
3114 self.assertEqual((i ^ j).value, i.value ^ j.value)
3115 self.assertIs(type(i ^ j), Perm)
3116 for j in range(8):
3117 self.assertEqual(i ^ j, i.value ^ j)
3118 self.assertEqual((i ^ j).value, i.value ^ j)
3119 self.assertIs(type(i ^ j), Perm)
3120 self.assertEqual(j ^ i, j ^ i.value)
3121 self.assertEqual((j ^ i).value, j ^ i.value)
3122 self.assertIs(type(j ^ i), Perm)
3123 for i in Perm:
3124 self.assertIs(i ^ 0, i)
3125 self.assertIs(0 ^ i, i)
3126 Open = self.Open
3127 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3128 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3129
3130 def test_invert(self):
3131 Perm = self.Perm
3132 RW = Perm.R | Perm.W
3133 RX = Perm.R | Perm.X
3134 WX = Perm.W | Perm.X
3135 RWX = Perm.R | Perm.W | Perm.X
3136 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3137 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003138 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003139 self.assertIs(type(~i), Perm)
3140 self.assertEqual(~~i, i)
3141 for i in Perm:
3142 self.assertIs(~~i, i)
3143 Open = self.Open
3144 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3145 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3146
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003147 def test_boundary(self):
3148 self.assertIs(enum.IntFlag._boundary_, EJECT)
3149 class Iron(IntFlag, boundary=STRICT):
3150 ONE = 1
3151 TWO = 2
3152 EIGHT = 8
3153 self.assertIs(Iron._boundary_, STRICT)
3154 #
3155 class Water(IntFlag, boundary=CONFORM):
3156 ONE = 1
3157 TWO = 2
3158 EIGHT = 8
3159 self.assertIs(Water._boundary_, CONFORM)
3160 #
3161 class Space(IntFlag, boundary=EJECT):
3162 ONE = 1
3163 TWO = 2
3164 EIGHT = 8
3165 self.assertIs(Space._boundary_, EJECT)
3166 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003167 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003168 class Bizarre(IntFlag, boundary=KEEP):
3169 b = 3
3170 c = 4
3171 d = 6
3172 #
3173 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003174 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003175 self.assertIs(Water(7), Water.ONE|Water.TWO)
3176 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003177 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003178 self.assertEqual(Space(7), 7)
3179 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003180 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003181 self.assertEqual(list(Bizarre), [Bizarre.c])
3182 self.assertIs(Bizarre(3), Bizarre.b)
3183 self.assertIs(Bizarre(6), Bizarre.d)
3184
3185 def test_iter(self):
3186 Color = self.Color
3187 Open = self.Open
3188 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3189 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3190
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003191 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003192 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003193 lst = list(Perm)
3194 self.assertEqual(len(lst), len(Perm))
3195 self.assertEqual(len(Perm), 3, Perm)
3196 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3197 for i, n in enumerate('R W X'.split()):
3198 v = 1<<i
3199 e = Perm(v)
3200 self.assertEqual(e.value, v)
3201 self.assertEqual(type(e.value), int)
3202 self.assertEqual(e, v)
3203 self.assertEqual(e.name, n)
3204 self.assertIn(e, Perm)
3205 self.assertIs(type(e), Perm)
3206
3207 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003208 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003209 lst = list(Perm)
3210 self.assertEqual(len(lst), len(Perm))
3211 self.assertEqual(len(Perm), 3, Perm)
3212 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3213 for i, n in enumerate('R W X'.split()):
3214 v = 8<<i
3215 e = Perm(v)
3216 self.assertEqual(e.value, v)
3217 self.assertEqual(type(e.value), int)
3218 self.assertEqual(e, v)
3219 self.assertEqual(e.name, n)
3220 self.assertIn(e, Perm)
3221 self.assertIs(type(e), Perm)
3222
3223 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003224 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003225 lst = list(Perm)
3226 self.assertEqual(len(lst), len(Perm))
3227 self.assertEqual(len(Perm), 3, Perm)
3228 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3229 for i, n in enumerate('R W X'.split()):
3230 v = 1<<i
3231 e = Perm(v)
3232 self.assertEqual(e.value, v)
3233 self.assertEqual(type(e.value), int)
3234 self.assertEqual(e, v)
3235 self.assertEqual(e.name, n)
3236 self.assertIn(e, Perm)
3237 self.assertIs(type(e), Perm)
3238
3239 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003240 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003241 lst = list(Perm)
3242 self.assertEqual(len(lst), len(Perm))
3243 self.assertEqual(len(Perm), 3, Perm)
3244 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3245 for i, n in enumerate('R W X'.split()):
3246 v = 1<<(2*i+1)
3247 e = Perm(v)
3248 self.assertEqual(e.value, v)
3249 self.assertEqual(type(e.value), int)
3250 self.assertEqual(e, v)
3251 self.assertEqual(e.name, n)
3252 self.assertIn(e, Perm)
3253 self.assertIs(type(e), Perm)
3254
3255 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003256 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003257 lst = list(Perm)
3258 self.assertEqual(len(lst), len(Perm))
3259 self.assertEqual(len(Perm), 3, Perm)
3260 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3261 for i, n in enumerate('R W X'.split()):
3262 v = 1<<(2*i+1)
3263 e = Perm(v)
3264 self.assertEqual(e.value, v)
3265 self.assertEqual(type(e.value), int)
3266 self.assertEqual(e, v)
3267 self.assertEqual(e.name, n)
3268 self.assertIn(e, Perm)
3269 self.assertIs(type(e), Perm)
3270
3271
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003272 def test_programatic_function_from_empty_list(self):
3273 Perm = enum.IntFlag('Perm', [])
3274 lst = list(Perm)
3275 self.assertEqual(len(lst), len(Perm))
3276 self.assertEqual(len(Perm), 0, Perm)
3277 Thing = enum.Enum('Thing', [])
3278 lst = list(Thing)
3279 self.assertEqual(len(lst), len(Thing))
3280 self.assertEqual(len(Thing), 0, Thing)
3281
3282
3283 def test_programatic_function_from_empty_tuple(self):
3284 Perm = enum.IntFlag('Perm', ())
3285 lst = list(Perm)
3286 self.assertEqual(len(lst), len(Perm))
3287 self.assertEqual(len(Perm), 0, Perm)
3288 Thing = enum.Enum('Thing', ())
3289 self.assertEqual(len(lst), len(Thing))
3290 self.assertEqual(len(Thing), 0, Thing)
3291
Ethan Furman6bd92882021-04-27 13:05:08 -07003292 @unittest.skipIf(
3293 python_version >= (3, 12),
3294 '__contains__ now returns True/False for all inputs',
3295 )
3296 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303297 Open = self.Open
3298 Color = self.Color
3299 self.assertTrue(Color.GREEN in Color)
3300 self.assertTrue(Open.RW in Open)
3301 self.assertFalse(Color.GREEN in Open)
3302 self.assertFalse(Open.RW in Color)
3303 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003304 with self.assertWarns(DeprecationWarning):
3305 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303306 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003307 with self.assertWarns(DeprecationWarning):
3308 'RW' in Open
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 2 in Color
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 Open
3315
3316 @unittest.skipIf(
3317 python_version < (3, 12),
3318 '__contains__ only works with enum memmbers before 3.12',
3319 )
3320 def test_contains_tf(self):
3321 Open = self.Open
3322 Color = self.Color
3323 self.assertTrue(Color.GREEN in Color)
3324 self.assertTrue(Open.RW in Open)
3325 self.assertTrue(Color.GREEN in Open)
3326 self.assertTrue(Open.RW in Color)
3327 self.assertFalse('GREEN' in Color)
3328 self.assertFalse('RW' in Open)
3329 self.assertTrue(2 in Color)
3330 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303331
3332 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003333 Perm = self.Perm
3334 R, W, X = Perm
3335 RW = R | W
3336 RX = R | X
3337 WX = W | X
3338 RWX = R | W | X
3339 self.assertTrue(R in RW)
3340 self.assertTrue(R in RX)
3341 self.assertTrue(R in RWX)
3342 self.assertTrue(W in RW)
3343 self.assertTrue(W in WX)
3344 self.assertTrue(W in RWX)
3345 self.assertTrue(X in RX)
3346 self.assertTrue(X in WX)
3347 self.assertTrue(X in RWX)
3348 self.assertFalse(R in WX)
3349 self.assertFalse(W in RX)
3350 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303351 with self.assertRaises(TypeError):
3352 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003353
Ethan Furman7219e272020-09-16 13:01:00 -07003354 def test_member_iter(self):
3355 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003356 self.assertEqual(list(Color.BLACK), [])
3357 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003358 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3359 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003360 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3361
3362 def test_member_length(self):
3363 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3364 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3365 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3366 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3367
3368 def test_aliases(self):
3369 Color = self.Color
3370 self.assertEqual(Color(1).name, 'RED')
3371 self.assertEqual(Color['ROJO'].name, 'RED')
3372 self.assertEqual(Color(7).name, 'WHITE')
3373 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3374 self.assertIs(Color.BLANCO, Color.WHITE)
3375 Open = self.Open
3376 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003377
Ethan Furman25d94bb2016-09-02 16:32:32 -07003378 def test_bool(self):
3379 Perm = self.Perm
3380 for f in Perm:
3381 self.assertTrue(f)
3382 Open = self.Open
3383 for f in Open:
3384 self.assertEqual(bool(f.value), bool(f))
3385
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003386
Ethan Furman5bdab642018-09-21 19:03:09 -07003387 def test_multiple_mixin(self):
3388 class AllMixin:
3389 @classproperty
3390 def ALL(cls):
3391 members = list(cls)
3392 all_value = None
3393 if members:
3394 all_value = members[0]
3395 for member in members[1:]:
3396 all_value |= member
3397 cls.ALL = all_value
3398 return all_value
3399 class StrMixin:
3400 def __str__(self):
3401 return self._name_.lower()
3402 class Color(AllMixin, IntFlag):
3403 RED = auto()
3404 GREEN = auto()
3405 BLUE = auto()
3406 self.assertEqual(Color.RED.value, 1)
3407 self.assertEqual(Color.GREEN.value, 2)
3408 self.assertEqual(Color.BLUE.value, 4)
3409 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003410 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003411 class Color(AllMixin, StrMixin, IntFlag):
3412 RED = auto()
3413 GREEN = auto()
3414 BLUE = auto()
3415 self.assertEqual(Color.RED.value, 1)
3416 self.assertEqual(Color.GREEN.value, 2)
3417 self.assertEqual(Color.BLUE.value, 4)
3418 self.assertEqual(Color.ALL.value, 7)
3419 self.assertEqual(str(Color.BLUE), 'blue')
3420 class Color(StrMixin, AllMixin, IntFlag):
3421 RED = auto()
3422 GREEN = auto()
3423 BLUE = auto()
3424 self.assertEqual(Color.RED.value, 1)
3425 self.assertEqual(Color.GREEN.value, 2)
3426 self.assertEqual(Color.BLUE.value, 4)
3427 self.assertEqual(Color.ALL.value, 7)
3428 self.assertEqual(str(Color.BLUE), 'blue')
3429
Hai Shie80697d2020-05-28 06:10:27 +08003430 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003431 def test_unique_composite(self):
3432 # override __eq__ to be identity only
3433 class TestFlag(IntFlag):
3434 one = auto()
3435 two = auto()
3436 three = auto()
3437 four = auto()
3438 five = auto()
3439 six = auto()
3440 seven = auto()
3441 eight = auto()
3442 def __eq__(self, other):
3443 return self is other
3444 def __hash__(self):
3445 return hash(self._value_)
3446 # have multiple threads competing to complete the composite members
3447 seen = set()
3448 failed = False
3449 def cycle_enum():
3450 nonlocal failed
3451 try:
3452 for i in range(256):
3453 seen.add(TestFlag(i))
3454 except Exception:
3455 failed = True
3456 threads = [
3457 threading.Thread(target=cycle_enum)
3458 for _ in range(8)
3459 ]
Hai Shie80697d2020-05-28 06:10:27 +08003460 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003461 pass
3462 # check that only 248 members were created
3463 self.assertFalse(
3464 failed,
3465 'at least one thread failed while creating composite members')
3466 self.assertEqual(256, len(seen), 'too many composite members created')
3467
3468
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003469class TestEmptyAndNonLatinStrings(unittest.TestCase):
3470
3471 def test_empty_string(self):
3472 with self.assertRaises(ValueError):
3473 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3474
3475 def test_non_latin_character_string(self):
3476 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3477 item = getattr(greek_abc, '\u03B1')
3478 self.assertEqual(item.value, 1)
3479
3480 def test_non_latin_number_string(self):
3481 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3482 item = getattr(hebrew_123, '\u05D0')
3483 self.assertEqual(item.value, 1)
3484
3485
Ethan Furmanf24bb352013-07-18 17:05:39 -07003486class TestUnique(unittest.TestCase):
3487
3488 def test_unique_clean(self):
3489 @unique
3490 class Clean(Enum):
3491 one = 1
3492 two = 'dos'
3493 tres = 4.0
Ethan Furman74964862021-06-10 07:24:20 -07003494 #
Ethan Furmanf24bb352013-07-18 17:05:39 -07003495 @unique
3496 class Cleaner(IntEnum):
3497 single = 1
3498 double = 2
3499 triple = 3
3500
3501 def test_unique_dirty(self):
3502 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3503 @unique
3504 class Dirty(Enum):
3505 one = 1
3506 two = 'dos'
3507 tres = 1
3508 with self.assertRaisesRegex(
3509 ValueError,
3510 'double.*single.*turkey.*triple',
3511 ):
3512 @unique
3513 class Dirtier(IntEnum):
3514 single = 1
3515 double = 1
3516 triple = 3
3517 turkey = 3
3518
Ethan Furman3803ad42016-05-01 10:03:53 -07003519 def test_unique_with_name(self):
Ethan Furman74964862021-06-10 07:24:20 -07003520 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003521 class Silly(Enum):
3522 one = 1
3523 two = 'dos'
3524 name = 3
Ethan Furman74964862021-06-10 07:24:20 -07003525 #
3526 @verify(UNIQUE)
3527 class Sillier(IntEnum):
3528 single = 1
3529 name = 2
3530 triple = 3
3531 value = 4
3532
3533class TestVerify(unittest.TestCase):
3534
3535 def test_continuous(self):
3536 @verify(CONTINUOUS)
3537 class Auto(Enum):
3538 FIRST = auto()
3539 SECOND = auto()
3540 THIRD = auto()
3541 FORTH = auto()
3542 #
3543 @verify(CONTINUOUS)
3544 class Manual(Enum):
3545 FIRST = 3
3546 SECOND = 4
3547 THIRD = 5
3548 FORTH = 6
3549 #
3550 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
3551 @verify(CONTINUOUS)
3552 class Missing(Enum):
3553 FIRST = 3
3554 SECOND = 4
3555 THIRD = 11
3556 FORTH = 13
3557 #
3558 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
3559 @verify(CONTINUOUS)
3560 class Incomplete(Flag):
3561 FIRST = 4
3562 SECOND = 8
3563 THIRD = 16
3564 FORTH = 64
3565 #
3566 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
3567 @verify(CONTINUOUS)
3568 class StillIncomplete(Flag):
3569 FIRST = 4
3570 SECOND = 8
3571 THIRD = 11
3572 FORTH = 32
3573
3574
3575 def test_composite(self):
3576 class Bizarre(Flag):
3577 b = 3
3578 c = 4
3579 d = 6
3580 self.assertEqual(list(Bizarre), [Bizarre.c])
3581 self.assertEqual(Bizarre.b.value, 3)
3582 self.assertEqual(Bizarre.c.value, 4)
3583 self.assertEqual(Bizarre.d.value, 6)
3584 with self.assertRaisesRegex(
3585 ValueError,
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003586 "invalid Flag 'Bizarre': aliases b and d are missing combined values of 0x3 .use `enum.show_flag_values.value.` for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003587 ):
3588 @verify(NAMED_FLAGS)
3589 class Bizarre(Flag):
3590 b = 3
3591 c = 4
3592 d = 6
3593 #
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003594 self.assertEqual(enum.show_flag_values(3), [1, 2])
Ethan Furman74964862021-06-10 07:24:20 -07003595 class Bizarre(IntFlag):
3596 b = 3
3597 c = 4
3598 d = 6
3599 self.assertEqual(list(Bizarre), [Bizarre.c])
3600 self.assertEqual(Bizarre.b.value, 3)
3601 self.assertEqual(Bizarre.c.value, 4)
3602 self.assertEqual(Bizarre.d.value, 6)
3603 with self.assertRaisesRegex(
3604 ValueError,
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003605 "invalid Flag 'Bizarre': alias d is missing value 0x2 .use `enum.show_flag_values.value.` for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003606 ):
3607 @verify(NAMED_FLAGS)
3608 class Bizarre(IntFlag):
Ethan Furman74964862021-06-10 07:24:20 -07003609 c = 4
3610 d = 6
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003611 self.assertEqual(enum.show_flag_values(2), [2])
Ethan Furman74964862021-06-10 07:24:20 -07003612
3613 def test_unique_clean(self):
3614 @verify(UNIQUE)
3615 class Clean(Enum):
3616 one = 1
3617 two = 'dos'
3618 tres = 4.0
3619 #
3620 @verify(UNIQUE)
3621 class Cleaner(IntEnum):
3622 single = 1
3623 double = 2
3624 triple = 3
3625
3626 def test_unique_dirty(self):
3627 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3628 @verify(UNIQUE)
3629 class Dirty(Enum):
3630 one = 1
3631 two = 'dos'
3632 tres = 1
3633 with self.assertRaisesRegex(
3634 ValueError,
3635 'double.*single.*turkey.*triple',
3636 ):
3637 @verify(UNIQUE)
3638 class Dirtier(IntEnum):
3639 single = 1
3640 double = 1
3641 triple = 3
3642 turkey = 3
3643
3644 def test_unique_with_name(self):
3645 @verify(UNIQUE)
3646 class Silly(Enum):
3647 one = 1
3648 two = 'dos'
3649 name = 3
3650 #
3651 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003652 class Sillier(IntEnum):
3653 single = 1
3654 name = 2
3655 triple = 3
3656 value = 4
3657
Ethan Furmanec099732021-04-15 06:58:33 -07003658class TestHelpers(unittest.TestCase):
3659
3660 sunder_names = '_bad_', '_good_', '_what_ho_'
3661 dunder_names = '__mal__', '__bien__', '__que_que__'
3662 private_names = '_MyEnum__private', '_MyEnum__still_private'
3663 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3664 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3665
3666 def test_sunder(self):
3667 for name in self.sunder_names + self.private_and_sunder_names:
3668 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3669 for name in self.dunder_names + self.private_names + self.random_names:
3670 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3671
3672 def test_dunder(self):
3673 for name in self.dunder_names:
3674 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3675 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3676 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3677
3678 def test_is_private(self):
3679 for name in self.private_names + self.private_and_sunder_names:
3680 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3681 for name in self.sunder_names + self.dunder_names + self.random_names:
3682 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003683
Ethan Furmanb7751062021-03-30 21:17:26 -07003684class TestEnumTypeSubclassing(unittest.TestCase):
3685 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003686
Ethan Furman3323da92015-04-11 09:39:59 -07003687expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003688Help on class Color in module %s:
3689
3690class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003691 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003692 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003693 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003694 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003695 | Method resolution order:
3696 | Color
3697 | enum.Enum
3698 | builtins.object
3699 |\x20\x20
3700 | Data and other attributes defined here:
3701 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003702 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003703 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003704 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003705 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003706 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003707 |\x20\x20
3708 | ----------------------------------------------------------------------
3709 | Data descriptors inherited from enum.Enum:
3710 |\x20\x20
3711 | name
3712 | The name of the Enum member.
3713 |\x20\x20
3714 | value
3715 | The value of the Enum member.
3716 |\x20\x20
3717 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003718 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003719 |\x20\x20
3720 | __members__
3721 | Returns a mapping of member name->value.
3722 |\x20\x20\x20\x20\x20\x20
3723 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003724 | is a read-only view of the internal mapping."""
3725
3726expected_help_output_without_docs = """\
3727Help on class Color in module %s:
3728
3729class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003730 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3731 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003732 | Method resolution order:
3733 | Color
3734 | enum.Enum
3735 | builtins.object
3736 |\x20\x20
3737 | Data and other attributes defined here:
3738 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003739 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003740 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003741 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003742 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003743 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003744 |\x20\x20
3745 | ----------------------------------------------------------------------
3746 | Data descriptors inherited from enum.Enum:
3747 |\x20\x20
3748 | name
3749 |\x20\x20
3750 | value
3751 |\x20\x20
3752 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003753 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003754 |\x20\x20
3755 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003756
3757class TestStdLib(unittest.TestCase):
3758
Ethan Furman48a724f2015-04-11 23:23:06 -07003759 maxDiff = None
3760
Ethan Furman5875d742013-10-21 20:45:55 -07003761 class Color(Enum):
3762 red = 1
3763 green = 2
3764 blue = 3
3765
3766 def test_pydoc(self):
3767 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003768 if StrEnum.__doc__ is None:
3769 expected_text = expected_help_output_without_docs % __name__
3770 else:
3771 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003772 output = StringIO()
3773 helper = pydoc.Helper(output=output)
3774 helper(self.Color)
3775 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003776 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003777
3778 def test_inspect_getmembers(self):
3779 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003780 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003781 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003782 ('__members__', self.Color.__members__),
3783 ('__module__', __name__),
3784 ('blue', self.Color.blue),
3785 ('green', self.Color.green),
3786 ('name', Enum.__dict__['name']),
3787 ('red', self.Color.red),
3788 ('value', Enum.__dict__['value']),
3789 ))
3790 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003791 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003792 failed = False
3793 for k in values.keys():
3794 if result[k] != values[k]:
3795 print()
3796 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3797 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3798 failed = True
3799 if failed:
3800 self.fail("result does not equal expected, see print above")
3801
3802 def test_inspect_classify_class_attrs(self):
3803 # indirectly test __objclass__
3804 from inspect import Attribute
3805 values = [
3806 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003807 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003808 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003809 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003810 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003811 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003812 Attribute(name='__module__', kind='data',
3813 defining_class=self.Color, object=__name__),
3814 Attribute(name='blue', kind='data',
3815 defining_class=self.Color, object=self.Color.blue),
3816 Attribute(name='green', kind='data',
3817 defining_class=self.Color, object=self.Color.green),
3818 Attribute(name='red', kind='data',
3819 defining_class=self.Color, object=self.Color.red),
3820 Attribute(name='name', kind='data',
3821 defining_class=Enum, object=Enum.__dict__['name']),
3822 Attribute(name='value', kind='data',
3823 defining_class=Enum, object=Enum.__dict__['value']),
3824 ]
3825 values.sort(key=lambda item: item.name)
3826 result = list(inspect.classify_class_attrs(self.Color))
3827 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003828 self.assertEqual(
3829 len(values), len(result),
3830 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3831 )
Ethan Furman5875d742013-10-21 20:45:55 -07003832 failed = False
3833 for v, r in zip(values, result):
3834 if r != v:
3835 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3836 failed = True
3837 if failed:
3838 self.fail("result does not equal expected, see print above")
3839
Ethan Furmana02cb472021-04-21 10:20:44 -07003840 def test_test_simple_enum(self):
3841 @_simple_enum(Enum)
3842 class SimpleColor:
3843 RED = 1
3844 GREEN = 2
3845 BLUE = 3
3846 class CheckedColor(Enum):
3847 RED = 1
3848 GREEN = 2
3849 BLUE = 3
3850 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3851 SimpleColor.GREEN._value_ = 9
3852 self.assertRaisesRegex(
3853 TypeError, "enum mismatch",
3854 _test_simple_enum, CheckedColor, SimpleColor,
3855 )
3856 class CheckedMissing(IntFlag, boundary=KEEP):
3857 SIXTY_FOUR = 64
3858 ONE_TWENTY_EIGHT = 128
3859 TWENTY_FORTY_EIGHT = 2048
3860 ALL = 2048 + 128 + 64 + 12
3861 CM = CheckedMissing
3862 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3863 #
3864 @_simple_enum(IntFlag, boundary=KEEP)
3865 class Missing:
3866 SIXTY_FOUR = 64
3867 ONE_TWENTY_EIGHT = 128
3868 TWENTY_FORTY_EIGHT = 2048
3869 ALL = 2048 + 128 + 64 + 12
3870 M = Missing
3871 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3872 #
3873 _test_simple_enum(CheckedMissing, Missing)
3874
Martin Panter19e69c52015-11-14 12:46:42 +00003875
3876class MiscTestCase(unittest.TestCase):
3877 def test__all__(self):
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003878 support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
Martin Panter19e69c52015-11-14 12:46:42 +00003879
3880
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003881# These are unordered here on purpose to ensure that declaration order
3882# makes no difference.
3883CONVERT_TEST_NAME_D = 5
3884CONVERT_TEST_NAME_C = 5
3885CONVERT_TEST_NAME_B = 5
3886CONVERT_TEST_NAME_A = 5 # This one should sort first.
3887CONVERT_TEST_NAME_E = 5
3888CONVERT_TEST_NAME_F = 5
3889
Ethan Furmana02cb472021-04-21 10:20:44 -07003890CONVERT_STRING_TEST_NAME_D = 5
3891CONVERT_STRING_TEST_NAME_C = 5
3892CONVERT_STRING_TEST_NAME_B = 5
3893CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3894CONVERT_STRING_TEST_NAME_E = 5
3895CONVERT_STRING_TEST_NAME_F = 5
3896
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003897class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003898 def setUp(self):
3899 # Reset the module-level test variables to their original integer
3900 # values, otherwise the already created enum values get converted
3901 # instead.
3902 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3903 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3904 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3905
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003906 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003907 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003908 'UnittestConvert',
3909 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003910 filter=lambda x: x.startswith('CONVERT_TEST_'))
3911 # We don't want the reverse lookup value to vary when there are
3912 # multiple possible names for a given value. It should always
3913 # report the first lexigraphical name in that case.
3914 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3915
3916 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003917 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003918 'UnittestConvert',
3919 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003920 filter=lambda x: x.startswith('CONVERT_TEST_'))
3921 # Ensure that test_type has all of the desired names and values.
3922 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3923 test_type.CONVERT_TEST_NAME_A)
3924 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3925 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3926 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3927 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3928 # Ensure that test_type only picked up names matching the filter.
3929 self.assertEqual([name for name in dir(test_type)
3930 if name[0:2] not in ('CO', '__')],
3931 [], msg='Names other than CONVERT_TEST_* found.')
3932
Ethan Furman6bd92882021-04-27 13:05:08 -07003933 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003934 '_convert was deprecated in 3.8')
3935 def test_convert_warn(self):
3936 with self.assertWarns(DeprecationWarning):
3937 enum.IntEnum._convert(
3938 'UnittestConvert',
3939 ('test.test_enum', '__main__')[__name__=='__main__'],
3940 filter=lambda x: x.startswith('CONVERT_TEST_'))
3941
Ethan Furman6bd92882021-04-27 13:05:08 -07003942 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003943 '_convert was removed in 3.9')
3944 def test_convert_raise(self):
3945 with self.assertRaises(AttributeError):
3946 enum.IntEnum._convert(
3947 'UnittestConvert',
3948 ('test.test_enum', '__main__')[__name__=='__main__'],
3949 filter=lambda x: x.startswith('CONVERT_TEST_'))
3950
Ethan Furman6bd92882021-04-27 13:05:08 -07003951 @unittest.skipUnless(
3952 python_version < (3, 12),
3953 'mixin-format now uses member instead of member.value',
3954 )
Ethan Furmanb7751062021-03-30 21:17:26 -07003955 def test_convert_repr_and_str(self):
3956 module = ('test.test_enum', '__main__')[__name__=='__main__']
3957 test_type = enum.IntEnum._convert_(
3958 'UnittestConvert',
3959 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003960 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3961 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3962 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman6bd92882021-04-27 13:05:08 -07003963 with self.assertWarns(DeprecationWarning):
3964 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003965
3966# global names for StrEnum._convert_ test
3967CONVERT_STR_TEST_2 = 'goodbye'
3968CONVERT_STR_TEST_1 = 'hello'
3969
3970class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003971 def setUp(self):
3972 global CONVERT_STR_TEST_1
3973 global CONVERT_STR_TEST_2
3974 CONVERT_STR_TEST_2 = 'goodbye'
3975 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07003976
3977 def test_convert(self):
3978 test_type = enum.StrEnum._convert_(
3979 'UnittestConvert',
3980 ('test.test_enum', '__main__')[__name__=='__main__'],
3981 filter=lambda x: x.startswith('CONVERT_STR_'))
3982 # Ensure that test_type has all of the desired names and values.
3983 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3984 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3985 # Ensure that test_type only picked up names matching the filter.
3986 self.assertEqual([name for name in dir(test_type)
3987 if name[0:2] not in ('CO', '__')],
3988 [], msg='Names other than CONVERT_STR_* found.')
3989
3990 def test_convert_repr_and_str(self):
3991 module = ('test.test_enum', '__main__')[__name__=='__main__']
3992 test_type = enum.StrEnum._convert_(
3993 'UnittestConvert',
3994 module,
3995 filter=lambda x: x.startswith('CONVERT_STR_'))
3996 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3997 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
3998 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
3999
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004000
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004001if __name__ == '__main__':
4002 unittest.main()