blob: 956b8347b1e1cb9e40f74ece6e4819cee5e01d43 [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>')
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700661 #
662 class SillyInt(HexInt):
663 pass
664 class MyOtherEnum(SillyInt, enum.Enum):
665 D = 4
666 E = 5
667 F = 6
668 self.assertIs(MyOtherEnum._member_type_, SillyInt)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700669
670 def test_too_many_data_types(self):
671 with self.assertRaisesRegex(TypeError, 'too many data types'):
672 class Huh(str, int, Enum):
673 One = 1
674
675 class MyStr(str):
676 def hello(self):
677 return 'hello, %s' % self
678 class MyInt(int):
679 def repr(self):
680 return hex(self)
681 with self.assertRaisesRegex(TypeError, 'too many data types'):
682 class Huh(MyStr, MyInt, Enum):
683 One = 1
684
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700685 def test_hash(self):
686 Season = self.Season
687 dates = {}
688 dates[Season.WINTER] = '1225'
689 dates[Season.SPRING] = '0315'
690 dates[Season.SUMMER] = '0704'
691 dates[Season.AUTUMN] = '1031'
692 self.assertEqual(dates[Season.AUTUMN], '1031')
693
694 def test_intenum_from_scratch(self):
695 class phy(int, Enum):
696 pi = 3
697 tau = 2 * pi
698 self.assertTrue(phy.pi < phy.tau)
699
700 def test_intenum_inherited(self):
701 class IntEnum(int, Enum):
702 pass
703 class phy(IntEnum):
704 pi = 3
705 tau = 2 * pi
706 self.assertTrue(phy.pi < phy.tau)
707
708 def test_floatenum_from_scratch(self):
709 class phy(float, Enum):
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_floatenum_inherited(self):
715 class FloatEnum(float, Enum):
716 pass
717 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700718 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700719 tau = 2 * pi
720 self.assertTrue(phy.pi < phy.tau)
721
722 def test_strenum_from_scratch(self):
723 class phy(str, Enum):
724 pi = 'Pi'
725 tau = 'Tau'
726 self.assertTrue(phy.pi < phy.tau)
727
Ethan Furman0063ff42020-09-21 17:23:13 -0700728 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700729 class phy(StrEnum):
730 pi = 'Pi'
731 tau = 'Tau'
732 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700733 self.assertEqual(phy.pi.upper(), 'PI')
734 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700735
736 def test_intenum(self):
737 class WeekDay(IntEnum):
738 SUNDAY = 1
739 MONDAY = 2
740 TUESDAY = 3
741 WEDNESDAY = 4
742 THURSDAY = 5
743 FRIDAY = 6
744 SATURDAY = 7
745
746 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
747 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
748
749 lst = list(WeekDay)
750 self.assertEqual(len(lst), len(WeekDay))
751 self.assertEqual(len(WeekDay), 7)
752 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
753 target = target.split()
754 for i, weekday in enumerate(target, 1):
755 e = WeekDay(i)
756 self.assertEqual(e, i)
757 self.assertEqual(int(e), i)
758 self.assertEqual(e.name, weekday)
759 self.assertIn(e, WeekDay)
760 self.assertEqual(lst.index(e)+1, i)
761 self.assertTrue(0 < e < 8)
762 self.assertIs(type(e), WeekDay)
763 self.assertIsInstance(e, int)
764 self.assertIsInstance(e, Enum)
765
766 def test_intenum_duplicates(self):
767 class WeekDay(IntEnum):
768 SUNDAY = 1
769 MONDAY = 2
770 TUESDAY = TEUSDAY = 3
771 WEDNESDAY = 4
772 THURSDAY = 5
773 FRIDAY = 6
774 SATURDAY = 7
775 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
776 self.assertEqual(WeekDay(3).name, 'TUESDAY')
777 self.assertEqual([k for k,v in WeekDay.__members__.items()
778 if v.name != k], ['TEUSDAY', ])
779
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300780 def test_intenum_from_bytes(self):
781 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
782 with self.assertRaises(ValueError):
783 IntStooges.from_bytes(b'\x00\x05', 'big')
784
785 def test_floatenum_fromhex(self):
786 h = float.hex(FloatStooges.MOE.value)
787 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
788 h = float.hex(FloatStooges.MOE.value + 0.01)
789 with self.assertRaises(ValueError):
790 FloatStooges.fromhex(h)
791
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700792 def test_pickle_enum(self):
793 if isinstance(Stooges, Exception):
794 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800795 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
796 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700797
798 def test_pickle_int(self):
799 if isinstance(IntStooges, Exception):
800 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800801 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
802 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700803
804 def test_pickle_float(self):
805 if isinstance(FloatStooges, Exception):
806 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800807 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
808 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700809
810 def test_pickle_enum_function(self):
811 if isinstance(Answer, Exception):
812 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800813 test_pickle_dump_load(self.assertIs, Answer.him)
814 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700815
816 def test_pickle_enum_function_with_module(self):
817 if isinstance(Question, Exception):
818 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800819 test_pickle_dump_load(self.assertIs, Question.who)
820 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700821
Ethan Furmanca1b7942014-02-08 11:36:27 -0800822 def test_enum_function_with_qualname(self):
823 if isinstance(Theory, Exception):
824 raise Theory
825 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
826
827 def test_class_nested_enum_and_pickle_protocol_four(self):
828 # would normally just have this directly in the class namespace
829 class NestedEnum(Enum):
830 twigs = 'common'
831 shiny = 'rare'
832
833 self.__class__.NestedEnum = NestedEnum
834 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300835 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800836
Ethan Furman24e837f2015-03-18 17:27:57 -0700837 def test_pickle_by_name(self):
838 class ReplaceGlobalInt(IntEnum):
839 ONE = 1
840 TWO = 2
Miss Islington (bot)b6131322021-06-10 16:37:27 -0700841 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700842 for proto in range(HIGHEST_PROTOCOL):
843 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
844
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700845 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800846 BadPickle = Enum(
847 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700848 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800849 # now break BadPickle to test exception raising
850 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800851 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
852 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700853
854 def test_string_enum(self):
855 class SkillLevel(str, Enum):
856 master = 'what is the sound of one hand clapping?'
857 journeyman = 'why did the chicken cross the road?'
858 apprentice = 'knock, knock!'
859 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
860
861 def test_getattr_getitem(self):
862 class Period(Enum):
863 morning = 1
864 noon = 2
865 evening = 3
866 night = 4
867 self.assertIs(Period(2), Period.noon)
868 self.assertIs(getattr(Period, 'night'), Period.night)
869 self.assertIs(Period['morning'], Period.morning)
870
871 def test_getattr_dunder(self):
872 Season = self.Season
873 self.assertTrue(getattr(Season, '__eq__'))
874
875 def test_iteration_order(self):
876 class Season(Enum):
877 SUMMER = 2
878 WINTER = 4
879 AUTUMN = 3
880 SPRING = 1
881 self.assertEqual(
882 list(Season),
883 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
884 )
885
Ethan Furman2131a4a2013-09-14 18:11:24 -0700886 def test_reversed_iteration_order(self):
887 self.assertEqual(
888 list(reversed(self.Season)),
889 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
890 self.Season.SPRING]
891 )
892
Martin Pantereb995702016-07-28 01:11:04 +0000893 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700894 SummerMonth = Enum('SummerMonth', 'june july august')
895 lst = list(SummerMonth)
896 self.assertEqual(len(lst), len(SummerMonth))
897 self.assertEqual(len(SummerMonth), 3, SummerMonth)
898 self.assertEqual(
899 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
900 lst,
901 )
902 for i, month in enumerate('june july august'.split(), 1):
903 e = SummerMonth(i)
904 self.assertEqual(int(e.value), i)
905 self.assertNotEqual(e, i)
906 self.assertEqual(e.name, month)
907 self.assertIn(e, SummerMonth)
908 self.assertIs(type(e), SummerMonth)
909
Martin Pantereb995702016-07-28 01:11:04 +0000910 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700911 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
912 lst = list(SummerMonth)
913 self.assertEqual(len(lst), len(SummerMonth))
914 self.assertEqual(len(SummerMonth), 3, SummerMonth)
915 self.assertEqual(
916 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
917 lst,
918 )
919 for i, month in enumerate('june july august'.split(), 10):
920 e = SummerMonth(i)
921 self.assertEqual(int(e.value), i)
922 self.assertNotEqual(e, i)
923 self.assertEqual(e.name, month)
924 self.assertIn(e, SummerMonth)
925 self.assertIs(type(e), SummerMonth)
926
Martin Pantereb995702016-07-28 01:11:04 +0000927 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700928 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
929 lst = list(SummerMonth)
930 self.assertEqual(len(lst), len(SummerMonth))
931 self.assertEqual(len(SummerMonth), 3, SummerMonth)
932 self.assertEqual(
933 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
934 lst,
935 )
936 for i, month in enumerate('june july august'.split(), 1):
937 e = SummerMonth(i)
938 self.assertEqual(int(e.value), i)
939 self.assertNotEqual(e, i)
940 self.assertEqual(e.name, month)
941 self.assertIn(e, SummerMonth)
942 self.assertIs(type(e), SummerMonth)
943
Martin Pantereb995702016-07-28 01:11:04 +0000944 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700945 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
946 lst = list(SummerMonth)
947 self.assertEqual(len(lst), len(SummerMonth))
948 self.assertEqual(len(SummerMonth), 3, SummerMonth)
949 self.assertEqual(
950 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
951 lst,
952 )
953 for i, month in enumerate('june july august'.split(), 20):
954 e = SummerMonth(i)
955 self.assertEqual(int(e.value), i)
956 self.assertNotEqual(e, i)
957 self.assertEqual(e.name, month)
958 self.assertIn(e, SummerMonth)
959 self.assertIs(type(e), SummerMonth)
960
Martin Pantereb995702016-07-28 01:11:04 +0000961 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700962 SummerMonth = Enum(
963 'SummerMonth',
964 (('june', 1), ('july', 2), ('august', 3))
965 )
966 lst = list(SummerMonth)
967 self.assertEqual(len(lst), len(SummerMonth))
968 self.assertEqual(len(SummerMonth), 3, SummerMonth)
969 self.assertEqual(
970 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
971 lst,
972 )
973 for i, month in enumerate('june july august'.split(), 1):
974 e = SummerMonth(i)
975 self.assertEqual(int(e.value), i)
976 self.assertNotEqual(e, i)
977 self.assertEqual(e.name, month)
978 self.assertIn(e, SummerMonth)
979 self.assertIs(type(e), SummerMonth)
980
Martin Pantereb995702016-07-28 01:11:04 +0000981 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700982 SummerMonth = Enum(
983 'SummerMonth',
984 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
985 )
986 lst = list(SummerMonth)
987 self.assertEqual(len(lst), len(SummerMonth))
988 self.assertEqual(len(SummerMonth), 3, SummerMonth)
989 self.assertEqual(
990 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
991 lst,
992 )
993 for i, month in enumerate('june july august'.split(), 1):
994 e = SummerMonth(i)
995 self.assertEqual(int(e.value), i)
996 self.assertNotEqual(e, i)
997 self.assertEqual(e.name, month)
998 self.assertIn(e, SummerMonth)
999 self.assertIs(type(e), SummerMonth)
1000
Martin Pantereb995702016-07-28 01:11:04 +00001001 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001002 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
1003 lst = list(SummerMonth)
1004 self.assertEqual(len(lst), len(SummerMonth))
1005 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1006 self.assertEqual(
1007 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1008 lst,
1009 )
1010 for i, month in enumerate('june july august'.split(), 1):
1011 e = SummerMonth(i)
1012 self.assertEqual(e, i)
1013 self.assertEqual(e.name, month)
1014 self.assertIn(e, SummerMonth)
1015 self.assertIs(type(e), SummerMonth)
1016
Martin Pantereb995702016-07-28 01:11:04 +00001017 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001018 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1019 lst = list(SummerMonth)
1020 self.assertEqual(len(lst), len(SummerMonth))
1021 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1022 self.assertEqual(
1023 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1024 lst,
1025 )
1026 for i, month in enumerate('june july august'.split(), 30):
1027 e = SummerMonth(i)
1028 self.assertEqual(e, i)
1029 self.assertEqual(e.name, month)
1030 self.assertIn(e, SummerMonth)
1031 self.assertIs(type(e), SummerMonth)
1032
Martin Pantereb995702016-07-28 01:11:04 +00001033 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034 SummerMonth = IntEnum('SummerMonth', 'june july august')
1035 lst = list(SummerMonth)
1036 self.assertEqual(len(lst), len(SummerMonth))
1037 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1038 self.assertEqual(
1039 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1040 lst,
1041 )
1042 for i, month in enumerate('june july august'.split(), 1):
1043 e = SummerMonth(i)
1044 self.assertEqual(e, i)
1045 self.assertEqual(e.name, month)
1046 self.assertIn(e, SummerMonth)
1047 self.assertIs(type(e), SummerMonth)
1048
Martin Pantereb995702016-07-28 01:11:04 +00001049 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001050 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1051 lst = list(SummerMonth)
1052 self.assertEqual(len(lst), len(SummerMonth))
1053 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1054 self.assertEqual(
1055 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1056 lst,
1057 )
1058 for i, month in enumerate('june july august'.split(), 40):
1059 e = SummerMonth(i)
1060 self.assertEqual(e, i)
1061 self.assertEqual(e.name, month)
1062 self.assertIn(e, SummerMonth)
1063 self.assertIs(type(e), SummerMonth)
1064
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001065 def test_subclassing(self):
1066 if isinstance(Name, Exception):
1067 raise Name
1068 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1069 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1070 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001071 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001072
1073 def test_extending(self):
1074 class Color(Enum):
1075 red = 1
1076 green = 2
1077 blue = 3
1078 with self.assertRaises(TypeError):
1079 class MoreColor(Color):
1080 cyan = 4
1081 magenta = 5
1082 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001083 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1084 class EvenMoreColor(Color, IntEnum):
1085 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001086
1087 def test_exclude_methods(self):
1088 class whatever(Enum):
1089 this = 'that'
1090 these = 'those'
1091 def really(self):
1092 return 'no, not %s' % self.value
1093 self.assertIsNot(type(whatever.really), whatever)
1094 self.assertEqual(whatever.this.really(), 'no, not that')
1095
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001096 def test_wrong_inheritance_order(self):
1097 with self.assertRaises(TypeError):
1098 class Wrong(Enum, str):
1099 NotHere = 'error before this point'
1100
1101 def test_intenum_transitivity(self):
1102 class number(IntEnum):
1103 one = 1
1104 two = 2
1105 three = 3
1106 class numero(IntEnum):
1107 uno = 1
1108 dos = 2
1109 tres = 3
1110 self.assertEqual(number.one, numero.uno)
1111 self.assertEqual(number.two, numero.dos)
1112 self.assertEqual(number.three, numero.tres)
1113
1114 def test_wrong_enum_in_call(self):
1115 class Monochrome(Enum):
1116 black = 0
1117 white = 1
1118 class Gender(Enum):
1119 male = 0
1120 female = 1
1121 self.assertRaises(ValueError, Monochrome, Gender.male)
1122
1123 def test_wrong_enum_in_mixed_call(self):
1124 class Monochrome(IntEnum):
1125 black = 0
1126 white = 1
1127 class Gender(Enum):
1128 male = 0
1129 female = 1
1130 self.assertRaises(ValueError, Monochrome, Gender.male)
1131
1132 def test_mixed_enum_in_call_1(self):
1133 class Monochrome(IntEnum):
1134 black = 0
1135 white = 1
1136 class Gender(IntEnum):
1137 male = 0
1138 female = 1
1139 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1140
1141 def test_mixed_enum_in_call_2(self):
1142 class Monochrome(Enum):
1143 black = 0
1144 white = 1
1145 class Gender(IntEnum):
1146 male = 0
1147 female = 1
1148 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1149
1150 def test_flufl_enum(self):
1151 class Fluflnum(Enum):
1152 def __int__(self):
1153 return int(self.value)
1154 class MailManOptions(Fluflnum):
1155 option1 = 1
1156 option2 = 2
1157 option3 = 3
1158 self.assertEqual(int(MailManOptions.option1), 1)
1159
Ethan Furman5e5a8232013-08-04 08:42:23 -07001160 def test_introspection(self):
1161 class Number(IntEnum):
1162 one = 100
1163 two = 200
1164 self.assertIs(Number.one._member_type_, int)
1165 self.assertIs(Number._member_type_, int)
1166 class String(str, Enum):
1167 yarn = 'soft'
1168 rope = 'rough'
1169 wire = 'hard'
1170 self.assertIs(String.yarn._member_type_, str)
1171 self.assertIs(String._member_type_, str)
1172 class Plain(Enum):
1173 vanilla = 'white'
1174 one = 1
1175 self.assertIs(Plain.vanilla._member_type_, object)
1176 self.assertIs(Plain._member_type_, object)
1177
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001178 def test_no_such_enum_member(self):
1179 class Color(Enum):
1180 red = 1
1181 green = 2
1182 blue = 3
1183 with self.assertRaises(ValueError):
1184 Color(4)
1185 with self.assertRaises(KeyError):
1186 Color['chartreuse']
1187
1188 def test_new_repr(self):
1189 class Color(Enum):
1190 red = 1
1191 green = 2
1192 blue = 3
1193 def __repr__(self):
1194 return "don't you just love shades of %s?" % self.name
1195 self.assertEqual(
1196 repr(Color.blue),
1197 "don't you just love shades of blue?",
1198 )
1199
1200 def test_inherited_repr(self):
1201 class MyEnum(Enum):
1202 def __repr__(self):
1203 return "My name is %s." % self.name
1204 class MyIntEnum(int, MyEnum):
1205 this = 1
1206 that = 2
1207 theother = 3
1208 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1209
1210 def test_multiple_mixin_mro(self):
1211 class auto_enum(type(Enum)):
1212 def __new__(metacls, cls, bases, classdict):
1213 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001214 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001215 names = set(classdict._member_names)
1216 i = 0
1217 for k in classdict._member_names:
1218 v = classdict[k]
1219 if v is Ellipsis:
1220 v = i
1221 else:
1222 i = v
1223 i += 1
1224 temp[k] = v
1225 for k, v in classdict.items():
1226 if k not in names:
1227 temp[k] = v
1228 return super(auto_enum, metacls).__new__(
1229 metacls, cls, bases, temp)
1230
1231 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1232 pass
1233
1234 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1235 pass
1236
1237 class TestAutoNumber(AutoNumberedEnum):
1238 a = ...
1239 b = 3
1240 c = ...
1241
1242 class TestAutoInt(AutoIntEnum):
1243 a = ...
1244 b = 3
1245 c = ...
1246
1247 def test_subclasses_with_getnewargs(self):
1248 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001249 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001250 def __new__(cls, *args):
1251 _args = args
1252 name, *args = args
1253 if len(args) == 0:
1254 raise TypeError("name and value must be specified")
1255 self = int.__new__(cls, *args)
1256 self._intname = name
1257 self._args = _args
1258 return self
1259 def __getnewargs__(self):
1260 return self._args
1261 @property
1262 def __name__(self):
1263 return self._intname
1264 def __repr__(self):
1265 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001266 return "{}({!r}, {})".format(
1267 type(self).__name__,
1268 self.__name__,
1269 int.__repr__(self),
1270 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001271 def __str__(self):
1272 # str() is unchanged, even if it relies on the repr() fallback
1273 base = int
1274 base_str = base.__str__
1275 if base_str.__objclass__ is object:
1276 return base.__repr__(self)
1277 return base_str(self)
1278 # for simplicity, we only define one operator that
1279 # propagates expressions
1280 def __add__(self, other):
1281 temp = int(self) + int( other)
1282 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1283 return NamedInt(
1284 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001285 temp,
1286 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001287 else:
1288 return temp
1289
1290 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001291 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001292 x = ('the-x', 1)
1293 y = ('the-y', 2)
1294
Ethan Furman2aa27322013-07-19 19:35:56 -07001295
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001296 self.assertIs(NEI.__new__, Enum.__new__)
1297 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1298 globals()['NamedInt'] = NamedInt
1299 globals()['NEI'] = NEI
1300 NI5 = NamedInt('test', 5)
1301 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001302 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001303 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001304 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001305 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001306
Ethan Furmanca1b7942014-02-08 11:36:27 -08001307 def test_subclasses_with_getnewargs_ex(self):
1308 class NamedInt(int):
1309 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1310 def __new__(cls, *args):
1311 _args = args
1312 name, *args = args
1313 if len(args) == 0:
1314 raise TypeError("name and value must be specified")
1315 self = int.__new__(cls, *args)
1316 self._intname = name
1317 self._args = _args
1318 return self
1319 def __getnewargs_ex__(self):
1320 return self._args, {}
1321 @property
1322 def __name__(self):
1323 return self._intname
1324 def __repr__(self):
1325 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001326 return "{}({!r}, {})".format(
1327 type(self).__name__,
1328 self.__name__,
1329 int.__repr__(self),
1330 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001331 def __str__(self):
1332 # str() is unchanged, even if it relies on the repr() fallback
1333 base = int
1334 base_str = base.__str__
1335 if base_str.__objclass__ is object:
1336 return base.__repr__(self)
1337 return base_str(self)
1338 # for simplicity, we only define one operator that
1339 # propagates expressions
1340 def __add__(self, other):
1341 temp = int(self) + int( other)
1342 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1343 return NamedInt(
1344 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001345 temp,
1346 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001347 else:
1348 return temp
1349
1350 class NEI(NamedInt, Enum):
1351 __qualname__ = 'NEI' # needed for pickle protocol 4
1352 x = ('the-x', 1)
1353 y = ('the-y', 2)
1354
1355
1356 self.assertIs(NEI.__new__, Enum.__new__)
1357 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1358 globals()['NamedInt'] = NamedInt
1359 globals()['NEI'] = NEI
1360 NI5 = NamedInt('test', 5)
1361 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001362 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001363 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001364 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001365 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001366
1367 def test_subclasses_with_reduce(self):
1368 class NamedInt(int):
1369 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1370 def __new__(cls, *args):
1371 _args = args
1372 name, *args = args
1373 if len(args) == 0:
1374 raise TypeError("name and value must be specified")
1375 self = int.__new__(cls, *args)
1376 self._intname = name
1377 self._args = _args
1378 return self
1379 def __reduce__(self):
1380 return self.__class__, self._args
1381 @property
1382 def __name__(self):
1383 return self._intname
1384 def __repr__(self):
1385 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001386 return "{}({!r}, {})".format(
1387 type(self).__name__,
1388 self.__name__,
1389 int.__repr__(self),
1390 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001391 def __str__(self):
1392 # str() is unchanged, even if it relies on the repr() fallback
1393 base = int
1394 base_str = base.__str__
1395 if base_str.__objclass__ is object:
1396 return base.__repr__(self)
1397 return base_str(self)
1398 # for simplicity, we only define one operator that
1399 # propagates expressions
1400 def __add__(self, other):
1401 temp = int(self) + int( other)
1402 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1403 return NamedInt(
1404 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001405 temp,
1406 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001407 else:
1408 return temp
1409
1410 class NEI(NamedInt, Enum):
1411 __qualname__ = 'NEI' # needed for pickle protocol 4
1412 x = ('the-x', 1)
1413 y = ('the-y', 2)
1414
1415
1416 self.assertIs(NEI.__new__, Enum.__new__)
1417 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1418 globals()['NamedInt'] = NamedInt
1419 globals()['NEI'] = NEI
1420 NI5 = NamedInt('test', 5)
1421 self.assertEqual(NI5, 5)
1422 test_pickle_dump_load(self.assertEqual, NI5, 5)
1423 self.assertEqual(NEI.y.value, 2)
1424 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001425 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001426
1427 def test_subclasses_with_reduce_ex(self):
1428 class NamedInt(int):
1429 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1430 def __new__(cls, *args):
1431 _args = args
1432 name, *args = args
1433 if len(args) == 0:
1434 raise TypeError("name and value must be specified")
1435 self = int.__new__(cls, *args)
1436 self._intname = name
1437 self._args = _args
1438 return self
1439 def __reduce_ex__(self, proto):
1440 return self.__class__, self._args
1441 @property
1442 def __name__(self):
1443 return self._intname
1444 def __repr__(self):
1445 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001446 return "{}({!r}, {})".format(
1447 type(self).__name__,
1448 self.__name__,
1449 int.__repr__(self),
1450 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001451 def __str__(self):
1452 # str() is unchanged, even if it relies on the repr() fallback
1453 base = int
1454 base_str = base.__str__
1455 if base_str.__objclass__ is object:
1456 return base.__repr__(self)
1457 return base_str(self)
1458 # for simplicity, we only define one operator that
1459 # propagates expressions
1460 def __add__(self, other):
1461 temp = int(self) + int( other)
1462 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1463 return NamedInt(
1464 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001465 temp,
1466 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001467 else:
1468 return temp
1469
1470 class NEI(NamedInt, Enum):
1471 __qualname__ = 'NEI' # needed for pickle protocol 4
1472 x = ('the-x', 1)
1473 y = ('the-y', 2)
1474
Ethan Furmanca1b7942014-02-08 11:36:27 -08001475 self.assertIs(NEI.__new__, Enum.__new__)
1476 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1477 globals()['NamedInt'] = NamedInt
1478 globals()['NEI'] = NEI
1479 NI5 = NamedInt('test', 5)
1480 self.assertEqual(NI5, 5)
1481 test_pickle_dump_load(self.assertEqual, NI5, 5)
1482 self.assertEqual(NEI.y.value, 2)
1483 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001484 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001485
Ethan Furmandc870522014-02-18 12:37:12 -08001486 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001487 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001488 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001489 def __new__(cls, *args):
1490 _args = args
1491 name, *args = args
1492 if len(args) == 0:
1493 raise TypeError("name and value must be specified")
1494 self = int.__new__(cls, *args)
1495 self._intname = name
1496 self._args = _args
1497 return self
1498 @property
1499 def __name__(self):
1500 return self._intname
1501 def __repr__(self):
1502 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001503 return "{}({!r}, {})".format(
1504 type(self).__name__,
1505 self.__name__,
1506 int.__repr__(self),
1507 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001508 def __str__(self):
1509 # str() is unchanged, even if it relies on the repr() fallback
1510 base = int
1511 base_str = base.__str__
1512 if base_str.__objclass__ is object:
1513 return base.__repr__(self)
1514 return base_str(self)
1515 # for simplicity, we only define one operator that
1516 # propagates expressions
1517 def __add__(self, other):
1518 temp = int(self) + int( other)
1519 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1520 return NamedInt(
1521 '({0} + {1})'.format(self.__name__, other.__name__),
1522 temp )
1523 else:
1524 return temp
1525
1526 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001527 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001528 x = ('the-x', 1)
1529 y = ('the-y', 2)
1530
1531 self.assertIs(NEI.__new__, Enum.__new__)
1532 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1533 globals()['NamedInt'] = NamedInt
1534 globals()['NEI'] = NEI
1535 NI5 = NamedInt('test', 5)
1536 self.assertEqual(NI5, 5)
1537 self.assertEqual(NEI.y.value, 2)
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001538 test_pickle_dump_load(self.assertIs, NEI.y)
1539 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001540
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001541 def test_subclasses_with_direct_pickle_support(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001542 class NamedInt(int):
1543 __qualname__ = 'NamedInt'
1544 def __new__(cls, *args):
1545 _args = args
1546 name, *args = args
1547 if len(args) == 0:
1548 raise TypeError("name and value must be specified")
1549 self = int.__new__(cls, *args)
1550 self._intname = name
1551 self._args = _args
1552 return self
1553 @property
1554 def __name__(self):
1555 return self._intname
1556 def __repr__(self):
1557 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001558 return "{}({!r}, {})".format(
1559 type(self).__name__,
1560 self.__name__,
1561 int.__repr__(self),
1562 )
Ethan Furmandc870522014-02-18 12:37:12 -08001563 def __str__(self):
1564 # str() is unchanged, even if it relies on the repr() fallback
1565 base = int
1566 base_str = base.__str__
1567 if base_str.__objclass__ is object:
1568 return base.__repr__(self)
1569 return base_str(self)
1570 # for simplicity, we only define one operator that
1571 # propagates expressions
1572 def __add__(self, other):
1573 temp = int(self) + int( other)
1574 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1575 return NamedInt(
1576 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001577 temp,
1578 )
Ethan Furmandc870522014-02-18 12:37:12 -08001579 else:
1580 return temp
1581
1582 class NEI(NamedInt, Enum):
1583 __qualname__ = 'NEI'
1584 x = ('the-x', 1)
1585 y = ('the-y', 2)
1586 def __reduce_ex__(self, proto):
1587 return getattr, (self.__class__, self._name_)
1588
1589 self.assertIs(NEI.__new__, Enum.__new__)
1590 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1591 globals()['NamedInt'] = NamedInt
1592 globals()['NEI'] = NEI
1593 NI5 = NamedInt('test', 5)
1594 self.assertEqual(NI5, 5)
1595 self.assertEqual(NEI.y.value, 2)
1596 test_pickle_dump_load(self.assertIs, NEI.y)
1597 test_pickle_dump_load(self.assertIs, NEI)
1598
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001599 def test_tuple_subclass(self):
1600 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001601 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001602 first = (1, 'for the money')
1603 second = (2, 'for the show')
1604 third = (3, 'for the music')
1605 self.assertIs(type(SomeTuple.first), SomeTuple)
1606 self.assertIsInstance(SomeTuple.second, tuple)
1607 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1608 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001609 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001610
1611 def test_duplicate_values_give_unique_enum_items(self):
1612 class AutoNumber(Enum):
1613 first = ()
1614 second = ()
1615 third = ()
1616 def __new__(cls):
1617 value = len(cls.__members__) + 1
1618 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001619 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001620 return obj
1621 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001622 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001623 self.assertEqual(
1624 list(AutoNumber),
1625 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1626 )
1627 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001628 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001629 self.assertIs(AutoNumber(1), AutoNumber.first)
1630
1631 def test_inherited_new_from_enhanced_enum(self):
1632 class AutoNumber(Enum):
1633 def __new__(cls):
1634 value = len(cls.__members__) + 1
1635 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001636 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001637 return obj
1638 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001639 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001640 class Color(AutoNumber):
1641 red = ()
1642 green = ()
1643 blue = ()
1644 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1645 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1646
1647 def test_inherited_new_from_mixed_enum(self):
1648 class AutoNumber(IntEnum):
1649 def __new__(cls):
1650 value = len(cls.__members__) + 1
1651 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001652 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001653 return obj
1654 class Color(AutoNumber):
1655 red = ()
1656 green = ()
1657 blue = ()
1658 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1659 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1660
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001661 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001662 class OrdinaryEnum(Enum):
1663 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001664 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1665 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001666
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001667 def test_ordered_mixin(self):
1668 class OrderedEnum(Enum):
1669 def __ge__(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 __gt__(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 def __le__(self, other):
1678 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001679 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001680 return NotImplemented
1681 def __lt__(self, other):
1682 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001683 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001684 return NotImplemented
1685 class Grade(OrderedEnum):
1686 A = 5
1687 B = 4
1688 C = 3
1689 D = 2
1690 F = 1
1691 self.assertGreater(Grade.A, Grade.B)
1692 self.assertLessEqual(Grade.F, Grade.C)
1693 self.assertLess(Grade.D, Grade.A)
1694 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001695 self.assertEqual(Grade.B, Grade.B)
1696 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001697
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001698 def test_extending2(self):
1699 class Shade(Enum):
1700 def shade(self):
1701 print(self.name)
1702 class Color(Shade):
1703 red = 1
1704 green = 2
1705 blue = 3
1706 with self.assertRaises(TypeError):
1707 class MoreColor(Color):
1708 cyan = 4
1709 magenta = 5
1710 yellow = 6
1711
1712 def test_extending3(self):
1713 class Shade(Enum):
1714 def shade(self):
1715 return self.name
1716 class Color(Shade):
1717 def hex(self):
1718 return '%s hexlified!' % self.value
1719 class MoreColor(Color):
1720 cyan = 4
1721 magenta = 5
1722 yellow = 6
1723 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1724
orlnub1230fb9fad2018-09-12 20:28:53 +03001725 def test_subclass_duplicate_name(self):
1726 class Base(Enum):
1727 def test(self):
1728 pass
1729 class Test(Base):
1730 test = 1
1731 self.assertIs(type(Test.test), Test)
1732
1733 def test_subclass_duplicate_name_dynamic(self):
1734 from types import DynamicClassAttribute
1735 class Base(Enum):
1736 @DynamicClassAttribute
1737 def test(self):
1738 return 'dynamic'
1739 class Test(Base):
1740 test = 1
1741 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001742 class Base2(Enum):
1743 @enum.property
1744 def flash(self):
1745 return 'flashy dynamic'
1746 class Test(Base2):
1747 flash = 1
1748 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001749
1750 def test_no_duplicates(self):
1751 class UniqueEnum(Enum):
1752 def __init__(self, *args):
1753 cls = self.__class__
1754 if any(self.value == e.value for e in cls):
1755 a = self.name
1756 e = cls(self.value).name
1757 raise ValueError(
1758 "aliases not allowed in UniqueEnum: %r --> %r"
1759 % (a, e)
1760 )
1761 class Color(UniqueEnum):
1762 red = 1
1763 green = 2
1764 blue = 3
1765 with self.assertRaises(ValueError):
1766 class Color(UniqueEnum):
1767 red = 1
1768 green = 2
1769 blue = 3
1770 grene = 2
1771
1772 def test_init(self):
1773 class Planet(Enum):
1774 MERCURY = (3.303e+23, 2.4397e6)
1775 VENUS = (4.869e+24, 6.0518e6)
1776 EARTH = (5.976e+24, 6.37814e6)
1777 MARS = (6.421e+23, 3.3972e6)
1778 JUPITER = (1.9e+27, 7.1492e7)
1779 SATURN = (5.688e+26, 6.0268e7)
1780 URANUS = (8.686e+25, 2.5559e7)
1781 NEPTUNE = (1.024e+26, 2.4746e7)
1782 def __init__(self, mass, radius):
1783 self.mass = mass # in kilograms
1784 self.radius = radius # in meters
1785 @property
1786 def surface_gravity(self):
1787 # universal gravitational constant (m3 kg-1 s-2)
1788 G = 6.67300E-11
1789 return G * self.mass / (self.radius * self.radius)
1790 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1791 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1792
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001793 def test_ignore(self):
1794 class Period(timedelta, Enum):
1795 '''
1796 different lengths of time
1797 '''
1798 def __new__(cls, value, period):
1799 obj = timedelta.__new__(cls, value)
1800 obj._value_ = value
1801 obj.period = period
1802 return obj
1803 _ignore_ = 'Period i'
1804 Period = vars()
1805 for i in range(13):
1806 Period['month_%d' % i] = i*30, 'month'
1807 for i in range(53):
1808 Period['week_%d' % i] = i*7, 'week'
1809 for i in range(32):
1810 Period['day_%d' % i] = i, 'day'
1811 OneDay = day_1
1812 OneWeek = week_1
1813 OneMonth = month_1
1814 self.assertFalse(hasattr(Period, '_ignore_'))
1815 self.assertFalse(hasattr(Period, 'Period'))
1816 self.assertFalse(hasattr(Period, 'i'))
1817 self.assertTrue(isinstance(Period.day_1, timedelta))
1818 self.assertTrue(Period.month_1 is Period.day_30)
1819 self.assertTrue(Period.week_4 is Period.day_28)
1820
Ethan Furman2aa27322013-07-19 19:35:56 -07001821 def test_nonhash_value(self):
1822 class AutoNumberInAList(Enum):
1823 def __new__(cls):
1824 value = [len(cls.__members__) + 1]
1825 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001826 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001827 return obj
1828 class ColorInAList(AutoNumberInAList):
1829 red = ()
1830 green = ()
1831 blue = ()
1832 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001833 for enum, value in zip(ColorInAList, range(3)):
1834 value += 1
1835 self.assertEqual(enum.value, [value])
1836 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001837
Ethan Furmanb41803e2013-07-25 13:50:45 -07001838 def test_conflicting_types_resolved_in_new(self):
1839 class LabelledIntEnum(int, Enum):
1840 def __new__(cls, *args):
1841 value, label = args
1842 obj = int.__new__(cls, value)
1843 obj.label = label
1844 obj._value_ = value
1845 return obj
1846
1847 class LabelledList(LabelledIntEnum):
1848 unprocessed = (1, "Unprocessed")
1849 payment_complete = (2, "Payment Complete")
1850
1851 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1852 self.assertEqual(LabelledList.unprocessed, 1)
1853 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001854
Ethan Furmanc16595e2016-09-10 23:36:59 -07001855 def test_auto_number(self):
1856 class Color(Enum):
1857 red = auto()
1858 blue = auto()
1859 green = auto()
1860
1861 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1862 self.assertEqual(Color.red.value, 1)
1863 self.assertEqual(Color.blue.value, 2)
1864 self.assertEqual(Color.green.value, 3)
1865
1866 def test_auto_name(self):
1867 class Color(Enum):
1868 def _generate_next_value_(name, start, count, last):
1869 return name
1870 red = auto()
1871 blue = auto()
1872 green = auto()
1873
1874 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1875 self.assertEqual(Color.red.value, 'red')
1876 self.assertEqual(Color.blue.value, 'blue')
1877 self.assertEqual(Color.green.value, 'green')
1878
1879 def test_auto_name_inherit(self):
1880 class AutoNameEnum(Enum):
1881 def _generate_next_value_(name, start, count, last):
1882 return name
1883 class Color(AutoNameEnum):
1884 red = auto()
1885 blue = auto()
1886 green = auto()
1887
1888 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1889 self.assertEqual(Color.red.value, 'red')
1890 self.assertEqual(Color.blue.value, 'blue')
1891 self.assertEqual(Color.green.value, 'green')
1892
1893 def test_auto_garbage(self):
1894 class Color(Enum):
1895 red = 'red'
1896 blue = auto()
1897 self.assertEqual(Color.blue.value, 1)
1898
1899 def test_auto_garbage_corrected(self):
1900 class Color(Enum):
1901 red = 'red'
1902 blue = 2
1903 green = auto()
1904
1905 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1906 self.assertEqual(Color.red.value, 'red')
1907 self.assertEqual(Color.blue.value, 2)
1908 self.assertEqual(Color.green.value, 3)
1909
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001910 def test_auto_order(self):
1911 with self.assertRaises(TypeError):
1912 class Color(Enum):
1913 red = auto()
1914 green = auto()
1915 blue = auto()
1916 def _generate_next_value_(name, start, count, last):
1917 return name
1918
Ethan Furmanfc23a942020-09-16 12:37:54 -07001919 def test_auto_order_wierd(self):
1920 weird_auto = auto()
1921 weird_auto.value = 'pathological case'
1922 class Color(Enum):
1923 red = weird_auto
1924 def _generate_next_value_(name, start, count, last):
1925 return name
1926 blue = auto()
1927 self.assertEqual(list(Color), [Color.red, Color.blue])
1928 self.assertEqual(Color.red.value, 'pathological case')
1929 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001930
Ethan Furman3515dcc2016-09-18 13:15:41 -07001931 def test_duplicate_auto(self):
1932 class Dupes(Enum):
1933 first = primero = auto()
1934 second = auto()
1935 third = auto()
1936 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1937
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001938 def test_default_missing(self):
1939 class Color(Enum):
1940 RED = 1
1941 GREEN = 2
1942 BLUE = 3
1943 try:
1944 Color(7)
1945 except ValueError as exc:
1946 self.assertTrue(exc.__context__ is None)
1947 else:
1948 raise Exception('Exception not raised.')
1949
Ethan Furman019f0a02018-09-12 11:43:34 -07001950 def test_missing(self):
1951 class Color(Enum):
1952 red = 1
1953 green = 2
1954 blue = 3
1955 @classmethod
1956 def _missing_(cls, item):
1957 if item == 'three':
1958 return cls.blue
1959 elif item == 'bad return':
1960 # trigger internal error
1961 return 5
1962 elif item == 'error out':
1963 raise ZeroDivisionError
1964 else:
1965 # trigger not found
1966 return None
1967 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001968 try:
1969 Color(7)
1970 except ValueError as exc:
1971 self.assertTrue(exc.__context__ is None)
1972 else:
1973 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001974 try:
1975 Color('bad return')
1976 except TypeError as exc:
1977 self.assertTrue(isinstance(exc.__context__, ValueError))
1978 else:
1979 raise Exception('Exception not raised.')
1980 try:
1981 Color('error out')
1982 except ZeroDivisionError as exc:
1983 self.assertTrue(isinstance(exc.__context__, ValueError))
1984 else:
1985 raise Exception('Exception not raised.')
1986
Ethan Furman8c14f5a2021-04-12 08:51:20 -07001987 def test_missing_exceptions_reset(self):
1988 import weakref
1989 #
1990 class TestEnum(enum.Enum):
1991 VAL1 = 'val1'
1992 VAL2 = 'val2'
1993 #
1994 class Class1:
1995 def __init__(self):
1996 # Gracefully handle an exception of our own making
1997 try:
1998 raise ValueError()
1999 except ValueError:
2000 pass
2001 #
2002 class Class2:
2003 def __init__(self):
2004 # Gracefully handle an exception of Enum's making
2005 try:
2006 TestEnum('invalid_value')
2007 except ValueError:
2008 pass
2009 # No strong refs here so these are free to die.
2010 class_1_ref = weakref.ref(Class1())
2011 class_2_ref = weakref.ref(Class2())
2012 #
2013 # The exception raised by Enum creates a reference loop and thus
2014 # Class2 instances will stick around until the next gargage collection
2015 # cycle, unlike Class1.
2016 self.assertIs(class_1_ref(), None)
2017 self.assertIs(class_2_ref(), None)
2018
Ethan Furman5bdab642018-09-21 19:03:09 -07002019 def test_multiple_mixin(self):
2020 class MaxMixin:
2021 @classproperty
2022 def MAX(cls):
2023 max = len(cls)
2024 cls.MAX = max
2025 return max
2026 class StrMixin:
2027 def __str__(self):
2028 return self._name_.lower()
2029 class SomeEnum(Enum):
2030 def behavior(self):
2031 return 'booyah'
2032 class AnotherEnum(Enum):
2033 def behavior(self):
2034 return 'nuhuh!'
2035 def social(self):
2036 return "what's up?"
2037 class Color(MaxMixin, Enum):
2038 RED = auto()
2039 GREEN = auto()
2040 BLUE = auto()
2041 self.assertEqual(Color.RED.value, 1)
2042 self.assertEqual(Color.GREEN.value, 2)
2043 self.assertEqual(Color.BLUE.value, 3)
2044 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002045 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002046 class Color(MaxMixin, StrMixin, Enum):
2047 RED = auto()
2048 GREEN = auto()
2049 BLUE = auto()
2050 self.assertEqual(Color.RED.value, 1)
2051 self.assertEqual(Color.GREEN.value, 2)
2052 self.assertEqual(Color.BLUE.value, 3)
2053 self.assertEqual(Color.MAX, 3)
2054 self.assertEqual(str(Color.BLUE), 'blue')
2055 class Color(StrMixin, MaxMixin, Enum):
2056 RED = auto()
2057 GREEN = auto()
2058 BLUE = auto()
2059 self.assertEqual(Color.RED.value, 1)
2060 self.assertEqual(Color.GREEN.value, 2)
2061 self.assertEqual(Color.BLUE.value, 3)
2062 self.assertEqual(Color.MAX, 3)
2063 self.assertEqual(str(Color.BLUE), 'blue')
2064 class CoolColor(StrMixin, SomeEnum, Enum):
2065 RED = auto()
2066 GREEN = auto()
2067 BLUE = auto()
2068 self.assertEqual(CoolColor.RED.value, 1)
2069 self.assertEqual(CoolColor.GREEN.value, 2)
2070 self.assertEqual(CoolColor.BLUE.value, 3)
2071 self.assertEqual(str(CoolColor.BLUE), 'blue')
2072 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2073 class CoolerColor(StrMixin, AnotherEnum, Enum):
2074 RED = auto()
2075 GREEN = auto()
2076 BLUE = auto()
2077 self.assertEqual(CoolerColor.RED.value, 1)
2078 self.assertEqual(CoolerColor.GREEN.value, 2)
2079 self.assertEqual(CoolerColor.BLUE.value, 3)
2080 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2081 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2082 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2083 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2084 RED = auto()
2085 GREEN = auto()
2086 BLUE = auto()
2087 self.assertEqual(CoolestColor.RED.value, 1)
2088 self.assertEqual(CoolestColor.GREEN.value, 2)
2089 self.assertEqual(CoolestColor.BLUE.value, 3)
2090 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2091 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2092 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2093 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2094 RED = auto()
2095 GREEN = auto()
2096 BLUE = auto()
2097 self.assertEqual(ConfusedColor.RED.value, 1)
2098 self.assertEqual(ConfusedColor.GREEN.value, 2)
2099 self.assertEqual(ConfusedColor.BLUE.value, 3)
2100 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2101 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2102 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2103 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2104 RED = auto()
2105 GREEN = auto()
2106 BLUE = auto()
2107 self.assertEqual(ReformedColor.RED.value, 1)
2108 self.assertEqual(ReformedColor.GREEN.value, 2)
2109 self.assertEqual(ReformedColor.BLUE.value, 3)
2110 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2111 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2112 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2113 self.assertTrue(issubclass(ReformedColor, int))
2114
Ethan Furmancd453852018-10-05 23:29:36 -07002115 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002116 @unique
2117 class Decision1(StrEnum):
2118 REVERT = "REVERT"
2119 REVERT_ALL = "REVERT_ALL"
2120 RETRY = "RETRY"
2121 class MyEnum(StrEnum):
2122 pass
2123 @unique
2124 class Decision2(MyEnum):
2125 REVERT = "REVERT"
2126 REVERT_ALL = "REVERT_ALL"
2127 RETRY = "RETRY"
2128
Ethan Furmanc2667362020-12-07 00:17:31 -08002129 def test_multiple_mixin_inherited(self):
2130 class MyInt(int):
2131 def __new__(cls, value):
2132 return super().__new__(cls, value)
2133
2134 class HexMixin:
2135 def __repr__(self):
2136 return hex(self)
2137
2138 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2139 pass
2140
2141 class Foo(MyIntEnum):
2142 TEST = 1
2143 self.assertTrue(isinstance(Foo.TEST, MyInt))
2144 self.assertEqual(repr(Foo.TEST), "0x1")
2145
2146 class Fee(MyIntEnum):
2147 TEST = 1
2148 def __new__(cls, value):
2149 value += 1
2150 member = int.__new__(cls, value)
2151 member._value_ = value
2152 return member
2153 self.assertEqual(Fee.TEST, 2)
2154
Miss Islington (bot)01286012021-06-10 15:01:03 -07002155 def test_miltuple_mixin_with_common_data_type(self):
2156 class CaseInsensitiveStrEnum(str, Enum):
2157 @classmethod
2158 def _missing_(cls, value):
2159 for member in cls._member_map_.values():
2160 if member._value_.lower() == value.lower():
2161 return member
2162 return super()._missing_(value)
2163 #
2164 class LenientStrEnum(str, Enum):
2165 def __init__(self, *args):
2166 self._valid = True
2167 @classmethod
2168 def _missing_(cls, value):
Miss Islington (bot)01286012021-06-10 15:01:03 -07002169 unknown = cls._member_type_.__new__(cls, value)
2170 unknown._valid = False
2171 unknown._name_ = value.upper()
2172 unknown._value_ = value
2173 cls._member_map_[value] = unknown
2174 return unknown
2175 @property
2176 def valid(self):
2177 return self._valid
2178 #
2179 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2180 ACTIVE = "active"
2181 PENDING = "pending"
2182 TERMINATED = "terminated"
2183 #
2184 JS = JobStatus
2185 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2186 self.assertEqual(JS.ACTIVE, 'active')
2187 self.assertEqual(JS.ACTIVE.value, 'active')
2188 self.assertIs(JS('Active'), JS.ACTIVE)
2189 self.assertTrue(JS.ACTIVE.valid)
2190 missing = JS('missing')
2191 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2192 self.assertEqual(JS.ACTIVE, 'active')
2193 self.assertEqual(JS.ACTIVE.value, 'active')
2194 self.assertIs(JS('Active'), JS.ACTIVE)
2195 self.assertTrue(JS.ACTIVE.valid)
2196 self.assertTrue(isinstance(missing, JS))
2197 self.assertFalse(missing.valid)
2198
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002199 def test_empty_globals(self):
2200 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2201 # when using compile and exec because f_globals is empty
2202 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2203 code = compile(code, "<string>", "exec")
2204 global_ns = {}
2205 local_ls = {}
2206 exec(code, global_ns, local_ls)
2207
Ethan Furman0063ff42020-09-21 17:23:13 -07002208 def test_strenum(self):
2209 class GoodStrEnum(StrEnum):
2210 one = '1'
2211 two = '2'
2212 three = b'3', 'ascii'
2213 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002214 self.assertEqual(GoodStrEnum.one, '1')
2215 self.assertEqual(str(GoodStrEnum.one), '1')
2216 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2217 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2218 #
2219 class DumbMixin:
2220 def __str__(self):
2221 return "don't do this"
2222 class DumbStrEnum(DumbMixin, StrEnum):
2223 five = '5'
2224 six = '6'
2225 seven = '7'
2226 self.assertEqual(DumbStrEnum.seven, '7')
2227 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2228 #
2229 class EnumMixin(Enum):
2230 def hello(self):
2231 print('hello from %s' % (self, ))
2232 class HelloEnum(EnumMixin, StrEnum):
2233 eight = '8'
2234 self.assertEqual(HelloEnum.eight, '8')
2235 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2236 #
2237 class GoodbyeMixin:
2238 def goodbye(self):
2239 print('%s wishes you a fond farewell')
2240 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2241 nine = '9'
2242 self.assertEqual(GoodbyeEnum.nine, '9')
2243 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2244 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002245 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2246 class FirstFailedStrEnum(StrEnum):
2247 one = 1
2248 two = '2'
2249 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2250 class SecondFailedStrEnum(StrEnum):
2251 one = '1'
2252 two = 2,
2253 three = '3'
2254 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2255 class ThirdFailedStrEnum(StrEnum):
2256 one = '1'
2257 two = 2
2258 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2259 class ThirdFailedStrEnum(StrEnum):
2260 one = '1'
2261 two = b'2', sys.getdefaultencoding
2262 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2263 class ThirdFailedStrEnum(StrEnum):
2264 one = '1'
2265 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002266
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002267 def test_missing_value_error(self):
2268 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2269 class Combined(str, Enum):
2270 #
2271 def __new__(cls, value, sequence):
2272 enum = str.__new__(cls, value)
2273 if '(' in value:
2274 fis_name, segment = value.split('(', 1)
2275 segment = segment.strip(' )')
2276 else:
2277 fis_name = value
2278 segment = None
2279 enum.fis_name = fis_name
2280 enum.segment = segment
2281 enum.sequence = sequence
2282 return enum
2283 #
2284 def __repr__(self):
2285 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2286 #
2287 key_type = 'An$(1,2)', 0
2288 company_id = 'An$(3,2)', 1
2289 code = 'An$(5,1)', 2
2290 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002291
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002292 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002293 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002294 'private variables are now normal attributes',
2295 )
2296 def test_warning_for_private_variables(self):
2297 with self.assertWarns(DeprecationWarning):
2298 class Private(Enum):
2299 __corporal = 'Radar'
2300 self.assertEqual(Private._Private__corporal.value, 'Radar')
2301 try:
2302 with self.assertWarns(DeprecationWarning):
2303 class Private(Enum):
2304 __major_ = 'Hoolihan'
2305 except ValueError:
2306 pass
2307
2308 def test_private_variable_is_normal_attribute(self):
2309 class Private(Enum):
2310 __corporal = 'Radar'
2311 __major_ = 'Hoolihan'
2312 self.assertEqual(Private._Private__corporal, 'Radar')
2313 self.assertEqual(Private._Private__major_, 'Hoolihan')
2314
Ethan Furmand65b9032021-02-08 17:32:38 -08002315 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002316 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002317 'member-member access now raises an exception',
2318 )
2319 def test_warning_for_member_from_member_access(self):
2320 with self.assertWarns(DeprecationWarning):
2321 class Di(Enum):
2322 YES = 1
2323 NO = 0
2324 nope = Di.YES.NO
2325 self.assertIs(Di.NO, nope)
2326
2327 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002328 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002329 'member-member access currently issues a warning',
2330 )
2331 def test_exception_for_member_from_member_access(self):
2332 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2333 class Di(Enum):
2334 YES = 1
2335 NO = 0
2336 nope = Di.YES.NO
2337
Ethan Furmanefb13be2020-12-10 12:20:06 -08002338 def test_strenum_auto(self):
2339 class Strings(StrEnum):
2340 ONE = auto()
2341 TWO = auto()
2342 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2343
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002344
Ethan Furmana6582872020-12-10 13:07:00 -08002345 def test_dynamic_members_with_static_methods(self):
2346 #
2347 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2348 class Foo(Enum):
2349 vars().update({
2350 k: v
2351 for k, v in foo_defines.items()
2352 if k.startswith('FOO_')
2353 })
2354 def upper(self):
2355 return self.value.upper()
2356 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2357 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2358 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2359 #
2360 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2361 class FooBar(Enum):
2362 vars().update({
2363 k: v
2364 for k, v in foo_defines.items()
2365 if k.startswith('FOO_')
2366 },
2367 **{'FOO_CAT': 'small'},
2368 )
2369 def upper(self):
2370 return self.value.upper()
2371
2372
Ethan Furmane8e61272016-08-20 07:19:31 -07002373class TestOrder(unittest.TestCase):
2374
2375 def test_same_members(self):
2376 class Color(Enum):
2377 _order_ = 'red green blue'
2378 red = 1
2379 green = 2
2380 blue = 3
2381
2382 def test_same_members_with_aliases(self):
2383 class Color(Enum):
2384 _order_ = 'red green blue'
2385 red = 1
2386 green = 2
2387 blue = 3
2388 verde = green
2389
2390 def test_same_members_wrong_order(self):
2391 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2392 class Color(Enum):
2393 _order_ = 'red green blue'
2394 red = 1
2395 blue = 3
2396 green = 2
2397
2398 def test_order_has_extra_members(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
2406 def test_order_has_extra_members_with_aliases(self):
2407 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2408 class Color(Enum):
2409 _order_ = 'red green blue purple'
2410 red = 1
2411 green = 2
2412 blue = 3
2413 verde = green
2414
2415 def test_enum_has_extra_members(self):
2416 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2417 class Color(Enum):
2418 _order_ = 'red green blue'
2419 red = 1
2420 green = 2
2421 blue = 3
2422 purple = 4
2423
2424 def test_enum_has_extra_members_with_aliases(self):
2425 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2426 class Color(Enum):
2427 _order_ = 'red green blue'
2428 red = 1
2429 green = 2
2430 blue = 3
2431 purple = 4
2432 verde = green
2433
2434
Ethan Furman65a5a472016-09-01 23:55:19 -07002435class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002436 """Tests of the Flags."""
2437
Ethan Furman65a5a472016-09-01 23:55:19 -07002438 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002439 R, W, X = 4, 2, 1
2440
Ethan Furman65a5a472016-09-01 23:55:19 -07002441 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002442 RO = 0
2443 WO = 1
2444 RW = 2
2445 AC = 3
2446 CE = 1<<19
2447
Rahul Jha94306522018-09-10 23:51:04 +05302448 class Color(Flag):
2449 BLACK = 0
2450 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002451 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302452 GREEN = 2
2453 BLUE = 4
2454 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002455 WHITE = RED|GREEN|BLUE
2456 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302457
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002458 def test_str(self):
2459 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002460 self.assertEqual(str(Perm.R), 'R')
2461 self.assertEqual(str(Perm.W), 'W')
2462 self.assertEqual(str(Perm.X), 'X')
2463 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2464 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002465 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002466 self.assertEqual(str(~Perm.R), 'W|X')
2467 self.assertEqual(str(~Perm.W), 'R|X')
2468 self.assertEqual(str(~Perm.X), 'R|W')
2469 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002470 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002471 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002472
2473 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002474 self.assertEqual(str(Open.RO), 'RO')
2475 self.assertEqual(str(Open.WO), 'WO')
2476 self.assertEqual(str(Open.AC), 'AC')
2477 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2478 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2479 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2480 self.assertEqual(str(~Open.WO), 'RW|CE')
2481 self.assertEqual(str(~Open.AC), 'CE')
2482 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2483 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002484
2485 def test_repr(self):
2486 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002487 self.assertEqual(repr(Perm.R), 'Perm.R')
2488 self.assertEqual(repr(Perm.W), 'Perm.W')
2489 self.assertEqual(repr(Perm.X), 'Perm.X')
2490 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2491 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2492 self.assertEqual(repr(Perm(0)), '0x0')
2493 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2494 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2495 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2496 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2497 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2498 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002499
2500 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002501 self.assertEqual(repr(Open.RO), 'Open.RO')
2502 self.assertEqual(repr(Open.WO), 'Open.WO')
2503 self.assertEqual(repr(Open.AC), 'Open.AC')
2504 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2505 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2506 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2507 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2508 self.assertEqual(repr(~Open.AC), 'Open.CE')
2509 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2510 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002511
Ethan Furman37440ee2020-12-08 11:14:10 -08002512 def test_format(self):
2513 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002514 self.assertEqual(format(Perm.R, ''), 'R')
2515 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002516
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002517 def test_or(self):
2518 Perm = self.Perm
2519 for i in Perm:
2520 for j in Perm:
2521 self.assertEqual((i | j), Perm(i.value | j.value))
2522 self.assertEqual((i | j).value, i.value | j.value)
2523 self.assertIs(type(i | j), Perm)
2524 for i in Perm:
2525 self.assertIs(i | i, i)
2526 Open = self.Open
2527 self.assertIs(Open.RO | Open.CE, Open.CE)
2528
2529 def test_and(self):
2530 Perm = self.Perm
2531 RW = Perm.R | Perm.W
2532 RX = Perm.R | Perm.X
2533 WX = Perm.W | Perm.X
2534 RWX = Perm.R | Perm.W | Perm.X
2535 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2536 for i in values:
2537 for j in values:
2538 self.assertEqual((i & j).value, i.value & j.value)
2539 self.assertIs(type(i & j), Perm)
2540 for i in Perm:
2541 self.assertIs(i & i, i)
2542 self.assertIs(i & RWX, i)
2543 self.assertIs(RWX & i, i)
2544 Open = self.Open
2545 self.assertIs(Open.RO & Open.CE, Open.RO)
2546
2547 def test_xor(self):
2548 Perm = self.Perm
2549 for i in Perm:
2550 for j in Perm:
2551 self.assertEqual((i ^ j).value, i.value ^ j.value)
2552 self.assertIs(type(i ^ j), Perm)
2553 for i in Perm:
2554 self.assertIs(i ^ Perm(0), i)
2555 self.assertIs(Perm(0) ^ i, i)
2556 Open = self.Open
2557 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2558 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2559
2560 def test_invert(self):
2561 Perm = self.Perm
2562 RW = Perm.R | Perm.W
2563 RX = Perm.R | Perm.X
2564 WX = Perm.W | Perm.X
2565 RWX = Perm.R | Perm.W | Perm.X
2566 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2567 for i in values:
2568 self.assertIs(type(~i), Perm)
2569 self.assertEqual(~~i, i)
2570 for i in Perm:
2571 self.assertIs(~~i, i)
2572 Open = self.Open
2573 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2574 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2575
Ethan Furman25d94bb2016-09-02 16:32:32 -07002576 def test_bool(self):
2577 Perm = self.Perm
2578 for f in Perm:
2579 self.assertTrue(f)
2580 Open = self.Open
2581 for f in Open:
2582 self.assertEqual(bool(f.value), bool(f))
2583
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002584 def test_boundary(self):
2585 self.assertIs(enum.Flag._boundary_, STRICT)
2586 class Iron(Flag, boundary=STRICT):
2587 ONE = 1
2588 TWO = 2
2589 EIGHT = 8
2590 self.assertIs(Iron._boundary_, STRICT)
2591 #
2592 class Water(Flag, boundary=CONFORM):
2593 ONE = 1
2594 TWO = 2
2595 EIGHT = 8
2596 self.assertIs(Water._boundary_, CONFORM)
2597 #
2598 class Space(Flag, boundary=EJECT):
2599 ONE = 1
2600 TWO = 2
2601 EIGHT = 8
2602 self.assertIs(Space._boundary_, EJECT)
2603 #
2604 class Bizarre(Flag, boundary=KEEP):
2605 b = 3
2606 c = 4
2607 d = 6
2608 #
2609 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002610 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002611 self.assertIs(Water(7), Water.ONE|Water.TWO)
2612 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002613 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002614 self.assertEqual(Space(7), 7)
2615 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002616 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002617 self.assertEqual(list(Bizarre), [Bizarre.c])
2618 self.assertIs(Bizarre(3), Bizarre.b)
2619 self.assertIs(Bizarre(6), Bizarre.d)
2620
2621 def test_iter(self):
2622 Color = self.Color
2623 Open = self.Open
2624 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2625 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2626
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002627 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002628 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002629 lst = list(Perm)
2630 self.assertEqual(len(lst), len(Perm))
2631 self.assertEqual(len(Perm), 3, Perm)
2632 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2633 for i, n in enumerate('R W X'.split()):
2634 v = 1<<i
2635 e = Perm(v)
2636 self.assertEqual(e.value, v)
2637 self.assertEqual(type(e.value), int)
2638 self.assertEqual(e.name, n)
2639 self.assertIn(e, Perm)
2640 self.assertIs(type(e), Perm)
2641
2642 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002643 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002644 lst = list(Perm)
2645 self.assertEqual(len(lst), len(Perm))
2646 self.assertEqual(len(Perm), 3, Perm)
2647 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2648 for i, n in enumerate('R W X'.split()):
2649 v = 8<<i
2650 e = Perm(v)
2651 self.assertEqual(e.value, v)
2652 self.assertEqual(type(e.value), int)
2653 self.assertEqual(e.name, n)
2654 self.assertIn(e, Perm)
2655 self.assertIs(type(e), Perm)
2656
2657 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002658 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002659 lst = list(Perm)
2660 self.assertEqual(len(lst), len(Perm))
2661 self.assertEqual(len(Perm), 3, Perm)
2662 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2663 for i, n in enumerate('R W X'.split()):
2664 v = 1<<i
2665 e = Perm(v)
2666 self.assertEqual(e.value, v)
2667 self.assertEqual(type(e.value), int)
2668 self.assertEqual(e.name, n)
2669 self.assertIn(e, Perm)
2670 self.assertIs(type(e), Perm)
2671
2672 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002673 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002674 lst = list(Perm)
2675 self.assertEqual(len(lst), len(Perm))
2676 self.assertEqual(len(Perm), 3, Perm)
2677 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2678 for i, n in enumerate('R W X'.split()):
2679 v = 1<<(2*i+1)
2680 e = Perm(v)
2681 self.assertEqual(e.value, v)
2682 self.assertEqual(type(e.value), int)
2683 self.assertEqual(e.name, n)
2684 self.assertIn(e, Perm)
2685 self.assertIs(type(e), Perm)
2686
2687 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002688 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002689 lst = list(Perm)
2690 self.assertEqual(len(lst), len(Perm))
2691 self.assertEqual(len(Perm), 3, Perm)
2692 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2693 for i, n in enumerate('R W X'.split()):
2694 v = 1<<(2*i+1)
2695 e = Perm(v)
2696 self.assertEqual(e.value, v)
2697 self.assertEqual(type(e.value), int)
2698 self.assertEqual(e.name, n)
2699 self.assertIn(e, Perm)
2700 self.assertIs(type(e), Perm)
2701
Ethan Furman65a5a472016-09-01 23:55:19 -07002702 def test_pickle(self):
2703 if isinstance(FlagStooges, Exception):
2704 raise FlagStooges
2705 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2706 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002707
Ethan Furman6bd92882021-04-27 13:05:08 -07002708 @unittest.skipIf(
2709 python_version >= (3, 12),
2710 '__contains__ now returns True/False for all inputs',
2711 )
2712 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302713 Open = self.Open
2714 Color = self.Color
2715 self.assertFalse(Color.BLACK in Open)
2716 self.assertFalse(Open.RO in Color)
2717 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002718 with self.assertWarns(DeprecationWarning):
2719 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302720 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002721 with self.assertWarns(DeprecationWarning):
2722 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302723 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002724 with self.assertWarns(DeprecationWarning):
2725 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302726 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002727 with self.assertWarns(DeprecationWarning):
2728 1 in Open
2729
2730 @unittest.skipIf(
2731 python_version < (3, 12),
2732 '__contains__ only works with enum memmbers before 3.12',
2733 )
2734 def test_contains_tf(self):
2735 Open = self.Open
2736 Color = self.Color
2737 self.assertFalse(Color.BLACK in Open)
2738 self.assertFalse(Open.RO in Color)
2739 self.assertFalse('BLACK' in Color)
2740 self.assertFalse('RO' in Open)
2741 self.assertTrue(1 in Color)
2742 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302743
2744 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002745 Perm = self.Perm
2746 R, W, X = Perm
2747 RW = R | W
2748 RX = R | X
2749 WX = W | X
2750 RWX = R | W | X
2751 self.assertTrue(R in RW)
2752 self.assertTrue(R in RX)
2753 self.assertTrue(R in RWX)
2754 self.assertTrue(W in RW)
2755 self.assertTrue(W in WX)
2756 self.assertTrue(W in RWX)
2757 self.assertTrue(X in RX)
2758 self.assertTrue(X in WX)
2759 self.assertTrue(X in RWX)
2760 self.assertFalse(R in WX)
2761 self.assertFalse(W in RX)
2762 self.assertFalse(X in RW)
2763
Ethan Furman7219e272020-09-16 13:01:00 -07002764 def test_member_iter(self):
2765 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002766 self.assertEqual(list(Color.BLACK), [])
2767 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002768 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2769 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002770 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2771 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2772
2773 def test_member_length(self):
2774 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2775 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2776 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2777 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2778
2779 def test_number_reset_and_order_cleanup(self):
2780 class Confused(Flag):
2781 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2782 ONE = auto()
2783 TWO = auto()
2784 FOUR = auto()
2785 DOS = 2
2786 EIGHT = auto()
2787 SIXTEEN = auto()
2788 self.assertEqual(
2789 list(Confused),
2790 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2791 self.assertIs(Confused.TWO, Confused.DOS)
2792 self.assertEqual(Confused.DOS._value_, 2)
2793 self.assertEqual(Confused.EIGHT._value_, 8)
2794 self.assertEqual(Confused.SIXTEEN._value_, 16)
2795
2796 def test_aliases(self):
2797 Color = self.Color
2798 self.assertEqual(Color(1).name, 'RED')
2799 self.assertEqual(Color['ROJO'].name, 'RED')
2800 self.assertEqual(Color(7).name, 'WHITE')
2801 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2802 self.assertIs(Color.BLANCO, Color.WHITE)
2803 Open = self.Open
2804 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002805
Ethan Furmanc16595e2016-09-10 23:36:59 -07002806 def test_auto_number(self):
2807 class Color(Flag):
2808 red = auto()
2809 blue = auto()
2810 green = auto()
2811
2812 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2813 self.assertEqual(Color.red.value, 1)
2814 self.assertEqual(Color.blue.value, 2)
2815 self.assertEqual(Color.green.value, 4)
2816
2817 def test_auto_number_garbage(self):
2818 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2819 class Color(Flag):
2820 red = 'not an int'
2821 blue = auto()
2822
Ethan Furman3515dcc2016-09-18 13:15:41 -07002823 def test_duplicate_auto(self):
2824 class Dupes(Enum):
2825 first = primero = auto()
2826 second = auto()
2827 third = auto()
2828 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2829
Ethan Furman5bdab642018-09-21 19:03:09 -07002830 def test_multiple_mixin(self):
2831 class AllMixin:
2832 @classproperty
2833 def ALL(cls):
2834 members = list(cls)
2835 all_value = None
2836 if members:
2837 all_value = members[0]
2838 for member in members[1:]:
2839 all_value |= member
2840 cls.ALL = all_value
2841 return all_value
2842 class StrMixin:
2843 def __str__(self):
2844 return self._name_.lower()
2845 class Color(AllMixin, Flag):
2846 RED = auto()
2847 GREEN = auto()
2848 BLUE = auto()
2849 self.assertEqual(Color.RED.value, 1)
2850 self.assertEqual(Color.GREEN.value, 2)
2851 self.assertEqual(Color.BLUE.value, 4)
2852 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002853 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002854 class Color(AllMixin, StrMixin, Flag):
2855 RED = auto()
2856 GREEN = auto()
2857 BLUE = auto()
2858 self.assertEqual(Color.RED.value, 1)
2859 self.assertEqual(Color.GREEN.value, 2)
2860 self.assertEqual(Color.BLUE.value, 4)
2861 self.assertEqual(Color.ALL.value, 7)
2862 self.assertEqual(str(Color.BLUE), 'blue')
2863 class Color(StrMixin, AllMixin, Flag):
2864 RED = auto()
2865 GREEN = auto()
2866 BLUE = auto()
2867 self.assertEqual(Color.RED.value, 1)
2868 self.assertEqual(Color.GREEN.value, 2)
2869 self.assertEqual(Color.BLUE.value, 4)
2870 self.assertEqual(Color.ALL.value, 7)
2871 self.assertEqual(str(Color.BLUE), 'blue')
2872
Hai Shie80697d2020-05-28 06:10:27 +08002873 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002874 def test_unique_composite(self):
2875 # override __eq__ to be identity only
2876 class TestFlag(Flag):
2877 one = auto()
2878 two = auto()
2879 three = auto()
2880 four = auto()
2881 five = auto()
2882 six = auto()
2883 seven = auto()
2884 eight = auto()
2885 def __eq__(self, other):
2886 return self is other
2887 def __hash__(self):
2888 return hash(self._value_)
2889 # have multiple threads competing to complete the composite members
2890 seen = set()
2891 failed = False
2892 def cycle_enum():
2893 nonlocal failed
2894 try:
2895 for i in range(256):
2896 seen.add(TestFlag(i))
2897 except Exception:
2898 failed = True
2899 threads = [
2900 threading.Thread(target=cycle_enum)
2901 for _ in range(8)
2902 ]
Hai Shie80697d2020-05-28 06:10:27 +08002903 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002904 pass
2905 # check that only 248 members were created
2906 self.assertFalse(
2907 failed,
2908 'at least one thread failed while creating composite members')
2909 self.assertEqual(256, len(seen), 'too many composite members created')
2910
Ethan Furman6bd94de2020-12-09 16:41:22 -08002911 def test_init_subclass(self):
2912 class MyEnum(Flag):
2913 def __init_subclass__(cls, **kwds):
2914 super().__init_subclass__(**kwds)
2915 self.assertFalse(cls.__dict__.get('_test', False))
2916 cls._test1 = 'MyEnum'
2917 #
2918 class TheirEnum(MyEnum):
2919 def __init_subclass__(cls, **kwds):
2920 super(TheirEnum, cls).__init_subclass__(**kwds)
2921 cls._test2 = 'TheirEnum'
2922 class WhoseEnum(TheirEnum):
2923 def __init_subclass__(cls, **kwds):
2924 pass
2925 class NoEnum(WhoseEnum):
2926 ONE = 1
2927 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2928 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2929 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2930 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2931 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2932 #
2933 class OurEnum(MyEnum):
2934 def __init_subclass__(cls, **kwds):
2935 cls._test2 = 'OurEnum'
2936 class WhereEnum(OurEnum):
2937 def __init_subclass__(cls, **kwds):
2938 pass
2939 class NeverEnum(WhereEnum):
2940 ONE = 1
2941 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2942 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2943 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2944 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2945 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2946
Ethan Furmanc16595e2016-09-10 23:36:59 -07002947
Ethan Furman65a5a472016-09-01 23:55:19 -07002948class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002949 """Tests of the IntFlags."""
2950
Ethan Furman65a5a472016-09-01 23:55:19 -07002951 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002952 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002953 W = 1 << 1
2954 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002955
Ethan Furman65a5a472016-09-01 23:55:19 -07002956 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002957 RO = 0
2958 WO = 1
2959 RW = 2
2960 AC = 3
2961 CE = 1<<19
2962
Rahul Jha94306522018-09-10 23:51:04 +05302963 class Color(IntFlag):
2964 BLACK = 0
2965 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002966 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302967 GREEN = 2
2968 BLUE = 4
2969 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002970 WHITE = RED|GREEN|BLUE
2971 BLANCO = RED|GREEN|BLUE
2972
2973 class Skip(IntFlag):
2974 FIRST = 1
2975 SECOND = 2
2976 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302977
Ethan Furman3515dcc2016-09-18 13:15:41 -07002978 def test_type(self):
2979 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002980 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002981 Open = self.Open
2982 for f in Perm:
2983 self.assertTrue(isinstance(f, Perm))
2984 self.assertEqual(f, f.value)
2985 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2986 self.assertEqual(Perm.W | Perm.X, 3)
2987 for f in Open:
2988 self.assertTrue(isinstance(f, Open))
2989 self.assertEqual(f, f.value)
2990 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2991 self.assertEqual(Open.WO | Open.RW, 3)
2992
2993
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002994 def test_str(self):
2995 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002996 self.assertEqual(str(Perm.R), 'R')
2997 self.assertEqual(str(Perm.W), 'W')
2998 self.assertEqual(str(Perm.X), 'X')
2999 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
3000 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003001 self.assertEqual(str(Perm.R | 8), '12')
3002 self.assertEqual(str(Perm(0)), 'Perm(0)')
3003 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003004 self.assertEqual(str(~Perm.R), 'W|X')
3005 self.assertEqual(str(~Perm.W), 'R|X')
3006 self.assertEqual(str(~Perm.X), 'R|W')
3007 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003008 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3009 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003010 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003011 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003012
3013 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003014 self.assertEqual(str(Open.RO), 'RO')
3015 self.assertEqual(str(Open.WO), 'WO')
3016 self.assertEqual(str(Open.AC), 'AC')
3017 self.assertEqual(str(Open.RO | Open.CE), 'CE')
3018 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003019 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003020 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3021 self.assertEqual(str(~Open.WO), 'RW|CE')
3022 self.assertEqual(str(~Open.AC), 'CE')
3023 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3024 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003025 self.assertEqual(str(Open(~4)), '-5')
3026
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003027 def test_repr(self):
3028 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003029 self.assertEqual(repr(Perm.R), 'Perm.R')
3030 self.assertEqual(repr(Perm.W), 'Perm.W')
3031 self.assertEqual(repr(Perm.X), 'Perm.X')
3032 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3033 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003034 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07003035 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003036 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003037 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3038 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3039 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3040 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3041 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003042 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003043 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003044 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003045
3046 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003047 self.assertEqual(repr(Open.RO), 'Open.RO')
3048 self.assertEqual(repr(Open.WO), 'Open.WO')
3049 self.assertEqual(repr(Open.AC), 'Open.AC')
3050 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3051 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003052 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003053 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3054 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3055 self.assertEqual(repr(~Open.AC), 'Open.CE')
3056 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3057 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003058 self.assertEqual(repr(Open(~4)), '-5')
3059
Ethan Furman6bd92882021-04-27 13:05:08 -07003060 @unittest.skipUnless(
3061 python_version < (3, 12),
3062 'mixin-format now uses member instead of member.value',
3063 )
Ethan Furman37440ee2020-12-08 11:14:10 -08003064 def test_format(self):
Ethan Furman6bd92882021-04-27 13:05:08 -07003065 with self.assertWarns(DeprecationWarning):
3066 Perm = self.Perm
3067 self.assertEqual(format(Perm.R, ''), '4')
3068 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08003069
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003070 def test_or(self):
3071 Perm = self.Perm
3072 for i in Perm:
3073 for j in Perm:
3074 self.assertEqual(i | j, i.value | j.value)
3075 self.assertEqual((i | j).value, i.value | j.value)
3076 self.assertIs(type(i | j), Perm)
3077 for j in range(8):
3078 self.assertEqual(i | j, i.value | j)
3079 self.assertEqual((i | j).value, i.value | j)
3080 self.assertIs(type(i | j), Perm)
3081 self.assertEqual(j | i, j | i.value)
3082 self.assertEqual((j | i).value, j | i.value)
3083 self.assertIs(type(j | i), Perm)
3084 for i in Perm:
3085 self.assertIs(i | i, i)
3086 self.assertIs(i | 0, i)
3087 self.assertIs(0 | i, i)
3088 Open = self.Open
3089 self.assertIs(Open.RO | Open.CE, Open.CE)
3090
3091 def test_and(self):
3092 Perm = self.Perm
3093 RW = Perm.R | Perm.W
3094 RX = Perm.R | Perm.X
3095 WX = Perm.W | Perm.X
3096 RWX = Perm.R | Perm.W | Perm.X
3097 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3098 for i in values:
3099 for j in values:
3100 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3101 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3102 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3103 for j in range(8):
3104 self.assertEqual(i & j, i.value & j)
3105 self.assertEqual((i & j).value, i.value & j)
3106 self.assertIs(type(i & j), Perm)
3107 self.assertEqual(j & i, j & i.value)
3108 self.assertEqual((j & i).value, j & i.value)
3109 self.assertIs(type(j & i), Perm)
3110 for i in Perm:
3111 self.assertIs(i & i, i)
3112 self.assertIs(i & 7, i)
3113 self.assertIs(7 & i, i)
3114 Open = self.Open
3115 self.assertIs(Open.RO & Open.CE, Open.RO)
3116
3117 def test_xor(self):
3118 Perm = self.Perm
3119 for i in Perm:
3120 for j in Perm:
3121 self.assertEqual(i ^ j, i.value ^ j.value)
3122 self.assertEqual((i ^ j).value, i.value ^ j.value)
3123 self.assertIs(type(i ^ j), Perm)
3124 for j in range(8):
3125 self.assertEqual(i ^ j, i.value ^ j)
3126 self.assertEqual((i ^ j).value, i.value ^ j)
3127 self.assertIs(type(i ^ j), Perm)
3128 self.assertEqual(j ^ i, j ^ i.value)
3129 self.assertEqual((j ^ i).value, j ^ i.value)
3130 self.assertIs(type(j ^ i), Perm)
3131 for i in Perm:
3132 self.assertIs(i ^ 0, i)
3133 self.assertIs(0 ^ i, i)
3134 Open = self.Open
3135 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3136 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3137
3138 def test_invert(self):
3139 Perm = self.Perm
3140 RW = Perm.R | Perm.W
3141 RX = Perm.R | Perm.X
3142 WX = Perm.W | Perm.X
3143 RWX = Perm.R | Perm.W | Perm.X
3144 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3145 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003146 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003147 self.assertIs(type(~i), Perm)
3148 self.assertEqual(~~i, i)
3149 for i in Perm:
3150 self.assertIs(~~i, i)
3151 Open = self.Open
3152 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3153 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3154
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003155 def test_boundary(self):
3156 self.assertIs(enum.IntFlag._boundary_, EJECT)
3157 class Iron(IntFlag, boundary=STRICT):
3158 ONE = 1
3159 TWO = 2
3160 EIGHT = 8
3161 self.assertIs(Iron._boundary_, STRICT)
3162 #
3163 class Water(IntFlag, boundary=CONFORM):
3164 ONE = 1
3165 TWO = 2
3166 EIGHT = 8
3167 self.assertIs(Water._boundary_, CONFORM)
3168 #
3169 class Space(IntFlag, boundary=EJECT):
3170 ONE = 1
3171 TWO = 2
3172 EIGHT = 8
3173 self.assertIs(Space._boundary_, EJECT)
3174 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003175 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003176 class Bizarre(IntFlag, boundary=KEEP):
3177 b = 3
3178 c = 4
3179 d = 6
3180 #
3181 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003182 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003183 self.assertIs(Water(7), Water.ONE|Water.TWO)
3184 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003185 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003186 self.assertEqual(Space(7), 7)
3187 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003188 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003189 self.assertEqual(list(Bizarre), [Bizarre.c])
3190 self.assertIs(Bizarre(3), Bizarre.b)
3191 self.assertIs(Bizarre(6), Bizarre.d)
3192
3193 def test_iter(self):
3194 Color = self.Color
3195 Open = self.Open
3196 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3197 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3198
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003199 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003200 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003201 lst = list(Perm)
3202 self.assertEqual(len(lst), len(Perm))
3203 self.assertEqual(len(Perm), 3, Perm)
3204 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3205 for i, n in enumerate('R W X'.split()):
3206 v = 1<<i
3207 e = Perm(v)
3208 self.assertEqual(e.value, v)
3209 self.assertEqual(type(e.value), int)
3210 self.assertEqual(e, v)
3211 self.assertEqual(e.name, n)
3212 self.assertIn(e, Perm)
3213 self.assertIs(type(e), Perm)
3214
3215 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003216 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003217 lst = list(Perm)
3218 self.assertEqual(len(lst), len(Perm))
3219 self.assertEqual(len(Perm), 3, Perm)
3220 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3221 for i, n in enumerate('R W X'.split()):
3222 v = 8<<i
3223 e = Perm(v)
3224 self.assertEqual(e.value, v)
3225 self.assertEqual(type(e.value), int)
3226 self.assertEqual(e, v)
3227 self.assertEqual(e.name, n)
3228 self.assertIn(e, Perm)
3229 self.assertIs(type(e), Perm)
3230
3231 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003232 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003233 lst = list(Perm)
3234 self.assertEqual(len(lst), len(Perm))
3235 self.assertEqual(len(Perm), 3, Perm)
3236 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3237 for i, n in enumerate('R W X'.split()):
3238 v = 1<<i
3239 e = Perm(v)
3240 self.assertEqual(e.value, v)
3241 self.assertEqual(type(e.value), int)
3242 self.assertEqual(e, v)
3243 self.assertEqual(e.name, n)
3244 self.assertIn(e, Perm)
3245 self.assertIs(type(e), Perm)
3246
3247 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003248 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003249 lst = list(Perm)
3250 self.assertEqual(len(lst), len(Perm))
3251 self.assertEqual(len(Perm), 3, Perm)
3252 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3253 for i, n in enumerate('R W X'.split()):
3254 v = 1<<(2*i+1)
3255 e = Perm(v)
3256 self.assertEqual(e.value, v)
3257 self.assertEqual(type(e.value), int)
3258 self.assertEqual(e, v)
3259 self.assertEqual(e.name, n)
3260 self.assertIn(e, Perm)
3261 self.assertIs(type(e), Perm)
3262
3263 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003264 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003265 lst = list(Perm)
3266 self.assertEqual(len(lst), len(Perm))
3267 self.assertEqual(len(Perm), 3, Perm)
3268 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3269 for i, n in enumerate('R W X'.split()):
3270 v = 1<<(2*i+1)
3271 e = Perm(v)
3272 self.assertEqual(e.value, v)
3273 self.assertEqual(type(e.value), int)
3274 self.assertEqual(e, v)
3275 self.assertEqual(e.name, n)
3276 self.assertIn(e, Perm)
3277 self.assertIs(type(e), Perm)
3278
3279
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003280 def test_programatic_function_from_empty_list(self):
3281 Perm = enum.IntFlag('Perm', [])
3282 lst = list(Perm)
3283 self.assertEqual(len(lst), len(Perm))
3284 self.assertEqual(len(Perm), 0, Perm)
3285 Thing = enum.Enum('Thing', [])
3286 lst = list(Thing)
3287 self.assertEqual(len(lst), len(Thing))
3288 self.assertEqual(len(Thing), 0, Thing)
3289
3290
3291 def test_programatic_function_from_empty_tuple(self):
3292 Perm = enum.IntFlag('Perm', ())
3293 lst = list(Perm)
3294 self.assertEqual(len(lst), len(Perm))
3295 self.assertEqual(len(Perm), 0, Perm)
3296 Thing = enum.Enum('Thing', ())
3297 self.assertEqual(len(lst), len(Thing))
3298 self.assertEqual(len(Thing), 0, Thing)
3299
Ethan Furman6bd92882021-04-27 13:05:08 -07003300 @unittest.skipIf(
3301 python_version >= (3, 12),
3302 '__contains__ now returns True/False for all inputs',
3303 )
3304 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303305 Open = self.Open
3306 Color = self.Color
3307 self.assertTrue(Color.GREEN in Color)
3308 self.assertTrue(Open.RW in Open)
3309 self.assertFalse(Color.GREEN in Open)
3310 self.assertFalse(Open.RW in Color)
3311 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003312 with self.assertWarns(DeprecationWarning):
3313 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303314 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003315 with self.assertWarns(DeprecationWarning):
3316 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05303317 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003318 with self.assertWarns(DeprecationWarning):
3319 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05303320 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003321 with self.assertWarns(DeprecationWarning):
3322 2 in Open
3323
3324 @unittest.skipIf(
3325 python_version < (3, 12),
3326 '__contains__ only works with enum memmbers before 3.12',
3327 )
3328 def test_contains_tf(self):
3329 Open = self.Open
3330 Color = self.Color
3331 self.assertTrue(Color.GREEN in Color)
3332 self.assertTrue(Open.RW in Open)
3333 self.assertTrue(Color.GREEN in Open)
3334 self.assertTrue(Open.RW in Color)
3335 self.assertFalse('GREEN' in Color)
3336 self.assertFalse('RW' in Open)
3337 self.assertTrue(2 in Color)
3338 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303339
3340 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003341 Perm = self.Perm
3342 R, W, X = Perm
3343 RW = R | W
3344 RX = R | X
3345 WX = W | X
3346 RWX = R | W | X
3347 self.assertTrue(R in RW)
3348 self.assertTrue(R in RX)
3349 self.assertTrue(R in RWX)
3350 self.assertTrue(W in RW)
3351 self.assertTrue(W in WX)
3352 self.assertTrue(W in RWX)
3353 self.assertTrue(X in RX)
3354 self.assertTrue(X in WX)
3355 self.assertTrue(X in RWX)
3356 self.assertFalse(R in WX)
3357 self.assertFalse(W in RX)
3358 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303359 with self.assertRaises(TypeError):
3360 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003361
Ethan Furman7219e272020-09-16 13:01:00 -07003362 def test_member_iter(self):
3363 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003364 self.assertEqual(list(Color.BLACK), [])
3365 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003366 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3367 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003368 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3369
3370 def test_member_length(self):
3371 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3372 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3373 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3374 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3375
3376 def test_aliases(self):
3377 Color = self.Color
3378 self.assertEqual(Color(1).name, 'RED')
3379 self.assertEqual(Color['ROJO'].name, 'RED')
3380 self.assertEqual(Color(7).name, 'WHITE')
3381 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3382 self.assertIs(Color.BLANCO, Color.WHITE)
3383 Open = self.Open
3384 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003385
Ethan Furman25d94bb2016-09-02 16:32:32 -07003386 def test_bool(self):
3387 Perm = self.Perm
3388 for f in Perm:
3389 self.assertTrue(f)
3390 Open = self.Open
3391 for f in Open:
3392 self.assertEqual(bool(f.value), bool(f))
3393
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003394
Ethan Furman5bdab642018-09-21 19:03:09 -07003395 def test_multiple_mixin(self):
3396 class AllMixin:
3397 @classproperty
3398 def ALL(cls):
3399 members = list(cls)
3400 all_value = None
3401 if members:
3402 all_value = members[0]
3403 for member in members[1:]:
3404 all_value |= member
3405 cls.ALL = all_value
3406 return all_value
3407 class StrMixin:
3408 def __str__(self):
3409 return self._name_.lower()
3410 class Color(AllMixin, IntFlag):
3411 RED = auto()
3412 GREEN = auto()
3413 BLUE = auto()
3414 self.assertEqual(Color.RED.value, 1)
3415 self.assertEqual(Color.GREEN.value, 2)
3416 self.assertEqual(Color.BLUE.value, 4)
3417 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003418 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003419 class Color(AllMixin, StrMixin, IntFlag):
3420 RED = auto()
3421 GREEN = auto()
3422 BLUE = auto()
3423 self.assertEqual(Color.RED.value, 1)
3424 self.assertEqual(Color.GREEN.value, 2)
3425 self.assertEqual(Color.BLUE.value, 4)
3426 self.assertEqual(Color.ALL.value, 7)
3427 self.assertEqual(str(Color.BLUE), 'blue')
3428 class Color(StrMixin, AllMixin, IntFlag):
3429 RED = auto()
3430 GREEN = auto()
3431 BLUE = auto()
3432 self.assertEqual(Color.RED.value, 1)
3433 self.assertEqual(Color.GREEN.value, 2)
3434 self.assertEqual(Color.BLUE.value, 4)
3435 self.assertEqual(Color.ALL.value, 7)
3436 self.assertEqual(str(Color.BLUE), 'blue')
3437
Hai Shie80697d2020-05-28 06:10:27 +08003438 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003439 def test_unique_composite(self):
3440 # override __eq__ to be identity only
3441 class TestFlag(IntFlag):
3442 one = auto()
3443 two = auto()
3444 three = auto()
3445 four = auto()
3446 five = auto()
3447 six = auto()
3448 seven = auto()
3449 eight = auto()
3450 def __eq__(self, other):
3451 return self is other
3452 def __hash__(self):
3453 return hash(self._value_)
3454 # have multiple threads competing to complete the composite members
3455 seen = set()
3456 failed = False
3457 def cycle_enum():
3458 nonlocal failed
3459 try:
3460 for i in range(256):
3461 seen.add(TestFlag(i))
3462 except Exception:
3463 failed = True
3464 threads = [
3465 threading.Thread(target=cycle_enum)
3466 for _ in range(8)
3467 ]
Hai Shie80697d2020-05-28 06:10:27 +08003468 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003469 pass
3470 # check that only 248 members were created
3471 self.assertFalse(
3472 failed,
3473 'at least one thread failed while creating composite members')
3474 self.assertEqual(256, len(seen), 'too many composite members created')
3475
3476
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003477class TestEmptyAndNonLatinStrings(unittest.TestCase):
3478
3479 def test_empty_string(self):
3480 with self.assertRaises(ValueError):
3481 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3482
3483 def test_non_latin_character_string(self):
3484 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3485 item = getattr(greek_abc, '\u03B1')
3486 self.assertEqual(item.value, 1)
3487
3488 def test_non_latin_number_string(self):
3489 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3490 item = getattr(hebrew_123, '\u05D0')
3491 self.assertEqual(item.value, 1)
3492
3493
Ethan Furmanf24bb352013-07-18 17:05:39 -07003494class TestUnique(unittest.TestCase):
3495
3496 def test_unique_clean(self):
3497 @unique
3498 class Clean(Enum):
3499 one = 1
3500 two = 'dos'
3501 tres = 4.0
Ethan Furman74964862021-06-10 07:24:20 -07003502 #
Ethan Furmanf24bb352013-07-18 17:05:39 -07003503 @unique
3504 class Cleaner(IntEnum):
3505 single = 1
3506 double = 2
3507 triple = 3
3508
3509 def test_unique_dirty(self):
3510 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3511 @unique
3512 class Dirty(Enum):
3513 one = 1
3514 two = 'dos'
3515 tres = 1
3516 with self.assertRaisesRegex(
3517 ValueError,
3518 'double.*single.*turkey.*triple',
3519 ):
3520 @unique
3521 class Dirtier(IntEnum):
3522 single = 1
3523 double = 1
3524 triple = 3
3525 turkey = 3
3526
Ethan Furman3803ad42016-05-01 10:03:53 -07003527 def test_unique_with_name(self):
Ethan Furman74964862021-06-10 07:24:20 -07003528 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003529 class Silly(Enum):
3530 one = 1
3531 two = 'dos'
3532 name = 3
Ethan Furman74964862021-06-10 07:24:20 -07003533 #
3534 @verify(UNIQUE)
3535 class Sillier(IntEnum):
3536 single = 1
3537 name = 2
3538 triple = 3
3539 value = 4
3540
3541class TestVerify(unittest.TestCase):
3542
3543 def test_continuous(self):
3544 @verify(CONTINUOUS)
3545 class Auto(Enum):
3546 FIRST = auto()
3547 SECOND = auto()
3548 THIRD = auto()
3549 FORTH = auto()
3550 #
3551 @verify(CONTINUOUS)
3552 class Manual(Enum):
3553 FIRST = 3
3554 SECOND = 4
3555 THIRD = 5
3556 FORTH = 6
3557 #
3558 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
3559 @verify(CONTINUOUS)
3560 class Missing(Enum):
3561 FIRST = 3
3562 SECOND = 4
3563 THIRD = 11
3564 FORTH = 13
3565 #
3566 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
3567 @verify(CONTINUOUS)
3568 class Incomplete(Flag):
3569 FIRST = 4
3570 SECOND = 8
3571 THIRD = 16
3572 FORTH = 64
3573 #
3574 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
3575 @verify(CONTINUOUS)
3576 class StillIncomplete(Flag):
3577 FIRST = 4
3578 SECOND = 8
3579 THIRD = 11
3580 FORTH = 32
3581
3582
3583 def test_composite(self):
3584 class Bizarre(Flag):
3585 b = 3
3586 c = 4
3587 d = 6
3588 self.assertEqual(list(Bizarre), [Bizarre.c])
3589 self.assertEqual(Bizarre.b.value, 3)
3590 self.assertEqual(Bizarre.c.value, 4)
3591 self.assertEqual(Bizarre.d.value, 6)
3592 with self.assertRaisesRegex(
3593 ValueError,
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003594 "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 -07003595 ):
3596 @verify(NAMED_FLAGS)
3597 class Bizarre(Flag):
3598 b = 3
3599 c = 4
3600 d = 6
3601 #
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003602 self.assertEqual(enum.show_flag_values(3), [1, 2])
Ethan Furman74964862021-06-10 07:24:20 -07003603 class Bizarre(IntFlag):
3604 b = 3
3605 c = 4
3606 d = 6
3607 self.assertEqual(list(Bizarre), [Bizarre.c])
3608 self.assertEqual(Bizarre.b.value, 3)
3609 self.assertEqual(Bizarre.c.value, 4)
3610 self.assertEqual(Bizarre.d.value, 6)
3611 with self.assertRaisesRegex(
3612 ValueError,
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003613 "invalid Flag 'Bizarre': alias d is missing value 0x2 .use `enum.show_flag_values.value.` for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003614 ):
3615 @verify(NAMED_FLAGS)
3616 class Bizarre(IntFlag):
Ethan Furman74964862021-06-10 07:24:20 -07003617 c = 4
3618 d = 6
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003619 self.assertEqual(enum.show_flag_values(2), [2])
Ethan Furman74964862021-06-10 07:24:20 -07003620
3621 def test_unique_clean(self):
3622 @verify(UNIQUE)
3623 class Clean(Enum):
3624 one = 1
3625 two = 'dos'
3626 tres = 4.0
3627 #
3628 @verify(UNIQUE)
3629 class Cleaner(IntEnum):
3630 single = 1
3631 double = 2
3632 triple = 3
3633
3634 def test_unique_dirty(self):
3635 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3636 @verify(UNIQUE)
3637 class Dirty(Enum):
3638 one = 1
3639 two = 'dos'
3640 tres = 1
3641 with self.assertRaisesRegex(
3642 ValueError,
3643 'double.*single.*turkey.*triple',
3644 ):
3645 @verify(UNIQUE)
3646 class Dirtier(IntEnum):
3647 single = 1
3648 double = 1
3649 triple = 3
3650 turkey = 3
3651
3652 def test_unique_with_name(self):
3653 @verify(UNIQUE)
3654 class Silly(Enum):
3655 one = 1
3656 two = 'dos'
3657 name = 3
3658 #
3659 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003660 class Sillier(IntEnum):
3661 single = 1
3662 name = 2
3663 triple = 3
3664 value = 4
3665
Ethan Furmanec099732021-04-15 06:58:33 -07003666class TestHelpers(unittest.TestCase):
3667
3668 sunder_names = '_bad_', '_good_', '_what_ho_'
3669 dunder_names = '__mal__', '__bien__', '__que_que__'
3670 private_names = '_MyEnum__private', '_MyEnum__still_private'
3671 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3672 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3673
3674 def test_sunder(self):
3675 for name in self.sunder_names + self.private_and_sunder_names:
3676 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3677 for name in self.dunder_names + self.private_names + self.random_names:
3678 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3679
3680 def test_dunder(self):
3681 for name in self.dunder_names:
3682 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3683 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3684 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3685
3686 def test_is_private(self):
3687 for name in self.private_names + self.private_and_sunder_names:
3688 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3689 for name in self.sunder_names + self.dunder_names + self.random_names:
3690 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003691
Ethan Furmanb7751062021-03-30 21:17:26 -07003692class TestEnumTypeSubclassing(unittest.TestCase):
3693 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003694
Ethan Furman3323da92015-04-11 09:39:59 -07003695expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003696Help on class Color in module %s:
3697
3698class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003699 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003700 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003701 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003702 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003703 | Method resolution order:
3704 | Color
3705 | enum.Enum
3706 | builtins.object
3707 |\x20\x20
3708 | Data and other attributes defined here:
3709 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003710 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003711 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003712 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003713 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003714 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003715 |\x20\x20
3716 | ----------------------------------------------------------------------
3717 | Data descriptors inherited from enum.Enum:
3718 |\x20\x20
3719 | name
3720 | The name of the Enum member.
3721 |\x20\x20
3722 | value
3723 | The value of the Enum member.
3724 |\x20\x20
3725 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003726 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003727 |\x20\x20
3728 | __members__
3729 | Returns a mapping of member name->value.
3730 |\x20\x20\x20\x20\x20\x20
3731 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003732 | is a read-only view of the internal mapping."""
3733
3734expected_help_output_without_docs = """\
3735Help on class Color in module %s:
3736
3737class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003738 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3739 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003740 | Method resolution order:
3741 | Color
3742 | enum.Enum
3743 | builtins.object
3744 |\x20\x20
3745 | Data and other attributes defined here:
3746 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003747 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003748 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003749 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003750 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003751 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003752 |\x20\x20
3753 | ----------------------------------------------------------------------
3754 | Data descriptors inherited from enum.Enum:
3755 |\x20\x20
3756 | name
3757 |\x20\x20
3758 | value
3759 |\x20\x20
3760 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003761 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003762 |\x20\x20
3763 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003764
3765class TestStdLib(unittest.TestCase):
3766
Ethan Furman48a724f2015-04-11 23:23:06 -07003767 maxDiff = None
3768
Ethan Furman5875d742013-10-21 20:45:55 -07003769 class Color(Enum):
3770 red = 1
3771 green = 2
3772 blue = 3
3773
3774 def test_pydoc(self):
3775 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003776 if StrEnum.__doc__ is None:
3777 expected_text = expected_help_output_without_docs % __name__
3778 else:
3779 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003780 output = StringIO()
3781 helper = pydoc.Helper(output=output)
3782 helper(self.Color)
3783 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003784 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003785
3786 def test_inspect_getmembers(self):
3787 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003788 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003789 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003790 ('__members__', self.Color.__members__),
3791 ('__module__', __name__),
3792 ('blue', self.Color.blue),
3793 ('green', self.Color.green),
3794 ('name', Enum.__dict__['name']),
3795 ('red', self.Color.red),
3796 ('value', Enum.__dict__['value']),
3797 ))
3798 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003799 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003800 failed = False
3801 for k in values.keys():
3802 if result[k] != values[k]:
3803 print()
3804 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3805 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3806 failed = True
3807 if failed:
3808 self.fail("result does not equal expected, see print above")
3809
3810 def test_inspect_classify_class_attrs(self):
3811 # indirectly test __objclass__
3812 from inspect import Attribute
3813 values = [
3814 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003815 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003816 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003817 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003818 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003819 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003820 Attribute(name='__module__', kind='data',
3821 defining_class=self.Color, object=__name__),
3822 Attribute(name='blue', kind='data',
3823 defining_class=self.Color, object=self.Color.blue),
3824 Attribute(name='green', kind='data',
3825 defining_class=self.Color, object=self.Color.green),
3826 Attribute(name='red', kind='data',
3827 defining_class=self.Color, object=self.Color.red),
3828 Attribute(name='name', kind='data',
3829 defining_class=Enum, object=Enum.__dict__['name']),
3830 Attribute(name='value', kind='data',
3831 defining_class=Enum, object=Enum.__dict__['value']),
3832 ]
3833 values.sort(key=lambda item: item.name)
3834 result = list(inspect.classify_class_attrs(self.Color))
3835 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003836 self.assertEqual(
3837 len(values), len(result),
3838 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3839 )
Ethan Furman5875d742013-10-21 20:45:55 -07003840 failed = False
3841 for v, r in zip(values, result):
3842 if r != v:
3843 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3844 failed = True
3845 if failed:
3846 self.fail("result does not equal expected, see print above")
3847
Ethan Furmana02cb472021-04-21 10:20:44 -07003848 def test_test_simple_enum(self):
3849 @_simple_enum(Enum)
3850 class SimpleColor:
3851 RED = 1
3852 GREEN = 2
3853 BLUE = 3
3854 class CheckedColor(Enum):
3855 RED = 1
3856 GREEN = 2
3857 BLUE = 3
3858 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3859 SimpleColor.GREEN._value_ = 9
3860 self.assertRaisesRegex(
3861 TypeError, "enum mismatch",
3862 _test_simple_enum, CheckedColor, SimpleColor,
3863 )
3864 class CheckedMissing(IntFlag, boundary=KEEP):
3865 SIXTY_FOUR = 64
3866 ONE_TWENTY_EIGHT = 128
3867 TWENTY_FORTY_EIGHT = 2048
3868 ALL = 2048 + 128 + 64 + 12
3869 CM = CheckedMissing
3870 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3871 #
3872 @_simple_enum(IntFlag, boundary=KEEP)
3873 class Missing:
3874 SIXTY_FOUR = 64
3875 ONE_TWENTY_EIGHT = 128
3876 TWENTY_FORTY_EIGHT = 2048
3877 ALL = 2048 + 128 + 64 + 12
3878 M = Missing
3879 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3880 #
3881 _test_simple_enum(CheckedMissing, Missing)
3882
Martin Panter19e69c52015-11-14 12:46:42 +00003883
3884class MiscTestCase(unittest.TestCase):
3885 def test__all__(self):
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003886 support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
Martin Panter19e69c52015-11-14 12:46:42 +00003887
3888
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003889# These are unordered here on purpose to ensure that declaration order
3890# makes no difference.
3891CONVERT_TEST_NAME_D = 5
3892CONVERT_TEST_NAME_C = 5
3893CONVERT_TEST_NAME_B = 5
3894CONVERT_TEST_NAME_A = 5 # This one should sort first.
3895CONVERT_TEST_NAME_E = 5
3896CONVERT_TEST_NAME_F = 5
3897
Ethan Furmana02cb472021-04-21 10:20:44 -07003898CONVERT_STRING_TEST_NAME_D = 5
3899CONVERT_STRING_TEST_NAME_C = 5
3900CONVERT_STRING_TEST_NAME_B = 5
3901CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3902CONVERT_STRING_TEST_NAME_E = 5
3903CONVERT_STRING_TEST_NAME_F = 5
3904
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003905class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003906 def setUp(self):
3907 # Reset the module-level test variables to their original integer
3908 # values, otherwise the already created enum values get converted
3909 # instead.
3910 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3911 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3912 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3913
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003914 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003915 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003916 'UnittestConvert',
3917 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003918 filter=lambda x: x.startswith('CONVERT_TEST_'))
3919 # We don't want the reverse lookup value to vary when there are
3920 # multiple possible names for a given value. It should always
3921 # report the first lexigraphical name in that case.
3922 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3923
3924 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003925 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003926 'UnittestConvert',
3927 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003928 filter=lambda x: x.startswith('CONVERT_TEST_'))
3929 # Ensure that test_type has all of the desired names and values.
3930 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3931 test_type.CONVERT_TEST_NAME_A)
3932 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3933 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3934 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3935 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3936 # Ensure that test_type only picked up names matching the filter.
3937 self.assertEqual([name for name in dir(test_type)
3938 if name[0:2] not in ('CO', '__')],
3939 [], msg='Names other than CONVERT_TEST_* found.')
3940
Ethan Furman6bd92882021-04-27 13:05:08 -07003941 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003942 '_convert was deprecated in 3.8')
3943 def test_convert_warn(self):
3944 with self.assertWarns(DeprecationWarning):
3945 enum.IntEnum._convert(
3946 'UnittestConvert',
3947 ('test.test_enum', '__main__')[__name__=='__main__'],
3948 filter=lambda x: x.startswith('CONVERT_TEST_'))
3949
Ethan Furman6bd92882021-04-27 13:05:08 -07003950 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003951 '_convert was removed in 3.9')
3952 def test_convert_raise(self):
3953 with self.assertRaises(AttributeError):
3954 enum.IntEnum._convert(
3955 'UnittestConvert',
3956 ('test.test_enum', '__main__')[__name__=='__main__'],
3957 filter=lambda x: x.startswith('CONVERT_TEST_'))
3958
Ethan Furman6bd92882021-04-27 13:05:08 -07003959 @unittest.skipUnless(
3960 python_version < (3, 12),
3961 'mixin-format now uses member instead of member.value',
3962 )
Ethan Furmanb7751062021-03-30 21:17:26 -07003963 def test_convert_repr_and_str(self):
3964 module = ('test.test_enum', '__main__')[__name__=='__main__']
3965 test_type = enum.IntEnum._convert_(
3966 'UnittestConvert',
3967 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003968 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3969 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3970 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman6bd92882021-04-27 13:05:08 -07003971 with self.assertWarns(DeprecationWarning):
3972 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003973
3974# global names for StrEnum._convert_ test
3975CONVERT_STR_TEST_2 = 'goodbye'
3976CONVERT_STR_TEST_1 = 'hello'
3977
3978class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003979 def setUp(self):
3980 global CONVERT_STR_TEST_1
3981 global CONVERT_STR_TEST_2
3982 CONVERT_STR_TEST_2 = 'goodbye'
3983 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07003984
3985 def test_convert(self):
3986 test_type = enum.StrEnum._convert_(
3987 'UnittestConvert',
3988 ('test.test_enum', '__main__')[__name__=='__main__'],
3989 filter=lambda x: x.startswith('CONVERT_STR_'))
3990 # Ensure that test_type has all of the desired names and values.
3991 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3992 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3993 # Ensure that test_type only picked up names matching the filter.
3994 self.assertEqual([name for name in dir(test_type)
3995 if name[0:2] not in ('CO', '__')],
3996 [], msg='Names other than CONVERT_STR_* found.')
3997
3998 def test_convert_repr_and_str(self):
3999 module = ('test.test_enum', '__main__')[__name__=='__main__']
4000 test_type = enum.StrEnum._convert_(
4001 'UnittestConvert',
4002 module,
4003 filter=lambda x: x.startswith('CONVERT_STR_'))
4004 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
4005 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
4006 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
4007
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004008
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004009if __name__ == '__main__':
4010 unittest.main()