blob: 0267ff5684c0d4de5a6396f4276f1f140d3401ef [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):
Ethan Furman1b4addf2021-06-18 14:25:42 -0700560 class Grades(int, Enum):
561 A = 5
562 B = 4
563 C = 3
564 D = 2
565 F = 0
566 self.assertEqual(f'{self.Grades.B}', 'B')
Ethan Furman6bd92882021-04-27 13:05:08 -0700567
568 @unittest.skipIf(
569 python_version >= (3, 12),
Ethan Furman5987b8c2021-04-26 22:42:57 -0700570 'mixin-format now uses member instead of member.value',
571 )
572 def test_mixin_format_warning(self):
Ethan Furman1b4addf2021-06-18 14:25:42 -0700573 class Grades(int, Enum):
574 A = 5
575 B = 4
576 C = 3
577 D = 2
578 F = 0
Ethan Furman5987b8c2021-04-26 22:42:57 -0700579 with self.assertWarns(DeprecationWarning):
Ethan Furman1b4addf2021-06-18 14:25:42 -0700580 self.assertEqual(f'{Grades.B}', '4')
Ethan Furman5987b8c2021-04-26 22:42:57 -0700581
Ethan Furmanec15a822013-08-31 19:17:41 -0700582 def assertFormatIsValue(self, spec, member):
Ethan Furman6bd92882021-04-27 13:05:08 -0700583 if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
584 with self.assertWarns(DeprecationWarning):
585 self.assertEqual(spec.format(member), spec.format(member.value))
586 else:
587 self.assertEqual(spec.format(member), spec.format(member.value))
Ethan Furmanec15a822013-08-31 19:17:41 -0700588
589 def test_format_enum_date(self):
590 Holiday = self.Holiday
591 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
592 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
593 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
594 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
595 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
596 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
597 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
598 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
599
600 def test_format_enum_float(self):
601 Konstants = self.Konstants
602 self.assertFormatIsValue('{}', Konstants.TAU)
603 self.assertFormatIsValue('{:}', Konstants.TAU)
604 self.assertFormatIsValue('{:20}', Konstants.TAU)
605 self.assertFormatIsValue('{:^20}', Konstants.TAU)
606 self.assertFormatIsValue('{:>20}', Konstants.TAU)
607 self.assertFormatIsValue('{:<20}', Konstants.TAU)
608 self.assertFormatIsValue('{:n}', Konstants.TAU)
609 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
610 self.assertFormatIsValue('{:f}', Konstants.TAU)
611
612 def test_format_enum_int(self):
Ethan Furman1b4addf2021-06-18 14:25:42 -0700613 class Grades(int, Enum):
614 A = 5
615 B = 4
616 C = 3
617 D = 2
618 F = 0
Ethan Furmanec15a822013-08-31 19:17:41 -0700619 self.assertFormatIsValue('{}', Grades.C)
620 self.assertFormatIsValue('{:}', Grades.C)
621 self.assertFormatIsValue('{:20}', Grades.C)
622 self.assertFormatIsValue('{:^20}', Grades.C)
623 self.assertFormatIsValue('{:>20}', Grades.C)
624 self.assertFormatIsValue('{:<20}', Grades.C)
625 self.assertFormatIsValue('{:+}', Grades.C)
626 self.assertFormatIsValue('{:08X}', Grades.C)
627 self.assertFormatIsValue('{:b}', Grades.C)
628
629 def test_format_enum_str(self):
630 Directional = self.Directional
631 self.assertFormatIsValue('{}', Directional.WEST)
632 self.assertFormatIsValue('{:}', Directional.WEST)
633 self.assertFormatIsValue('{:20}', Directional.WEST)
634 self.assertFormatIsValue('{:^20}', Directional.WEST)
635 self.assertFormatIsValue('{:>20}', Directional.WEST)
636 self.assertFormatIsValue('{:<20}', Directional.WEST)
637
Ethan Furman22415ad2020-09-15 16:28:25 -0700638 def test_object_str_override(self):
639 class Colors(Enum):
640 RED, GREEN, BLUE = 1, 2, 3
641 def __repr__(self):
642 return "test.%s" % (self._name_, )
643 __str__ = object.__str__
644 self.assertEqual(str(Colors.RED), 'test.RED')
645
Ethan Furmanbff01f32020-09-15 15:56:26 -0700646 def test_enum_str_override(self):
647 class MyStrEnum(Enum):
648 def __str__(self):
649 return 'MyStr'
650 class MyMethodEnum(Enum):
651 def hello(self):
652 return 'Hello! My name is %s' % self.name
653 class Test1Enum(MyMethodEnum, int, MyStrEnum):
654 One = 1
655 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800656 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700657 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800658 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700659 #
660 class Test2Enum(MyStrEnum, MyMethodEnum):
661 One = 1
662 Two = 2
663 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800664 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700665
666 def test_inherited_data_type(self):
667 class HexInt(int):
668 def __repr__(self):
669 return hex(self)
670 class MyEnum(HexInt, enum.Enum):
671 A = 1
672 B = 2
673 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700674 def __repr__(self):
675 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700676 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700677 #
678 class SillyInt(HexInt):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700679 __qualname__ = 'SillyInt'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700680 pass
681 class MyOtherEnum(SillyInt, enum.Enum):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700682 __qualname__ = 'MyOtherEnum'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700683 D = 4
684 E = 5
685 F = 6
686 self.assertIs(MyOtherEnum._member_type_, SillyInt)
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700687 globals()['SillyInt'] = SillyInt
688 globals()['MyOtherEnum'] = MyOtherEnum
689 test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
690 test_pickle_dump_load(self.assertIs, MyOtherEnum)
691 #
692 # This did not work in 3.9, but does now with pickling by name
693 class UnBrokenInt(int):
694 __qualname__ = 'UnBrokenInt'
695 def __new__(cls, value):
696 return int.__new__(cls, value)
697 class MyUnBrokenEnum(UnBrokenInt, Enum):
698 __qualname__ = 'MyUnBrokenEnum'
699 G = 7
700 H = 8
701 I = 9
702 self.assertIs(MyUnBrokenEnum._member_type_, UnBrokenInt)
703 self.assertIs(MyUnBrokenEnum(7), MyUnBrokenEnum.G)
704 globals()['UnBrokenInt'] = UnBrokenInt
705 globals()['MyUnBrokenEnum'] = MyUnBrokenEnum
706 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
707 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700708
709 def test_too_many_data_types(self):
710 with self.assertRaisesRegex(TypeError, 'too many data types'):
711 class Huh(str, int, Enum):
712 One = 1
713
714 class MyStr(str):
715 def hello(self):
716 return 'hello, %s' % self
717 class MyInt(int):
718 def repr(self):
719 return hex(self)
720 with self.assertRaisesRegex(TypeError, 'too many data types'):
721 class Huh(MyStr, MyInt, Enum):
722 One = 1
723
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700724 def test_hash(self):
725 Season = self.Season
726 dates = {}
727 dates[Season.WINTER] = '1225'
728 dates[Season.SPRING] = '0315'
729 dates[Season.SUMMER] = '0704'
730 dates[Season.AUTUMN] = '1031'
731 self.assertEqual(dates[Season.AUTUMN], '1031')
732
733 def test_intenum_from_scratch(self):
734 class phy(int, Enum):
735 pi = 3
736 tau = 2 * pi
737 self.assertTrue(phy.pi < phy.tau)
738
739 def test_intenum_inherited(self):
740 class IntEnum(int, Enum):
741 pass
742 class phy(IntEnum):
743 pi = 3
744 tau = 2 * pi
745 self.assertTrue(phy.pi < phy.tau)
746
747 def test_floatenum_from_scratch(self):
748 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700749 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750 tau = 2 * pi
751 self.assertTrue(phy.pi < phy.tau)
752
753 def test_floatenum_inherited(self):
754 class FloatEnum(float, Enum):
755 pass
756 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700757 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700758 tau = 2 * pi
759 self.assertTrue(phy.pi < phy.tau)
760
761 def test_strenum_from_scratch(self):
762 class phy(str, Enum):
763 pi = 'Pi'
764 tau = 'Tau'
765 self.assertTrue(phy.pi < phy.tau)
766
Ethan Furman0063ff42020-09-21 17:23:13 -0700767 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700768 class phy(StrEnum):
769 pi = 'Pi'
770 tau = 'Tau'
771 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700772 self.assertEqual(phy.pi.upper(), 'PI')
773 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700774
775 def test_intenum(self):
776 class WeekDay(IntEnum):
777 SUNDAY = 1
778 MONDAY = 2
779 TUESDAY = 3
780 WEDNESDAY = 4
781 THURSDAY = 5
782 FRIDAY = 6
783 SATURDAY = 7
784
785 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
786 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
787
788 lst = list(WeekDay)
789 self.assertEqual(len(lst), len(WeekDay))
790 self.assertEqual(len(WeekDay), 7)
791 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
792 target = target.split()
793 for i, weekday in enumerate(target, 1):
794 e = WeekDay(i)
795 self.assertEqual(e, i)
796 self.assertEqual(int(e), i)
797 self.assertEqual(e.name, weekday)
798 self.assertIn(e, WeekDay)
799 self.assertEqual(lst.index(e)+1, i)
800 self.assertTrue(0 < e < 8)
801 self.assertIs(type(e), WeekDay)
802 self.assertIsInstance(e, int)
803 self.assertIsInstance(e, Enum)
804
805 def test_intenum_duplicates(self):
806 class WeekDay(IntEnum):
807 SUNDAY = 1
808 MONDAY = 2
809 TUESDAY = TEUSDAY = 3
810 WEDNESDAY = 4
811 THURSDAY = 5
812 FRIDAY = 6
813 SATURDAY = 7
814 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
815 self.assertEqual(WeekDay(3).name, 'TUESDAY')
816 self.assertEqual([k for k,v in WeekDay.__members__.items()
817 if v.name != k], ['TEUSDAY', ])
818
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300819 def test_intenum_from_bytes(self):
820 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
821 with self.assertRaises(ValueError):
822 IntStooges.from_bytes(b'\x00\x05', 'big')
823
824 def test_floatenum_fromhex(self):
825 h = float.hex(FloatStooges.MOE.value)
826 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
827 h = float.hex(FloatStooges.MOE.value + 0.01)
828 with self.assertRaises(ValueError):
829 FloatStooges.fromhex(h)
830
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700831 def test_pickle_enum(self):
832 if isinstance(Stooges, Exception):
833 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800834 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
835 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700836
837 def test_pickle_int(self):
838 if isinstance(IntStooges, Exception):
839 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800840 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
841 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700842
843 def test_pickle_float(self):
844 if isinstance(FloatStooges, Exception):
845 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800846 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
847 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700848
849 def test_pickle_enum_function(self):
850 if isinstance(Answer, Exception):
851 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800852 test_pickle_dump_load(self.assertIs, Answer.him)
853 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700854
855 def test_pickle_enum_function_with_module(self):
856 if isinstance(Question, Exception):
857 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800858 test_pickle_dump_load(self.assertIs, Question.who)
859 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700860
Ethan Furmanca1b7942014-02-08 11:36:27 -0800861 def test_enum_function_with_qualname(self):
862 if isinstance(Theory, Exception):
863 raise Theory
864 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
865
866 def test_class_nested_enum_and_pickle_protocol_four(self):
867 # would normally just have this directly in the class namespace
868 class NestedEnum(Enum):
869 twigs = 'common'
870 shiny = 'rare'
871
872 self.__class__.NestedEnum = NestedEnum
873 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300874 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800875
Ethan Furman24e837f2015-03-18 17:27:57 -0700876 def test_pickle_by_name(self):
877 class ReplaceGlobalInt(IntEnum):
878 ONE = 1
879 TWO = 2
Miss Islington (bot)b6131322021-06-10 16:37:27 -0700880 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700881 for proto in range(HIGHEST_PROTOCOL):
882 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
883
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700884 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800885 BadPickle = Enum(
886 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700887 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800888 # now break BadPickle to test exception raising
889 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800890 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
891 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700892
893 def test_string_enum(self):
894 class SkillLevel(str, Enum):
895 master = 'what is the sound of one hand clapping?'
896 journeyman = 'why did the chicken cross the road?'
897 apprentice = 'knock, knock!'
898 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
899
900 def test_getattr_getitem(self):
901 class Period(Enum):
902 morning = 1
903 noon = 2
904 evening = 3
905 night = 4
906 self.assertIs(Period(2), Period.noon)
907 self.assertIs(getattr(Period, 'night'), Period.night)
908 self.assertIs(Period['morning'], Period.morning)
909
910 def test_getattr_dunder(self):
911 Season = self.Season
912 self.assertTrue(getattr(Season, '__eq__'))
913
914 def test_iteration_order(self):
915 class Season(Enum):
916 SUMMER = 2
917 WINTER = 4
918 AUTUMN = 3
919 SPRING = 1
920 self.assertEqual(
921 list(Season),
922 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
923 )
924
Ethan Furman2131a4a2013-09-14 18:11:24 -0700925 def test_reversed_iteration_order(self):
926 self.assertEqual(
927 list(reversed(self.Season)),
928 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
929 self.Season.SPRING]
930 )
931
Martin Pantereb995702016-07-28 01:11:04 +0000932 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700933 SummerMonth = Enum('SummerMonth', 'june july august')
934 lst = list(SummerMonth)
935 self.assertEqual(len(lst), len(SummerMonth))
936 self.assertEqual(len(SummerMonth), 3, SummerMonth)
937 self.assertEqual(
938 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
939 lst,
940 )
941 for i, month in enumerate('june july august'.split(), 1):
942 e = SummerMonth(i)
943 self.assertEqual(int(e.value), i)
944 self.assertNotEqual(e, i)
945 self.assertEqual(e.name, month)
946 self.assertIn(e, SummerMonth)
947 self.assertIs(type(e), SummerMonth)
948
Martin Pantereb995702016-07-28 01:11:04 +0000949 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700950 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
951 lst = list(SummerMonth)
952 self.assertEqual(len(lst), len(SummerMonth))
953 self.assertEqual(len(SummerMonth), 3, SummerMonth)
954 self.assertEqual(
955 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
956 lst,
957 )
958 for i, month in enumerate('june july august'.split(), 10):
959 e = SummerMonth(i)
960 self.assertEqual(int(e.value), i)
961 self.assertNotEqual(e, i)
962 self.assertEqual(e.name, month)
963 self.assertIn(e, SummerMonth)
964 self.assertIs(type(e), SummerMonth)
965
Martin Pantereb995702016-07-28 01:11:04 +0000966 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700967 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
968 lst = list(SummerMonth)
969 self.assertEqual(len(lst), len(SummerMonth))
970 self.assertEqual(len(SummerMonth), 3, SummerMonth)
971 self.assertEqual(
972 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
973 lst,
974 )
975 for i, month in enumerate('june july august'.split(), 1):
976 e = SummerMonth(i)
977 self.assertEqual(int(e.value), i)
978 self.assertNotEqual(e, i)
979 self.assertEqual(e.name, month)
980 self.assertIn(e, SummerMonth)
981 self.assertIs(type(e), SummerMonth)
982
Martin Pantereb995702016-07-28 01:11:04 +0000983 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700984 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
985 lst = list(SummerMonth)
986 self.assertEqual(len(lst), len(SummerMonth))
987 self.assertEqual(len(SummerMonth), 3, SummerMonth)
988 self.assertEqual(
989 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
990 lst,
991 )
992 for i, month in enumerate('june july august'.split(), 20):
993 e = SummerMonth(i)
994 self.assertEqual(int(e.value), i)
995 self.assertNotEqual(e, i)
996 self.assertEqual(e.name, month)
997 self.assertIn(e, SummerMonth)
998 self.assertIs(type(e), SummerMonth)
999
Martin Pantereb995702016-07-28 01:11:04 +00001000 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001001 SummerMonth = Enum(
1002 'SummerMonth',
1003 (('june', 1), ('july', 2), ('august', 3))
1004 )
1005 lst = list(SummerMonth)
1006 self.assertEqual(len(lst), len(SummerMonth))
1007 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1008 self.assertEqual(
1009 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1010 lst,
1011 )
1012 for i, month in enumerate('june july august'.split(), 1):
1013 e = SummerMonth(i)
1014 self.assertEqual(int(e.value), i)
1015 self.assertNotEqual(e, i)
1016 self.assertEqual(e.name, month)
1017 self.assertIn(e, SummerMonth)
1018 self.assertIs(type(e), SummerMonth)
1019
Martin Pantereb995702016-07-28 01:11:04 +00001020 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001021 SummerMonth = Enum(
1022 'SummerMonth',
1023 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
1024 )
1025 lst = list(SummerMonth)
1026 self.assertEqual(len(lst), len(SummerMonth))
1027 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1028 self.assertEqual(
1029 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1030 lst,
1031 )
1032 for i, month in enumerate('june july august'.split(), 1):
1033 e = SummerMonth(i)
1034 self.assertEqual(int(e.value), i)
1035 self.assertNotEqual(e, i)
1036 self.assertEqual(e.name, month)
1037 self.assertIn(e, SummerMonth)
1038 self.assertIs(type(e), SummerMonth)
1039
Martin Pantereb995702016-07-28 01:11:04 +00001040 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001041 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
1042 lst = list(SummerMonth)
1043 self.assertEqual(len(lst), len(SummerMonth))
1044 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1045 self.assertEqual(
1046 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1047 lst,
1048 )
1049 for i, month in enumerate('june july august'.split(), 1):
1050 e = SummerMonth(i)
1051 self.assertEqual(e, i)
1052 self.assertEqual(e.name, month)
1053 self.assertIn(e, SummerMonth)
1054 self.assertIs(type(e), SummerMonth)
1055
Martin Pantereb995702016-07-28 01:11:04 +00001056 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001057 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1058 lst = list(SummerMonth)
1059 self.assertEqual(len(lst), len(SummerMonth))
1060 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1061 self.assertEqual(
1062 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1063 lst,
1064 )
1065 for i, month in enumerate('june july august'.split(), 30):
1066 e = SummerMonth(i)
1067 self.assertEqual(e, i)
1068 self.assertEqual(e.name, month)
1069 self.assertIn(e, SummerMonth)
1070 self.assertIs(type(e), SummerMonth)
1071
Martin Pantereb995702016-07-28 01:11:04 +00001072 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001073 SummerMonth = IntEnum('SummerMonth', 'june july august')
1074 lst = list(SummerMonth)
1075 self.assertEqual(len(lst), len(SummerMonth))
1076 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1077 self.assertEqual(
1078 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1079 lst,
1080 )
1081 for i, month in enumerate('june july august'.split(), 1):
1082 e = SummerMonth(i)
1083 self.assertEqual(e, i)
1084 self.assertEqual(e.name, month)
1085 self.assertIn(e, SummerMonth)
1086 self.assertIs(type(e), SummerMonth)
1087
Martin Pantereb995702016-07-28 01:11:04 +00001088 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001089 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1090 lst = list(SummerMonth)
1091 self.assertEqual(len(lst), len(SummerMonth))
1092 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1093 self.assertEqual(
1094 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1095 lst,
1096 )
1097 for i, month in enumerate('june july august'.split(), 40):
1098 e = SummerMonth(i)
1099 self.assertEqual(e, i)
1100 self.assertEqual(e.name, month)
1101 self.assertIn(e, SummerMonth)
1102 self.assertIs(type(e), SummerMonth)
1103
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001104 def test_subclassing(self):
1105 if isinstance(Name, Exception):
1106 raise Name
1107 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1108 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1109 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001110 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001111
1112 def test_extending(self):
1113 class Color(Enum):
1114 red = 1
1115 green = 2
1116 blue = 3
1117 with self.assertRaises(TypeError):
1118 class MoreColor(Color):
1119 cyan = 4
1120 magenta = 5
1121 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001122 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1123 class EvenMoreColor(Color, IntEnum):
1124 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001125
1126 def test_exclude_methods(self):
1127 class whatever(Enum):
1128 this = 'that'
1129 these = 'those'
1130 def really(self):
1131 return 'no, not %s' % self.value
1132 self.assertIsNot(type(whatever.really), whatever)
1133 self.assertEqual(whatever.this.really(), 'no, not that')
1134
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001135 def test_wrong_inheritance_order(self):
1136 with self.assertRaises(TypeError):
1137 class Wrong(Enum, str):
1138 NotHere = 'error before this point'
1139
1140 def test_intenum_transitivity(self):
1141 class number(IntEnum):
1142 one = 1
1143 two = 2
1144 three = 3
1145 class numero(IntEnum):
1146 uno = 1
1147 dos = 2
1148 tres = 3
1149 self.assertEqual(number.one, numero.uno)
1150 self.assertEqual(number.two, numero.dos)
1151 self.assertEqual(number.three, numero.tres)
1152
1153 def test_wrong_enum_in_call(self):
1154 class Monochrome(Enum):
1155 black = 0
1156 white = 1
1157 class Gender(Enum):
1158 male = 0
1159 female = 1
1160 self.assertRaises(ValueError, Monochrome, Gender.male)
1161
1162 def test_wrong_enum_in_mixed_call(self):
1163 class Monochrome(IntEnum):
1164 black = 0
1165 white = 1
1166 class Gender(Enum):
1167 male = 0
1168 female = 1
1169 self.assertRaises(ValueError, Monochrome, Gender.male)
1170
1171 def test_mixed_enum_in_call_1(self):
1172 class Monochrome(IntEnum):
1173 black = 0
1174 white = 1
1175 class Gender(IntEnum):
1176 male = 0
1177 female = 1
1178 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1179
1180 def test_mixed_enum_in_call_2(self):
1181 class Monochrome(Enum):
1182 black = 0
1183 white = 1
1184 class Gender(IntEnum):
1185 male = 0
1186 female = 1
1187 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1188
1189 def test_flufl_enum(self):
1190 class Fluflnum(Enum):
1191 def __int__(self):
1192 return int(self.value)
1193 class MailManOptions(Fluflnum):
1194 option1 = 1
1195 option2 = 2
1196 option3 = 3
1197 self.assertEqual(int(MailManOptions.option1), 1)
1198
Ethan Furman5e5a8232013-08-04 08:42:23 -07001199 def test_introspection(self):
1200 class Number(IntEnum):
1201 one = 100
1202 two = 200
1203 self.assertIs(Number.one._member_type_, int)
1204 self.assertIs(Number._member_type_, int)
1205 class String(str, Enum):
1206 yarn = 'soft'
1207 rope = 'rough'
1208 wire = 'hard'
1209 self.assertIs(String.yarn._member_type_, str)
1210 self.assertIs(String._member_type_, str)
1211 class Plain(Enum):
1212 vanilla = 'white'
1213 one = 1
1214 self.assertIs(Plain.vanilla._member_type_, object)
1215 self.assertIs(Plain._member_type_, object)
1216
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001217 def test_no_such_enum_member(self):
1218 class Color(Enum):
1219 red = 1
1220 green = 2
1221 blue = 3
1222 with self.assertRaises(ValueError):
1223 Color(4)
1224 with self.assertRaises(KeyError):
1225 Color['chartreuse']
1226
1227 def test_new_repr(self):
1228 class Color(Enum):
1229 red = 1
1230 green = 2
1231 blue = 3
1232 def __repr__(self):
1233 return "don't you just love shades of %s?" % self.name
1234 self.assertEqual(
1235 repr(Color.blue),
1236 "don't you just love shades of blue?",
1237 )
1238
1239 def test_inherited_repr(self):
1240 class MyEnum(Enum):
1241 def __repr__(self):
1242 return "My name is %s." % self.name
1243 class MyIntEnum(int, MyEnum):
1244 this = 1
1245 that = 2
1246 theother = 3
1247 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1248
1249 def test_multiple_mixin_mro(self):
1250 class auto_enum(type(Enum)):
1251 def __new__(metacls, cls, bases, classdict):
1252 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001253 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001254 names = set(classdict._member_names)
1255 i = 0
1256 for k in classdict._member_names:
1257 v = classdict[k]
1258 if v is Ellipsis:
1259 v = i
1260 else:
1261 i = v
1262 i += 1
1263 temp[k] = v
1264 for k, v in classdict.items():
1265 if k not in names:
1266 temp[k] = v
1267 return super(auto_enum, metacls).__new__(
1268 metacls, cls, bases, temp)
1269
1270 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1271 pass
1272
1273 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1274 pass
1275
1276 class TestAutoNumber(AutoNumberedEnum):
1277 a = ...
1278 b = 3
1279 c = ...
1280
1281 class TestAutoInt(AutoIntEnum):
1282 a = ...
1283 b = 3
1284 c = ...
1285
1286 def test_subclasses_with_getnewargs(self):
1287 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001288 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001289 def __new__(cls, *args):
1290 _args = args
1291 name, *args = args
1292 if len(args) == 0:
1293 raise TypeError("name and value must be specified")
1294 self = int.__new__(cls, *args)
1295 self._intname = name
1296 self._args = _args
1297 return self
1298 def __getnewargs__(self):
1299 return self._args
1300 @property
1301 def __name__(self):
1302 return self._intname
1303 def __repr__(self):
1304 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001305 return "{}({!r}, {})".format(
1306 type(self).__name__,
1307 self.__name__,
1308 int.__repr__(self),
1309 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001310 def __str__(self):
1311 # str() is unchanged, even if it relies on the repr() fallback
1312 base = int
1313 base_str = base.__str__
1314 if base_str.__objclass__ is object:
1315 return base.__repr__(self)
1316 return base_str(self)
1317 # for simplicity, we only define one operator that
1318 # propagates expressions
1319 def __add__(self, other):
1320 temp = int(self) + int( other)
1321 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1322 return NamedInt(
1323 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001324 temp,
1325 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001326 else:
1327 return temp
1328
1329 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001330 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001331 x = ('the-x', 1)
1332 y = ('the-y', 2)
1333
Ethan Furman2aa27322013-07-19 19:35:56 -07001334
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001335 self.assertIs(NEI.__new__, Enum.__new__)
1336 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1337 globals()['NamedInt'] = NamedInt
1338 globals()['NEI'] = NEI
1339 NI5 = NamedInt('test', 5)
1340 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001341 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001342 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001343 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001344 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001345
Ethan Furmanca1b7942014-02-08 11:36:27 -08001346 def test_subclasses_with_getnewargs_ex(self):
1347 class NamedInt(int):
1348 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1349 def __new__(cls, *args):
1350 _args = args
1351 name, *args = args
1352 if len(args) == 0:
1353 raise TypeError("name and value must be specified")
1354 self = int.__new__(cls, *args)
1355 self._intname = name
1356 self._args = _args
1357 return self
1358 def __getnewargs_ex__(self):
1359 return self._args, {}
1360 @property
1361 def __name__(self):
1362 return self._intname
1363 def __repr__(self):
1364 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001365 return "{}({!r}, {})".format(
1366 type(self).__name__,
1367 self.__name__,
1368 int.__repr__(self),
1369 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001370 def __str__(self):
1371 # str() is unchanged, even if it relies on the repr() fallback
1372 base = int
1373 base_str = base.__str__
1374 if base_str.__objclass__ is object:
1375 return base.__repr__(self)
1376 return base_str(self)
1377 # for simplicity, we only define one operator that
1378 # propagates expressions
1379 def __add__(self, other):
1380 temp = int(self) + int( other)
1381 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1382 return NamedInt(
1383 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001384 temp,
1385 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001386 else:
1387 return temp
1388
1389 class NEI(NamedInt, Enum):
1390 __qualname__ = 'NEI' # needed for pickle protocol 4
1391 x = ('the-x', 1)
1392 y = ('the-y', 2)
1393
1394
1395 self.assertIs(NEI.__new__, Enum.__new__)
1396 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1397 globals()['NamedInt'] = NamedInt
1398 globals()['NEI'] = NEI
1399 NI5 = NamedInt('test', 5)
1400 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001401 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001402 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001403 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001404 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001405
1406 def test_subclasses_with_reduce(self):
1407 class NamedInt(int):
1408 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1409 def __new__(cls, *args):
1410 _args = args
1411 name, *args = args
1412 if len(args) == 0:
1413 raise TypeError("name and value must be specified")
1414 self = int.__new__(cls, *args)
1415 self._intname = name
1416 self._args = _args
1417 return self
1418 def __reduce__(self):
1419 return self.__class__, self._args
1420 @property
1421 def __name__(self):
1422 return self._intname
1423 def __repr__(self):
1424 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001425 return "{}({!r}, {})".format(
1426 type(self).__name__,
1427 self.__name__,
1428 int.__repr__(self),
1429 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001430 def __str__(self):
1431 # str() is unchanged, even if it relies on the repr() fallback
1432 base = int
1433 base_str = base.__str__
1434 if base_str.__objclass__ is object:
1435 return base.__repr__(self)
1436 return base_str(self)
1437 # for simplicity, we only define one operator that
1438 # propagates expressions
1439 def __add__(self, other):
1440 temp = int(self) + int( other)
1441 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1442 return NamedInt(
1443 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001444 temp,
1445 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001446 else:
1447 return temp
1448
1449 class NEI(NamedInt, Enum):
1450 __qualname__ = 'NEI' # needed for pickle protocol 4
1451 x = ('the-x', 1)
1452 y = ('the-y', 2)
1453
1454
1455 self.assertIs(NEI.__new__, Enum.__new__)
1456 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1457 globals()['NamedInt'] = NamedInt
1458 globals()['NEI'] = NEI
1459 NI5 = NamedInt('test', 5)
1460 self.assertEqual(NI5, 5)
1461 test_pickle_dump_load(self.assertEqual, NI5, 5)
1462 self.assertEqual(NEI.y.value, 2)
1463 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001464 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001465
1466 def test_subclasses_with_reduce_ex(self):
1467 class NamedInt(int):
1468 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1469 def __new__(cls, *args):
1470 _args = args
1471 name, *args = args
1472 if len(args) == 0:
1473 raise TypeError("name and value must be specified")
1474 self = int.__new__(cls, *args)
1475 self._intname = name
1476 self._args = _args
1477 return self
1478 def __reduce_ex__(self, proto):
1479 return self.__class__, self._args
1480 @property
1481 def __name__(self):
1482 return self._intname
1483 def __repr__(self):
1484 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001485 return "{}({!r}, {})".format(
1486 type(self).__name__,
1487 self.__name__,
1488 int.__repr__(self),
1489 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001490 def __str__(self):
1491 # str() is unchanged, even if it relies on the repr() fallback
1492 base = int
1493 base_str = base.__str__
1494 if base_str.__objclass__ is object:
1495 return base.__repr__(self)
1496 return base_str(self)
1497 # for simplicity, we only define one operator that
1498 # propagates expressions
1499 def __add__(self, other):
1500 temp = int(self) + int( other)
1501 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1502 return NamedInt(
1503 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001504 temp,
1505 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001506 else:
1507 return temp
1508
1509 class NEI(NamedInt, Enum):
1510 __qualname__ = 'NEI' # needed for pickle protocol 4
1511 x = ('the-x', 1)
1512 y = ('the-y', 2)
1513
Ethan Furmanca1b7942014-02-08 11:36:27 -08001514 self.assertIs(NEI.__new__, Enum.__new__)
1515 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1516 globals()['NamedInt'] = NamedInt
1517 globals()['NEI'] = NEI
1518 NI5 = NamedInt('test', 5)
1519 self.assertEqual(NI5, 5)
1520 test_pickle_dump_load(self.assertEqual, NI5, 5)
1521 self.assertEqual(NEI.y.value, 2)
1522 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001523 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001524
Ethan Furmandc870522014-02-18 12:37:12 -08001525 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001526 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001527 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001528 def __new__(cls, *args):
1529 _args = args
1530 name, *args = args
1531 if len(args) == 0:
1532 raise TypeError("name and value must be specified")
1533 self = int.__new__(cls, *args)
1534 self._intname = name
1535 self._args = _args
1536 return self
1537 @property
1538 def __name__(self):
1539 return self._intname
1540 def __repr__(self):
1541 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001542 return "{}({!r}, {})".format(
1543 type(self).__name__,
1544 self.__name__,
1545 int.__repr__(self),
1546 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 def __str__(self):
1548 # str() is unchanged, even if it relies on the repr() fallback
1549 base = int
1550 base_str = base.__str__
1551 if base_str.__objclass__ is object:
1552 return base.__repr__(self)
1553 return base_str(self)
1554 # for simplicity, we only define one operator that
1555 # propagates expressions
1556 def __add__(self, other):
1557 temp = int(self) + int( other)
1558 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1559 return NamedInt(
1560 '({0} + {1})'.format(self.__name__, other.__name__),
1561 temp )
1562 else:
1563 return temp
1564
1565 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001566 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001567 x = ('the-x', 1)
1568 y = ('the-y', 2)
1569
1570 self.assertIs(NEI.__new__, Enum.__new__)
1571 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1572 globals()['NamedInt'] = NamedInt
1573 globals()['NEI'] = NEI
1574 NI5 = NamedInt('test', 5)
1575 self.assertEqual(NI5, 5)
1576 self.assertEqual(NEI.y.value, 2)
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001577 test_pickle_dump_load(self.assertIs, NEI.y)
1578 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001579
Miss Islington (bot)b6131322021-06-10 16:37:27 -07001580 def test_subclasses_with_direct_pickle_support(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001581 class NamedInt(int):
1582 __qualname__ = 'NamedInt'
1583 def __new__(cls, *args):
1584 _args = args
1585 name, *args = args
1586 if len(args) == 0:
1587 raise TypeError("name and value must be specified")
1588 self = int.__new__(cls, *args)
1589 self._intname = name
1590 self._args = _args
1591 return self
1592 @property
1593 def __name__(self):
1594 return self._intname
1595 def __repr__(self):
1596 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001597 return "{}({!r}, {})".format(
1598 type(self).__name__,
1599 self.__name__,
1600 int.__repr__(self),
1601 )
Ethan Furmandc870522014-02-18 12:37:12 -08001602 def __str__(self):
1603 # str() is unchanged, even if it relies on the repr() fallback
1604 base = int
1605 base_str = base.__str__
1606 if base_str.__objclass__ is object:
1607 return base.__repr__(self)
1608 return base_str(self)
1609 # for simplicity, we only define one operator that
1610 # propagates expressions
1611 def __add__(self, other):
1612 temp = int(self) + int( other)
1613 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1614 return NamedInt(
1615 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001616 temp,
1617 )
Ethan Furmandc870522014-02-18 12:37:12 -08001618 else:
1619 return temp
1620
1621 class NEI(NamedInt, Enum):
1622 __qualname__ = 'NEI'
1623 x = ('the-x', 1)
1624 y = ('the-y', 2)
1625 def __reduce_ex__(self, proto):
1626 return getattr, (self.__class__, self._name_)
1627
1628 self.assertIs(NEI.__new__, Enum.__new__)
1629 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1630 globals()['NamedInt'] = NamedInt
1631 globals()['NEI'] = NEI
1632 NI5 = NamedInt('test', 5)
1633 self.assertEqual(NI5, 5)
1634 self.assertEqual(NEI.y.value, 2)
1635 test_pickle_dump_load(self.assertIs, NEI.y)
1636 test_pickle_dump_load(self.assertIs, NEI)
1637
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001638 def test_tuple_subclass(self):
1639 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001640 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001641 first = (1, 'for the money')
1642 second = (2, 'for the show')
1643 third = (3, 'for the music')
1644 self.assertIs(type(SomeTuple.first), SomeTuple)
1645 self.assertIsInstance(SomeTuple.second, tuple)
1646 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1647 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001648 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001649
1650 def test_duplicate_values_give_unique_enum_items(self):
1651 class AutoNumber(Enum):
1652 first = ()
1653 second = ()
1654 third = ()
1655 def __new__(cls):
1656 value = len(cls.__members__) + 1
1657 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001658 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001659 return obj
1660 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001661 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001662 self.assertEqual(
1663 list(AutoNumber),
1664 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1665 )
1666 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001667 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001668 self.assertIs(AutoNumber(1), AutoNumber.first)
1669
1670 def test_inherited_new_from_enhanced_enum(self):
1671 class AutoNumber(Enum):
1672 def __new__(cls):
1673 value = len(cls.__members__) + 1
1674 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001675 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001676 return obj
1677 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001678 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001679 class Color(AutoNumber):
1680 red = ()
1681 green = ()
1682 blue = ()
1683 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1684 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1685
1686 def test_inherited_new_from_mixed_enum(self):
1687 class AutoNumber(IntEnum):
1688 def __new__(cls):
1689 value = len(cls.__members__) + 1
1690 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001691 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001692 return obj
1693 class Color(AutoNumber):
1694 red = ()
1695 green = ()
1696 blue = ()
1697 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1698 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1699
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001700 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001701 class OrdinaryEnum(Enum):
1702 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001703 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1704 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001705
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001706 def test_ordered_mixin(self):
1707 class OrderedEnum(Enum):
1708 def __ge__(self, other):
1709 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001710 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001711 return NotImplemented
1712 def __gt__(self, other):
1713 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001714 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001715 return NotImplemented
1716 def __le__(self, other):
1717 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001718 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001719 return NotImplemented
1720 def __lt__(self, other):
1721 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001722 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001723 return NotImplemented
1724 class Grade(OrderedEnum):
1725 A = 5
1726 B = 4
1727 C = 3
1728 D = 2
1729 F = 1
1730 self.assertGreater(Grade.A, Grade.B)
1731 self.assertLessEqual(Grade.F, Grade.C)
1732 self.assertLess(Grade.D, Grade.A)
1733 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001734 self.assertEqual(Grade.B, Grade.B)
1735 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001736
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001737 def test_extending2(self):
1738 class Shade(Enum):
1739 def shade(self):
1740 print(self.name)
1741 class Color(Shade):
1742 red = 1
1743 green = 2
1744 blue = 3
1745 with self.assertRaises(TypeError):
1746 class MoreColor(Color):
1747 cyan = 4
1748 magenta = 5
1749 yellow = 6
1750
1751 def test_extending3(self):
1752 class Shade(Enum):
1753 def shade(self):
1754 return self.name
1755 class Color(Shade):
1756 def hex(self):
1757 return '%s hexlified!' % self.value
1758 class MoreColor(Color):
1759 cyan = 4
1760 magenta = 5
1761 yellow = 6
1762 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1763
orlnub1230fb9fad2018-09-12 20:28:53 +03001764 def test_subclass_duplicate_name(self):
1765 class Base(Enum):
1766 def test(self):
1767 pass
1768 class Test(Base):
1769 test = 1
1770 self.assertIs(type(Test.test), Test)
1771
1772 def test_subclass_duplicate_name_dynamic(self):
1773 from types import DynamicClassAttribute
1774 class Base(Enum):
1775 @DynamicClassAttribute
1776 def test(self):
1777 return 'dynamic'
1778 class Test(Base):
1779 test = 1
1780 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001781 class Base2(Enum):
1782 @enum.property
1783 def flash(self):
1784 return 'flashy dynamic'
1785 class Test(Base2):
1786 flash = 1
1787 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001788
1789 def test_no_duplicates(self):
1790 class UniqueEnum(Enum):
1791 def __init__(self, *args):
1792 cls = self.__class__
1793 if any(self.value == e.value for e in cls):
1794 a = self.name
1795 e = cls(self.value).name
1796 raise ValueError(
1797 "aliases not allowed in UniqueEnum: %r --> %r"
1798 % (a, e)
1799 )
1800 class Color(UniqueEnum):
1801 red = 1
1802 green = 2
1803 blue = 3
1804 with self.assertRaises(ValueError):
1805 class Color(UniqueEnum):
1806 red = 1
1807 green = 2
1808 blue = 3
1809 grene = 2
1810
1811 def test_init(self):
1812 class Planet(Enum):
1813 MERCURY = (3.303e+23, 2.4397e6)
1814 VENUS = (4.869e+24, 6.0518e6)
1815 EARTH = (5.976e+24, 6.37814e6)
1816 MARS = (6.421e+23, 3.3972e6)
1817 JUPITER = (1.9e+27, 7.1492e7)
1818 SATURN = (5.688e+26, 6.0268e7)
1819 URANUS = (8.686e+25, 2.5559e7)
1820 NEPTUNE = (1.024e+26, 2.4746e7)
1821 def __init__(self, mass, radius):
1822 self.mass = mass # in kilograms
1823 self.radius = radius # in meters
1824 @property
1825 def surface_gravity(self):
1826 # universal gravitational constant (m3 kg-1 s-2)
1827 G = 6.67300E-11
1828 return G * self.mass / (self.radius * self.radius)
1829 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1830 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1831
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001832 def test_ignore(self):
1833 class Period(timedelta, Enum):
1834 '''
1835 different lengths of time
1836 '''
1837 def __new__(cls, value, period):
1838 obj = timedelta.__new__(cls, value)
1839 obj._value_ = value
1840 obj.period = period
1841 return obj
1842 _ignore_ = 'Period i'
1843 Period = vars()
1844 for i in range(13):
1845 Period['month_%d' % i] = i*30, 'month'
1846 for i in range(53):
1847 Period['week_%d' % i] = i*7, 'week'
1848 for i in range(32):
1849 Period['day_%d' % i] = i, 'day'
1850 OneDay = day_1
1851 OneWeek = week_1
1852 OneMonth = month_1
1853 self.assertFalse(hasattr(Period, '_ignore_'))
1854 self.assertFalse(hasattr(Period, 'Period'))
1855 self.assertFalse(hasattr(Period, 'i'))
1856 self.assertTrue(isinstance(Period.day_1, timedelta))
1857 self.assertTrue(Period.month_1 is Period.day_30)
1858 self.assertTrue(Period.week_4 is Period.day_28)
1859
Ethan Furman2aa27322013-07-19 19:35:56 -07001860 def test_nonhash_value(self):
1861 class AutoNumberInAList(Enum):
1862 def __new__(cls):
1863 value = [len(cls.__members__) + 1]
1864 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001865 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001866 return obj
1867 class ColorInAList(AutoNumberInAList):
1868 red = ()
1869 green = ()
1870 blue = ()
1871 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001872 for enum, value in zip(ColorInAList, range(3)):
1873 value += 1
1874 self.assertEqual(enum.value, [value])
1875 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001876
Ethan Furmanb41803e2013-07-25 13:50:45 -07001877 def test_conflicting_types_resolved_in_new(self):
1878 class LabelledIntEnum(int, Enum):
1879 def __new__(cls, *args):
1880 value, label = args
1881 obj = int.__new__(cls, value)
1882 obj.label = label
1883 obj._value_ = value
1884 return obj
1885
1886 class LabelledList(LabelledIntEnum):
1887 unprocessed = (1, "Unprocessed")
1888 payment_complete = (2, "Payment Complete")
1889
1890 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1891 self.assertEqual(LabelledList.unprocessed, 1)
1892 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001893
Ethan Furmanc16595e2016-09-10 23:36:59 -07001894 def test_auto_number(self):
1895 class Color(Enum):
1896 red = auto()
1897 blue = auto()
1898 green = auto()
1899
1900 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1901 self.assertEqual(Color.red.value, 1)
1902 self.assertEqual(Color.blue.value, 2)
1903 self.assertEqual(Color.green.value, 3)
1904
1905 def test_auto_name(self):
1906 class Color(Enum):
1907 def _generate_next_value_(name, start, count, last):
1908 return name
1909 red = auto()
1910 blue = auto()
1911 green = auto()
1912
1913 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1914 self.assertEqual(Color.red.value, 'red')
1915 self.assertEqual(Color.blue.value, 'blue')
1916 self.assertEqual(Color.green.value, 'green')
1917
1918 def test_auto_name_inherit(self):
1919 class AutoNameEnum(Enum):
1920 def _generate_next_value_(name, start, count, last):
1921 return name
1922 class Color(AutoNameEnum):
1923 red = auto()
1924 blue = auto()
1925 green = auto()
1926
1927 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1928 self.assertEqual(Color.red.value, 'red')
1929 self.assertEqual(Color.blue.value, 'blue')
1930 self.assertEqual(Color.green.value, 'green')
1931
1932 def test_auto_garbage(self):
1933 class Color(Enum):
1934 red = 'red'
1935 blue = auto()
1936 self.assertEqual(Color.blue.value, 1)
1937
1938 def test_auto_garbage_corrected(self):
1939 class Color(Enum):
1940 red = 'red'
1941 blue = 2
1942 green = auto()
1943
1944 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1945 self.assertEqual(Color.red.value, 'red')
1946 self.assertEqual(Color.blue.value, 2)
1947 self.assertEqual(Color.green.value, 3)
1948
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001949 def test_auto_order(self):
1950 with self.assertRaises(TypeError):
1951 class Color(Enum):
1952 red = auto()
1953 green = auto()
1954 blue = auto()
1955 def _generate_next_value_(name, start, count, last):
1956 return name
1957
Ethan Furmanfc23a942020-09-16 12:37:54 -07001958 def test_auto_order_wierd(self):
1959 weird_auto = auto()
1960 weird_auto.value = 'pathological case'
1961 class Color(Enum):
1962 red = weird_auto
1963 def _generate_next_value_(name, start, count, last):
1964 return name
1965 blue = auto()
1966 self.assertEqual(list(Color), [Color.red, Color.blue])
1967 self.assertEqual(Color.red.value, 'pathological case')
1968 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001969
Ethan Furman3515dcc2016-09-18 13:15:41 -07001970 def test_duplicate_auto(self):
1971 class Dupes(Enum):
1972 first = primero = auto()
1973 second = auto()
1974 third = auto()
1975 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1976
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001977 def test_default_missing(self):
1978 class Color(Enum):
1979 RED = 1
1980 GREEN = 2
1981 BLUE = 3
1982 try:
1983 Color(7)
1984 except ValueError as exc:
1985 self.assertTrue(exc.__context__ is None)
1986 else:
1987 raise Exception('Exception not raised.')
1988
Ethan Furman019f0a02018-09-12 11:43:34 -07001989 def test_missing(self):
1990 class Color(Enum):
1991 red = 1
1992 green = 2
1993 blue = 3
1994 @classmethod
1995 def _missing_(cls, item):
1996 if item == 'three':
1997 return cls.blue
1998 elif item == 'bad return':
1999 # trigger internal error
2000 return 5
2001 elif item == 'error out':
2002 raise ZeroDivisionError
2003 else:
2004 # trigger not found
2005 return None
2006 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07002007 try:
2008 Color(7)
2009 except ValueError as exc:
2010 self.assertTrue(exc.__context__ is None)
2011 else:
2012 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07002013 try:
2014 Color('bad return')
2015 except TypeError as exc:
2016 self.assertTrue(isinstance(exc.__context__, ValueError))
2017 else:
2018 raise Exception('Exception not raised.')
2019 try:
2020 Color('error out')
2021 except ZeroDivisionError as exc:
2022 self.assertTrue(isinstance(exc.__context__, ValueError))
2023 else:
2024 raise Exception('Exception not raised.')
2025
Ethan Furman8c14f5a2021-04-12 08:51:20 -07002026 def test_missing_exceptions_reset(self):
2027 import weakref
2028 #
2029 class TestEnum(enum.Enum):
2030 VAL1 = 'val1'
2031 VAL2 = 'val2'
2032 #
2033 class Class1:
2034 def __init__(self):
2035 # Gracefully handle an exception of our own making
2036 try:
2037 raise ValueError()
2038 except ValueError:
2039 pass
2040 #
2041 class Class2:
2042 def __init__(self):
2043 # Gracefully handle an exception of Enum's making
2044 try:
2045 TestEnum('invalid_value')
2046 except ValueError:
2047 pass
2048 # No strong refs here so these are free to die.
2049 class_1_ref = weakref.ref(Class1())
2050 class_2_ref = weakref.ref(Class2())
2051 #
2052 # The exception raised by Enum creates a reference loop and thus
2053 # Class2 instances will stick around until the next gargage collection
2054 # cycle, unlike Class1.
2055 self.assertIs(class_1_ref(), None)
2056 self.assertIs(class_2_ref(), None)
2057
Ethan Furman5bdab642018-09-21 19:03:09 -07002058 def test_multiple_mixin(self):
2059 class MaxMixin:
2060 @classproperty
2061 def MAX(cls):
2062 max = len(cls)
2063 cls.MAX = max
2064 return max
2065 class StrMixin:
2066 def __str__(self):
2067 return self._name_.lower()
2068 class SomeEnum(Enum):
2069 def behavior(self):
2070 return 'booyah'
2071 class AnotherEnum(Enum):
2072 def behavior(self):
2073 return 'nuhuh!'
2074 def social(self):
2075 return "what's up?"
2076 class Color(MaxMixin, Enum):
2077 RED = auto()
2078 GREEN = auto()
2079 BLUE = auto()
2080 self.assertEqual(Color.RED.value, 1)
2081 self.assertEqual(Color.GREEN.value, 2)
2082 self.assertEqual(Color.BLUE.value, 3)
2083 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002084 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002085 class Color(MaxMixin, StrMixin, Enum):
2086 RED = auto()
2087 GREEN = auto()
2088 BLUE = auto()
2089 self.assertEqual(Color.RED.value, 1)
2090 self.assertEqual(Color.GREEN.value, 2)
2091 self.assertEqual(Color.BLUE.value, 3)
2092 self.assertEqual(Color.MAX, 3)
2093 self.assertEqual(str(Color.BLUE), 'blue')
2094 class Color(StrMixin, MaxMixin, Enum):
2095 RED = auto()
2096 GREEN = auto()
2097 BLUE = auto()
2098 self.assertEqual(Color.RED.value, 1)
2099 self.assertEqual(Color.GREEN.value, 2)
2100 self.assertEqual(Color.BLUE.value, 3)
2101 self.assertEqual(Color.MAX, 3)
2102 self.assertEqual(str(Color.BLUE), 'blue')
2103 class CoolColor(StrMixin, SomeEnum, Enum):
2104 RED = auto()
2105 GREEN = auto()
2106 BLUE = auto()
2107 self.assertEqual(CoolColor.RED.value, 1)
2108 self.assertEqual(CoolColor.GREEN.value, 2)
2109 self.assertEqual(CoolColor.BLUE.value, 3)
2110 self.assertEqual(str(CoolColor.BLUE), 'blue')
2111 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2112 class CoolerColor(StrMixin, AnotherEnum, Enum):
2113 RED = auto()
2114 GREEN = auto()
2115 BLUE = auto()
2116 self.assertEqual(CoolerColor.RED.value, 1)
2117 self.assertEqual(CoolerColor.GREEN.value, 2)
2118 self.assertEqual(CoolerColor.BLUE.value, 3)
2119 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2120 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2121 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2122 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2123 RED = auto()
2124 GREEN = auto()
2125 BLUE = auto()
2126 self.assertEqual(CoolestColor.RED.value, 1)
2127 self.assertEqual(CoolestColor.GREEN.value, 2)
2128 self.assertEqual(CoolestColor.BLUE.value, 3)
2129 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2130 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2131 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2132 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2133 RED = auto()
2134 GREEN = auto()
2135 BLUE = auto()
2136 self.assertEqual(ConfusedColor.RED.value, 1)
2137 self.assertEqual(ConfusedColor.GREEN.value, 2)
2138 self.assertEqual(ConfusedColor.BLUE.value, 3)
2139 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2140 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2141 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2142 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2143 RED = auto()
2144 GREEN = auto()
2145 BLUE = auto()
2146 self.assertEqual(ReformedColor.RED.value, 1)
2147 self.assertEqual(ReformedColor.GREEN.value, 2)
2148 self.assertEqual(ReformedColor.BLUE.value, 3)
2149 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2150 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2151 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2152 self.assertTrue(issubclass(ReformedColor, int))
2153
Ethan Furmancd453852018-10-05 23:29:36 -07002154 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002155 @unique
2156 class Decision1(StrEnum):
2157 REVERT = "REVERT"
2158 REVERT_ALL = "REVERT_ALL"
2159 RETRY = "RETRY"
2160 class MyEnum(StrEnum):
2161 pass
2162 @unique
2163 class Decision2(MyEnum):
2164 REVERT = "REVERT"
2165 REVERT_ALL = "REVERT_ALL"
2166 RETRY = "RETRY"
2167
Ethan Furmanc2667362020-12-07 00:17:31 -08002168 def test_multiple_mixin_inherited(self):
2169 class MyInt(int):
2170 def __new__(cls, value):
2171 return super().__new__(cls, value)
2172
2173 class HexMixin:
2174 def __repr__(self):
2175 return hex(self)
2176
2177 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2178 pass
2179
2180 class Foo(MyIntEnum):
2181 TEST = 1
2182 self.assertTrue(isinstance(Foo.TEST, MyInt))
2183 self.assertEqual(repr(Foo.TEST), "0x1")
2184
2185 class Fee(MyIntEnum):
2186 TEST = 1
2187 def __new__(cls, value):
2188 value += 1
2189 member = int.__new__(cls, value)
2190 member._value_ = value
2191 return member
2192 self.assertEqual(Fee.TEST, 2)
2193
Miss Islington (bot)01286012021-06-10 15:01:03 -07002194 def test_miltuple_mixin_with_common_data_type(self):
2195 class CaseInsensitiveStrEnum(str, Enum):
2196 @classmethod
2197 def _missing_(cls, value):
2198 for member in cls._member_map_.values():
2199 if member._value_.lower() == value.lower():
2200 return member
2201 return super()._missing_(value)
2202 #
2203 class LenientStrEnum(str, Enum):
2204 def __init__(self, *args):
2205 self._valid = True
2206 @classmethod
2207 def _missing_(cls, value):
Miss Islington (bot)01286012021-06-10 15:01:03 -07002208 unknown = cls._member_type_.__new__(cls, value)
2209 unknown._valid = False
2210 unknown._name_ = value.upper()
2211 unknown._value_ = value
2212 cls._member_map_[value] = unknown
2213 return unknown
2214 @property
2215 def valid(self):
2216 return self._valid
2217 #
2218 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2219 ACTIVE = "active"
2220 PENDING = "pending"
2221 TERMINATED = "terminated"
2222 #
2223 JS = JobStatus
2224 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2225 self.assertEqual(JS.ACTIVE, 'active')
2226 self.assertEqual(JS.ACTIVE.value, 'active')
2227 self.assertIs(JS('Active'), JS.ACTIVE)
2228 self.assertTrue(JS.ACTIVE.valid)
2229 missing = JS('missing')
2230 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2231 self.assertEqual(JS.ACTIVE, 'active')
2232 self.assertEqual(JS.ACTIVE.value, 'active')
2233 self.assertIs(JS('Active'), JS.ACTIVE)
2234 self.assertTrue(JS.ACTIVE.valid)
2235 self.assertTrue(isinstance(missing, JS))
2236 self.assertFalse(missing.valid)
2237
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002238 def test_empty_globals(self):
2239 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2240 # when using compile and exec because f_globals is empty
2241 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2242 code = compile(code, "<string>", "exec")
2243 global_ns = {}
2244 local_ls = {}
2245 exec(code, global_ns, local_ls)
2246
Ethan Furman0063ff42020-09-21 17:23:13 -07002247 def test_strenum(self):
2248 class GoodStrEnum(StrEnum):
2249 one = '1'
2250 two = '2'
2251 three = b'3', 'ascii'
2252 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002253 self.assertEqual(GoodStrEnum.one, '1')
2254 self.assertEqual(str(GoodStrEnum.one), '1')
Ethan Furman1b4addf2021-06-18 14:25:42 -07002255 self.assertEqual('{}'.format(GoodStrEnum.one), '1')
Ethan Furmand986d162020-09-22 13:00:07 -07002256 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2257 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
Ethan Furman1b4addf2021-06-18 14:25:42 -07002258 self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one')
Ethan Furmand986d162020-09-22 13:00:07 -07002259 #
2260 class DumbMixin:
2261 def __str__(self):
2262 return "don't do this"
2263 class DumbStrEnum(DumbMixin, StrEnum):
2264 five = '5'
2265 six = '6'
2266 seven = '7'
2267 self.assertEqual(DumbStrEnum.seven, '7')
2268 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2269 #
2270 class EnumMixin(Enum):
2271 def hello(self):
2272 print('hello from %s' % (self, ))
2273 class HelloEnum(EnumMixin, StrEnum):
2274 eight = '8'
2275 self.assertEqual(HelloEnum.eight, '8')
2276 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2277 #
2278 class GoodbyeMixin:
2279 def goodbye(self):
2280 print('%s wishes you a fond farewell')
2281 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2282 nine = '9'
2283 self.assertEqual(GoodbyeEnum.nine, '9')
2284 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2285 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002286 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2287 class FirstFailedStrEnum(StrEnum):
2288 one = 1
2289 two = '2'
2290 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2291 class SecondFailedStrEnum(StrEnum):
2292 one = '1'
2293 two = 2,
2294 three = '3'
2295 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2296 class ThirdFailedStrEnum(StrEnum):
2297 one = '1'
2298 two = 2
2299 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2300 class ThirdFailedStrEnum(StrEnum):
2301 one = '1'
2302 two = b'2', sys.getdefaultencoding
2303 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2304 class ThirdFailedStrEnum(StrEnum):
2305 one = '1'
2306 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002307
Ethan Furman1b4addf2021-06-18 14:25:42 -07002308 @unittest.skipIf(
2309 python_version >= (3, 12),
2310 'mixin-format now uses member instead of member.value',
2311 )
2312 def test_custom_strenum_with_warning(self):
2313 class CustomStrEnum(str, Enum):
2314 pass
2315 class OkayEnum(CustomStrEnum):
2316 one = '1'
2317 two = '2'
2318 three = b'3', 'ascii'
2319 four = b'4', 'latin1', 'strict'
2320 self.assertEqual(OkayEnum.one, '1')
2321 self.assertEqual(str(OkayEnum.one), 'one')
2322 with self.assertWarns(DeprecationWarning):
2323 self.assertEqual('{}'.format(OkayEnum.one), '1')
2324 self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one))
2325 self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
2326 #
2327 class DumbMixin:
2328 def __str__(self):
2329 return "don't do this"
2330 class DumbStrEnum(DumbMixin, CustomStrEnum):
2331 five = '5'
2332 six = '6'
2333 seven = '7'
2334 self.assertEqual(DumbStrEnum.seven, '7')
2335 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2336 #
2337 class EnumMixin(Enum):
2338 def hello(self):
2339 print('hello from %s' % (self, ))
2340 class HelloEnum(EnumMixin, CustomStrEnum):
2341 eight = '8'
2342 self.assertEqual(HelloEnum.eight, '8')
2343 self.assertEqual(str(HelloEnum.eight), 'eight')
2344 #
2345 class GoodbyeMixin:
2346 def goodbye(self):
2347 print('%s wishes you a fond farewell')
2348 class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
2349 nine = '9'
2350 self.assertEqual(GoodbyeEnum.nine, '9')
2351 self.assertEqual(str(GoodbyeEnum.nine), 'nine')
2352 #
2353 class FirstFailedStrEnum(CustomStrEnum):
2354 one = 1 # this will become '1'
2355 two = '2'
2356 class SecondFailedStrEnum(CustomStrEnum):
2357 one = '1'
2358 two = 2, # this will become '2'
2359 three = '3'
2360 class ThirdFailedStrEnum(CustomStrEnum):
2361 one = '1'
2362 two = 2 # this will become '2'
2363 with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
2364 class ThirdFailedStrEnum(CustomStrEnum):
2365 one = '1'
2366 two = b'2', sys.getdefaultencoding
2367 with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
2368 class ThirdFailedStrEnum(CustomStrEnum):
2369 one = '1'
2370 two = b'2', 'ascii', 9
2371
2372 @unittest.skipIf(
2373 python_version < (3, 12),
2374 'mixin-format currently uses member.value',
2375 )
2376 def test_custom_strenum(self):
2377 class CustomStrEnum(str, Enum):
2378 pass
2379 class OkayEnum(CustomStrEnum):
2380 one = '1'
2381 two = '2'
2382 three = b'3', 'ascii'
2383 four = b'4', 'latin1', 'strict'
2384 self.assertEqual(OkayEnum.one, '1')
2385 self.assertEqual(str(OkayEnum.one), 'one')
2386 self.assertEqual('{}'.format(OkayEnum.one), 'one')
2387 self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
2388 #
2389 class DumbMixin:
2390 def __str__(self):
2391 return "don't do this"
2392 class DumbStrEnum(DumbMixin, CustomStrEnum):
2393 five = '5'
2394 six = '6'
2395 seven = '7'
2396 self.assertEqual(DumbStrEnum.seven, '7')
2397 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2398 #
2399 class EnumMixin(Enum):
2400 def hello(self):
2401 print('hello from %s' % (self, ))
2402 class HelloEnum(EnumMixin, CustomStrEnum):
2403 eight = '8'
2404 self.assertEqual(HelloEnum.eight, '8')
2405 self.assertEqual(str(HelloEnum.eight), 'eight')
2406 #
2407 class GoodbyeMixin:
2408 def goodbye(self):
2409 print('%s wishes you a fond farewell')
2410 class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
2411 nine = '9'
2412 self.assertEqual(GoodbyeEnum.nine, '9')
2413 self.assertEqual(str(GoodbyeEnum.nine), 'nine')
2414 #
2415 class FirstFailedStrEnum(CustomStrEnum):
2416 one = 1 # this will become '1'
2417 two = '2'
2418 class SecondFailedStrEnum(CustomStrEnum):
2419 one = '1'
2420 two = 2, # this will become '2'
2421 three = '3'
2422 class ThirdFailedStrEnum(CustomStrEnum):
2423 one = '1'
2424 two = 2 # this will become '2'
2425 with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
2426 class ThirdFailedStrEnum(CustomStrEnum):
2427 one = '1'
2428 two = b'2', sys.getdefaultencoding
2429 with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
2430 class ThirdFailedStrEnum(CustomStrEnum):
2431 one = '1'
2432 two = b'2', 'ascii', 9
2433
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002434 def test_missing_value_error(self):
2435 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2436 class Combined(str, Enum):
2437 #
2438 def __new__(cls, value, sequence):
2439 enum = str.__new__(cls, value)
2440 if '(' in value:
2441 fis_name, segment = value.split('(', 1)
2442 segment = segment.strip(' )')
2443 else:
2444 fis_name = value
2445 segment = None
2446 enum.fis_name = fis_name
2447 enum.segment = segment
2448 enum.sequence = sequence
2449 return enum
2450 #
2451 def __repr__(self):
2452 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2453 #
2454 key_type = 'An$(1,2)', 0
2455 company_id = 'An$(3,2)', 1
2456 code = 'An$(5,1)', 2
2457 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002458
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002459 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002460 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002461 'private variables are now normal attributes',
2462 )
2463 def test_warning_for_private_variables(self):
2464 with self.assertWarns(DeprecationWarning):
2465 class Private(Enum):
2466 __corporal = 'Radar'
2467 self.assertEqual(Private._Private__corporal.value, 'Radar')
2468 try:
2469 with self.assertWarns(DeprecationWarning):
2470 class Private(Enum):
2471 __major_ = 'Hoolihan'
2472 except ValueError:
2473 pass
2474
2475 def test_private_variable_is_normal_attribute(self):
2476 class Private(Enum):
2477 __corporal = 'Radar'
2478 __major_ = 'Hoolihan'
2479 self.assertEqual(Private._Private__corporal, 'Radar')
2480 self.assertEqual(Private._Private__major_, 'Hoolihan')
2481
Ethan Furmand65b9032021-02-08 17:32:38 -08002482 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002483 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002484 'member-member access now raises an exception',
2485 )
2486 def test_warning_for_member_from_member_access(self):
2487 with self.assertWarns(DeprecationWarning):
2488 class Di(Enum):
2489 YES = 1
2490 NO = 0
2491 nope = Di.YES.NO
2492 self.assertIs(Di.NO, nope)
2493
2494 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002495 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002496 'member-member access currently issues a warning',
2497 )
2498 def test_exception_for_member_from_member_access(self):
2499 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2500 class Di(Enum):
2501 YES = 1
2502 NO = 0
2503 nope = Di.YES.NO
2504
Ethan Furmanefb13be2020-12-10 12:20:06 -08002505 def test_strenum_auto(self):
2506 class Strings(StrEnum):
2507 ONE = auto()
2508 TWO = auto()
2509 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2510
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002511
Ethan Furmana6582872020-12-10 13:07:00 -08002512 def test_dynamic_members_with_static_methods(self):
2513 #
2514 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2515 class Foo(Enum):
2516 vars().update({
2517 k: v
2518 for k, v in foo_defines.items()
2519 if k.startswith('FOO_')
2520 })
2521 def upper(self):
2522 return self.value.upper()
2523 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2524 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2525 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2526 #
2527 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2528 class FooBar(Enum):
2529 vars().update({
2530 k: v
2531 for k, v in foo_defines.items()
2532 if k.startswith('FOO_')
2533 },
2534 **{'FOO_CAT': 'small'},
2535 )
2536 def upper(self):
2537 return self.value.upper()
2538
2539
Ethan Furmane8e61272016-08-20 07:19:31 -07002540class TestOrder(unittest.TestCase):
2541
2542 def test_same_members(self):
2543 class Color(Enum):
2544 _order_ = 'red green blue'
2545 red = 1
2546 green = 2
2547 blue = 3
2548
2549 def test_same_members_with_aliases(self):
2550 class Color(Enum):
2551 _order_ = 'red green blue'
2552 red = 1
2553 green = 2
2554 blue = 3
2555 verde = green
2556
2557 def test_same_members_wrong_order(self):
2558 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2559 class Color(Enum):
2560 _order_ = 'red green blue'
2561 red = 1
2562 blue = 3
2563 green = 2
2564
2565 def test_order_has_extra_members(self):
2566 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2567 class Color(Enum):
2568 _order_ = 'red green blue purple'
2569 red = 1
2570 green = 2
2571 blue = 3
2572
2573 def test_order_has_extra_members_with_aliases(self):
2574 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2575 class Color(Enum):
2576 _order_ = 'red green blue purple'
2577 red = 1
2578 green = 2
2579 blue = 3
2580 verde = green
2581
2582 def test_enum_has_extra_members(self):
2583 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2584 class Color(Enum):
2585 _order_ = 'red green blue'
2586 red = 1
2587 green = 2
2588 blue = 3
2589 purple = 4
2590
2591 def test_enum_has_extra_members_with_aliases(self):
2592 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2593 class Color(Enum):
2594 _order_ = 'red green blue'
2595 red = 1
2596 green = 2
2597 blue = 3
2598 purple = 4
2599 verde = green
2600
2601
Ethan Furman65a5a472016-09-01 23:55:19 -07002602class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002603 """Tests of the Flags."""
2604
Ethan Furman65a5a472016-09-01 23:55:19 -07002605 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002606 R, W, X = 4, 2, 1
2607
Ethan Furman65a5a472016-09-01 23:55:19 -07002608 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002609 RO = 0
2610 WO = 1
2611 RW = 2
2612 AC = 3
2613 CE = 1<<19
2614
Rahul Jha94306522018-09-10 23:51:04 +05302615 class Color(Flag):
2616 BLACK = 0
2617 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002618 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302619 GREEN = 2
2620 BLUE = 4
2621 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002622 WHITE = RED|GREEN|BLUE
2623 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302624
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002625 def test_str(self):
2626 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002627 self.assertEqual(str(Perm.R), 'R')
2628 self.assertEqual(str(Perm.W), 'W')
2629 self.assertEqual(str(Perm.X), 'X')
2630 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2631 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002632 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002633 self.assertEqual(str(~Perm.R), 'W|X')
2634 self.assertEqual(str(~Perm.W), 'R|X')
2635 self.assertEqual(str(~Perm.X), 'R|W')
2636 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002637 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002638 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002639
2640 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002641 self.assertEqual(str(Open.RO), 'RO')
2642 self.assertEqual(str(Open.WO), 'WO')
2643 self.assertEqual(str(Open.AC), 'AC')
2644 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2645 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2646 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2647 self.assertEqual(str(~Open.WO), 'RW|CE')
2648 self.assertEqual(str(~Open.AC), 'CE')
2649 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2650 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002651
2652 def test_repr(self):
2653 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002654 self.assertEqual(repr(Perm.R), 'Perm.R')
2655 self.assertEqual(repr(Perm.W), 'Perm.W')
2656 self.assertEqual(repr(Perm.X), 'Perm.X')
2657 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2658 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2659 self.assertEqual(repr(Perm(0)), '0x0')
2660 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2661 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2662 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2663 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2664 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2665 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002666
2667 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002668 self.assertEqual(repr(Open.RO), 'Open.RO')
2669 self.assertEqual(repr(Open.WO), 'Open.WO')
2670 self.assertEqual(repr(Open.AC), 'Open.AC')
2671 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2672 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2673 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2674 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2675 self.assertEqual(repr(~Open.AC), 'Open.CE')
2676 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2677 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002678
Ethan Furman37440ee2020-12-08 11:14:10 -08002679 def test_format(self):
2680 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002681 self.assertEqual(format(Perm.R, ''), 'R')
2682 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002683
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002684 def test_or(self):
2685 Perm = self.Perm
2686 for i in Perm:
2687 for j in Perm:
2688 self.assertEqual((i | j), Perm(i.value | j.value))
2689 self.assertEqual((i | j).value, i.value | j.value)
2690 self.assertIs(type(i | j), Perm)
2691 for i in Perm:
2692 self.assertIs(i | i, i)
2693 Open = self.Open
2694 self.assertIs(Open.RO | Open.CE, Open.CE)
2695
2696 def test_and(self):
2697 Perm = self.Perm
2698 RW = Perm.R | Perm.W
2699 RX = Perm.R | Perm.X
2700 WX = Perm.W | Perm.X
2701 RWX = Perm.R | Perm.W | Perm.X
2702 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2703 for i in values:
2704 for j in values:
2705 self.assertEqual((i & j).value, i.value & j.value)
2706 self.assertIs(type(i & j), Perm)
2707 for i in Perm:
2708 self.assertIs(i & i, i)
2709 self.assertIs(i & RWX, i)
2710 self.assertIs(RWX & i, i)
2711 Open = self.Open
2712 self.assertIs(Open.RO & Open.CE, Open.RO)
2713
2714 def test_xor(self):
2715 Perm = self.Perm
2716 for i in Perm:
2717 for j in Perm:
2718 self.assertEqual((i ^ j).value, i.value ^ j.value)
2719 self.assertIs(type(i ^ j), Perm)
2720 for i in Perm:
2721 self.assertIs(i ^ Perm(0), i)
2722 self.assertIs(Perm(0) ^ i, i)
2723 Open = self.Open
2724 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2725 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2726
2727 def test_invert(self):
2728 Perm = self.Perm
2729 RW = Perm.R | Perm.W
2730 RX = Perm.R | Perm.X
2731 WX = Perm.W | Perm.X
2732 RWX = Perm.R | Perm.W | Perm.X
2733 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2734 for i in values:
2735 self.assertIs(type(~i), Perm)
2736 self.assertEqual(~~i, i)
2737 for i in Perm:
2738 self.assertIs(~~i, i)
2739 Open = self.Open
2740 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2741 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2742
Ethan Furman25d94bb2016-09-02 16:32:32 -07002743 def test_bool(self):
2744 Perm = self.Perm
2745 for f in Perm:
2746 self.assertTrue(f)
2747 Open = self.Open
2748 for f in Open:
2749 self.assertEqual(bool(f.value), bool(f))
2750
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002751 def test_boundary(self):
2752 self.assertIs(enum.Flag._boundary_, STRICT)
2753 class Iron(Flag, boundary=STRICT):
2754 ONE = 1
2755 TWO = 2
2756 EIGHT = 8
2757 self.assertIs(Iron._boundary_, STRICT)
2758 #
2759 class Water(Flag, boundary=CONFORM):
2760 ONE = 1
2761 TWO = 2
2762 EIGHT = 8
2763 self.assertIs(Water._boundary_, CONFORM)
2764 #
2765 class Space(Flag, boundary=EJECT):
2766 ONE = 1
2767 TWO = 2
2768 EIGHT = 8
2769 self.assertIs(Space._boundary_, EJECT)
2770 #
2771 class Bizarre(Flag, boundary=KEEP):
2772 b = 3
2773 c = 4
2774 d = 6
2775 #
2776 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002777 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002778 self.assertIs(Water(7), Water.ONE|Water.TWO)
2779 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002780 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002781 self.assertEqual(Space(7), 7)
2782 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002783 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002784 self.assertEqual(list(Bizarre), [Bizarre.c])
2785 self.assertIs(Bizarre(3), Bizarre.b)
2786 self.assertIs(Bizarre(6), Bizarre.d)
2787
2788 def test_iter(self):
2789 Color = self.Color
2790 Open = self.Open
2791 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2792 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2793
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002794 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002795 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002796 lst = list(Perm)
2797 self.assertEqual(len(lst), len(Perm))
2798 self.assertEqual(len(Perm), 3, Perm)
2799 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2800 for i, n in enumerate('R W X'.split()):
2801 v = 1<<i
2802 e = Perm(v)
2803 self.assertEqual(e.value, v)
2804 self.assertEqual(type(e.value), int)
2805 self.assertEqual(e.name, n)
2806 self.assertIn(e, Perm)
2807 self.assertIs(type(e), Perm)
2808
2809 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002810 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002811 lst = list(Perm)
2812 self.assertEqual(len(lst), len(Perm))
2813 self.assertEqual(len(Perm), 3, Perm)
2814 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2815 for i, n in enumerate('R W X'.split()):
2816 v = 8<<i
2817 e = Perm(v)
2818 self.assertEqual(e.value, v)
2819 self.assertEqual(type(e.value), int)
2820 self.assertEqual(e.name, n)
2821 self.assertIn(e, Perm)
2822 self.assertIs(type(e), Perm)
2823
2824 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002825 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002826 lst = list(Perm)
2827 self.assertEqual(len(lst), len(Perm))
2828 self.assertEqual(len(Perm), 3, Perm)
2829 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2830 for i, n in enumerate('R W X'.split()):
2831 v = 1<<i
2832 e = Perm(v)
2833 self.assertEqual(e.value, v)
2834 self.assertEqual(type(e.value), int)
2835 self.assertEqual(e.name, n)
2836 self.assertIn(e, Perm)
2837 self.assertIs(type(e), Perm)
2838
2839 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002840 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002841 lst = list(Perm)
2842 self.assertEqual(len(lst), len(Perm))
2843 self.assertEqual(len(Perm), 3, Perm)
2844 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2845 for i, n in enumerate('R W X'.split()):
2846 v = 1<<(2*i+1)
2847 e = Perm(v)
2848 self.assertEqual(e.value, v)
2849 self.assertEqual(type(e.value), int)
2850 self.assertEqual(e.name, n)
2851 self.assertIn(e, Perm)
2852 self.assertIs(type(e), Perm)
2853
2854 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002855 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002856 lst = list(Perm)
2857 self.assertEqual(len(lst), len(Perm))
2858 self.assertEqual(len(Perm), 3, Perm)
2859 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2860 for i, n in enumerate('R W X'.split()):
2861 v = 1<<(2*i+1)
2862 e = Perm(v)
2863 self.assertEqual(e.value, v)
2864 self.assertEqual(type(e.value), int)
2865 self.assertEqual(e.name, n)
2866 self.assertIn(e, Perm)
2867 self.assertIs(type(e), Perm)
2868
Ethan Furman65a5a472016-09-01 23:55:19 -07002869 def test_pickle(self):
2870 if isinstance(FlagStooges, Exception):
2871 raise FlagStooges
2872 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2873 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002874
Ethan Furman6bd92882021-04-27 13:05:08 -07002875 @unittest.skipIf(
2876 python_version >= (3, 12),
2877 '__contains__ now returns True/False for all inputs',
2878 )
2879 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302880 Open = self.Open
2881 Color = self.Color
2882 self.assertFalse(Color.BLACK in Open)
2883 self.assertFalse(Open.RO in Color)
2884 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002885 with self.assertWarns(DeprecationWarning):
2886 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302887 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002888 with self.assertWarns(DeprecationWarning):
2889 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302890 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002891 with self.assertWarns(DeprecationWarning):
2892 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302893 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002894 with self.assertWarns(DeprecationWarning):
2895 1 in Open
2896
2897 @unittest.skipIf(
2898 python_version < (3, 12),
2899 '__contains__ only works with enum memmbers before 3.12',
2900 )
2901 def test_contains_tf(self):
2902 Open = self.Open
2903 Color = self.Color
2904 self.assertFalse(Color.BLACK in Open)
2905 self.assertFalse(Open.RO in Color)
2906 self.assertFalse('BLACK' in Color)
2907 self.assertFalse('RO' in Open)
2908 self.assertTrue(1 in Color)
2909 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302910
2911 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002912 Perm = self.Perm
2913 R, W, X = Perm
2914 RW = R | W
2915 RX = R | X
2916 WX = W | X
2917 RWX = R | W | X
2918 self.assertTrue(R in RW)
2919 self.assertTrue(R in RX)
2920 self.assertTrue(R in RWX)
2921 self.assertTrue(W in RW)
2922 self.assertTrue(W in WX)
2923 self.assertTrue(W in RWX)
2924 self.assertTrue(X in RX)
2925 self.assertTrue(X in WX)
2926 self.assertTrue(X in RWX)
2927 self.assertFalse(R in WX)
2928 self.assertFalse(W in RX)
2929 self.assertFalse(X in RW)
2930
Ethan Furman7219e272020-09-16 13:01:00 -07002931 def test_member_iter(self):
2932 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002933 self.assertEqual(list(Color.BLACK), [])
2934 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002935 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2936 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002937 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2938 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2939
2940 def test_member_length(self):
2941 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2942 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2943 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2944 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2945
2946 def test_number_reset_and_order_cleanup(self):
2947 class Confused(Flag):
2948 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2949 ONE = auto()
2950 TWO = auto()
2951 FOUR = auto()
2952 DOS = 2
2953 EIGHT = auto()
2954 SIXTEEN = auto()
2955 self.assertEqual(
2956 list(Confused),
2957 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2958 self.assertIs(Confused.TWO, Confused.DOS)
2959 self.assertEqual(Confused.DOS._value_, 2)
2960 self.assertEqual(Confused.EIGHT._value_, 8)
2961 self.assertEqual(Confused.SIXTEEN._value_, 16)
2962
2963 def test_aliases(self):
2964 Color = self.Color
2965 self.assertEqual(Color(1).name, 'RED')
2966 self.assertEqual(Color['ROJO'].name, 'RED')
2967 self.assertEqual(Color(7).name, 'WHITE')
2968 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2969 self.assertIs(Color.BLANCO, Color.WHITE)
2970 Open = self.Open
2971 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002972
Ethan Furmanc16595e2016-09-10 23:36:59 -07002973 def test_auto_number(self):
2974 class Color(Flag):
2975 red = auto()
2976 blue = auto()
2977 green = auto()
2978
2979 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2980 self.assertEqual(Color.red.value, 1)
2981 self.assertEqual(Color.blue.value, 2)
2982 self.assertEqual(Color.green.value, 4)
2983
2984 def test_auto_number_garbage(self):
2985 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2986 class Color(Flag):
2987 red = 'not an int'
2988 blue = auto()
2989
Ethan Furman3515dcc2016-09-18 13:15:41 -07002990 def test_duplicate_auto(self):
2991 class Dupes(Enum):
2992 first = primero = auto()
2993 second = auto()
2994 third = auto()
2995 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2996
Ethan Furman5bdab642018-09-21 19:03:09 -07002997 def test_multiple_mixin(self):
2998 class AllMixin:
2999 @classproperty
3000 def ALL(cls):
3001 members = list(cls)
3002 all_value = None
3003 if members:
3004 all_value = members[0]
3005 for member in members[1:]:
3006 all_value |= member
3007 cls.ALL = all_value
3008 return all_value
3009 class StrMixin:
3010 def __str__(self):
3011 return self._name_.lower()
3012 class Color(AllMixin, Flag):
3013 RED = auto()
3014 GREEN = auto()
3015 BLUE = auto()
3016 self.assertEqual(Color.RED.value, 1)
3017 self.assertEqual(Color.GREEN.value, 2)
3018 self.assertEqual(Color.BLUE.value, 4)
3019 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003020 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003021 class Color(AllMixin, StrMixin, Flag):
3022 RED = auto()
3023 GREEN = auto()
3024 BLUE = auto()
3025 self.assertEqual(Color.RED.value, 1)
3026 self.assertEqual(Color.GREEN.value, 2)
3027 self.assertEqual(Color.BLUE.value, 4)
3028 self.assertEqual(Color.ALL.value, 7)
3029 self.assertEqual(str(Color.BLUE), 'blue')
3030 class Color(StrMixin, AllMixin, Flag):
3031 RED = auto()
3032 GREEN = auto()
3033 BLUE = auto()
3034 self.assertEqual(Color.RED.value, 1)
3035 self.assertEqual(Color.GREEN.value, 2)
3036 self.assertEqual(Color.BLUE.value, 4)
3037 self.assertEqual(Color.ALL.value, 7)
3038 self.assertEqual(str(Color.BLUE), 'blue')
3039
Hai Shie80697d2020-05-28 06:10:27 +08003040 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003041 def test_unique_composite(self):
3042 # override __eq__ to be identity only
3043 class TestFlag(Flag):
3044 one = auto()
3045 two = auto()
3046 three = auto()
3047 four = auto()
3048 five = auto()
3049 six = auto()
3050 seven = auto()
3051 eight = auto()
3052 def __eq__(self, other):
3053 return self is other
3054 def __hash__(self):
3055 return hash(self._value_)
3056 # have multiple threads competing to complete the composite members
3057 seen = set()
3058 failed = False
3059 def cycle_enum():
3060 nonlocal failed
3061 try:
3062 for i in range(256):
3063 seen.add(TestFlag(i))
3064 except Exception:
3065 failed = True
3066 threads = [
3067 threading.Thread(target=cycle_enum)
3068 for _ in range(8)
3069 ]
Hai Shie80697d2020-05-28 06:10:27 +08003070 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003071 pass
3072 # check that only 248 members were created
3073 self.assertFalse(
3074 failed,
3075 'at least one thread failed while creating composite members')
3076 self.assertEqual(256, len(seen), 'too many composite members created')
3077
Ethan Furman6bd94de2020-12-09 16:41:22 -08003078 def test_init_subclass(self):
3079 class MyEnum(Flag):
3080 def __init_subclass__(cls, **kwds):
3081 super().__init_subclass__(**kwds)
3082 self.assertFalse(cls.__dict__.get('_test', False))
3083 cls._test1 = 'MyEnum'
3084 #
3085 class TheirEnum(MyEnum):
3086 def __init_subclass__(cls, **kwds):
3087 super(TheirEnum, cls).__init_subclass__(**kwds)
3088 cls._test2 = 'TheirEnum'
3089 class WhoseEnum(TheirEnum):
3090 def __init_subclass__(cls, **kwds):
3091 pass
3092 class NoEnum(WhoseEnum):
3093 ONE = 1
3094 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
3095 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
3096 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
3097 self.assertFalse(NoEnum.__dict__.get('_test1', False))
3098 self.assertFalse(NoEnum.__dict__.get('_test2', False))
3099 #
3100 class OurEnum(MyEnum):
3101 def __init_subclass__(cls, **kwds):
3102 cls._test2 = 'OurEnum'
3103 class WhereEnum(OurEnum):
3104 def __init_subclass__(cls, **kwds):
3105 pass
3106 class NeverEnum(WhereEnum):
3107 ONE = 1
3108 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
3109 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
3110 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
3111 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
3112 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
3113
Ethan Furmanc16595e2016-09-10 23:36:59 -07003114
Ethan Furman65a5a472016-09-01 23:55:19 -07003115class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003116 """Tests of the IntFlags."""
3117
Ethan Furman65a5a472016-09-01 23:55:19 -07003118 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003119 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003120 W = 1 << 1
3121 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003122
Ethan Furman65a5a472016-09-01 23:55:19 -07003123 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003124 RO = 0
3125 WO = 1
3126 RW = 2
3127 AC = 3
3128 CE = 1<<19
3129
Rahul Jha94306522018-09-10 23:51:04 +05303130 class Color(IntFlag):
3131 BLACK = 0
3132 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003133 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05303134 GREEN = 2
3135 BLUE = 4
3136 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003137 WHITE = RED|GREEN|BLUE
3138 BLANCO = RED|GREEN|BLUE
3139
3140 class Skip(IntFlag):
3141 FIRST = 1
3142 SECOND = 2
3143 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05303144
Ethan Furman3515dcc2016-09-18 13:15:41 -07003145 def test_type(self):
3146 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08003147 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07003148 Open = self.Open
3149 for f in Perm:
3150 self.assertTrue(isinstance(f, Perm))
3151 self.assertEqual(f, f.value)
3152 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
3153 self.assertEqual(Perm.W | Perm.X, 3)
3154 for f in Open:
3155 self.assertTrue(isinstance(f, Open))
3156 self.assertEqual(f, f.value)
3157 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
3158 self.assertEqual(Open.WO | Open.RW, 3)
3159
3160
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003161 def test_str(self):
3162 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003163 self.assertEqual(str(Perm.R), 'R')
3164 self.assertEqual(str(Perm.W), 'W')
3165 self.assertEqual(str(Perm.X), 'X')
3166 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
3167 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003168 self.assertEqual(str(Perm.R | 8), '12')
3169 self.assertEqual(str(Perm(0)), 'Perm(0)')
3170 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003171 self.assertEqual(str(~Perm.R), 'W|X')
3172 self.assertEqual(str(~Perm.W), 'R|X')
3173 self.assertEqual(str(~Perm.X), 'R|W')
3174 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003175 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
3176 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003177 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003178 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003179
3180 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003181 self.assertEqual(str(Open.RO), 'RO')
3182 self.assertEqual(str(Open.WO), 'WO')
3183 self.assertEqual(str(Open.AC), 'AC')
3184 self.assertEqual(str(Open.RO | Open.CE), 'CE')
3185 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003186 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003187 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
3188 self.assertEqual(str(~Open.WO), 'RW|CE')
3189 self.assertEqual(str(~Open.AC), 'CE')
3190 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
3191 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003192 self.assertEqual(str(Open(~4)), '-5')
3193
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003194 def test_repr(self):
3195 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07003196 self.assertEqual(repr(Perm.R), 'Perm.R')
3197 self.assertEqual(repr(Perm.W), 'Perm.W')
3198 self.assertEqual(repr(Perm.X), 'Perm.X')
3199 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
3200 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003201 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07003202 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003203 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07003204 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
3205 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
3206 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
3207 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
3208 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003209 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07003210 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003211 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003212
3213 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003214 self.assertEqual(repr(Open.RO), 'Open.RO')
3215 self.assertEqual(repr(Open.WO), 'Open.WO')
3216 self.assertEqual(repr(Open.AC), 'Open.AC')
3217 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3218 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003219 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003220 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3221 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3222 self.assertEqual(repr(~Open.AC), 'Open.CE')
3223 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3224 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003225 self.assertEqual(repr(Open(~4)), '-5')
3226
Ethan Furman37440ee2020-12-08 11:14:10 -08003227 def test_format(self):
Ethan Furman1b4addf2021-06-18 14:25:42 -07003228 Perm = self.Perm
3229 self.assertEqual(format(Perm.R, ''), '4')
3230 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
3231 #
3232 class NewPerm(IntFlag):
3233 R = 1 << 2
3234 W = 1 << 1
3235 X = 1 << 0
3236 def __str__(self):
3237 return self._name_
3238 self.assertEqual(format(NewPerm.R, ''), 'R')
3239 self.assertEqual(format(NewPerm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08003240
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003241 def test_or(self):
3242 Perm = self.Perm
3243 for i in Perm:
3244 for j in Perm:
3245 self.assertEqual(i | j, i.value | j.value)
3246 self.assertEqual((i | j).value, i.value | j.value)
3247 self.assertIs(type(i | j), Perm)
3248 for j in range(8):
3249 self.assertEqual(i | j, i.value | j)
3250 self.assertEqual((i | j).value, i.value | j)
3251 self.assertIs(type(i | j), Perm)
3252 self.assertEqual(j | i, j | i.value)
3253 self.assertEqual((j | i).value, j | i.value)
3254 self.assertIs(type(j | i), Perm)
3255 for i in Perm:
3256 self.assertIs(i | i, i)
3257 self.assertIs(i | 0, i)
3258 self.assertIs(0 | i, i)
3259 Open = self.Open
3260 self.assertIs(Open.RO | Open.CE, Open.CE)
3261
3262 def test_and(self):
3263 Perm = self.Perm
3264 RW = Perm.R | Perm.W
3265 RX = Perm.R | Perm.X
3266 WX = Perm.W | Perm.X
3267 RWX = Perm.R | Perm.W | Perm.X
3268 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3269 for i in values:
3270 for j in values:
3271 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3272 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3273 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3274 for j in range(8):
3275 self.assertEqual(i & j, i.value & j)
3276 self.assertEqual((i & j).value, i.value & j)
3277 self.assertIs(type(i & j), Perm)
3278 self.assertEqual(j & i, j & i.value)
3279 self.assertEqual((j & i).value, j & i.value)
3280 self.assertIs(type(j & i), Perm)
3281 for i in Perm:
3282 self.assertIs(i & i, i)
3283 self.assertIs(i & 7, i)
3284 self.assertIs(7 & i, i)
3285 Open = self.Open
3286 self.assertIs(Open.RO & Open.CE, Open.RO)
3287
3288 def test_xor(self):
3289 Perm = self.Perm
3290 for i in Perm:
3291 for j in Perm:
3292 self.assertEqual(i ^ j, i.value ^ j.value)
3293 self.assertEqual((i ^ j).value, i.value ^ j.value)
3294 self.assertIs(type(i ^ j), Perm)
3295 for j in range(8):
3296 self.assertEqual(i ^ j, i.value ^ j)
3297 self.assertEqual((i ^ j).value, i.value ^ j)
3298 self.assertIs(type(i ^ j), Perm)
3299 self.assertEqual(j ^ i, j ^ i.value)
3300 self.assertEqual((j ^ i).value, j ^ i.value)
3301 self.assertIs(type(j ^ i), Perm)
3302 for i in Perm:
3303 self.assertIs(i ^ 0, i)
3304 self.assertIs(0 ^ i, i)
3305 Open = self.Open
3306 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3307 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3308
3309 def test_invert(self):
3310 Perm = self.Perm
3311 RW = Perm.R | Perm.W
3312 RX = Perm.R | Perm.X
3313 WX = Perm.W | Perm.X
3314 RWX = Perm.R | Perm.W | Perm.X
3315 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3316 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003317 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003318 self.assertIs(type(~i), Perm)
3319 self.assertEqual(~~i, i)
3320 for i in Perm:
3321 self.assertIs(~~i, i)
3322 Open = self.Open
3323 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3324 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3325
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003326 def test_boundary(self):
3327 self.assertIs(enum.IntFlag._boundary_, EJECT)
3328 class Iron(IntFlag, boundary=STRICT):
3329 ONE = 1
3330 TWO = 2
3331 EIGHT = 8
3332 self.assertIs(Iron._boundary_, STRICT)
3333 #
3334 class Water(IntFlag, boundary=CONFORM):
3335 ONE = 1
3336 TWO = 2
3337 EIGHT = 8
3338 self.assertIs(Water._boundary_, CONFORM)
3339 #
3340 class Space(IntFlag, boundary=EJECT):
3341 ONE = 1
3342 TWO = 2
3343 EIGHT = 8
3344 self.assertIs(Space._boundary_, EJECT)
3345 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003346 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003347 class Bizarre(IntFlag, boundary=KEEP):
3348 b = 3
3349 c = 4
3350 d = 6
3351 #
3352 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003353 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003354 self.assertIs(Water(7), Water.ONE|Water.TWO)
3355 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003356 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003357 self.assertEqual(Space(7), 7)
3358 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003359 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003360 self.assertEqual(list(Bizarre), [Bizarre.c])
3361 self.assertIs(Bizarre(3), Bizarre.b)
3362 self.assertIs(Bizarre(6), Bizarre.d)
3363
3364 def test_iter(self):
3365 Color = self.Color
3366 Open = self.Open
3367 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3368 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3369
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003370 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003371 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003372 lst = list(Perm)
3373 self.assertEqual(len(lst), len(Perm))
3374 self.assertEqual(len(Perm), 3, Perm)
3375 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3376 for i, n in enumerate('R W X'.split()):
3377 v = 1<<i
3378 e = Perm(v)
3379 self.assertEqual(e.value, v)
3380 self.assertEqual(type(e.value), int)
3381 self.assertEqual(e, v)
3382 self.assertEqual(e.name, n)
3383 self.assertIn(e, Perm)
3384 self.assertIs(type(e), Perm)
3385
3386 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003387 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003388 lst = list(Perm)
3389 self.assertEqual(len(lst), len(Perm))
3390 self.assertEqual(len(Perm), 3, Perm)
3391 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3392 for i, n in enumerate('R W X'.split()):
3393 v = 8<<i
3394 e = Perm(v)
3395 self.assertEqual(e.value, v)
3396 self.assertEqual(type(e.value), int)
3397 self.assertEqual(e, v)
3398 self.assertEqual(e.name, n)
3399 self.assertIn(e, Perm)
3400 self.assertIs(type(e), Perm)
3401
3402 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003403 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003404 lst = list(Perm)
3405 self.assertEqual(len(lst), len(Perm))
3406 self.assertEqual(len(Perm), 3, Perm)
3407 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3408 for i, n in enumerate('R W X'.split()):
3409 v = 1<<i
3410 e = Perm(v)
3411 self.assertEqual(e.value, v)
3412 self.assertEqual(type(e.value), int)
3413 self.assertEqual(e, v)
3414 self.assertEqual(e.name, n)
3415 self.assertIn(e, Perm)
3416 self.assertIs(type(e), Perm)
3417
3418 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003419 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003420 lst = list(Perm)
3421 self.assertEqual(len(lst), len(Perm))
3422 self.assertEqual(len(Perm), 3, Perm)
3423 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3424 for i, n in enumerate('R W X'.split()):
3425 v = 1<<(2*i+1)
3426 e = Perm(v)
3427 self.assertEqual(e.value, v)
3428 self.assertEqual(type(e.value), int)
3429 self.assertEqual(e, v)
3430 self.assertEqual(e.name, n)
3431 self.assertIn(e, Perm)
3432 self.assertIs(type(e), Perm)
3433
3434 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003435 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003436 lst = list(Perm)
3437 self.assertEqual(len(lst), len(Perm))
3438 self.assertEqual(len(Perm), 3, Perm)
3439 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3440 for i, n in enumerate('R W X'.split()):
3441 v = 1<<(2*i+1)
3442 e = Perm(v)
3443 self.assertEqual(e.value, v)
3444 self.assertEqual(type(e.value), int)
3445 self.assertEqual(e, v)
3446 self.assertEqual(e.name, n)
3447 self.assertIn(e, Perm)
3448 self.assertIs(type(e), Perm)
3449
3450
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003451 def test_programatic_function_from_empty_list(self):
3452 Perm = enum.IntFlag('Perm', [])
3453 lst = list(Perm)
3454 self.assertEqual(len(lst), len(Perm))
3455 self.assertEqual(len(Perm), 0, Perm)
3456 Thing = enum.Enum('Thing', [])
3457 lst = list(Thing)
3458 self.assertEqual(len(lst), len(Thing))
3459 self.assertEqual(len(Thing), 0, Thing)
3460
3461
3462 def test_programatic_function_from_empty_tuple(self):
3463 Perm = enum.IntFlag('Perm', ())
3464 lst = list(Perm)
3465 self.assertEqual(len(lst), len(Perm))
3466 self.assertEqual(len(Perm), 0, Perm)
3467 Thing = enum.Enum('Thing', ())
3468 self.assertEqual(len(lst), len(Thing))
3469 self.assertEqual(len(Thing), 0, Thing)
3470
Ethan Furman6bd92882021-04-27 13:05:08 -07003471 @unittest.skipIf(
3472 python_version >= (3, 12),
3473 '__contains__ now returns True/False for all inputs',
3474 )
3475 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303476 Open = self.Open
3477 Color = self.Color
3478 self.assertTrue(Color.GREEN in Color)
3479 self.assertTrue(Open.RW in Open)
3480 self.assertFalse(Color.GREEN in Open)
3481 self.assertFalse(Open.RW in Color)
3482 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003483 with self.assertWarns(DeprecationWarning):
3484 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303485 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003486 with self.assertWarns(DeprecationWarning):
3487 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05303488 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003489 with self.assertWarns(DeprecationWarning):
3490 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05303491 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003492 with self.assertWarns(DeprecationWarning):
3493 2 in Open
3494
3495 @unittest.skipIf(
3496 python_version < (3, 12),
3497 '__contains__ only works with enum memmbers before 3.12',
3498 )
3499 def test_contains_tf(self):
3500 Open = self.Open
3501 Color = self.Color
3502 self.assertTrue(Color.GREEN in Color)
3503 self.assertTrue(Open.RW in Open)
3504 self.assertTrue(Color.GREEN in Open)
3505 self.assertTrue(Open.RW in Color)
3506 self.assertFalse('GREEN' in Color)
3507 self.assertFalse('RW' in Open)
3508 self.assertTrue(2 in Color)
3509 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303510
3511 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003512 Perm = self.Perm
3513 R, W, X = Perm
3514 RW = R | W
3515 RX = R | X
3516 WX = W | X
3517 RWX = R | W | X
3518 self.assertTrue(R in RW)
3519 self.assertTrue(R in RX)
3520 self.assertTrue(R in RWX)
3521 self.assertTrue(W in RW)
3522 self.assertTrue(W in WX)
3523 self.assertTrue(W in RWX)
3524 self.assertTrue(X in RX)
3525 self.assertTrue(X in WX)
3526 self.assertTrue(X in RWX)
3527 self.assertFalse(R in WX)
3528 self.assertFalse(W in RX)
3529 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303530 with self.assertRaises(TypeError):
3531 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003532
Ethan Furman7219e272020-09-16 13:01:00 -07003533 def test_member_iter(self):
3534 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003535 self.assertEqual(list(Color.BLACK), [])
3536 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003537 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3538 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003539 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3540
3541 def test_member_length(self):
3542 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3543 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3544 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3545 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3546
3547 def test_aliases(self):
3548 Color = self.Color
3549 self.assertEqual(Color(1).name, 'RED')
3550 self.assertEqual(Color['ROJO'].name, 'RED')
3551 self.assertEqual(Color(7).name, 'WHITE')
3552 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3553 self.assertIs(Color.BLANCO, Color.WHITE)
3554 Open = self.Open
3555 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003556
Ethan Furman25d94bb2016-09-02 16:32:32 -07003557 def test_bool(self):
3558 Perm = self.Perm
3559 for f in Perm:
3560 self.assertTrue(f)
3561 Open = self.Open
3562 for f in Open:
3563 self.assertEqual(bool(f.value), bool(f))
3564
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003565
Ethan Furman5bdab642018-09-21 19:03:09 -07003566 def test_multiple_mixin(self):
3567 class AllMixin:
3568 @classproperty
3569 def ALL(cls):
3570 members = list(cls)
3571 all_value = None
3572 if members:
3573 all_value = members[0]
3574 for member in members[1:]:
3575 all_value |= member
3576 cls.ALL = all_value
3577 return all_value
3578 class StrMixin:
3579 def __str__(self):
3580 return self._name_.lower()
3581 class Color(AllMixin, IntFlag):
3582 RED = auto()
3583 GREEN = auto()
3584 BLUE = auto()
3585 self.assertEqual(Color.RED.value, 1)
3586 self.assertEqual(Color.GREEN.value, 2)
3587 self.assertEqual(Color.BLUE.value, 4)
3588 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003589 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003590 class Color(AllMixin, StrMixin, IntFlag):
3591 RED = auto()
3592 GREEN = auto()
3593 BLUE = auto()
3594 self.assertEqual(Color.RED.value, 1)
3595 self.assertEqual(Color.GREEN.value, 2)
3596 self.assertEqual(Color.BLUE.value, 4)
3597 self.assertEqual(Color.ALL.value, 7)
3598 self.assertEqual(str(Color.BLUE), 'blue')
3599 class Color(StrMixin, AllMixin, IntFlag):
3600 RED = auto()
3601 GREEN = auto()
3602 BLUE = auto()
3603 self.assertEqual(Color.RED.value, 1)
3604 self.assertEqual(Color.GREEN.value, 2)
3605 self.assertEqual(Color.BLUE.value, 4)
3606 self.assertEqual(Color.ALL.value, 7)
3607 self.assertEqual(str(Color.BLUE), 'blue')
3608
Hai Shie80697d2020-05-28 06:10:27 +08003609 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003610 def test_unique_composite(self):
3611 # override __eq__ to be identity only
3612 class TestFlag(IntFlag):
3613 one = auto()
3614 two = auto()
3615 three = auto()
3616 four = auto()
3617 five = auto()
3618 six = auto()
3619 seven = auto()
3620 eight = auto()
3621 def __eq__(self, other):
3622 return self is other
3623 def __hash__(self):
3624 return hash(self._value_)
3625 # have multiple threads competing to complete the composite members
3626 seen = set()
3627 failed = False
3628 def cycle_enum():
3629 nonlocal failed
3630 try:
3631 for i in range(256):
3632 seen.add(TestFlag(i))
3633 except Exception:
3634 failed = True
3635 threads = [
3636 threading.Thread(target=cycle_enum)
3637 for _ in range(8)
3638 ]
Hai Shie80697d2020-05-28 06:10:27 +08003639 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003640 pass
3641 # check that only 248 members were created
3642 self.assertFalse(
3643 failed,
3644 'at least one thread failed while creating composite members')
3645 self.assertEqual(256, len(seen), 'too many composite members created')
3646
3647
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003648class TestEmptyAndNonLatinStrings(unittest.TestCase):
3649
3650 def test_empty_string(self):
3651 with self.assertRaises(ValueError):
3652 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3653
3654 def test_non_latin_character_string(self):
3655 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3656 item = getattr(greek_abc, '\u03B1')
3657 self.assertEqual(item.value, 1)
3658
3659 def test_non_latin_number_string(self):
3660 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3661 item = getattr(hebrew_123, '\u05D0')
3662 self.assertEqual(item.value, 1)
3663
3664
Ethan Furmanf24bb352013-07-18 17:05:39 -07003665class TestUnique(unittest.TestCase):
3666
3667 def test_unique_clean(self):
3668 @unique
3669 class Clean(Enum):
3670 one = 1
3671 two = 'dos'
3672 tres = 4.0
Ethan Furman74964862021-06-10 07:24:20 -07003673 #
Ethan Furmanf24bb352013-07-18 17:05:39 -07003674 @unique
3675 class Cleaner(IntEnum):
3676 single = 1
3677 double = 2
3678 triple = 3
3679
3680 def test_unique_dirty(self):
3681 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3682 @unique
3683 class Dirty(Enum):
3684 one = 1
3685 two = 'dos'
3686 tres = 1
3687 with self.assertRaisesRegex(
3688 ValueError,
3689 'double.*single.*turkey.*triple',
3690 ):
3691 @unique
3692 class Dirtier(IntEnum):
3693 single = 1
3694 double = 1
3695 triple = 3
3696 turkey = 3
3697
Ethan Furman3803ad42016-05-01 10:03:53 -07003698 def test_unique_with_name(self):
Ethan Furman74964862021-06-10 07:24:20 -07003699 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003700 class Silly(Enum):
3701 one = 1
3702 two = 'dos'
3703 name = 3
Ethan Furman74964862021-06-10 07:24:20 -07003704 #
3705 @verify(UNIQUE)
3706 class Sillier(IntEnum):
3707 single = 1
3708 name = 2
3709 triple = 3
3710 value = 4
3711
3712class TestVerify(unittest.TestCase):
3713
3714 def test_continuous(self):
3715 @verify(CONTINUOUS)
3716 class Auto(Enum):
3717 FIRST = auto()
3718 SECOND = auto()
3719 THIRD = auto()
3720 FORTH = auto()
3721 #
3722 @verify(CONTINUOUS)
3723 class Manual(Enum):
3724 FIRST = 3
3725 SECOND = 4
3726 THIRD = 5
3727 FORTH = 6
3728 #
3729 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
3730 @verify(CONTINUOUS)
3731 class Missing(Enum):
3732 FIRST = 3
3733 SECOND = 4
3734 THIRD = 11
3735 FORTH = 13
3736 #
3737 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
3738 @verify(CONTINUOUS)
3739 class Incomplete(Flag):
3740 FIRST = 4
3741 SECOND = 8
3742 THIRD = 16
3743 FORTH = 64
3744 #
3745 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
3746 @verify(CONTINUOUS)
3747 class StillIncomplete(Flag):
3748 FIRST = 4
3749 SECOND = 8
3750 THIRD = 11
3751 FORTH = 32
3752
3753
3754 def test_composite(self):
3755 class Bizarre(Flag):
3756 b = 3
3757 c = 4
3758 d = 6
3759 self.assertEqual(list(Bizarre), [Bizarre.c])
3760 self.assertEqual(Bizarre.b.value, 3)
3761 self.assertEqual(Bizarre.c.value, 4)
3762 self.assertEqual(Bizarre.d.value, 6)
3763 with self.assertRaisesRegex(
3764 ValueError,
Ethan Furman41c2a4a2021-06-15 18:50:59 -07003765 "invalid Flag 'Bizarre': aliases b and d are missing combined values of 0x3 .use enum.show_flag_values.value. for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003766 ):
3767 @verify(NAMED_FLAGS)
3768 class Bizarre(Flag):
3769 b = 3
3770 c = 4
3771 d = 6
3772 #
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003773 self.assertEqual(enum.show_flag_values(3), [1, 2])
Ethan Furman74964862021-06-10 07:24:20 -07003774 class Bizarre(IntFlag):
3775 b = 3
3776 c = 4
3777 d = 6
3778 self.assertEqual(list(Bizarre), [Bizarre.c])
3779 self.assertEqual(Bizarre.b.value, 3)
3780 self.assertEqual(Bizarre.c.value, 4)
3781 self.assertEqual(Bizarre.d.value, 6)
3782 with self.assertRaisesRegex(
3783 ValueError,
Ethan Furman41c2a4a2021-06-15 18:50:59 -07003784 "invalid Flag 'Bizarre': alias d is missing value 0x2 .use enum.show_flag_values.value. for details.",
Ethan Furman74964862021-06-10 07:24:20 -07003785 ):
3786 @verify(NAMED_FLAGS)
3787 class Bizarre(IntFlag):
Ethan Furman74964862021-06-10 07:24:20 -07003788 c = 4
3789 d = 6
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07003790 self.assertEqual(enum.show_flag_values(2), [2])
Ethan Furman74964862021-06-10 07:24:20 -07003791
3792 def test_unique_clean(self):
3793 @verify(UNIQUE)
3794 class Clean(Enum):
3795 one = 1
3796 two = 'dos'
3797 tres = 4.0
3798 #
3799 @verify(UNIQUE)
3800 class Cleaner(IntEnum):
3801 single = 1
3802 double = 2
3803 triple = 3
3804
3805 def test_unique_dirty(self):
3806 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3807 @verify(UNIQUE)
3808 class Dirty(Enum):
3809 one = 1
3810 two = 'dos'
3811 tres = 1
3812 with self.assertRaisesRegex(
3813 ValueError,
3814 'double.*single.*turkey.*triple',
3815 ):
3816 @verify(UNIQUE)
3817 class Dirtier(IntEnum):
3818 single = 1
3819 double = 1
3820 triple = 3
3821 turkey = 3
3822
3823 def test_unique_with_name(self):
3824 @verify(UNIQUE)
3825 class Silly(Enum):
3826 one = 1
3827 two = 'dos'
3828 name = 3
3829 #
3830 @verify(UNIQUE)
Ethan Furman3803ad42016-05-01 10:03:53 -07003831 class Sillier(IntEnum):
3832 single = 1
3833 name = 2
3834 triple = 3
3835 value = 4
3836
Ethan Furmanec099732021-04-15 06:58:33 -07003837class TestHelpers(unittest.TestCase):
3838
3839 sunder_names = '_bad_', '_good_', '_what_ho_'
3840 dunder_names = '__mal__', '__bien__', '__que_que__'
3841 private_names = '_MyEnum__private', '_MyEnum__still_private'
3842 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3843 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3844
3845 def test_sunder(self):
3846 for name in self.sunder_names + self.private_and_sunder_names:
3847 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3848 for name in self.dunder_names + self.private_names + self.random_names:
3849 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3850
3851 def test_dunder(self):
3852 for name in self.dunder_names:
3853 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3854 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3855 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3856
3857 def test_is_private(self):
3858 for name in self.private_names + self.private_and_sunder_names:
3859 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3860 for name in self.sunder_names + self.dunder_names + self.random_names:
3861 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003862
Ethan Furmanb7751062021-03-30 21:17:26 -07003863class TestEnumTypeSubclassing(unittest.TestCase):
3864 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003865
Ethan Furman3323da92015-04-11 09:39:59 -07003866expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003867Help on class Color in module %s:
3868
3869class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003870 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003871 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003872 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003873 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003874 | Method resolution order:
3875 | Color
3876 | enum.Enum
3877 | builtins.object
3878 |\x20\x20
3879 | Data and other attributes defined here:
3880 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003881 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003882 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003883 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003884 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003885 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003886 |\x20\x20
3887 | ----------------------------------------------------------------------
3888 | Data descriptors inherited from enum.Enum:
3889 |\x20\x20
3890 | name
3891 | The name of the Enum member.
3892 |\x20\x20
3893 | value
3894 | The value of the Enum member.
3895 |\x20\x20
3896 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003897 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003898 |\x20\x20
3899 | __members__
3900 | Returns a mapping of member name->value.
3901 |\x20\x20\x20\x20\x20\x20
3902 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003903 | is a read-only view of the internal mapping."""
3904
3905expected_help_output_without_docs = """\
3906Help on class Color in module %s:
3907
3908class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003909 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3910 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003911 | Method resolution order:
3912 | Color
3913 | enum.Enum
3914 | builtins.object
3915 |\x20\x20
3916 | Data and other attributes defined here:
3917 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003918 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003919 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003920 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003921 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003922 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003923 |\x20\x20
3924 | ----------------------------------------------------------------------
3925 | Data descriptors inherited from enum.Enum:
3926 |\x20\x20
3927 | name
3928 |\x20\x20
3929 | value
3930 |\x20\x20
3931 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003932 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003933 |\x20\x20
3934 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003935
3936class TestStdLib(unittest.TestCase):
3937
Ethan Furman48a724f2015-04-11 23:23:06 -07003938 maxDiff = None
3939
Ethan Furman5875d742013-10-21 20:45:55 -07003940 class Color(Enum):
3941 red = 1
3942 green = 2
3943 blue = 3
3944
3945 def test_pydoc(self):
3946 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003947 if StrEnum.__doc__ is None:
3948 expected_text = expected_help_output_without_docs % __name__
3949 else:
3950 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003951 output = StringIO()
3952 helper = pydoc.Helper(output=output)
3953 helper(self.Color)
3954 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003955 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003956
3957 def test_inspect_getmembers(self):
3958 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003959 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003960 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003961 ('__members__', self.Color.__members__),
3962 ('__module__', __name__),
3963 ('blue', self.Color.blue),
3964 ('green', self.Color.green),
3965 ('name', Enum.__dict__['name']),
3966 ('red', self.Color.red),
3967 ('value', Enum.__dict__['value']),
3968 ))
3969 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003970 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003971 failed = False
3972 for k in values.keys():
3973 if result[k] != values[k]:
3974 print()
3975 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3976 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3977 failed = True
3978 if failed:
3979 self.fail("result does not equal expected, see print above")
3980
3981 def test_inspect_classify_class_attrs(self):
3982 # indirectly test __objclass__
3983 from inspect import Attribute
3984 values = [
3985 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003986 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003987 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003988 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003989 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003990 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003991 Attribute(name='__module__', kind='data',
3992 defining_class=self.Color, object=__name__),
3993 Attribute(name='blue', kind='data',
3994 defining_class=self.Color, object=self.Color.blue),
3995 Attribute(name='green', kind='data',
3996 defining_class=self.Color, object=self.Color.green),
3997 Attribute(name='red', kind='data',
3998 defining_class=self.Color, object=self.Color.red),
3999 Attribute(name='name', kind='data',
4000 defining_class=Enum, object=Enum.__dict__['name']),
4001 Attribute(name='value', kind='data',
4002 defining_class=Enum, object=Enum.__dict__['value']),
4003 ]
4004 values.sort(key=lambda item: item.name)
4005 result = list(inspect.classify_class_attrs(self.Color))
4006 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08004007 self.assertEqual(
4008 len(values), len(result),
4009 "%s != %s" % ([a.name for a in values], [a.name for a in result])
4010 )
Ethan Furman5875d742013-10-21 20:45:55 -07004011 failed = False
4012 for v, r in zip(values, result):
4013 if r != v:
4014 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
4015 failed = True
4016 if failed:
4017 self.fail("result does not equal expected, see print above")
4018
Ethan Furmana02cb472021-04-21 10:20:44 -07004019 def test_test_simple_enum(self):
4020 @_simple_enum(Enum)
4021 class SimpleColor:
4022 RED = 1
4023 GREEN = 2
4024 BLUE = 3
4025 class CheckedColor(Enum):
4026 RED = 1
4027 GREEN = 2
4028 BLUE = 3
4029 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
4030 SimpleColor.GREEN._value_ = 9
4031 self.assertRaisesRegex(
4032 TypeError, "enum mismatch",
4033 _test_simple_enum, CheckedColor, SimpleColor,
4034 )
4035 class CheckedMissing(IntFlag, boundary=KEEP):
4036 SIXTY_FOUR = 64
4037 ONE_TWENTY_EIGHT = 128
4038 TWENTY_FORTY_EIGHT = 2048
4039 ALL = 2048 + 128 + 64 + 12
4040 CM = CheckedMissing
4041 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
4042 #
4043 @_simple_enum(IntFlag, boundary=KEEP)
4044 class Missing:
4045 SIXTY_FOUR = 64
4046 ONE_TWENTY_EIGHT = 128
4047 TWENTY_FORTY_EIGHT = 2048
4048 ALL = 2048 + 128 + 64 + 12
4049 M = Missing
4050 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
4051 #
4052 _test_simple_enum(CheckedMissing, Missing)
4053
Martin Panter19e69c52015-11-14 12:46:42 +00004054
4055class MiscTestCase(unittest.TestCase):
4056 def test__all__(self):
Miss Islington (bot)0a186b12021-06-11 02:58:57 -07004057 support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
Martin Panter19e69c52015-11-14 12:46:42 +00004058
4059
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004060# These are unordered here on purpose to ensure that declaration order
4061# makes no difference.
4062CONVERT_TEST_NAME_D = 5
4063CONVERT_TEST_NAME_C = 5
4064CONVERT_TEST_NAME_B = 5
4065CONVERT_TEST_NAME_A = 5 # This one should sort first.
4066CONVERT_TEST_NAME_E = 5
4067CONVERT_TEST_NAME_F = 5
4068
Ethan Furmana02cb472021-04-21 10:20:44 -07004069CONVERT_STRING_TEST_NAME_D = 5
4070CONVERT_STRING_TEST_NAME_C = 5
4071CONVERT_STRING_TEST_NAME_B = 5
4072CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
4073CONVERT_STRING_TEST_NAME_E = 5
4074CONVERT_STRING_TEST_NAME_F = 5
4075
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004076class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04004077 def setUp(self):
4078 # Reset the module-level test variables to their original integer
4079 # values, otherwise the already created enum values get converted
4080 # instead.
4081 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
4082 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
4083 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
4084
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004085 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03004086 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08004087 'UnittestConvert',
4088 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004089 filter=lambda x: x.startswith('CONVERT_TEST_'))
4090 # We don't want the reverse lookup value to vary when there are
4091 # multiple possible names for a given value. It should always
4092 # report the first lexigraphical name in that case.
4093 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
4094
4095 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03004096 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08004097 'UnittestConvert',
4098 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004099 filter=lambda x: x.startswith('CONVERT_TEST_'))
4100 # Ensure that test_type has all of the desired names and values.
4101 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
4102 test_type.CONVERT_TEST_NAME_A)
4103 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
4104 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
4105 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
4106 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
4107 # Ensure that test_type only picked up names matching the filter.
4108 self.assertEqual([name for name in dir(test_type)
4109 if name[0:2] not in ('CO', '__')],
4110 [], msg='Names other than CONVERT_TEST_* found.')
4111
Ethan Furman6bd92882021-04-27 13:05:08 -07004112 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03004113 '_convert was deprecated in 3.8')
4114 def test_convert_warn(self):
4115 with self.assertWarns(DeprecationWarning):
4116 enum.IntEnum._convert(
4117 'UnittestConvert',
4118 ('test.test_enum', '__main__')[__name__=='__main__'],
4119 filter=lambda x: x.startswith('CONVERT_TEST_'))
4120
Ethan Furman6bd92882021-04-27 13:05:08 -07004121 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03004122 '_convert was removed in 3.9')
4123 def test_convert_raise(self):
4124 with self.assertRaises(AttributeError):
4125 enum.IntEnum._convert(
4126 'UnittestConvert',
4127 ('test.test_enum', '__main__')[__name__=='__main__'],
4128 filter=lambda x: x.startswith('CONVERT_TEST_'))
4129
Ethan Furmanb7751062021-03-30 21:17:26 -07004130 def test_convert_repr_and_str(self):
4131 module = ('test.test_enum', '__main__')[__name__=='__main__']
4132 test_type = enum.IntEnum._convert_(
4133 'UnittestConvert',
4134 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07004135 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
4136 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
4137 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman1b4addf2021-06-18 14:25:42 -07004138 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07004139
4140# global names for StrEnum._convert_ test
4141CONVERT_STR_TEST_2 = 'goodbye'
4142CONVERT_STR_TEST_1 = 'hello'
4143
4144class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04004145 def setUp(self):
4146 global CONVERT_STR_TEST_1
4147 global CONVERT_STR_TEST_2
4148 CONVERT_STR_TEST_2 = 'goodbye'
4149 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07004150
4151 def test_convert(self):
4152 test_type = enum.StrEnum._convert_(
4153 'UnittestConvert',
4154 ('test.test_enum', '__main__')[__name__=='__main__'],
4155 filter=lambda x: x.startswith('CONVERT_STR_'))
4156 # Ensure that test_type has all of the desired names and values.
4157 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
4158 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
4159 # Ensure that test_type only picked up names matching the filter.
4160 self.assertEqual([name for name in dir(test_type)
4161 if name[0:2] not in ('CO', '__')],
4162 [], msg='Names other than CONVERT_STR_* found.')
4163
4164 def test_convert_repr_and_str(self):
4165 module = ('test.test_enum', '__main__')[__name__=='__main__']
4166 test_type = enum.StrEnum._convert_(
4167 'UnittestConvert',
4168 module,
4169 filter=lambda x: x.startswith('CONVERT_STR_'))
4170 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
4171 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
4172 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
4173
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00004174
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004175if __name__ == '__main__':
4176 unittest.main()