blob: c4c458e6bfc4ef4d897e6540315dbca3a6b1b9ba [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):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700663 __qualname__ = 'SillyInt'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700664 pass
665 class MyOtherEnum(SillyInt, enum.Enum):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700666 __qualname__ = 'MyOtherEnum'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700667 D = 4
668 E = 5
669 F = 6
670 self.assertIs(MyOtherEnum._member_type_, SillyInt)
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700671 globals()['SillyInt'] = SillyInt
672 globals()['MyOtherEnum'] = MyOtherEnum
673 test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
674 test_pickle_dump_load(self.assertIs, MyOtherEnum)
675 #
676 # This did not work in 3.9, but does now with pickling by name
677 class UnBrokenInt(int):
678 __qualname__ = 'UnBrokenInt'
679 def __new__(cls, value):
680 return int.__new__(cls, value)
681 class MyUnBrokenEnum(UnBrokenInt, Enum):
682 __qualname__ = 'MyUnBrokenEnum'
683 G = 7
684 H = 8
685 I = 9
686 self.assertIs(MyUnBrokenEnum._member_type_, UnBrokenInt)
687 self.assertIs(MyUnBrokenEnum(7), MyUnBrokenEnum.G)
688 globals()['UnBrokenInt'] = UnBrokenInt
689 globals()['MyUnBrokenEnum'] = MyUnBrokenEnum
690 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
691 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700692
693 def test_too_many_data_types(self):
694 with self.assertRaisesRegex(TypeError, 'too many data types'):
695 class Huh(str, int, Enum):
696 One = 1
697
698 class MyStr(str):
699 def hello(self):
700 return 'hello, %s' % self
701 class MyInt(int):
702 def repr(self):
703 return hex(self)
704 with self.assertRaisesRegex(TypeError, 'too many data types'):
705 class Huh(MyStr, MyInt, Enum):
706 One = 1
707
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700708 def test_hash(self):
709 Season = self.Season
710 dates = {}
711 dates[Season.WINTER] = '1225'
712 dates[Season.SPRING] = '0315'
713 dates[Season.SUMMER] = '0704'
714 dates[Season.AUTUMN] = '1031'
715 self.assertEqual(dates[Season.AUTUMN], '1031')
716
717 def test_intenum_from_scratch(self):
718 class phy(int, Enum):
719 pi = 3
720 tau = 2 * pi
721 self.assertTrue(phy.pi < phy.tau)
722
723 def test_intenum_inherited(self):
724 class IntEnum(int, Enum):
725 pass
726 class phy(IntEnum):
727 pi = 3
728 tau = 2 * pi
729 self.assertTrue(phy.pi < phy.tau)
730
731 def test_floatenum_from_scratch(self):
732 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700733 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700734 tau = 2 * pi
735 self.assertTrue(phy.pi < phy.tau)
736
737 def test_floatenum_inherited(self):
738 class FloatEnum(float, Enum):
739 pass
740 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700741 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700742 tau = 2 * pi
743 self.assertTrue(phy.pi < phy.tau)
744
745 def test_strenum_from_scratch(self):
746 class phy(str, Enum):
747 pi = 'Pi'
748 tau = 'Tau'
749 self.assertTrue(phy.pi < phy.tau)
750
Ethan Furman0063ff42020-09-21 17:23:13 -0700751 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700752 class phy(StrEnum):
753 pi = 'Pi'
754 tau = 'Tau'
755 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700756 self.assertEqual(phy.pi.upper(), 'PI')
757 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700758
759 def test_intenum(self):
760 class WeekDay(IntEnum):
761 SUNDAY = 1
762 MONDAY = 2
763 TUESDAY = 3
764 WEDNESDAY = 4
765 THURSDAY = 5
766 FRIDAY = 6
767 SATURDAY = 7
768
769 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
770 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
771
772 lst = list(WeekDay)
773 self.assertEqual(len(lst), len(WeekDay))
774 self.assertEqual(len(WeekDay), 7)
775 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
776 target = target.split()
777 for i, weekday in enumerate(target, 1):
778 e = WeekDay(i)
779 self.assertEqual(e, i)
780 self.assertEqual(int(e), i)
781 self.assertEqual(e.name, weekday)
782 self.assertIn(e, WeekDay)
783 self.assertEqual(lst.index(e)+1, i)
784 self.assertTrue(0 < e < 8)
785 self.assertIs(type(e), WeekDay)
786 self.assertIsInstance(e, int)
787 self.assertIsInstance(e, Enum)
788
789 def test_intenum_duplicates(self):
790 class WeekDay(IntEnum):
791 SUNDAY = 1
792 MONDAY = 2
793 TUESDAY = TEUSDAY = 3
794 WEDNESDAY = 4
795 THURSDAY = 5
796 FRIDAY = 6
797 SATURDAY = 7
798 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
799 self.assertEqual(WeekDay(3).name, 'TUESDAY')
800 self.assertEqual([k for k,v in WeekDay.__members__.items()
801 if v.name != k], ['TEUSDAY', ])
802
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300803 def test_intenum_from_bytes(self):
804 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
805 with self.assertRaises(ValueError):
806 IntStooges.from_bytes(b'\x00\x05', 'big')
807
808 def test_floatenum_fromhex(self):
809 h = float.hex(FloatStooges.MOE.value)
810 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
811 h = float.hex(FloatStooges.MOE.value + 0.01)
812 with self.assertRaises(ValueError):
813 FloatStooges.fromhex(h)
814
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700815 def test_pickle_enum(self):
816 if isinstance(Stooges, Exception):
817 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800818 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
819 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700820
821 def test_pickle_int(self):
822 if isinstance(IntStooges, Exception):
823 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800824 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
825 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700826
827 def test_pickle_float(self):
828 if isinstance(FloatStooges, Exception):
829 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800830 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
831 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832
833 def test_pickle_enum_function(self):
834 if isinstance(Answer, Exception):
835 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800836 test_pickle_dump_load(self.assertIs, Answer.him)
837 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700838
839 def test_pickle_enum_function_with_module(self):
840 if isinstance(Question, Exception):
841 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800842 test_pickle_dump_load(self.assertIs, Question.who)
843 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700844
Ethan Furmanca1b7942014-02-08 11:36:27 -0800845 def test_enum_function_with_qualname(self):
846 if isinstance(Theory, Exception):
847 raise Theory
848 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
849
850 def test_class_nested_enum_and_pickle_protocol_four(self):
851 # would normally just have this directly in the class namespace
852 class NestedEnum(Enum):
853 twigs = 'common'
854 shiny = 'rare'
855
856 self.__class__.NestedEnum = NestedEnum
857 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300858 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800859
Ethan Furman24e837f2015-03-18 17:27:57 -0700860 def test_pickle_by_name(self):
861 class ReplaceGlobalInt(IntEnum):
862 ONE = 1
863 TWO = 2
Miss Islington (bot)b6131322021-06-10 16:37:27 -0700864 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700865 for proto in range(HIGHEST_PROTOCOL):
866 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
867
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700868 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800869 BadPickle = Enum(
870 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700871 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800872 # now break BadPickle to test exception raising
873 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800874 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
875 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700876
877 def test_string_enum(self):
878 class SkillLevel(str, Enum):
879 master = 'what is the sound of one hand clapping?'
880 journeyman = 'why did the chicken cross the road?'
881 apprentice = 'knock, knock!'
882 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
883
884 def test_getattr_getitem(self):
885 class Period(Enum):
886 morning = 1
887 noon = 2
888 evening = 3
889 night = 4
890 self.assertIs(Period(2), Period.noon)
891 self.assertIs(getattr(Period, 'night'), Period.night)
892 self.assertIs(Period['morning'], Period.morning)
893
894 def test_getattr_dunder(self):
895 Season = self.Season
896 self.assertTrue(getattr(Season, '__eq__'))
897
898 def test_iteration_order(self):
899 class Season(Enum):
900 SUMMER = 2
901 WINTER = 4
902 AUTUMN = 3
903 SPRING = 1
904 self.assertEqual(
905 list(Season),
906 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
907 )
908
Ethan Furman2131a4a2013-09-14 18:11:24 -0700909 def test_reversed_iteration_order(self):
910 self.assertEqual(
911 list(reversed(self.Season)),
912 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
913 self.Season.SPRING]
914 )
915
Martin Pantereb995702016-07-28 01:11:04 +0000916 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700917 SummerMonth = Enum('SummerMonth', 'june july august')
918 lst = list(SummerMonth)
919 self.assertEqual(len(lst), len(SummerMonth))
920 self.assertEqual(len(SummerMonth), 3, SummerMonth)
921 self.assertEqual(
922 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
923 lst,
924 )
925 for i, month in enumerate('june july august'.split(), 1):
926 e = SummerMonth(i)
927 self.assertEqual(int(e.value), i)
928 self.assertNotEqual(e, i)
929 self.assertEqual(e.name, month)
930 self.assertIn(e, SummerMonth)
931 self.assertIs(type(e), SummerMonth)
932
Martin Pantereb995702016-07-28 01:11:04 +0000933 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700934 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
935 lst = list(SummerMonth)
936 self.assertEqual(len(lst), len(SummerMonth))
937 self.assertEqual(len(SummerMonth), 3, SummerMonth)
938 self.assertEqual(
939 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
940 lst,
941 )
942 for i, month in enumerate('june july august'.split(), 10):
943 e = SummerMonth(i)
944 self.assertEqual(int(e.value), i)
945 self.assertNotEqual(e, i)
946 self.assertEqual(e.name, month)
947 self.assertIn(e, SummerMonth)
948 self.assertIs(type(e), SummerMonth)
949
Martin Pantereb995702016-07-28 01:11:04 +0000950 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700951 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
952 lst = list(SummerMonth)
953 self.assertEqual(len(lst), len(SummerMonth))
954 self.assertEqual(len(SummerMonth), 3, SummerMonth)
955 self.assertEqual(
956 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
957 lst,
958 )
959 for i, month in enumerate('june july august'.split(), 1):
960 e = SummerMonth(i)
961 self.assertEqual(int(e.value), i)
962 self.assertNotEqual(e, i)
963 self.assertEqual(e.name, month)
964 self.assertIn(e, SummerMonth)
965 self.assertIs(type(e), SummerMonth)
966
Martin Pantereb995702016-07-28 01:11:04 +0000967 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700968 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
969 lst = list(SummerMonth)
970 self.assertEqual(len(lst), len(SummerMonth))
971 self.assertEqual(len(SummerMonth), 3, SummerMonth)
972 self.assertEqual(
973 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
974 lst,
975 )
976 for i, month in enumerate('june july august'.split(), 20):
977 e = SummerMonth(i)
978 self.assertEqual(int(e.value), i)
979 self.assertNotEqual(e, i)
980 self.assertEqual(e.name, month)
981 self.assertIn(e, SummerMonth)
982 self.assertIs(type(e), SummerMonth)
983
Martin Pantereb995702016-07-28 01:11:04 +0000984 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700985 SummerMonth = Enum(
986 'SummerMonth',
987 (('june', 1), ('july', 2), ('august', 3))
988 )
989 lst = list(SummerMonth)
990 self.assertEqual(len(lst), len(SummerMonth))
991 self.assertEqual(len(SummerMonth), 3, SummerMonth)
992 self.assertEqual(
993 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
994 lst,
995 )
996 for i, month in enumerate('june july august'.split(), 1):
997 e = SummerMonth(i)
998 self.assertEqual(int(e.value), i)
999 self.assertNotEqual(e, i)
1000 self.assertEqual(e.name, month)
1001 self.assertIn(e, SummerMonth)
1002 self.assertIs(type(e), SummerMonth)
1003
Martin Pantereb995702016-07-28 01:11:04 +00001004 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001005 SummerMonth = Enum(
1006 'SummerMonth',
1007 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
1008 )
1009 lst = list(SummerMonth)
1010 self.assertEqual(len(lst), len(SummerMonth))
1011 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1012 self.assertEqual(
1013 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1014 lst,
1015 )
1016 for i, month in enumerate('june july august'.split(), 1):
1017 e = SummerMonth(i)
1018 self.assertEqual(int(e.value), i)
1019 self.assertNotEqual(e, i)
1020 self.assertEqual(e.name, month)
1021 self.assertIn(e, SummerMonth)
1022 self.assertIs(type(e), SummerMonth)
1023
Martin Pantereb995702016-07-28 01:11:04 +00001024 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001025 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
1026 lst = list(SummerMonth)
1027 self.assertEqual(len(lst), len(SummerMonth))
1028 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1029 self.assertEqual(
1030 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1031 lst,
1032 )
1033 for i, month in enumerate('june july august'.split(), 1):
1034 e = SummerMonth(i)
1035 self.assertEqual(e, i)
1036 self.assertEqual(e.name, month)
1037 self.assertIn(e, SummerMonth)
1038 self.assertIs(type(e), SummerMonth)
1039
Martin Pantereb995702016-07-28 01:11:04 +00001040 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001041 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1042 lst = list(SummerMonth)
1043 self.assertEqual(len(lst), len(SummerMonth))
1044 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1045 self.assertEqual(
1046 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1047 lst,
1048 )
1049 for i, month in enumerate('june july august'.split(), 30):
1050 e = SummerMonth(i)
1051 self.assertEqual(e, i)
1052 self.assertEqual(e.name, month)
1053 self.assertIn(e, SummerMonth)
1054 self.assertIs(type(e), SummerMonth)
1055
Martin Pantereb995702016-07-28 01:11:04 +00001056 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001057 SummerMonth = IntEnum('SummerMonth', 'june july august')
1058 lst = list(SummerMonth)
1059 self.assertEqual(len(lst), len(SummerMonth))
1060 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1061 self.assertEqual(
1062 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1063 lst,
1064 )
1065 for i, month in enumerate('june july august'.split(), 1):
1066 e = SummerMonth(i)
1067 self.assertEqual(e, i)
1068 self.assertEqual(e.name, month)
1069 self.assertIn(e, SummerMonth)
1070 self.assertIs(type(e), SummerMonth)
1071
Martin Pantereb995702016-07-28 01:11:04 +00001072 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001073 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1074 lst = list(SummerMonth)
1075 self.assertEqual(len(lst), len(SummerMonth))
1076 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1077 self.assertEqual(
1078 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1079 lst,
1080 )
1081 for i, month in enumerate('june july august'.split(), 40):
1082 e = SummerMonth(i)
1083 self.assertEqual(e, i)
1084 self.assertEqual(e.name, month)
1085 self.assertIn(e, SummerMonth)
1086 self.assertIs(type(e), SummerMonth)
1087
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001088 def test_subclassing(self):
1089 if isinstance(Name, Exception):
1090 raise Name
1091 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1092 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1093 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001094 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001095
1096 def test_extending(self):
1097 class Color(Enum):
1098 red = 1
1099 green = 2
1100 blue = 3
1101 with self.assertRaises(TypeError):
1102 class MoreColor(Color):
1103 cyan = 4
1104 magenta = 5
1105 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001106 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1107 class EvenMoreColor(Color, IntEnum):
1108 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001109
1110 def test_exclude_methods(self):
1111 class whatever(Enum):
1112 this = 'that'
1113 these = 'those'
1114 def really(self):
1115 return 'no, not %s' % self.value
1116 self.assertIsNot(type(whatever.really), whatever)
1117 self.assertEqual(whatever.this.really(), 'no, not that')
1118
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001119 def test_wrong_inheritance_order(self):
1120 with self.assertRaises(TypeError):
1121 class Wrong(Enum, str):
1122 NotHere = 'error before this point'
1123
1124 def test_intenum_transitivity(self):
1125 class number(IntEnum):
1126 one = 1
1127 two = 2
1128 three = 3
1129 class numero(IntEnum):
1130 uno = 1
1131 dos = 2
1132 tres = 3
1133 self.assertEqual(number.one, numero.uno)
1134 self.assertEqual(number.two, numero.dos)
1135 self.assertEqual(number.three, numero.tres)
1136
1137 def test_wrong_enum_in_call(self):
1138 class Monochrome(Enum):
1139 black = 0
1140 white = 1
1141 class Gender(Enum):
1142 male = 0
1143 female = 1
1144 self.assertRaises(ValueError, Monochrome, Gender.male)
1145
1146 def test_wrong_enum_in_mixed_call(self):
1147 class Monochrome(IntEnum):
1148 black = 0
1149 white = 1
1150 class Gender(Enum):
1151 male = 0
1152 female = 1
1153 self.assertRaises(ValueError, Monochrome, Gender.male)
1154
1155 def test_mixed_enum_in_call_1(self):
1156 class Monochrome(IntEnum):
1157 black = 0
1158 white = 1
1159 class Gender(IntEnum):
1160 male = 0
1161 female = 1
1162 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1163
1164 def test_mixed_enum_in_call_2(self):
1165 class Monochrome(Enum):
1166 black = 0
1167 white = 1
1168 class Gender(IntEnum):
1169 male = 0
1170 female = 1
1171 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1172
1173 def test_flufl_enum(self):
1174 class Fluflnum(Enum):
1175 def __int__(self):
1176 return int(self.value)
1177 class MailManOptions(Fluflnum):
1178 option1 = 1
1179 option2 = 2
1180 option3 = 3
1181 self.assertEqual(int(MailManOptions.option1), 1)
1182
Ethan Furman5e5a8232013-08-04 08:42:23 -07001183 def test_introspection(self):
1184 class Number(IntEnum):
1185 one = 100
1186 two = 200
1187 self.assertIs(Number.one._member_type_, int)
1188 self.assertIs(Number._member_type_, int)
1189 class String(str, Enum):
1190 yarn = 'soft'
1191 rope = 'rough'
1192 wire = 'hard'
1193 self.assertIs(String.yarn._member_type_, str)
1194 self.assertIs(String._member_type_, str)
1195 class Plain(Enum):
1196 vanilla = 'white'
1197 one = 1
1198 self.assertIs(Plain.vanilla._member_type_, object)
1199 self.assertIs(Plain._member_type_, object)
1200
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001201 def test_no_such_enum_member(self):
1202 class Color(Enum):
1203 red = 1
1204 green = 2
1205 blue = 3
1206 with self.assertRaises(ValueError):
1207 Color(4)
1208 with self.assertRaises(KeyError):
1209 Color['chartreuse']
1210
1211 def test_new_repr(self):
1212 class Color(Enum):
1213 red = 1
1214 green = 2
1215 blue = 3
1216 def __repr__(self):
1217 return "don't you just love shades of %s?" % self.name
1218 self.assertEqual(
1219 repr(Color.blue),
1220 "don't you just love shades of blue?",
1221 )
1222
1223 def test_inherited_repr(self):
1224 class MyEnum(Enum):
1225 def __repr__(self):
1226 return "My name is %s." % self.name
1227 class MyIntEnum(int, MyEnum):
1228 this = 1
1229 that = 2
1230 theother = 3
1231 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1232
1233 def test_multiple_mixin_mro(self):
1234 class auto_enum(type(Enum)):
1235 def __new__(metacls, cls, bases, classdict):
1236 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001237 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001238 names = set(classdict._member_names)
1239 i = 0
1240 for k in classdict._member_names:
1241 v = classdict[k]
1242 if v is Ellipsis:
1243 v = i
1244 else:
1245 i = v
1246 i += 1
1247 temp[k] = v
1248 for k, v in classdict.items():
1249 if k not in names:
1250 temp[k] = v
1251 return super(auto_enum, metacls).__new__(
1252 metacls, cls, bases, temp)
1253
1254 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1255 pass
1256
1257 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1258 pass
1259
1260 class TestAutoNumber(AutoNumberedEnum):
1261 a = ...
1262 b = 3
1263 c = ...
1264
1265 class TestAutoInt(AutoIntEnum):
1266 a = ...
1267 b = 3
1268 c = ...
1269
1270 def test_subclasses_with_getnewargs(self):
1271 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001272 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001273 def __new__(cls, *args):
1274 _args = args
1275 name, *args = args
1276 if len(args) == 0:
1277 raise TypeError("name and value must be specified")
1278 self = int.__new__(cls, *args)
1279 self._intname = name
1280 self._args = _args
1281 return self
1282 def __getnewargs__(self):
1283 return self._args
1284 @property
1285 def __name__(self):
1286 return self._intname
1287 def __repr__(self):
1288 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001289 return "{}({!r}, {})".format(
1290 type(self).__name__,
1291 self.__name__,
1292 int.__repr__(self),
1293 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001294 def __str__(self):
1295 # str() is unchanged, even if it relies on the repr() fallback
1296 base = int
1297 base_str = base.__str__
1298 if base_str.__objclass__ is object:
1299 return base.__repr__(self)
1300 return base_str(self)
1301 # for simplicity, we only define one operator that
1302 # propagates expressions
1303 def __add__(self, other):
1304 temp = int(self) + int( other)
1305 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1306 return NamedInt(
1307 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001308 temp,
1309 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001310 else:
1311 return temp
1312
1313 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001314 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001315 x = ('the-x', 1)
1316 y = ('the-y', 2)
1317
Ethan Furman2aa27322013-07-19 19:35:56 -07001318
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001319 self.assertIs(NEI.__new__, Enum.__new__)
1320 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1321 globals()['NamedInt'] = NamedInt
1322 globals()['NEI'] = NEI
1323 NI5 = NamedInt('test', 5)
1324 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001325 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001326 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001327 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001328 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001329
Ethan Furmanca1b7942014-02-08 11:36:27 -08001330 def test_subclasses_with_getnewargs_ex(self):
1331 class NamedInt(int):
1332 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1333 def __new__(cls, *args):
1334 _args = args
1335 name, *args = args
1336 if len(args) == 0:
1337 raise TypeError("name and value must be specified")
1338 self = int.__new__(cls, *args)
1339 self._intname = name
1340 self._args = _args
1341 return self
1342 def __getnewargs_ex__(self):
1343 return self._args, {}
1344 @property
1345 def __name__(self):
1346 return self._intname
1347 def __repr__(self):
1348 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001349 return "{}({!r}, {})".format(
1350 type(self).__name__,
1351 self.__name__,
1352 int.__repr__(self),
1353 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354 def __str__(self):
1355 # str() is unchanged, even if it relies on the repr() fallback
1356 base = int
1357 base_str = base.__str__
1358 if base_str.__objclass__ is object:
1359 return base.__repr__(self)
1360 return base_str(self)
1361 # for simplicity, we only define one operator that
1362 # propagates expressions
1363 def __add__(self, other):
1364 temp = int(self) + int( other)
1365 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1366 return NamedInt(
1367 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001368 temp,
1369 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001370 else:
1371 return temp
1372
1373 class NEI(NamedInt, Enum):
1374 __qualname__ = 'NEI' # needed for pickle protocol 4
1375 x = ('the-x', 1)
1376 y = ('the-y', 2)
1377
1378
1379 self.assertIs(NEI.__new__, Enum.__new__)
1380 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1381 globals()['NamedInt'] = NamedInt
1382 globals()['NEI'] = NEI
1383 NI5 = NamedInt('test', 5)
1384 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001385 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001386 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001387 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001388 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001389
1390 def test_subclasses_with_reduce(self):
1391 class NamedInt(int):
1392 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1393 def __new__(cls, *args):
1394 _args = args
1395 name, *args = args
1396 if len(args) == 0:
1397 raise TypeError("name and value must be specified")
1398 self = int.__new__(cls, *args)
1399 self._intname = name
1400 self._args = _args
1401 return self
1402 def __reduce__(self):
1403 return self.__class__, self._args
1404 @property
1405 def __name__(self):
1406 return self._intname
1407 def __repr__(self):
1408 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001409 return "{}({!r}, {})".format(
1410 type(self).__name__,
1411 self.__name__,
1412 int.__repr__(self),
1413 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001414 def __str__(self):
1415 # str() is unchanged, even if it relies on the repr() fallback
1416 base = int
1417 base_str = base.__str__
1418 if base_str.__objclass__ is object:
1419 return base.__repr__(self)
1420 return base_str(self)
1421 # for simplicity, we only define one operator that
1422 # propagates expressions
1423 def __add__(self, other):
1424 temp = int(self) + int( other)
1425 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1426 return NamedInt(
1427 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001428 temp,
1429 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001430 else:
1431 return temp
1432
1433 class NEI(NamedInt, Enum):
1434 __qualname__ = 'NEI' # needed for pickle protocol 4
1435 x = ('the-x', 1)
1436 y = ('the-y', 2)
1437
1438
1439 self.assertIs(NEI.__new__, Enum.__new__)
1440 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1441 globals()['NamedInt'] = NamedInt
1442 globals()['NEI'] = NEI
1443 NI5 = NamedInt('test', 5)
1444 self.assertEqual(NI5, 5)
1445 test_pickle_dump_load(self.assertEqual, NI5, 5)
1446 self.assertEqual(NEI.y.value, 2)
1447 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001448 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001449
1450 def test_subclasses_with_reduce_ex(self):
1451 class NamedInt(int):
1452 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1453 def __new__(cls, *args):
1454 _args = args
1455 name, *args = args
1456 if len(args) == 0:
1457 raise TypeError("name and value must be specified")
1458 self = int.__new__(cls, *args)
1459 self._intname = name
1460 self._args = _args
1461 return self
1462 def __reduce_ex__(self, proto):
1463 return self.__class__, self._args
1464 @property
1465 def __name__(self):
1466 return self._intname
1467 def __repr__(self):
1468 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001469 return "{}({!r}, {})".format(
1470 type(self).__name__,
1471 self.__name__,
1472 int.__repr__(self),
1473 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001474 def __str__(self):
1475 # str() is unchanged, even if it relies on the repr() fallback
1476 base = int
1477 base_str = base.__str__
1478 if base_str.__objclass__ is object:
1479 return base.__repr__(self)
1480 return base_str(self)
1481 # for simplicity, we only define one operator that
1482 # propagates expressions
1483 def __add__(self, other):
1484 temp = int(self) + int( other)
1485 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1486 return NamedInt(
1487 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001488 temp,
1489 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001490 else:
1491 return temp
1492
1493 class NEI(NamedInt, Enum):
1494 __qualname__ = 'NEI' # needed for pickle protocol 4
1495 x = ('the-x', 1)
1496 y = ('the-y', 2)
1497
Ethan Furmanca1b7942014-02-08 11:36:27 -08001498 self.assertIs(NEI.__new__, Enum.__new__)
1499 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1500 globals()['NamedInt'] = NamedInt
1501 globals()['NEI'] = NEI
1502 NI5 = NamedInt('test', 5)
1503 self.assertEqual(NI5, 5)
1504 test_pickle_dump_load(self.assertEqual, NI5, 5)
1505 self.assertEqual(NEI.y.value, 2)
1506 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001507 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001508
Ethan Furmandc870522014-02-18 12:37:12 -08001509 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001510 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001511 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001512 def __new__(cls, *args):
1513 _args = args
1514 name, *args = args
1515 if len(args) == 0:
1516 raise TypeError("name and value must be specified")
1517 self = int.__new__(cls, *args)
1518 self._intname = name
1519 self._args = _args
1520 return self
1521 @property
1522 def __name__(self):
1523 return self._intname
1524 def __repr__(self):
1525 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001526 return "{}({!r}, {})".format(
1527 type(self).__name__,
1528 self.__name__,
1529 int.__repr__(self),
1530 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001531 def __str__(self):
1532 # str() is unchanged, even if it relies on the repr() fallback
1533 base = int
1534 base_str = base.__str__
1535 if base_str.__objclass__ is object:
1536 return base.__repr__(self)
1537 return base_str(self)
1538 # for simplicity, we only define one operator that
1539 # propagates expressions
1540 def __add__(self, other):
1541 temp = int(self) + int( other)
1542 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1543 return NamedInt(
1544 '({0} + {1})'.format(self.__name__, other.__name__),
1545 temp )
1546 else:
1547 return temp
1548
1549 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001550 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001551 x = ('the-x', 1)
1552 y = ('the-y', 2)
1553
1554 self.assertIs(NEI.__new__, Enum.__new__)
1555 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1556 globals()['NamedInt'] = NamedInt
1557 globals()['NEI'] = NEI
1558 NI5 = NamedInt('test', 5)
1559 self.assertEqual(NI5, 5)
1560 self.assertEqual(NEI.y.value, 2)
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001561 test_pickle_dump_load(self.assertIs, NEI.y)
1562 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001563
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001564 def test_subclasses_with_direct_pickle_support(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001565 class NamedInt(int):
1566 __qualname__ = 'NamedInt'
1567 def __new__(cls, *args):
1568 _args = args
1569 name, *args = args
1570 if len(args) == 0:
1571 raise TypeError("name and value must be specified")
1572 self = int.__new__(cls, *args)
1573 self._intname = name
1574 self._args = _args
1575 return self
1576 @property
1577 def __name__(self):
1578 return self._intname
1579 def __repr__(self):
1580 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001581 return "{}({!r}, {})".format(
1582 type(self).__name__,
1583 self.__name__,
1584 int.__repr__(self),
1585 )
Ethan Furmandc870522014-02-18 12:37:12 -08001586 def __str__(self):
1587 # str() is unchanged, even if it relies on the repr() fallback
1588 base = int
1589 base_str = base.__str__
1590 if base_str.__objclass__ is object:
1591 return base.__repr__(self)
1592 return base_str(self)
1593 # for simplicity, we only define one operator that
1594 # propagates expressions
1595 def __add__(self, other):
1596 temp = int(self) + int( other)
1597 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1598 return NamedInt(
1599 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001600 temp,
1601 )
Ethan Furmandc870522014-02-18 12:37:12 -08001602 else:
1603 return temp
1604
1605 class NEI(NamedInt, Enum):
1606 __qualname__ = 'NEI'
1607 x = ('the-x', 1)
1608 y = ('the-y', 2)
1609 def __reduce_ex__(self, proto):
1610 return getattr, (self.__class__, self._name_)
1611
1612 self.assertIs(NEI.__new__, Enum.__new__)
1613 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1614 globals()['NamedInt'] = NamedInt
1615 globals()['NEI'] = NEI
1616 NI5 = NamedInt('test', 5)
1617 self.assertEqual(NI5, 5)
1618 self.assertEqual(NEI.y.value, 2)
1619 test_pickle_dump_load(self.assertIs, NEI.y)
1620 test_pickle_dump_load(self.assertIs, NEI)
1621
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001622 def test_tuple_subclass(self):
1623 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001624 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001625 first = (1, 'for the money')
1626 second = (2, 'for the show')
1627 third = (3, 'for the music')
1628 self.assertIs(type(SomeTuple.first), SomeTuple)
1629 self.assertIsInstance(SomeTuple.second, tuple)
1630 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1631 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001632 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001633
1634 def test_duplicate_values_give_unique_enum_items(self):
1635 class AutoNumber(Enum):
1636 first = ()
1637 second = ()
1638 third = ()
1639 def __new__(cls):
1640 value = len(cls.__members__) + 1
1641 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001642 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001643 return obj
1644 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001645 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001646 self.assertEqual(
1647 list(AutoNumber),
1648 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1649 )
1650 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001651 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001652 self.assertIs(AutoNumber(1), AutoNumber.first)
1653
1654 def test_inherited_new_from_enhanced_enum(self):
1655 class AutoNumber(Enum):
1656 def __new__(cls):
1657 value = len(cls.__members__) + 1
1658 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001659 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001660 return obj
1661 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001662 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001663 class Color(AutoNumber):
1664 red = ()
1665 green = ()
1666 blue = ()
1667 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1668 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1669
1670 def test_inherited_new_from_mixed_enum(self):
1671 class AutoNumber(IntEnum):
1672 def __new__(cls):
1673 value = len(cls.__members__) + 1
1674 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001675 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001676 return obj
1677 class Color(AutoNumber):
1678 red = ()
1679 green = ()
1680 blue = ()
1681 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1682 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1683
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001684 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001685 class OrdinaryEnum(Enum):
1686 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001687 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1688 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001689
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001690 def test_ordered_mixin(self):
1691 class OrderedEnum(Enum):
1692 def __ge__(self, other):
1693 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001694 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001695 return NotImplemented
1696 def __gt__(self, other):
1697 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001698 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001699 return NotImplemented
1700 def __le__(self, other):
1701 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001702 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001703 return NotImplemented
1704 def __lt__(self, other):
1705 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001706 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001707 return NotImplemented
1708 class Grade(OrderedEnum):
1709 A = 5
1710 B = 4
1711 C = 3
1712 D = 2
1713 F = 1
1714 self.assertGreater(Grade.A, Grade.B)
1715 self.assertLessEqual(Grade.F, Grade.C)
1716 self.assertLess(Grade.D, Grade.A)
1717 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001718 self.assertEqual(Grade.B, Grade.B)
1719 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001720
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001721 def test_extending2(self):
1722 class Shade(Enum):
1723 def shade(self):
1724 print(self.name)
1725 class Color(Shade):
1726 red = 1
1727 green = 2
1728 blue = 3
1729 with self.assertRaises(TypeError):
1730 class MoreColor(Color):
1731 cyan = 4
1732 magenta = 5
1733 yellow = 6
1734
1735 def test_extending3(self):
1736 class Shade(Enum):
1737 def shade(self):
1738 return self.name
1739 class Color(Shade):
1740 def hex(self):
1741 return '%s hexlified!' % self.value
1742 class MoreColor(Color):
1743 cyan = 4
1744 magenta = 5
1745 yellow = 6
1746 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1747
orlnub1230fb9fad2018-09-12 20:28:53 +03001748 def test_subclass_duplicate_name(self):
1749 class Base(Enum):
1750 def test(self):
1751 pass
1752 class Test(Base):
1753 test = 1
1754 self.assertIs(type(Test.test), Test)
1755
1756 def test_subclass_duplicate_name_dynamic(self):
1757 from types import DynamicClassAttribute
1758 class Base(Enum):
1759 @DynamicClassAttribute
1760 def test(self):
1761 return 'dynamic'
1762 class Test(Base):
1763 test = 1
1764 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001765 class Base2(Enum):
1766 @enum.property
1767 def flash(self):
1768 return 'flashy dynamic'
1769 class Test(Base2):
1770 flash = 1
1771 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001772
1773 def test_no_duplicates(self):
1774 class UniqueEnum(Enum):
1775 def __init__(self, *args):
1776 cls = self.__class__
1777 if any(self.value == e.value for e in cls):
1778 a = self.name
1779 e = cls(self.value).name
1780 raise ValueError(
1781 "aliases not allowed in UniqueEnum: %r --> %r"
1782 % (a, e)
1783 )
1784 class Color(UniqueEnum):
1785 red = 1
1786 green = 2
1787 blue = 3
1788 with self.assertRaises(ValueError):
1789 class Color(UniqueEnum):
1790 red = 1
1791 green = 2
1792 blue = 3
1793 grene = 2
1794
1795 def test_init(self):
1796 class Planet(Enum):
1797 MERCURY = (3.303e+23, 2.4397e6)
1798 VENUS = (4.869e+24, 6.0518e6)
1799 EARTH = (5.976e+24, 6.37814e6)
1800 MARS = (6.421e+23, 3.3972e6)
1801 JUPITER = (1.9e+27, 7.1492e7)
1802 SATURN = (5.688e+26, 6.0268e7)
1803 URANUS = (8.686e+25, 2.5559e7)
1804 NEPTUNE = (1.024e+26, 2.4746e7)
1805 def __init__(self, mass, radius):
1806 self.mass = mass # in kilograms
1807 self.radius = radius # in meters
1808 @property
1809 def surface_gravity(self):
1810 # universal gravitational constant (m3 kg-1 s-2)
1811 G = 6.67300E-11
1812 return G * self.mass / (self.radius * self.radius)
1813 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1814 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1815
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001816 def test_ignore(self):
1817 class Period(timedelta, Enum):
1818 '''
1819 different lengths of time
1820 '''
1821 def __new__(cls, value, period):
1822 obj = timedelta.__new__(cls, value)
1823 obj._value_ = value
1824 obj.period = period
1825 return obj
1826 _ignore_ = 'Period i'
1827 Period = vars()
1828 for i in range(13):
1829 Period['month_%d' % i] = i*30, 'month'
1830 for i in range(53):
1831 Period['week_%d' % i] = i*7, 'week'
1832 for i in range(32):
1833 Period['day_%d' % i] = i, 'day'
1834 OneDay = day_1
1835 OneWeek = week_1
1836 OneMonth = month_1
1837 self.assertFalse(hasattr(Period, '_ignore_'))
1838 self.assertFalse(hasattr(Period, 'Period'))
1839 self.assertFalse(hasattr(Period, 'i'))
1840 self.assertTrue(isinstance(Period.day_1, timedelta))
1841 self.assertTrue(Period.month_1 is Period.day_30)
1842 self.assertTrue(Period.week_4 is Period.day_28)
1843
Ethan Furman2aa27322013-07-19 19:35:56 -07001844 def test_nonhash_value(self):
1845 class AutoNumberInAList(Enum):
1846 def __new__(cls):
1847 value = [len(cls.__members__) + 1]
1848 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001849 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001850 return obj
1851 class ColorInAList(AutoNumberInAList):
1852 red = ()
1853 green = ()
1854 blue = ()
1855 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001856 for enum, value in zip(ColorInAList, range(3)):
1857 value += 1
1858 self.assertEqual(enum.value, [value])
1859 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001860
Ethan Furmanb41803e2013-07-25 13:50:45 -07001861 def test_conflicting_types_resolved_in_new(self):
1862 class LabelledIntEnum(int, Enum):
1863 def __new__(cls, *args):
1864 value, label = args
1865 obj = int.__new__(cls, value)
1866 obj.label = label
1867 obj._value_ = value
1868 return obj
1869
1870 class LabelledList(LabelledIntEnum):
1871 unprocessed = (1, "Unprocessed")
1872 payment_complete = (2, "Payment Complete")
1873
1874 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1875 self.assertEqual(LabelledList.unprocessed, 1)
1876 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001877
Ethan Furmanc16595e2016-09-10 23:36:59 -07001878 def test_auto_number(self):
1879 class Color(Enum):
1880 red = auto()
1881 blue = auto()
1882 green = auto()
1883
1884 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1885 self.assertEqual(Color.red.value, 1)
1886 self.assertEqual(Color.blue.value, 2)
1887 self.assertEqual(Color.green.value, 3)
1888
1889 def test_auto_name(self):
1890 class Color(Enum):
1891 def _generate_next_value_(name, start, count, last):
1892 return name
1893 red = auto()
1894 blue = auto()
1895 green = auto()
1896
1897 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1898 self.assertEqual(Color.red.value, 'red')
1899 self.assertEqual(Color.blue.value, 'blue')
1900 self.assertEqual(Color.green.value, 'green')
1901
1902 def test_auto_name_inherit(self):
1903 class AutoNameEnum(Enum):
1904 def _generate_next_value_(name, start, count, last):
1905 return name
1906 class Color(AutoNameEnum):
1907 red = auto()
1908 blue = auto()
1909 green = auto()
1910
1911 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1912 self.assertEqual(Color.red.value, 'red')
1913 self.assertEqual(Color.blue.value, 'blue')
1914 self.assertEqual(Color.green.value, 'green')
1915
1916 def test_auto_garbage(self):
1917 class Color(Enum):
1918 red = 'red'
1919 blue = auto()
1920 self.assertEqual(Color.blue.value, 1)
1921
1922 def test_auto_garbage_corrected(self):
1923 class Color(Enum):
1924 red = 'red'
1925 blue = 2
1926 green = auto()
1927
1928 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1929 self.assertEqual(Color.red.value, 'red')
1930 self.assertEqual(Color.blue.value, 2)
1931 self.assertEqual(Color.green.value, 3)
1932
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001933 def test_auto_order(self):
1934 with self.assertRaises(TypeError):
1935 class Color(Enum):
1936 red = auto()
1937 green = auto()
1938 blue = auto()
1939 def _generate_next_value_(name, start, count, last):
1940 return name
1941
Ethan Furmanfc23a942020-09-16 12:37:54 -07001942 def test_auto_order_wierd(self):
1943 weird_auto = auto()
1944 weird_auto.value = 'pathological case'
1945 class Color(Enum):
1946 red = weird_auto
1947 def _generate_next_value_(name, start, count, last):
1948 return name
1949 blue = auto()
1950 self.assertEqual(list(Color), [Color.red, Color.blue])
1951 self.assertEqual(Color.red.value, 'pathological case')
1952 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001953
Ethan Furman3515dcc2016-09-18 13:15:41 -07001954 def test_duplicate_auto(self):
1955 class Dupes(Enum):
1956 first = primero = auto()
1957 second = auto()
1958 third = auto()
1959 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1960
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001961 def test_default_missing(self):
1962 class Color(Enum):
1963 RED = 1
1964 GREEN = 2
1965 BLUE = 3
1966 try:
1967 Color(7)
1968 except ValueError as exc:
1969 self.assertTrue(exc.__context__ is None)
1970 else:
1971 raise Exception('Exception not raised.')
1972
Ethan Furman019f0a02018-09-12 11:43:34 -07001973 def test_missing(self):
1974 class Color(Enum):
1975 red = 1
1976 green = 2
1977 blue = 3
1978 @classmethod
1979 def _missing_(cls, item):
1980 if item == 'three':
1981 return cls.blue
1982 elif item == 'bad return':
1983 # trigger internal error
1984 return 5
1985 elif item == 'error out':
1986 raise ZeroDivisionError
1987 else:
1988 # trigger not found
1989 return None
1990 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001991 try:
1992 Color(7)
1993 except ValueError as exc:
1994 self.assertTrue(exc.__context__ is None)
1995 else:
1996 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001997 try:
1998 Color('bad return')
1999 except TypeError as exc:
2000 self.assertTrue(isinstance(exc.__context__, ValueError))
2001 else:
2002 raise Exception('Exception not raised.')
2003 try:
2004 Color('error out')
2005 except ZeroDivisionError as exc:
2006 self.assertTrue(isinstance(exc.__context__, ValueError))
2007 else:
2008 raise Exception('Exception not raised.')
2009
Ethan Furman8c14f5a2021-04-12 08:51:20 -07002010 def test_missing_exceptions_reset(self):
2011 import weakref
2012 #
2013 class TestEnum(enum.Enum):
2014 VAL1 = 'val1'
2015 VAL2 = 'val2'
2016 #
2017 class Class1:
2018 def __init__(self):
2019 # Gracefully handle an exception of our own making
2020 try:
2021 raise ValueError()
2022 except ValueError:
2023 pass
2024 #
2025 class Class2:
2026 def __init__(self):
2027 # Gracefully handle an exception of Enum's making
2028 try:
2029 TestEnum('invalid_value')
2030 except ValueError:
2031 pass
2032 # No strong refs here so these are free to die.
2033 class_1_ref = weakref.ref(Class1())
2034 class_2_ref = weakref.ref(Class2())
2035 #
2036 # The exception raised by Enum creates a reference loop and thus
2037 # Class2 instances will stick around until the next gargage collection
2038 # cycle, unlike Class1.
2039 self.assertIs(class_1_ref(), None)
2040 self.assertIs(class_2_ref(), None)
2041
Ethan Furman5bdab642018-09-21 19:03:09 -07002042 def test_multiple_mixin(self):
2043 class MaxMixin:
2044 @classproperty
2045 def MAX(cls):
2046 max = len(cls)
2047 cls.MAX = max
2048 return max
2049 class StrMixin:
2050 def __str__(self):
2051 return self._name_.lower()
2052 class SomeEnum(Enum):
2053 def behavior(self):
2054 return 'booyah'
2055 class AnotherEnum(Enum):
2056 def behavior(self):
2057 return 'nuhuh!'
2058 def social(self):
2059 return "what's up?"
2060 class Color(MaxMixin, Enum):
2061 RED = auto()
2062 GREEN = auto()
2063 BLUE = auto()
2064 self.assertEqual(Color.RED.value, 1)
2065 self.assertEqual(Color.GREEN.value, 2)
2066 self.assertEqual(Color.BLUE.value, 3)
2067 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002068 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002069 class Color(MaxMixin, StrMixin, Enum):
2070 RED = auto()
2071 GREEN = auto()
2072 BLUE = auto()
2073 self.assertEqual(Color.RED.value, 1)
2074 self.assertEqual(Color.GREEN.value, 2)
2075 self.assertEqual(Color.BLUE.value, 3)
2076 self.assertEqual(Color.MAX, 3)
2077 self.assertEqual(str(Color.BLUE), 'blue')
2078 class Color(StrMixin, MaxMixin, Enum):
2079 RED = auto()
2080 GREEN = auto()
2081 BLUE = auto()
2082 self.assertEqual(Color.RED.value, 1)
2083 self.assertEqual(Color.GREEN.value, 2)
2084 self.assertEqual(Color.BLUE.value, 3)
2085 self.assertEqual(Color.MAX, 3)
2086 self.assertEqual(str(Color.BLUE), 'blue')
2087 class CoolColor(StrMixin, SomeEnum, Enum):
2088 RED = auto()
2089 GREEN = auto()
2090 BLUE = auto()
2091 self.assertEqual(CoolColor.RED.value, 1)
2092 self.assertEqual(CoolColor.GREEN.value, 2)
2093 self.assertEqual(CoolColor.BLUE.value, 3)
2094 self.assertEqual(str(CoolColor.BLUE), 'blue')
2095 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2096 class CoolerColor(StrMixin, AnotherEnum, Enum):
2097 RED = auto()
2098 GREEN = auto()
2099 BLUE = auto()
2100 self.assertEqual(CoolerColor.RED.value, 1)
2101 self.assertEqual(CoolerColor.GREEN.value, 2)
2102 self.assertEqual(CoolerColor.BLUE.value, 3)
2103 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2104 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2105 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2106 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2107 RED = auto()
2108 GREEN = auto()
2109 BLUE = auto()
2110 self.assertEqual(CoolestColor.RED.value, 1)
2111 self.assertEqual(CoolestColor.GREEN.value, 2)
2112 self.assertEqual(CoolestColor.BLUE.value, 3)
2113 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2114 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2115 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2116 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2117 RED = auto()
2118 GREEN = auto()
2119 BLUE = auto()
2120 self.assertEqual(ConfusedColor.RED.value, 1)
2121 self.assertEqual(ConfusedColor.GREEN.value, 2)
2122 self.assertEqual(ConfusedColor.BLUE.value, 3)
2123 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2124 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2125 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2126 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2127 RED = auto()
2128 GREEN = auto()
2129 BLUE = auto()
2130 self.assertEqual(ReformedColor.RED.value, 1)
2131 self.assertEqual(ReformedColor.GREEN.value, 2)
2132 self.assertEqual(ReformedColor.BLUE.value, 3)
2133 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2134 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2135 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2136 self.assertTrue(issubclass(ReformedColor, int))
2137
Ethan Furmancd453852018-10-05 23:29:36 -07002138 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002139 @unique
2140 class Decision1(StrEnum):
2141 REVERT = "REVERT"
2142 REVERT_ALL = "REVERT_ALL"
2143 RETRY = "RETRY"
2144 class MyEnum(StrEnum):
2145 pass
2146 @unique
2147 class Decision2(MyEnum):
2148 REVERT = "REVERT"
2149 REVERT_ALL = "REVERT_ALL"
2150 RETRY = "RETRY"
2151
Ethan Furmanc2667362020-12-07 00:17:31 -08002152 def test_multiple_mixin_inherited(self):
2153 class MyInt(int):
2154 def __new__(cls, value):
2155 return super().__new__(cls, value)
2156
2157 class HexMixin:
2158 def __repr__(self):
2159 return hex(self)
2160
2161 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2162 pass
2163
2164 class Foo(MyIntEnum):
2165 TEST = 1
2166 self.assertTrue(isinstance(Foo.TEST, MyInt))
2167 self.assertEqual(repr(Foo.TEST), "0x1")
2168
2169 class Fee(MyIntEnum):
2170 TEST = 1
2171 def __new__(cls, value):
2172 value += 1
2173 member = int.__new__(cls, value)
2174 member._value_ = value
2175 return member
2176 self.assertEqual(Fee.TEST, 2)
2177
Miss Islington (bot)01286012021-06-10 15:01:03 -07002178 def test_miltuple_mixin_with_common_data_type(self):
2179 class CaseInsensitiveStrEnum(str, Enum):
2180 @classmethod
2181 def _missing_(cls, value):
2182 for member in cls._member_map_.values():
2183 if member._value_.lower() == value.lower():
2184 return member
2185 return super()._missing_(value)
2186 #
2187 class LenientStrEnum(str, Enum):
2188 def __init__(self, *args):
2189 self._valid = True
2190 @classmethod
2191 def _missing_(cls, value):
Miss Islington (bot)01286012021-06-10 15:01:03 -07002192 unknown = cls._member_type_.__new__(cls, value)
2193 unknown._valid = False
2194 unknown._name_ = value.upper()
2195 unknown._value_ = value
2196 cls._member_map_[value] = unknown
2197 return unknown
2198 @property
2199 def valid(self):
2200 return self._valid
2201 #
2202 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2203 ACTIVE = "active"
2204 PENDING = "pending"
2205 TERMINATED = "terminated"
2206 #
2207 JS = JobStatus
2208 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2209 self.assertEqual(JS.ACTIVE, 'active')
2210 self.assertEqual(JS.ACTIVE.value, 'active')
2211 self.assertIs(JS('Active'), JS.ACTIVE)
2212 self.assertTrue(JS.ACTIVE.valid)
2213 missing = JS('missing')
2214 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2215 self.assertEqual(JS.ACTIVE, 'active')
2216 self.assertEqual(JS.ACTIVE.value, 'active')
2217 self.assertIs(JS('Active'), JS.ACTIVE)
2218 self.assertTrue(JS.ACTIVE.valid)
2219 self.assertTrue(isinstance(missing, JS))
2220 self.assertFalse(missing.valid)
2221
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002222 def test_empty_globals(self):
2223 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2224 # when using compile and exec because f_globals is empty
2225 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2226 code = compile(code, "<string>", "exec")
2227 global_ns = {}
2228 local_ls = {}
2229 exec(code, global_ns, local_ls)
2230
Ethan Furman0063ff42020-09-21 17:23:13 -07002231 def test_strenum(self):
2232 class GoodStrEnum(StrEnum):
2233 one = '1'
2234 two = '2'
2235 three = b'3', 'ascii'
2236 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002237 self.assertEqual(GoodStrEnum.one, '1')
2238 self.assertEqual(str(GoodStrEnum.one), '1')
2239 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2240 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2241 #
2242 class DumbMixin:
2243 def __str__(self):
2244 return "don't do this"
2245 class DumbStrEnum(DumbMixin, StrEnum):
2246 five = '5'
2247 six = '6'
2248 seven = '7'
2249 self.assertEqual(DumbStrEnum.seven, '7')
2250 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2251 #
2252 class EnumMixin(Enum):
2253 def hello(self):
2254 print('hello from %s' % (self, ))
2255 class HelloEnum(EnumMixin, StrEnum):
2256 eight = '8'
2257 self.assertEqual(HelloEnum.eight, '8')
2258 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2259 #
2260 class GoodbyeMixin:
2261 def goodbye(self):
2262 print('%s wishes you a fond farewell')
2263 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2264 nine = '9'
2265 self.assertEqual(GoodbyeEnum.nine, '9')
2266 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2267 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002268 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2269 class FirstFailedStrEnum(StrEnum):
2270 one = 1
2271 two = '2'
2272 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2273 class SecondFailedStrEnum(StrEnum):
2274 one = '1'
2275 two = 2,
2276 three = '3'
2277 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2278 class ThirdFailedStrEnum(StrEnum):
2279 one = '1'
2280 two = 2
2281 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2282 class ThirdFailedStrEnum(StrEnum):
2283 one = '1'
2284 two = b'2', sys.getdefaultencoding
2285 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2286 class ThirdFailedStrEnum(StrEnum):
2287 one = '1'
2288 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002289
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002290 def test_missing_value_error(self):
2291 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2292 class Combined(str, Enum):
2293 #
2294 def __new__(cls, value, sequence):
2295 enum = str.__new__(cls, value)
2296 if '(' in value:
2297 fis_name, segment = value.split('(', 1)
2298 segment = segment.strip(' )')
2299 else:
2300 fis_name = value
2301 segment = None
2302 enum.fis_name = fis_name
2303 enum.segment = segment
2304 enum.sequence = sequence
2305 return enum
2306 #
2307 def __repr__(self):
2308 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2309 #
2310 key_type = 'An$(1,2)', 0
2311 company_id = 'An$(3,2)', 1
2312 code = 'An$(5,1)', 2
2313 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002314
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002315 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002316 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002317 'private variables are now normal attributes',
2318 )
2319 def test_warning_for_private_variables(self):
2320 with self.assertWarns(DeprecationWarning):
2321 class Private(Enum):
2322 __corporal = 'Radar'
2323 self.assertEqual(Private._Private__corporal.value, 'Radar')
2324 try:
2325 with self.assertWarns(DeprecationWarning):
2326 class Private(Enum):
2327 __major_ = 'Hoolihan'
2328 except ValueError:
2329 pass
2330
2331 def test_private_variable_is_normal_attribute(self):
2332 class Private(Enum):
2333 __corporal = 'Radar'
2334 __major_ = 'Hoolihan'
2335 self.assertEqual(Private._Private__corporal, 'Radar')
2336 self.assertEqual(Private._Private__major_, 'Hoolihan')
2337
Ethan Furmand65b9032021-02-08 17:32:38 -08002338 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002339 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002340 'member-member access now raises an exception',
2341 )
2342 def test_warning_for_member_from_member_access(self):
2343 with self.assertWarns(DeprecationWarning):
2344 class Di(Enum):
2345 YES = 1
2346 NO = 0
2347 nope = Di.YES.NO
2348 self.assertIs(Di.NO, nope)
2349
2350 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002351 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002352 'member-member access currently issues a warning',
2353 )
2354 def test_exception_for_member_from_member_access(self):
2355 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2356 class Di(Enum):
2357 YES = 1
2358 NO = 0
2359 nope = Di.YES.NO
2360
Ethan Furmanefb13be2020-12-10 12:20:06 -08002361 def test_strenum_auto(self):
2362 class Strings(StrEnum):
2363 ONE = auto()
2364 TWO = auto()
2365 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2366
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002367
Ethan Furmana6582872020-12-10 13:07:00 -08002368 def test_dynamic_members_with_static_methods(self):
2369 #
2370 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2371 class Foo(Enum):
2372 vars().update({
2373 k: v
2374 for k, v in foo_defines.items()
2375 if k.startswith('FOO_')
2376 })
2377 def upper(self):
2378 return self.value.upper()
2379 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2380 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2381 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2382 #
2383 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2384 class FooBar(Enum):
2385 vars().update({
2386 k: v
2387 for k, v in foo_defines.items()
2388 if k.startswith('FOO_')
2389 },
2390 **{'FOO_CAT': 'small'},
2391 )
2392 def upper(self):
2393 return self.value.upper()
2394
2395
Ethan Furmane8e61272016-08-20 07:19:31 -07002396class TestOrder(unittest.TestCase):
2397
2398 def test_same_members(self):
2399 class Color(Enum):
2400 _order_ = 'red green blue'
2401 red = 1
2402 green = 2
2403 blue = 3
2404
2405 def test_same_members_with_aliases(self):
2406 class Color(Enum):
2407 _order_ = 'red green blue'
2408 red = 1
2409 green = 2
2410 blue = 3
2411 verde = green
2412
2413 def test_same_members_wrong_order(self):
2414 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2415 class Color(Enum):
2416 _order_ = 'red green blue'
2417 red = 1
2418 blue = 3
2419 green = 2
2420
2421 def test_order_has_extra_members(self):
2422 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2423 class Color(Enum):
2424 _order_ = 'red green blue purple'
2425 red = 1
2426 green = 2
2427 blue = 3
2428
2429 def test_order_has_extra_members_with_aliases(self):
2430 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2431 class Color(Enum):
2432 _order_ = 'red green blue purple'
2433 red = 1
2434 green = 2
2435 blue = 3
2436 verde = green
2437
2438 def test_enum_has_extra_members(self):
2439 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2440 class Color(Enum):
2441 _order_ = 'red green blue'
2442 red = 1
2443 green = 2
2444 blue = 3
2445 purple = 4
2446
2447 def test_enum_has_extra_members_with_aliases(self):
2448 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2449 class Color(Enum):
2450 _order_ = 'red green blue'
2451 red = 1
2452 green = 2
2453 blue = 3
2454 purple = 4
2455 verde = green
2456
2457
Ethan Furman65a5a472016-09-01 23:55:19 -07002458class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002459 """Tests of the Flags."""
2460
Ethan Furman65a5a472016-09-01 23:55:19 -07002461 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002462 R, W, X = 4, 2, 1
2463
Ethan Furman65a5a472016-09-01 23:55:19 -07002464 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002465 RO = 0
2466 WO = 1
2467 RW = 2
2468 AC = 3
2469 CE = 1<<19
2470
Rahul Jha94306522018-09-10 23:51:04 +05302471 class Color(Flag):
2472 BLACK = 0
2473 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002474 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302475 GREEN = 2
2476 BLUE = 4
2477 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002478 WHITE = RED|GREEN|BLUE
2479 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302480
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002481 def test_str(self):
2482 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002483 self.assertEqual(str(Perm.R), 'R')
2484 self.assertEqual(str(Perm.W), 'W')
2485 self.assertEqual(str(Perm.X), 'X')
2486 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2487 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002488 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002489 self.assertEqual(str(~Perm.R), 'W|X')
2490 self.assertEqual(str(~Perm.W), 'R|X')
2491 self.assertEqual(str(~Perm.X), 'R|W')
2492 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002493 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002494 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002495
2496 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002497 self.assertEqual(str(Open.RO), 'RO')
2498 self.assertEqual(str(Open.WO), 'WO')
2499 self.assertEqual(str(Open.AC), 'AC')
2500 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2501 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2502 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2503 self.assertEqual(str(~Open.WO), 'RW|CE')
2504 self.assertEqual(str(~Open.AC), 'CE')
2505 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2506 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002507
2508 def test_repr(self):
2509 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002510 self.assertEqual(repr(Perm.R), 'Perm.R')
2511 self.assertEqual(repr(Perm.W), 'Perm.W')
2512 self.assertEqual(repr(Perm.X), 'Perm.X')
2513 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2514 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2515 self.assertEqual(repr(Perm(0)), '0x0')
2516 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2517 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2518 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2519 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2520 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2521 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002522
2523 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002524 self.assertEqual(repr(Open.RO), 'Open.RO')
2525 self.assertEqual(repr(Open.WO), 'Open.WO')
2526 self.assertEqual(repr(Open.AC), 'Open.AC')
2527 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2528 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2529 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2530 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2531 self.assertEqual(repr(~Open.AC), 'Open.CE')
2532 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2533 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002534
Ethan Furman37440ee2020-12-08 11:14:10 -08002535 def test_format(self):
2536 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002537 self.assertEqual(format(Perm.R, ''), 'R')
2538 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002539
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002540 def test_or(self):
2541 Perm = self.Perm
2542 for i in Perm:
2543 for j in Perm:
2544 self.assertEqual((i | j), Perm(i.value | j.value))
2545 self.assertEqual((i | j).value, i.value | j.value)
2546 self.assertIs(type(i | j), Perm)
2547 for i in Perm:
2548 self.assertIs(i | i, i)
2549 Open = self.Open
2550 self.assertIs(Open.RO | Open.CE, Open.CE)
2551
2552 def test_and(self):
2553 Perm = self.Perm
2554 RW = Perm.R | Perm.W
2555 RX = Perm.R | Perm.X
2556 WX = Perm.W | Perm.X
2557 RWX = Perm.R | Perm.W | Perm.X
2558 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2559 for i in values:
2560 for j in values:
2561 self.assertEqual((i & j).value, i.value & j.value)
2562 self.assertIs(type(i & j), Perm)
2563 for i in Perm:
2564 self.assertIs(i & i, i)
2565 self.assertIs(i & RWX, i)
2566 self.assertIs(RWX & i, i)
2567 Open = self.Open
2568 self.assertIs(Open.RO & Open.CE, Open.RO)
2569
2570 def test_xor(self):
2571 Perm = self.Perm
2572 for i in Perm:
2573 for j in Perm:
2574 self.assertEqual((i ^ j).value, i.value ^ j.value)
2575 self.assertIs(type(i ^ j), Perm)
2576 for i in Perm:
2577 self.assertIs(i ^ Perm(0), i)
2578 self.assertIs(Perm(0) ^ i, i)
2579 Open = self.Open
2580 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2581 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2582
2583 def test_invert(self):
2584 Perm = self.Perm
2585 RW = Perm.R | Perm.W
2586 RX = Perm.R | Perm.X
2587 WX = Perm.W | Perm.X
2588 RWX = Perm.R | Perm.W | Perm.X
2589 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2590 for i in values:
2591 self.assertIs(type(~i), Perm)
2592 self.assertEqual(~~i, i)
2593 for i in Perm:
2594 self.assertIs(~~i, i)
2595 Open = self.Open
2596 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2597 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2598
Ethan Furman25d94bb2016-09-02 16:32:32 -07002599 def test_bool(self):
2600 Perm = self.Perm
2601 for f in Perm:
2602 self.assertTrue(f)
2603 Open = self.Open
2604 for f in Open:
2605 self.assertEqual(bool(f.value), bool(f))
2606
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002607 def test_boundary(self):
2608 self.assertIs(enum.Flag._boundary_, STRICT)
2609 class Iron(Flag, boundary=STRICT):
2610 ONE = 1
2611 TWO = 2
2612 EIGHT = 8
2613 self.assertIs(Iron._boundary_, STRICT)
2614 #
2615 class Water(Flag, boundary=CONFORM):
2616 ONE = 1
2617 TWO = 2
2618 EIGHT = 8
2619 self.assertIs(Water._boundary_, CONFORM)
2620 #
2621 class Space(Flag, boundary=EJECT):
2622 ONE = 1
2623 TWO = 2
2624 EIGHT = 8
2625 self.assertIs(Space._boundary_, EJECT)
2626 #
2627 class Bizarre(Flag, boundary=KEEP):
2628 b = 3
2629 c = 4
2630 d = 6
2631 #
2632 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002633 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002634 self.assertIs(Water(7), Water.ONE|Water.TWO)
2635 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002636 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002637 self.assertEqual(Space(7), 7)
2638 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002639 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002640 self.assertEqual(list(Bizarre), [Bizarre.c])
2641 self.assertIs(Bizarre(3), Bizarre.b)
2642 self.assertIs(Bizarre(6), Bizarre.d)
2643
2644 def test_iter(self):
2645 Color = self.Color
2646 Open = self.Open
2647 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2648 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2649
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002650 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002651 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002652 lst = list(Perm)
2653 self.assertEqual(len(lst), len(Perm))
2654 self.assertEqual(len(Perm), 3, Perm)
2655 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2656 for i, n in enumerate('R W X'.split()):
2657 v = 1<<i
2658 e = Perm(v)
2659 self.assertEqual(e.value, v)
2660 self.assertEqual(type(e.value), int)
2661 self.assertEqual(e.name, n)
2662 self.assertIn(e, Perm)
2663 self.assertIs(type(e), Perm)
2664
2665 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002666 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002667 lst = list(Perm)
2668 self.assertEqual(len(lst), len(Perm))
2669 self.assertEqual(len(Perm), 3, Perm)
2670 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2671 for i, n in enumerate('R W X'.split()):
2672 v = 8<<i
2673 e = Perm(v)
2674 self.assertEqual(e.value, v)
2675 self.assertEqual(type(e.value), int)
2676 self.assertEqual(e.name, n)
2677 self.assertIn(e, Perm)
2678 self.assertIs(type(e), Perm)
2679
2680 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002681 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002682 lst = list(Perm)
2683 self.assertEqual(len(lst), len(Perm))
2684 self.assertEqual(len(Perm), 3, Perm)
2685 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2686 for i, n in enumerate('R W X'.split()):
2687 v = 1<<i
2688 e = Perm(v)
2689 self.assertEqual(e.value, v)
2690 self.assertEqual(type(e.value), int)
2691 self.assertEqual(e.name, n)
2692 self.assertIn(e, Perm)
2693 self.assertIs(type(e), Perm)
2694
2695 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002696 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002697 lst = list(Perm)
2698 self.assertEqual(len(lst), len(Perm))
2699 self.assertEqual(len(Perm), 3, Perm)
2700 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2701 for i, n in enumerate('R W X'.split()):
2702 v = 1<<(2*i+1)
2703 e = Perm(v)
2704 self.assertEqual(e.value, v)
2705 self.assertEqual(type(e.value), int)
2706 self.assertEqual(e.name, n)
2707 self.assertIn(e, Perm)
2708 self.assertIs(type(e), Perm)
2709
2710 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002711 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002712 lst = list(Perm)
2713 self.assertEqual(len(lst), len(Perm))
2714 self.assertEqual(len(Perm), 3, Perm)
2715 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2716 for i, n in enumerate('R W X'.split()):
2717 v = 1<<(2*i+1)
2718 e = Perm(v)
2719 self.assertEqual(e.value, v)
2720 self.assertEqual(type(e.value), int)
2721 self.assertEqual(e.name, n)
2722 self.assertIn(e, Perm)
2723 self.assertIs(type(e), Perm)
2724
Ethan Furman65a5a472016-09-01 23:55:19 -07002725 def test_pickle(self):
2726 if isinstance(FlagStooges, Exception):
2727 raise FlagStooges
2728 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2729 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002730
Ethan Furman6bd92882021-04-27 13:05:08 -07002731 @unittest.skipIf(
2732 python_version >= (3, 12),
2733 '__contains__ now returns True/False for all inputs',
2734 )
2735 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302736 Open = self.Open
2737 Color = self.Color
2738 self.assertFalse(Color.BLACK in Open)
2739 self.assertFalse(Open.RO in Color)
2740 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002741 with self.assertWarns(DeprecationWarning):
2742 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302743 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002744 with self.assertWarns(DeprecationWarning):
2745 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302746 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002747 with self.assertWarns(DeprecationWarning):
2748 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302749 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002750 with self.assertWarns(DeprecationWarning):
2751 1 in Open
2752
2753 @unittest.skipIf(
2754 python_version < (3, 12),
2755 '__contains__ only works with enum memmbers before 3.12',
2756 )
2757 def test_contains_tf(self):
2758 Open = self.Open
2759 Color = self.Color
2760 self.assertFalse(Color.BLACK in Open)
2761 self.assertFalse(Open.RO in Color)
2762 self.assertFalse('BLACK' in Color)
2763 self.assertFalse('RO' in Open)
2764 self.assertTrue(1 in Color)
2765 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302766
2767 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002768 Perm = self.Perm
2769 R, W, X = Perm
2770 RW = R | W
2771 RX = R | X
2772 WX = W | X
2773 RWX = R | W | X
2774 self.assertTrue(R in RW)
2775 self.assertTrue(R in RX)
2776 self.assertTrue(R in RWX)
2777 self.assertTrue(W in RW)
2778 self.assertTrue(W in WX)
2779 self.assertTrue(W in RWX)
2780 self.assertTrue(X in RX)
2781 self.assertTrue(X in WX)
2782 self.assertTrue(X in RWX)
2783 self.assertFalse(R in WX)
2784 self.assertFalse(W in RX)
2785 self.assertFalse(X in RW)
2786
Ethan Furman7219e272020-09-16 13:01:00 -07002787 def test_member_iter(self):
2788 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002789 self.assertEqual(list(Color.BLACK), [])
2790 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002791 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2792 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002793 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2794 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2795
2796 def test_member_length(self):
2797 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2798 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2799 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2800 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2801
2802 def test_number_reset_and_order_cleanup(self):
2803 class Confused(Flag):
2804 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2805 ONE = auto()
2806 TWO = auto()
2807 FOUR = auto()
2808 DOS = 2
2809 EIGHT = auto()
2810 SIXTEEN = auto()
2811 self.assertEqual(
2812 list(Confused),
2813 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2814 self.assertIs(Confused.TWO, Confused.DOS)
2815 self.assertEqual(Confused.DOS._value_, 2)
2816 self.assertEqual(Confused.EIGHT._value_, 8)
2817 self.assertEqual(Confused.SIXTEEN._value_, 16)
2818
2819 def test_aliases(self):
2820 Color = self.Color
2821 self.assertEqual(Color(1).name, 'RED')
2822 self.assertEqual(Color['ROJO'].name, 'RED')
2823 self.assertEqual(Color(7).name, 'WHITE')
2824 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2825 self.assertIs(Color.BLANCO, Color.WHITE)
2826 Open = self.Open
2827 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002828
Ethan Furmanc16595e2016-09-10 23:36:59 -07002829 def test_auto_number(self):
2830 class Color(Flag):
2831 red = auto()
2832 blue = auto()
2833 green = auto()
2834
2835 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2836 self.assertEqual(Color.red.value, 1)
2837 self.assertEqual(Color.blue.value, 2)
2838 self.assertEqual(Color.green.value, 4)
2839
2840 def test_auto_number_garbage(self):
2841 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2842 class Color(Flag):
2843 red = 'not an int'
2844 blue = auto()
2845
Ethan Furman3515dcc2016-09-18 13:15:41 -07002846 def test_duplicate_auto(self):
2847 class Dupes(Enum):
2848 first = primero = auto()
2849 second = auto()
2850 third = auto()
2851 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2852
Ethan Furman5bdab642018-09-21 19:03:09 -07002853 def test_multiple_mixin(self):
2854 class AllMixin:
2855 @classproperty
2856 def ALL(cls):
2857 members = list(cls)
2858 all_value = None
2859 if members:
2860 all_value = members[0]
2861 for member in members[1:]:
2862 all_value |= member
2863 cls.ALL = all_value
2864 return all_value
2865 class StrMixin:
2866 def __str__(self):
2867 return self._name_.lower()
2868 class Color(AllMixin, Flag):
2869 RED = auto()
2870 GREEN = auto()
2871 BLUE = auto()
2872 self.assertEqual(Color.RED.value, 1)
2873 self.assertEqual(Color.GREEN.value, 2)
2874 self.assertEqual(Color.BLUE.value, 4)
2875 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002876 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002877 class Color(AllMixin, StrMixin, Flag):
2878 RED = auto()
2879 GREEN = auto()
2880 BLUE = auto()
2881 self.assertEqual(Color.RED.value, 1)
2882 self.assertEqual(Color.GREEN.value, 2)
2883 self.assertEqual(Color.BLUE.value, 4)
2884 self.assertEqual(Color.ALL.value, 7)
2885 self.assertEqual(str(Color.BLUE), 'blue')
2886 class Color(StrMixin, AllMixin, Flag):
2887 RED = auto()
2888 GREEN = auto()
2889 BLUE = auto()
2890 self.assertEqual(Color.RED.value, 1)
2891 self.assertEqual(Color.GREEN.value, 2)
2892 self.assertEqual(Color.BLUE.value, 4)
2893 self.assertEqual(Color.ALL.value, 7)
2894 self.assertEqual(str(Color.BLUE), 'blue')
2895
Hai Shie80697d2020-05-28 06:10:27 +08002896 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002897 def test_unique_composite(self):
2898 # override __eq__ to be identity only
2899 class TestFlag(Flag):
2900 one = auto()
2901 two = auto()
2902 three = auto()
2903 four = auto()
2904 five = auto()
2905 six = auto()
2906 seven = auto()
2907 eight = auto()
2908 def __eq__(self, other):
2909 return self is other
2910 def __hash__(self):
2911 return hash(self._value_)
2912 # have multiple threads competing to complete the composite members
2913 seen = set()
2914 failed = False
2915 def cycle_enum():
2916 nonlocal failed
2917 try:
2918 for i in range(256):
2919 seen.add(TestFlag(i))
2920 except Exception:
2921 failed = True
2922 threads = [
2923 threading.Thread(target=cycle_enum)
2924 for _ in range(8)
2925 ]
Hai Shie80697d2020-05-28 06:10:27 +08002926 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002927 pass
2928 # check that only 248 members were created
2929 self.assertFalse(
2930 failed,
2931 'at least one thread failed while creating composite members')
2932 self.assertEqual(256, len(seen), 'too many composite members created')
2933
Ethan Furman6bd94de2020-12-09 16:41:22 -08002934 def test_init_subclass(self):
2935 class MyEnum(Flag):
2936 def __init_subclass__(cls, **kwds):
2937 super().__init_subclass__(**kwds)
2938 self.assertFalse(cls.__dict__.get('_test', False))
2939 cls._test1 = 'MyEnum'
2940 #
2941 class TheirEnum(MyEnum):
2942 def __init_subclass__(cls, **kwds):
2943 super(TheirEnum, cls).__init_subclass__(**kwds)
2944 cls._test2 = 'TheirEnum'
2945 class WhoseEnum(TheirEnum):
2946 def __init_subclass__(cls, **kwds):
2947 pass
2948 class NoEnum(WhoseEnum):
2949 ONE = 1
2950 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2951 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2952 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2953 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2954 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2955 #
2956 class OurEnum(MyEnum):
2957 def __init_subclass__(cls, **kwds):
2958 cls._test2 = 'OurEnum'
2959 class WhereEnum(OurEnum):
2960 def __init_subclass__(cls, **kwds):
2961 pass
2962 class NeverEnum(WhereEnum):
2963 ONE = 1
2964 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2965 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2966 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2967 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2968 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2969
Ethan Furmanc16595e2016-09-10 23:36:59 -07002970
Ethan Furman65a5a472016-09-01 23:55:19 -07002971class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002972 """Tests of the IntFlags."""
2973
Ethan Furman65a5a472016-09-01 23:55:19 -07002974 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002975 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002976 W = 1 << 1
2977 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002978
Ethan Furman65a5a472016-09-01 23:55:19 -07002979 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002980 RO = 0
2981 WO = 1
2982 RW = 2
2983 AC = 3
2984 CE = 1<<19
2985
Rahul Jha94306522018-09-10 23:51:04 +05302986 class Color(IntFlag):
2987 BLACK = 0
2988 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002989 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302990 GREEN = 2
2991 BLUE = 4
2992 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002993 WHITE = RED|GREEN|BLUE
2994 BLANCO = RED|GREEN|BLUE
2995
2996 class Skip(IntFlag):
2997 FIRST = 1
2998 SECOND = 2
2999 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05303000
Ethan Furman3515dcc2016-09-18 13:15:41 -07003001 def test_type(self):
3002 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08003003 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07003004 Open = self.Open
3005 for f in Perm:
3006 self.assertTrue(isinstance(f, Perm))
3007 self.assertEqual(f, f.value)
3008 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
3009 self.assertEqual(Perm.W | Perm.X, 3)
3010 for f in Open:
3011 self.assertTrue(isinstance(f, Open))
3012 self.assertEqual(f, f.value)
3013 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
3014 self.assertEqual(Open.WO | Open.RW, 3)
3015
3016
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003017 def test_str(self):
3018 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003019 self.assertEqual(str(Perm.R), 'R')
3020 self.assertEqual(str(Perm.W), 'W')
3021 self.assertEqual(str(Perm.X), 'X')
3022 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
3023 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003024 self.assertEqual(str(Perm.R | 8), '12')
3025 self.assertEqual(str(Perm(0)), 'Perm(0)')
3026 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003027 self.assertEqual(str(~Perm.R), 'W|X')
3028 self.assertEqual(str(~Perm.W), 'R|X')
3029 self.assertEqual(str(~Perm.X), 'R|W')
3030 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003031 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3032 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003033 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003034 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003035
3036 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003037 self.assertEqual(str(Open.RO), 'RO')
3038 self.assertEqual(str(Open.WO), 'WO')
3039 self.assertEqual(str(Open.AC), 'AC')
3040 self.assertEqual(str(Open.RO | Open.CE), 'CE')
3041 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003042 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003043 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3044 self.assertEqual(str(~Open.WO), 'RW|CE')
3045 self.assertEqual(str(~Open.AC), 'CE')
3046 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3047 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003048 self.assertEqual(str(Open(~4)), '-5')
3049
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003050 def test_repr(self):
3051 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003052 self.assertEqual(repr(Perm.R), 'Perm.R')
3053 self.assertEqual(repr(Perm.W), 'Perm.W')
3054 self.assertEqual(repr(Perm.X), 'Perm.X')
3055 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3056 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003057 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07003058 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003059 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003060 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3061 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3062 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3063 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3064 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003065 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003066 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003067 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003068
3069 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003070 self.assertEqual(repr(Open.RO), 'Open.RO')
3071 self.assertEqual(repr(Open.WO), 'Open.WO')
3072 self.assertEqual(repr(Open.AC), 'Open.AC')
3073 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3074 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003075 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003076 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3077 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3078 self.assertEqual(repr(~Open.AC), 'Open.CE')
3079 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3080 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003081 self.assertEqual(repr(Open(~4)), '-5')
3082
Ethan Furman6bd92882021-04-27 13:05:08 -07003083 @unittest.skipUnless(
3084 python_version < (3, 12),
3085 'mixin-format now uses member instead of member.value',
3086 )
Ethan Furman37440ee2020-12-08 11:14:10 -08003087 def test_format(self):
Ethan Furman6bd92882021-04-27 13:05:08 -07003088 with self.assertWarns(DeprecationWarning):
3089 Perm = self.Perm
3090 self.assertEqual(format(Perm.R, ''), '4')
3091 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08003092
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003093 def test_or(self):
3094 Perm = self.Perm
3095 for i in Perm:
3096 for j in Perm:
3097 self.assertEqual(i | j, i.value | j.value)
3098 self.assertEqual((i | j).value, i.value | j.value)
3099 self.assertIs(type(i | j), Perm)
3100 for j in range(8):
3101 self.assertEqual(i | j, i.value | j)
3102 self.assertEqual((i | j).value, i.value | j)
3103 self.assertIs(type(i | j), Perm)
3104 self.assertEqual(j | i, j | i.value)
3105 self.assertEqual((j | i).value, j | i.value)
3106 self.assertIs(type(j | i), Perm)
3107 for i in Perm:
3108 self.assertIs(i | i, i)
3109 self.assertIs(i | 0, i)
3110 self.assertIs(0 | i, i)
3111 Open = self.Open
3112 self.assertIs(Open.RO | Open.CE, Open.CE)
3113
3114 def test_and(self):
3115 Perm = self.Perm
3116 RW = Perm.R | Perm.W
3117 RX = Perm.R | Perm.X
3118 WX = Perm.W | Perm.X
3119 RWX = Perm.R | Perm.W | Perm.X
3120 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3121 for i in values:
3122 for j in values:
3123 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3124 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3125 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3126 for j in range(8):
3127 self.assertEqual(i & j, i.value & j)
3128 self.assertEqual((i & j).value, i.value & j)
3129 self.assertIs(type(i & j), Perm)
3130 self.assertEqual(j & i, j & i.value)
3131 self.assertEqual((j & i).value, j & i.value)
3132 self.assertIs(type(j & i), Perm)
3133 for i in Perm:
3134 self.assertIs(i & i, i)
3135 self.assertIs(i & 7, i)
3136 self.assertIs(7 & i, i)
3137 Open = self.Open
3138 self.assertIs(Open.RO & Open.CE, Open.RO)
3139
3140 def test_xor(self):
3141 Perm = self.Perm
3142 for i in Perm:
3143 for j in Perm:
3144 self.assertEqual(i ^ j, i.value ^ j.value)
3145 self.assertEqual((i ^ j).value, i.value ^ j.value)
3146 self.assertIs(type(i ^ j), Perm)
3147 for j in range(8):
3148 self.assertEqual(i ^ j, i.value ^ j)
3149 self.assertEqual((i ^ j).value, i.value ^ j)
3150 self.assertIs(type(i ^ j), Perm)
3151 self.assertEqual(j ^ i, j ^ i.value)
3152 self.assertEqual((j ^ i).value, j ^ i.value)
3153 self.assertIs(type(j ^ i), Perm)
3154 for i in Perm:
3155 self.assertIs(i ^ 0, i)
3156 self.assertIs(0 ^ i, i)
3157 Open = self.Open
3158 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3159 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3160
3161 def test_invert(self):
3162 Perm = self.Perm
3163 RW = Perm.R | Perm.W
3164 RX = Perm.R | Perm.X
3165 WX = Perm.W | Perm.X
3166 RWX = Perm.R | Perm.W | Perm.X
3167 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3168 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003169 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003170 self.assertIs(type(~i), Perm)
3171 self.assertEqual(~~i, i)
3172 for i in Perm:
3173 self.assertIs(~~i, i)
3174 Open = self.Open
3175 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3176 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3177
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003178 def test_boundary(self):
3179 self.assertIs(enum.IntFlag._boundary_, EJECT)
3180 class Iron(IntFlag, boundary=STRICT):
3181 ONE = 1
3182 TWO = 2
3183 EIGHT = 8
3184 self.assertIs(Iron._boundary_, STRICT)
3185 #
3186 class Water(IntFlag, boundary=CONFORM):
3187 ONE = 1
3188 TWO = 2
3189 EIGHT = 8
3190 self.assertIs(Water._boundary_, CONFORM)
3191 #
3192 class Space(IntFlag, boundary=EJECT):
3193 ONE = 1
3194 TWO = 2
3195 EIGHT = 8
3196 self.assertIs(Space._boundary_, EJECT)
3197 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003198 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003199 class Bizarre(IntFlag, boundary=KEEP):
3200 b = 3
3201 c = 4
3202 d = 6
3203 #
3204 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003205 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003206 self.assertIs(Water(7), Water.ONE|Water.TWO)
3207 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003208 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003209 self.assertEqual(Space(7), 7)
3210 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003211 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003212 self.assertEqual(list(Bizarre), [Bizarre.c])
3213 self.assertIs(Bizarre(3), Bizarre.b)
3214 self.assertIs(Bizarre(6), Bizarre.d)
3215
3216 def test_iter(self):
3217 Color = self.Color
3218 Open = self.Open
3219 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3220 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3221
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003222 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003223 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003224 lst = list(Perm)
3225 self.assertEqual(len(lst), len(Perm))
3226 self.assertEqual(len(Perm), 3, Perm)
3227 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3228 for i, n in enumerate('R W X'.split()):
3229 v = 1<<i
3230 e = Perm(v)
3231 self.assertEqual(e.value, v)
3232 self.assertEqual(type(e.value), int)
3233 self.assertEqual(e, v)
3234 self.assertEqual(e.name, n)
3235 self.assertIn(e, Perm)
3236 self.assertIs(type(e), Perm)
3237
3238 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003239 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003240 lst = list(Perm)
3241 self.assertEqual(len(lst), len(Perm))
3242 self.assertEqual(len(Perm), 3, Perm)
3243 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3244 for i, n in enumerate('R W X'.split()):
3245 v = 8<<i
3246 e = Perm(v)
3247 self.assertEqual(e.value, v)
3248 self.assertEqual(type(e.value), int)
3249 self.assertEqual(e, v)
3250 self.assertEqual(e.name, n)
3251 self.assertIn(e, Perm)
3252 self.assertIs(type(e), Perm)
3253
3254 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003255 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003256 lst = list(Perm)
3257 self.assertEqual(len(lst), len(Perm))
3258 self.assertEqual(len(Perm), 3, Perm)
3259 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3260 for i, n in enumerate('R W X'.split()):
3261 v = 1<<i
3262 e = Perm(v)
3263 self.assertEqual(e.value, v)
3264 self.assertEqual(type(e.value), int)
3265 self.assertEqual(e, v)
3266 self.assertEqual(e.name, n)
3267 self.assertIn(e, Perm)
3268 self.assertIs(type(e), Perm)
3269
3270 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003271 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003272 lst = list(Perm)
3273 self.assertEqual(len(lst), len(Perm))
3274 self.assertEqual(len(Perm), 3, Perm)
3275 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3276 for i, n in enumerate('R W X'.split()):
3277 v = 1<<(2*i+1)
3278 e = Perm(v)
3279 self.assertEqual(e.value, v)
3280 self.assertEqual(type(e.value), int)
3281 self.assertEqual(e, v)
3282 self.assertEqual(e.name, n)
3283 self.assertIn(e, Perm)
3284 self.assertIs(type(e), Perm)
3285
3286 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003287 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003288 lst = list(Perm)
3289 self.assertEqual(len(lst), len(Perm))
3290 self.assertEqual(len(Perm), 3, Perm)
3291 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3292 for i, n in enumerate('R W X'.split()):
3293 v = 1<<(2*i+1)
3294 e = Perm(v)
3295 self.assertEqual(e.value, v)
3296 self.assertEqual(type(e.value), int)
3297 self.assertEqual(e, v)
3298 self.assertEqual(e.name, n)
3299 self.assertIn(e, Perm)
3300 self.assertIs(type(e), Perm)
3301
3302
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003303 def test_programatic_function_from_empty_list(self):
3304 Perm = enum.IntFlag('Perm', [])
3305 lst = list(Perm)
3306 self.assertEqual(len(lst), len(Perm))
3307 self.assertEqual(len(Perm), 0, Perm)
3308 Thing = enum.Enum('Thing', [])
3309 lst = list(Thing)
3310 self.assertEqual(len(lst), len(Thing))
3311 self.assertEqual(len(Thing), 0, Thing)
3312
3313
3314 def test_programatic_function_from_empty_tuple(self):
3315 Perm = enum.IntFlag('Perm', ())
3316 lst = list(Perm)
3317 self.assertEqual(len(lst), len(Perm))
3318 self.assertEqual(len(Perm), 0, Perm)
3319 Thing = enum.Enum('Thing', ())
3320 self.assertEqual(len(lst), len(Thing))
3321 self.assertEqual(len(Thing), 0, Thing)
3322
Ethan Furman6bd92882021-04-27 13:05:08 -07003323 @unittest.skipIf(
3324 python_version >= (3, 12),
3325 '__contains__ now returns True/False for all inputs',
3326 )
3327 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303328 Open = self.Open
3329 Color = self.Color
3330 self.assertTrue(Color.GREEN in Color)
3331 self.assertTrue(Open.RW in Open)
3332 self.assertFalse(Color.GREEN in Open)
3333 self.assertFalse(Open.RW in Color)
3334 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003335 with self.assertWarns(DeprecationWarning):
3336 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303337 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003338 with self.assertWarns(DeprecationWarning):
3339 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05303340 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003341 with self.assertWarns(DeprecationWarning):
3342 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05303343 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003344 with self.assertWarns(DeprecationWarning):
3345 2 in Open
3346
3347 @unittest.skipIf(
3348 python_version < (3, 12),
3349 '__contains__ only works with enum memmbers before 3.12',
3350 )
3351 def test_contains_tf(self):
3352 Open = self.Open
3353 Color = self.Color
3354 self.assertTrue(Color.GREEN in Color)
3355 self.assertTrue(Open.RW in Open)
3356 self.assertTrue(Color.GREEN in Open)
3357 self.assertTrue(Open.RW in Color)
3358 self.assertFalse('GREEN' in Color)
3359 self.assertFalse('RW' in Open)
3360 self.assertTrue(2 in Color)
3361 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303362
3363 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003364 Perm = self.Perm
3365 R, W, X = Perm
3366 RW = R | W
3367 RX = R | X
3368 WX = W | X
3369 RWX = R | W | X
3370 self.assertTrue(R in RW)
3371 self.assertTrue(R in RX)
3372 self.assertTrue(R in RWX)
3373 self.assertTrue(W in RW)
3374 self.assertTrue(W in WX)
3375 self.assertTrue(W in RWX)
3376 self.assertTrue(X in RX)
3377 self.assertTrue(X in WX)
3378 self.assertTrue(X in RWX)
3379 self.assertFalse(R in WX)
3380 self.assertFalse(W in RX)
3381 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303382 with self.assertRaises(TypeError):
3383 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003384
Ethan Furman7219e272020-09-16 13:01:00 -07003385 def test_member_iter(self):
3386 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003387 self.assertEqual(list(Color.BLACK), [])
3388 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003389 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3390 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003391 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3392
3393 def test_member_length(self):
3394 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3395 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3396 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3397 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3398
3399 def test_aliases(self):
3400 Color = self.Color
3401 self.assertEqual(Color(1).name, 'RED')
3402 self.assertEqual(Color['ROJO'].name, 'RED')
3403 self.assertEqual(Color(7).name, 'WHITE')
3404 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3405 self.assertIs(Color.BLANCO, Color.WHITE)
3406 Open = self.Open
3407 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003408
Ethan Furman25d94bb2016-09-02 16:32:32 -07003409 def test_bool(self):
3410 Perm = self.Perm
3411 for f in Perm:
3412 self.assertTrue(f)
3413 Open = self.Open
3414 for f in Open:
3415 self.assertEqual(bool(f.value), bool(f))
3416
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003417
Ethan Furman5bdab642018-09-21 19:03:09 -07003418 def test_multiple_mixin(self):
3419 class AllMixin:
3420 @classproperty
3421 def ALL(cls):
3422 members = list(cls)
3423 all_value = None
3424 if members:
3425 all_value = members[0]
3426 for member in members[1:]:
3427 all_value |= member
3428 cls.ALL = all_value
3429 return all_value
3430 class StrMixin:
3431 def __str__(self):
3432 return self._name_.lower()
3433 class Color(AllMixin, IntFlag):
3434 RED = auto()
3435 GREEN = auto()
3436 BLUE = auto()
3437 self.assertEqual(Color.RED.value, 1)
3438 self.assertEqual(Color.GREEN.value, 2)
3439 self.assertEqual(Color.BLUE.value, 4)
3440 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003441 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003442 class Color(AllMixin, StrMixin, IntFlag):
3443 RED = auto()
3444 GREEN = auto()
3445 BLUE = auto()
3446 self.assertEqual(Color.RED.value, 1)
3447 self.assertEqual(Color.GREEN.value, 2)
3448 self.assertEqual(Color.BLUE.value, 4)
3449 self.assertEqual(Color.ALL.value, 7)
3450 self.assertEqual(str(Color.BLUE), 'blue')
3451 class Color(StrMixin, AllMixin, IntFlag):
3452 RED = auto()
3453 GREEN = auto()
3454 BLUE = auto()
3455 self.assertEqual(Color.RED.value, 1)
3456 self.assertEqual(Color.GREEN.value, 2)
3457 self.assertEqual(Color.BLUE.value, 4)
3458 self.assertEqual(Color.ALL.value, 7)
3459 self.assertEqual(str(Color.BLUE), 'blue')
3460
Hai Shie80697d2020-05-28 06:10:27 +08003461 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003462 def test_unique_composite(self):
3463 # override __eq__ to be identity only
3464 class TestFlag(IntFlag):
3465 one = auto()
3466 two = auto()
3467 three = auto()
3468 four = auto()
3469 five = auto()
3470 six = auto()
3471 seven = auto()
3472 eight = auto()
3473 def __eq__(self, other):
3474 return self is other
3475 def __hash__(self):
3476 return hash(self._value_)
3477 # have multiple threads competing to complete the composite members
3478 seen = set()
3479 failed = False
3480 def cycle_enum():
3481 nonlocal failed
3482 try:
3483 for i in range(256):
3484 seen.add(TestFlag(i))
3485 except Exception:
3486 failed = True
3487 threads = [
3488 threading.Thread(target=cycle_enum)
3489 for _ in range(8)
3490 ]
Hai Shie80697d2020-05-28 06:10:27 +08003491 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003492 pass
3493 # check that only 248 members were created
3494 self.assertFalse(
3495 failed,
3496 'at least one thread failed while creating composite members')
3497 self.assertEqual(256, len(seen), 'too many composite members created')
3498
3499
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003500class TestEmptyAndNonLatinStrings(unittest.TestCase):
3501
3502 def test_empty_string(self):
3503 with self.assertRaises(ValueError):
3504 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3505
3506 def test_non_latin_character_string(self):
3507 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3508 item = getattr(greek_abc, '\u03B1')
3509 self.assertEqual(item.value, 1)
3510
3511 def test_non_latin_number_string(self):
3512 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3513 item = getattr(hebrew_123, '\u05D0')
3514 self.assertEqual(item.value, 1)
3515
3516
Ethan Furmanf24bb352013-07-18 17:05:39 -07003517class TestUnique(unittest.TestCase):
3518
3519 def test_unique_clean(self):
3520 @unique
3521 class Clean(Enum):
3522 one = 1
3523 two = 'dos'
3524 tres = 4.0
Ethan Furman74964862021-06-10 07:24:20 -07003525 #
Ethan Furmanf24bb352013-07-18 17:05:39 -07003526 @unique
3527 class Cleaner(IntEnum):
3528 single = 1
3529 double = 2
3530 triple = 3
3531
3532 def test_unique_dirty(self):
3533 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3534 @unique
3535 class Dirty(Enum):
3536 one = 1
3537 two = 'dos'
3538 tres = 1
3539 with self.assertRaisesRegex(
3540 ValueError,
3541 'double.*single.*turkey.*triple',
3542 ):
3543 @unique
3544 class Dirtier(IntEnum):
3545 single = 1
3546 double = 1
3547 triple = 3
3548 turkey = 3
3549
Ethan Furman3803ad42016-05-01 10:03:53 -07003550 def test_unique_with_name(self):
Ethan Furman74964862021-06-10 07:24:20 -07003551 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003552 class Silly(Enum):
3553 one = 1
3554 two = 'dos'
3555 name = 3
Ethan Furman74964862021-06-10 07:24:20 -07003556 #
3557 @verify(UNIQUE)
3558 class Sillier(IntEnum):
3559 single = 1
3560 name = 2
3561 triple = 3
3562 value = 4
3563
3564class TestVerify(unittest.TestCase):
3565
3566 def test_continuous(self):
3567 @verify(CONTINUOUS)
3568 class Auto(Enum):
3569 FIRST = auto()
3570 SECOND = auto()
3571 THIRD = auto()
3572 FORTH = auto()
3573 #
3574 @verify(CONTINUOUS)
3575 class Manual(Enum):
3576 FIRST = 3
3577 SECOND = 4
3578 THIRD = 5
3579 FORTH = 6
3580 #
3581 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
3582 @verify(CONTINUOUS)
3583 class Missing(Enum):
3584 FIRST = 3
3585 SECOND = 4
3586 THIRD = 11
3587 FORTH = 13
3588 #
3589 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
3590 @verify(CONTINUOUS)
3591 class Incomplete(Flag):
3592 FIRST = 4
3593 SECOND = 8
3594 THIRD = 16
3595 FORTH = 64
3596 #
3597 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
3598 @verify(CONTINUOUS)
3599 class StillIncomplete(Flag):
3600 FIRST = 4
3601 SECOND = 8
3602 THIRD = 11
3603 FORTH = 32
3604
3605
3606 def test_composite(self):
3607 class Bizarre(Flag):
3608 b = 3
3609 c = 4
3610 d = 6
3611 self.assertEqual(list(Bizarre), [Bizarre.c])
3612 self.assertEqual(Bizarre.b.value, 3)
3613 self.assertEqual(Bizarre.c.value, 4)
3614 self.assertEqual(Bizarre.d.value, 6)
3615 with self.assertRaisesRegex(
3616 ValueError,
Ethan Furman41c2a4a2021-06-15 18:50:59 -07003617 "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 -07003618 ):
3619 @verify(NAMED_FLAGS)
3620 class Bizarre(Flag):
3621 b = 3
3622 c = 4
3623 d = 6
3624 #
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003625 self.assertEqual(enum.show_flag_values(3), [1, 2])
Ethan Furman74964862021-06-10 07:24:20 -07003626 class Bizarre(IntFlag):
3627 b = 3
3628 c = 4
3629 d = 6
3630 self.assertEqual(list(Bizarre), [Bizarre.c])
3631 self.assertEqual(Bizarre.b.value, 3)
3632 self.assertEqual(Bizarre.c.value, 4)
3633 self.assertEqual(Bizarre.d.value, 6)
3634 with self.assertRaisesRegex(
3635 ValueError,
Ethan Furman41c2a4a2021-06-15 18:50:59 -07003636 "invalid Flag 'Bizarre': alias d is missing value 0x2 .use enum.show_flag_values.value. for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003637 ):
3638 @verify(NAMED_FLAGS)
3639 class Bizarre(IntFlag):
Ethan Furman74964862021-06-10 07:24:20 -07003640 c = 4
3641 d = 6
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003642 self.assertEqual(enum.show_flag_values(2), [2])
Ethan Furman74964862021-06-10 07:24:20 -07003643
3644 def test_unique_clean(self):
3645 @verify(UNIQUE)
3646 class Clean(Enum):
3647 one = 1
3648 two = 'dos'
3649 tres = 4.0
3650 #
3651 @verify(UNIQUE)
3652 class Cleaner(IntEnum):
3653 single = 1
3654 double = 2
3655 triple = 3
3656
3657 def test_unique_dirty(self):
3658 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3659 @verify(UNIQUE)
3660 class Dirty(Enum):
3661 one = 1
3662 two = 'dos'
3663 tres = 1
3664 with self.assertRaisesRegex(
3665 ValueError,
3666 'double.*single.*turkey.*triple',
3667 ):
3668 @verify(UNIQUE)
3669 class Dirtier(IntEnum):
3670 single = 1
3671 double = 1
3672 triple = 3
3673 turkey = 3
3674
3675 def test_unique_with_name(self):
3676 @verify(UNIQUE)
3677 class Silly(Enum):
3678 one = 1
3679 two = 'dos'
3680 name = 3
3681 #
3682 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003683 class Sillier(IntEnum):
3684 single = 1
3685 name = 2
3686 triple = 3
3687 value = 4
3688
Ethan Furmanec099732021-04-15 06:58:33 -07003689class TestHelpers(unittest.TestCase):
3690
3691 sunder_names = '_bad_', '_good_', '_what_ho_'
3692 dunder_names = '__mal__', '__bien__', '__que_que__'
3693 private_names = '_MyEnum__private', '_MyEnum__still_private'
3694 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3695 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3696
3697 def test_sunder(self):
3698 for name in self.sunder_names + self.private_and_sunder_names:
3699 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3700 for name in self.dunder_names + self.private_names + self.random_names:
3701 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3702
3703 def test_dunder(self):
3704 for name in self.dunder_names:
3705 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3706 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3707 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3708
3709 def test_is_private(self):
3710 for name in self.private_names + self.private_and_sunder_names:
3711 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3712 for name in self.sunder_names + self.dunder_names + self.random_names:
3713 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003714
Ethan Furmanb7751062021-03-30 21:17:26 -07003715class TestEnumTypeSubclassing(unittest.TestCase):
3716 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003717
Ethan Furman3323da92015-04-11 09:39:59 -07003718expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003719Help on class Color in module %s:
3720
3721class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003722 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003723 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003724 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003725 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003726 | Method resolution order:
3727 | Color
3728 | enum.Enum
3729 | builtins.object
3730 |\x20\x20
3731 | Data and other attributes defined here:
3732 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003733 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003734 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003735 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003736 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003737 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003738 |\x20\x20
3739 | ----------------------------------------------------------------------
3740 | Data descriptors inherited from enum.Enum:
3741 |\x20\x20
3742 | name
3743 | The name of the Enum member.
3744 |\x20\x20
3745 | value
3746 | The value of the Enum member.
3747 |\x20\x20
3748 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003749 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003750 |\x20\x20
3751 | __members__
3752 | Returns a mapping of member name->value.
3753 |\x20\x20\x20\x20\x20\x20
3754 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003755 | is a read-only view of the internal mapping."""
3756
3757expected_help_output_without_docs = """\
3758Help on class Color in module %s:
3759
3760class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003761 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3762 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003763 | Method resolution order:
3764 | Color
3765 | enum.Enum
3766 | builtins.object
3767 |\x20\x20
3768 | Data and other attributes defined here:
3769 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003770 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003771 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003772 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003773 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003774 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003775 |\x20\x20
3776 | ----------------------------------------------------------------------
3777 | Data descriptors inherited from enum.Enum:
3778 |\x20\x20
3779 | name
3780 |\x20\x20
3781 | value
3782 |\x20\x20
3783 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003784 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003785 |\x20\x20
3786 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003787
3788class TestStdLib(unittest.TestCase):
3789
Ethan Furman48a724f2015-04-11 23:23:06 -07003790 maxDiff = None
3791
Ethan Furman5875d742013-10-21 20:45:55 -07003792 class Color(Enum):
3793 red = 1
3794 green = 2
3795 blue = 3
3796
3797 def test_pydoc(self):
3798 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003799 if StrEnum.__doc__ is None:
3800 expected_text = expected_help_output_without_docs % __name__
3801 else:
3802 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003803 output = StringIO()
3804 helper = pydoc.Helper(output=output)
3805 helper(self.Color)
3806 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003807 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003808
3809 def test_inspect_getmembers(self):
3810 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003811 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003812 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003813 ('__members__', self.Color.__members__),
3814 ('__module__', __name__),
3815 ('blue', self.Color.blue),
3816 ('green', self.Color.green),
3817 ('name', Enum.__dict__['name']),
3818 ('red', self.Color.red),
3819 ('value', Enum.__dict__['value']),
3820 ))
3821 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003822 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003823 failed = False
3824 for k in values.keys():
3825 if result[k] != values[k]:
3826 print()
3827 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3828 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3829 failed = True
3830 if failed:
3831 self.fail("result does not equal expected, see print above")
3832
3833 def test_inspect_classify_class_attrs(self):
3834 # indirectly test __objclass__
3835 from inspect import Attribute
3836 values = [
3837 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003838 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003839 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003840 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003841 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003842 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003843 Attribute(name='__module__', kind='data',
3844 defining_class=self.Color, object=__name__),
3845 Attribute(name='blue', kind='data',
3846 defining_class=self.Color, object=self.Color.blue),
3847 Attribute(name='green', kind='data',
3848 defining_class=self.Color, object=self.Color.green),
3849 Attribute(name='red', kind='data',
3850 defining_class=self.Color, object=self.Color.red),
3851 Attribute(name='name', kind='data',
3852 defining_class=Enum, object=Enum.__dict__['name']),
3853 Attribute(name='value', kind='data',
3854 defining_class=Enum, object=Enum.__dict__['value']),
3855 ]
3856 values.sort(key=lambda item: item.name)
3857 result = list(inspect.classify_class_attrs(self.Color))
3858 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003859 self.assertEqual(
3860 len(values), len(result),
3861 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3862 )
Ethan Furman5875d742013-10-21 20:45:55 -07003863 failed = False
3864 for v, r in zip(values, result):
3865 if r != v:
3866 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3867 failed = True
3868 if failed:
3869 self.fail("result does not equal expected, see print above")
3870
Ethan Furmana02cb472021-04-21 10:20:44 -07003871 def test_test_simple_enum(self):
3872 @_simple_enum(Enum)
3873 class SimpleColor:
3874 RED = 1
3875 GREEN = 2
3876 BLUE = 3
3877 class CheckedColor(Enum):
3878 RED = 1
3879 GREEN = 2
3880 BLUE = 3
3881 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3882 SimpleColor.GREEN._value_ = 9
3883 self.assertRaisesRegex(
3884 TypeError, "enum mismatch",
3885 _test_simple_enum, CheckedColor, SimpleColor,
3886 )
3887 class CheckedMissing(IntFlag, boundary=KEEP):
3888 SIXTY_FOUR = 64
3889 ONE_TWENTY_EIGHT = 128
3890 TWENTY_FORTY_EIGHT = 2048
3891 ALL = 2048 + 128 + 64 + 12
3892 CM = CheckedMissing
3893 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3894 #
3895 @_simple_enum(IntFlag, boundary=KEEP)
3896 class Missing:
3897 SIXTY_FOUR = 64
3898 ONE_TWENTY_EIGHT = 128
3899 TWENTY_FORTY_EIGHT = 2048
3900 ALL = 2048 + 128 + 64 + 12
3901 M = Missing
3902 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3903 #
3904 _test_simple_enum(CheckedMissing, Missing)
3905
Martin Panter19e69c52015-11-14 12:46:42 +00003906
3907class MiscTestCase(unittest.TestCase):
3908 def test__all__(self):
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003909 support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
Martin Panter19e69c52015-11-14 12:46:42 +00003910
3911
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003912# These are unordered here on purpose to ensure that declaration order
3913# makes no difference.
3914CONVERT_TEST_NAME_D = 5
3915CONVERT_TEST_NAME_C = 5
3916CONVERT_TEST_NAME_B = 5
3917CONVERT_TEST_NAME_A = 5 # This one should sort first.
3918CONVERT_TEST_NAME_E = 5
3919CONVERT_TEST_NAME_F = 5
3920
Ethan Furmana02cb472021-04-21 10:20:44 -07003921CONVERT_STRING_TEST_NAME_D = 5
3922CONVERT_STRING_TEST_NAME_C = 5
3923CONVERT_STRING_TEST_NAME_B = 5
3924CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3925CONVERT_STRING_TEST_NAME_E = 5
3926CONVERT_STRING_TEST_NAME_F = 5
3927
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003928class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003929 def setUp(self):
3930 # Reset the module-level test variables to their original integer
3931 # values, otherwise the already created enum values get converted
3932 # instead.
3933 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3934 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3935 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3936
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003937 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003938 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003939 'UnittestConvert',
3940 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003941 filter=lambda x: x.startswith('CONVERT_TEST_'))
3942 # We don't want the reverse lookup value to vary when there are
3943 # multiple possible names for a given value. It should always
3944 # report the first lexigraphical name in that case.
3945 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3946
3947 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003948 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003949 'UnittestConvert',
3950 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003951 filter=lambda x: x.startswith('CONVERT_TEST_'))
3952 # Ensure that test_type has all of the desired names and values.
3953 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3954 test_type.CONVERT_TEST_NAME_A)
3955 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3956 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3957 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3958 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3959 # Ensure that test_type only picked up names matching the filter.
3960 self.assertEqual([name for name in dir(test_type)
3961 if name[0:2] not in ('CO', '__')],
3962 [], msg='Names other than CONVERT_TEST_* found.')
3963
Ethan Furman6bd92882021-04-27 13:05:08 -07003964 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003965 '_convert was deprecated in 3.8')
3966 def test_convert_warn(self):
3967 with self.assertWarns(DeprecationWarning):
3968 enum.IntEnum._convert(
3969 'UnittestConvert',
3970 ('test.test_enum', '__main__')[__name__=='__main__'],
3971 filter=lambda x: x.startswith('CONVERT_TEST_'))
3972
Ethan Furman6bd92882021-04-27 13:05:08 -07003973 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003974 '_convert was removed in 3.9')
3975 def test_convert_raise(self):
3976 with self.assertRaises(AttributeError):
3977 enum.IntEnum._convert(
3978 'UnittestConvert',
3979 ('test.test_enum', '__main__')[__name__=='__main__'],
3980 filter=lambda x: x.startswith('CONVERT_TEST_'))
3981
Ethan Furman6bd92882021-04-27 13:05:08 -07003982 @unittest.skipUnless(
3983 python_version < (3, 12),
3984 'mixin-format now uses member instead of member.value',
3985 )
Ethan Furmanb7751062021-03-30 21:17:26 -07003986 def test_convert_repr_and_str(self):
3987 module = ('test.test_enum', '__main__')[__name__=='__main__']
3988 test_type = enum.IntEnum._convert_(
3989 'UnittestConvert',
3990 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003991 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3992 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3993 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman6bd92882021-04-27 13:05:08 -07003994 with self.assertWarns(DeprecationWarning):
3995 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003996
3997# global names for StrEnum._convert_ test
3998CONVERT_STR_TEST_2 = 'goodbye'
3999CONVERT_STR_TEST_1 = 'hello'
4000
4001class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04004002 def setUp(self):
4003 global CONVERT_STR_TEST_1
4004 global CONVERT_STR_TEST_2
4005 CONVERT_STR_TEST_2 = 'goodbye'
4006 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07004007
4008 def test_convert(self):
4009 test_type = enum.StrEnum._convert_(
4010 'UnittestConvert',
4011 ('test.test_enum', '__main__')[__name__=='__main__'],
4012 filter=lambda x: x.startswith('CONVERT_STR_'))
4013 # Ensure that test_type has all of the desired names and values.
4014 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
4015 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
4016 # Ensure that test_type only picked up names matching the filter.
4017 self.assertEqual([name for name in dir(test_type)
4018 if name[0:2] not in ('CO', '__')],
4019 [], msg='Names other than CONVERT_STR_* found.')
4020
4021 def test_convert_repr_and_str(self):
4022 module = ('test.test_enum', '__main__')[__name__=='__main__']
4023 test_type = enum.StrEnum._convert_(
4024 'UnittestConvert',
4025 module,
4026 filter=lambda x: x.startswith('CONVERT_STR_'))
4027 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
4028 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
4029 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
4030
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004031
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004032if __name__ == '__main__':
4033 unittest.main()