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