blob: 983c54b8711991a1d776236711e55d6c65f3608f [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 Furman5875d742013-10-21 20:45:55 -070012from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080013from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000014from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030015from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080016from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080017from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080018
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080019def load_tests(loader, tests, ignore):
20 tests.addTests(doctest.DocTestSuite(enum))
Ethan Furman44e580f2021-03-03 09:54:30 -080021 if os.path.exists('Doc/library/enum.rst'):
Ethan Furman01faf452021-01-26 12:52:52 -080022 tests.addTests(doctest.DocFileSuite(
23 '../../Doc/library/enum.rst',
24 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
25 ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080026 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070027
28# for pickle tests
29try:
30 class Stooges(Enum):
31 LARRY = 1
32 CURLY = 2
33 MOE = 3
34except Exception as exc:
35 Stooges = exc
36
37try:
38 class IntStooges(int, Enum):
39 LARRY = 1
40 CURLY = 2
41 MOE = 3
42except Exception as exc:
43 IntStooges = exc
44
45try:
46 class FloatStooges(float, Enum):
47 LARRY = 1.39
48 CURLY = 2.72
49 MOE = 3.142596
50except Exception as exc:
51 FloatStooges = exc
52
Ethan Furman65a5a472016-09-01 23:55:19 -070053try:
54 class FlagStooges(Flag):
55 LARRY = 1
56 CURLY = 2
57 MOE = 3
58except Exception as exc:
59 FlagStooges = exc
60
Ethan Furman6b3d64a2013-06-14 16:55:46 -070061# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070062class Name(StrEnum):
63 BDFL = 'Guido van Rossum'
64 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070065
66try:
67 Question = Enum('Question', 'who what when where why', module=__name__)
68except Exception as exc:
69 Question = exc
70
71try:
72 Answer = Enum('Answer', 'him this then there because')
73except Exception as exc:
74 Answer = exc
75
Ethan Furmanca1b7942014-02-08 11:36:27 -080076try:
77 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
78except Exception as exc:
79 Theory = exc
80
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081# for doctests
82try:
83 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080084 TOMATO = 1
85 BANANA = 2
86 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070087except Exception:
88 pass
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 if target is None:
92 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030093 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080094 assertion(loads(dumps(source, protocol=protocol)), target)
95
Serhiy Storchakae50e7802015-03-31 16:56:49 +030096def test_pickle_exception(assertion, exception, obj):
97 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080098 with assertion(exception):
99 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -0700100
101class TestHelpers(unittest.TestCase):
102 # _is_descriptor, _is_sunder, _is_dunder
103
104 def test_is_descriptor(self):
105 class foo:
106 pass
107 for attr in ('__get__','__set__','__delete__'):
108 obj = foo()
109 self.assertFalse(enum._is_descriptor(obj))
110 setattr(obj, attr, 1)
111 self.assertTrue(enum._is_descriptor(obj))
112
113 def test_is_sunder(self):
114 for s in ('_a_', '_aa_'):
115 self.assertTrue(enum._is_sunder(s))
116
117 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_sunder(s))
120
121 def test_is_dunder(self):
122 for s in ('__a__', '__aa__'):
123 self.assertTrue(enum._is_dunder(s))
124 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
125 '__', '___', '____', '_____',):
126 self.assertFalse(enum._is_dunder(s))
127
Ethan Furman5bdab642018-09-21 19:03:09 -0700128# for subclassing tests
129
130class classproperty:
131
132 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
133 self.fget = fget
134 self.fset = fset
135 self.fdel = fdel
136 if doc is None and fget is not None:
137 doc = fget.__doc__
138 self.__doc__ = doc
139
140 def __get__(self, instance, ownerclass):
141 return self.fget(ownerclass)
142
143
Ethan Furmanc16595e2016-09-10 23:36:59 -0700144# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700145
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700146class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800147
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700148 def setUp(self):
149 class Season(Enum):
150 SPRING = 1
151 SUMMER = 2
152 AUTUMN = 3
153 WINTER = 4
154 self.Season = Season
155
Ethan Furmanec15a822013-08-31 19:17:41 -0700156 class Konstants(float, Enum):
157 E = 2.7182818
158 PI = 3.1415926
159 TAU = 2 * PI
160 self.Konstants = Konstants
161
162 class Grades(IntEnum):
163 A = 5
164 B = 4
165 C = 3
166 D = 2
167 F = 0
168 self.Grades = Grades
169
170 class Directional(str, Enum):
171 EAST = 'east'
172 WEST = 'west'
173 NORTH = 'north'
174 SOUTH = 'south'
175 self.Directional = Directional
176
177 from datetime import date
178 class Holiday(date, Enum):
179 NEW_YEAR = 2013, 1, 1
180 IDES_OF_MARCH = 2013, 3, 15
181 self.Holiday = Holiday
182
Ethan Furman388a3922013-08-12 06:51:41 -0700183 def test_dir_on_class(self):
184 Season = self.Season
185 self.assertEqual(
186 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700188 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
189 )
190
191 def test_dir_on_item(self):
192 Season = self.Season
193 self.assertEqual(
194 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700195 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700196 )
197
Ethan Furmanc850f342013-09-15 16:59:35 -0700198 def test_dir_with_added_behavior(self):
199 class Test(Enum):
200 this = 'that'
201 these = 'those'
202 def wowser(self):
203 return ("Wowser! I'm %s!" % self.name)
204 self.assertEqual(
205 set(dir(Test)),
206 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
207 )
208 self.assertEqual(
209 set(dir(Test.this)),
210 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
211 )
212
Ethan Furman0ae550b2014-10-14 08:58:32 -0700213 def test_dir_on_sub_with_behavior_on_super(self):
214 # see issue22506
215 class SuperEnum(Enum):
216 def invisible(self):
217 return "did you see me?"
218 class SubEnum(SuperEnum):
219 sample = 5
220 self.assertEqual(
221 set(dir(SubEnum.sample)),
222 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
223 )
224
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200225 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
226 # see issue40084
227 class SuperEnum(IntEnum):
228 def __new__(cls, value, description=""):
229 obj = int.__new__(cls, value)
230 obj._value_ = value
231 obj.description = description
232 return obj
233 class SubEnum(SuperEnum):
234 sample = 5
235 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum_in_enum_out(self):
238 Season = self.Season
239 self.assertIs(Season(Season.WINTER), Season.WINTER)
240
241 def test_enum_value(self):
242 Season = self.Season
243 self.assertEqual(Season.SPRING.value, 1)
244
245 def test_intenum_value(self):
246 self.assertEqual(IntStooges.CURLY.value, 2)
247
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700248 def test_enum(self):
249 Season = self.Season
250 lst = list(Season)
251 self.assertEqual(len(lst), len(Season))
252 self.assertEqual(len(Season), 4, Season)
253 self.assertEqual(
254 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
255
256 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
257 e = Season(i)
258 self.assertEqual(e, getattr(Season, season))
259 self.assertEqual(e.value, i)
260 self.assertNotEqual(e, i)
261 self.assertEqual(e.name, season)
262 self.assertIn(e, Season)
263 self.assertIs(type(e), Season)
264 self.assertIsInstance(e, Season)
Ethan Furmanb7751062021-03-30 21:17:26 -0700265 self.assertEqual(str(e), season)
266 self.assertEqual(repr(e), 'Season.{0}'.format(season))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700267
268 def test_value_name(self):
269 Season = self.Season
270 self.assertEqual(Season.SPRING.name, 'SPRING')
271 self.assertEqual(Season.SPRING.value, 1)
272 with self.assertRaises(AttributeError):
273 Season.SPRING.name = 'invierno'
274 with self.assertRaises(AttributeError):
275 Season.SPRING.value = 2
276
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700277 def test_changing_member(self):
278 Season = self.Season
279 with self.assertRaises(AttributeError):
280 Season.WINTER = 'really cold'
281
Ethan Furman64a99722013-09-22 16:18:19 -0700282 def test_attribute_deletion(self):
283 class Season(Enum):
284 SPRING = 1
285 SUMMER = 2
286 AUTUMN = 3
287 WINTER = 4
288
289 def spam(cls):
290 pass
291
292 self.assertTrue(hasattr(Season, 'spam'))
293 del Season.spam
294 self.assertFalse(hasattr(Season, 'spam'))
295
296 with self.assertRaises(AttributeError):
297 del Season.SPRING
298 with self.assertRaises(AttributeError):
299 del Season.DRY
300 with self.assertRaises(AttributeError):
301 del Season.SPRING.name
302
Ethan Furman5de67b12016-04-13 23:52:09 -0700303 def test_bool_of_class(self):
304 class Empty(Enum):
305 pass
306 self.assertTrue(bool(Empty))
307
308 def test_bool_of_member(self):
309 class Count(Enum):
310 zero = 0
311 one = 1
312 two = 2
313 for member in Count:
314 self.assertTrue(bool(member))
315
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700316 def test_invalid_names(self):
317 with self.assertRaises(ValueError):
318 class Wrong(Enum):
319 mro = 9
320 with self.assertRaises(ValueError):
321 class Wrong(Enum):
322 _create_= 11
323 with self.assertRaises(ValueError):
324 class Wrong(Enum):
325 _get_mixins_ = 9
326 with self.assertRaises(ValueError):
327 class Wrong(Enum):
328 _find_new_ = 1
329 with self.assertRaises(ValueError):
330 class Wrong(Enum):
331 _any_name_ = 9
332
Ethan Furman6db1fd52015-09-17 21:49:12 -0700333 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800334 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700335 class Logic(Enum):
336 true = True
337 false = False
338 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800339 self.assertTrue(Logic.false)
340 # unless overridden
341 class RealLogic(Enum):
342 true = True
343 false = False
344 def __bool__(self):
345 return bool(self._value_)
346 self.assertTrue(RealLogic.true)
347 self.assertFalse(RealLogic.false)
348 # mixed Enums depend on mixed-in type
349 class IntLogic(int, Enum):
350 true = 1
351 false = 0
352 self.assertTrue(IntLogic.true)
353 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700354
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700355 def test_contains(self):
356 Season = self.Season
357 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530358 with self.assertRaises(TypeError):
359 3 in Season
360 with self.assertRaises(TypeError):
361 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700362
363 val = Season(3)
364 self.assertIn(val, Season)
365
366 class OtherEnum(Enum):
367 one = 1; two = 2
368 self.assertNotIn(OtherEnum.two, Season)
369
370 def test_comparisons(self):
371 Season = self.Season
372 with self.assertRaises(TypeError):
373 Season.SPRING < Season.WINTER
374 with self.assertRaises(TypeError):
375 Season.SPRING > 4
376
377 self.assertNotEqual(Season.SPRING, 1)
378
379 class Part(Enum):
380 SPRING = 1
381 CLIP = 2
382 BARREL = 3
383
384 self.assertNotEqual(Season.SPRING, Part.SPRING)
385 with self.assertRaises(TypeError):
386 Season.SPRING < Part.CLIP
387
388 def test_enum_duplicates(self):
389 class Season(Enum):
390 SPRING = 1
391 SUMMER = 2
392 AUTUMN = FALL = 3
393 WINTER = 4
394 ANOTHER_SPRING = 1
395 lst = list(Season)
396 self.assertEqual(
397 lst,
398 [Season.SPRING, Season.SUMMER,
399 Season.AUTUMN, Season.WINTER,
400 ])
401 self.assertIs(Season.FALL, Season.AUTUMN)
402 self.assertEqual(Season.FALL.value, 3)
403 self.assertEqual(Season.AUTUMN.value, 3)
404 self.assertIs(Season(3), Season.AUTUMN)
405 self.assertIs(Season(1), Season.SPRING)
406 self.assertEqual(Season.FALL.name, 'AUTUMN')
407 self.assertEqual(
408 [k for k,v in Season.__members__.items() if v.name != k],
409 ['FALL', 'ANOTHER_SPRING'],
410 )
411
Ethan Furman101e0742013-09-15 12:34:36 -0700412 def test_duplicate_name(self):
413 with self.assertRaises(TypeError):
414 class Color(Enum):
415 red = 1
416 green = 2
417 blue = 3
418 red = 4
419
420 with self.assertRaises(TypeError):
421 class Color(Enum):
422 red = 1
423 green = 2
424 blue = 3
425 def red(self):
426 return 'red'
427
428 with self.assertRaises(TypeError):
429 class Color(Enum):
430 @property
431 def red(self):
432 return 'redder'
433 red = 1
434 green = 2
435 blue = 3
436
Zackery Spytz2ec67522020-09-13 14:27:51 -0600437 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700438 with self.assertRaisesRegex(
439 ValueError,
Ethan Furmanb7751062021-03-30 21:17:26 -0700440 '_sunder_ names, such as ._bad_., are reserved',
Ethan Furman5a565b32020-09-15 12:27:06 -0700441 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600442 class Bad(Enum):
443 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700444
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700445 def test_enum_with_value_name(self):
446 class Huh(Enum):
447 name = 1
448 value = 2
449 self.assertEqual(
450 list(Huh),
451 [Huh.name, Huh.value],
452 )
453 self.assertIs(type(Huh.name), Huh)
454 self.assertEqual(Huh.name.name, 'name')
455 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700456
457 def test_format_enum(self):
458 Season = self.Season
459 self.assertEqual('{}'.format(Season.SPRING),
460 '{}'.format(str(Season.SPRING)))
461 self.assertEqual( '{:}'.format(Season.SPRING),
462 '{:}'.format(str(Season.SPRING)))
463 self.assertEqual('{:20}'.format(Season.SPRING),
464 '{:20}'.format(str(Season.SPRING)))
465 self.assertEqual('{:^20}'.format(Season.SPRING),
466 '{:^20}'.format(str(Season.SPRING)))
467 self.assertEqual('{:>20}'.format(Season.SPRING),
468 '{:>20}'.format(str(Season.SPRING)))
469 self.assertEqual('{:<20}'.format(Season.SPRING),
470 '{:<20}'.format(str(Season.SPRING)))
471
thatneat2f19e822019-07-04 11:28:37 -0700472 def test_str_override_enum(self):
473 class EnumWithStrOverrides(Enum):
474 one = auto()
475 two = auto()
476
477 def __str__(self):
478 return 'Str!'
479 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
480 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
481
482 def test_format_override_enum(self):
483 class EnumWithFormatOverride(Enum):
484 one = 1.0
485 two = 2.0
486 def __format__(self, spec):
487 return 'Format!!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700488 self.assertEqual(str(EnumWithFormatOverride.one), 'one')
thatneat2f19e822019-07-04 11:28:37 -0700489 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
490
491 def test_str_and_format_override_enum(self):
492 class EnumWithStrFormatOverrides(Enum):
493 one = auto()
494 two = auto()
495 def __str__(self):
496 return 'Str!'
497 def __format__(self, spec):
498 return 'Format!'
499 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
500 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
501
502 def test_str_override_mixin(self):
503 class MixinEnumWithStrOverride(float, Enum):
504 one = 1.0
505 two = 2.0
506 def __str__(self):
507 return 'Overridden!'
508 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
509 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
510
511 def test_str_and_format_override_mixin(self):
512 class MixinWithStrFormatOverrides(float, Enum):
513 one = 1.0
514 two = 2.0
515 def __str__(self):
516 return 'Str!'
517 def __format__(self, spec):
518 return 'Format!'
519 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
520 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
521
522 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700523 class TestFloat(float, Enum):
524 one = 1.0
525 two = 2.0
526 def __format__(self, spec):
527 return 'TestFloat success!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700528 self.assertEqual(str(TestFloat.one), 'one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700529 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
530
Ethan Furman5987b8c2021-04-26 22:42:57 -0700531 @unittest.skipUnless(
532 sys.version_info[:2] < (3, 12),
533 'mixin-format now uses member instead of member.value',
534 )
535 def test_mixin_format_warning(self):
536 with self.assertWarns(DeprecationWarning):
537 self.assertEqual(f'{self.Grades.B}', '4')
538
Ethan Furmanec15a822013-08-31 19:17:41 -0700539 def assertFormatIsValue(self, spec, member):
540 self.assertEqual(spec.format(member), spec.format(member.value))
541
542 def test_format_enum_date(self):
543 Holiday = self.Holiday
544 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
545 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
546 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
547 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
548 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
549 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
550 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
551 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
552
553 def test_format_enum_float(self):
554 Konstants = self.Konstants
555 self.assertFormatIsValue('{}', Konstants.TAU)
556 self.assertFormatIsValue('{:}', Konstants.TAU)
557 self.assertFormatIsValue('{:20}', Konstants.TAU)
558 self.assertFormatIsValue('{:^20}', Konstants.TAU)
559 self.assertFormatIsValue('{:>20}', Konstants.TAU)
560 self.assertFormatIsValue('{:<20}', Konstants.TAU)
561 self.assertFormatIsValue('{:n}', Konstants.TAU)
562 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
563 self.assertFormatIsValue('{:f}', Konstants.TAU)
564
565 def test_format_enum_int(self):
566 Grades = self.Grades
567 self.assertFormatIsValue('{}', Grades.C)
568 self.assertFormatIsValue('{:}', Grades.C)
569 self.assertFormatIsValue('{:20}', Grades.C)
570 self.assertFormatIsValue('{:^20}', Grades.C)
571 self.assertFormatIsValue('{:>20}', Grades.C)
572 self.assertFormatIsValue('{:<20}', Grades.C)
573 self.assertFormatIsValue('{:+}', Grades.C)
574 self.assertFormatIsValue('{:08X}', Grades.C)
575 self.assertFormatIsValue('{:b}', Grades.C)
576
577 def test_format_enum_str(self):
578 Directional = self.Directional
579 self.assertFormatIsValue('{}', Directional.WEST)
580 self.assertFormatIsValue('{:}', Directional.WEST)
581 self.assertFormatIsValue('{:20}', Directional.WEST)
582 self.assertFormatIsValue('{:^20}', Directional.WEST)
583 self.assertFormatIsValue('{:>20}', Directional.WEST)
584 self.assertFormatIsValue('{:<20}', Directional.WEST)
585
Ethan Furman22415ad2020-09-15 16:28:25 -0700586 def test_object_str_override(self):
587 class Colors(Enum):
588 RED, GREEN, BLUE = 1, 2, 3
589 def __repr__(self):
590 return "test.%s" % (self._name_, )
591 __str__ = object.__str__
592 self.assertEqual(str(Colors.RED), 'test.RED')
593
Ethan Furmanbff01f32020-09-15 15:56:26 -0700594 def test_enum_str_override(self):
595 class MyStrEnum(Enum):
596 def __str__(self):
597 return 'MyStr'
598 class MyMethodEnum(Enum):
599 def hello(self):
600 return 'Hello! My name is %s' % self.name
601 class Test1Enum(MyMethodEnum, int, MyStrEnum):
602 One = 1
603 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800604 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700605 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800606 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700607 #
608 class Test2Enum(MyStrEnum, MyMethodEnum):
609 One = 1
610 Two = 2
611 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800612 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700613
614 def test_inherited_data_type(self):
615 class HexInt(int):
616 def __repr__(self):
617 return hex(self)
618 class MyEnum(HexInt, enum.Enum):
619 A = 1
620 B = 2
621 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700622 def __repr__(self):
623 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700624 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
625
626 def test_too_many_data_types(self):
627 with self.assertRaisesRegex(TypeError, 'too many data types'):
628 class Huh(str, int, Enum):
629 One = 1
630
631 class MyStr(str):
632 def hello(self):
633 return 'hello, %s' % self
634 class MyInt(int):
635 def repr(self):
636 return hex(self)
637 with self.assertRaisesRegex(TypeError, 'too many data types'):
638 class Huh(MyStr, MyInt, Enum):
639 One = 1
640
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700641 def test_hash(self):
642 Season = self.Season
643 dates = {}
644 dates[Season.WINTER] = '1225'
645 dates[Season.SPRING] = '0315'
646 dates[Season.SUMMER] = '0704'
647 dates[Season.AUTUMN] = '1031'
648 self.assertEqual(dates[Season.AUTUMN], '1031')
649
650 def test_intenum_from_scratch(self):
651 class phy(int, Enum):
652 pi = 3
653 tau = 2 * pi
654 self.assertTrue(phy.pi < phy.tau)
655
656 def test_intenum_inherited(self):
657 class IntEnum(int, Enum):
658 pass
659 class phy(IntEnum):
660 pi = 3
661 tau = 2 * pi
662 self.assertTrue(phy.pi < phy.tau)
663
664 def test_floatenum_from_scratch(self):
665 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700666 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 tau = 2 * pi
668 self.assertTrue(phy.pi < phy.tau)
669
670 def test_floatenum_inherited(self):
671 class FloatEnum(float, Enum):
672 pass
673 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700674 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700675 tau = 2 * pi
676 self.assertTrue(phy.pi < phy.tau)
677
678 def test_strenum_from_scratch(self):
679 class phy(str, Enum):
680 pi = 'Pi'
681 tau = 'Tau'
682 self.assertTrue(phy.pi < phy.tau)
683
Ethan Furman0063ff42020-09-21 17:23:13 -0700684 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700685 class phy(StrEnum):
686 pi = 'Pi'
687 tau = 'Tau'
688 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700689 self.assertEqual(phy.pi.upper(), 'PI')
690 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700691
692 def test_intenum(self):
693 class WeekDay(IntEnum):
694 SUNDAY = 1
695 MONDAY = 2
696 TUESDAY = 3
697 WEDNESDAY = 4
698 THURSDAY = 5
699 FRIDAY = 6
700 SATURDAY = 7
701
702 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
703 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
704
705 lst = list(WeekDay)
706 self.assertEqual(len(lst), len(WeekDay))
707 self.assertEqual(len(WeekDay), 7)
708 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
709 target = target.split()
710 for i, weekday in enumerate(target, 1):
711 e = WeekDay(i)
712 self.assertEqual(e, i)
713 self.assertEqual(int(e), i)
714 self.assertEqual(e.name, weekday)
715 self.assertIn(e, WeekDay)
716 self.assertEqual(lst.index(e)+1, i)
717 self.assertTrue(0 < e < 8)
718 self.assertIs(type(e), WeekDay)
719 self.assertIsInstance(e, int)
720 self.assertIsInstance(e, Enum)
721
722 def test_intenum_duplicates(self):
723 class WeekDay(IntEnum):
724 SUNDAY = 1
725 MONDAY = 2
726 TUESDAY = TEUSDAY = 3
727 WEDNESDAY = 4
728 THURSDAY = 5
729 FRIDAY = 6
730 SATURDAY = 7
731 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
732 self.assertEqual(WeekDay(3).name, 'TUESDAY')
733 self.assertEqual([k for k,v in WeekDay.__members__.items()
734 if v.name != k], ['TEUSDAY', ])
735
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300736 def test_intenum_from_bytes(self):
737 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
738 with self.assertRaises(ValueError):
739 IntStooges.from_bytes(b'\x00\x05', 'big')
740
741 def test_floatenum_fromhex(self):
742 h = float.hex(FloatStooges.MOE.value)
743 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
744 h = float.hex(FloatStooges.MOE.value + 0.01)
745 with self.assertRaises(ValueError):
746 FloatStooges.fromhex(h)
747
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700748 def test_pickle_enum(self):
749 if isinstance(Stooges, Exception):
750 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800751 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
752 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700753
754 def test_pickle_int(self):
755 if isinstance(IntStooges, Exception):
756 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800757 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
758 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700759
760 def test_pickle_float(self):
761 if isinstance(FloatStooges, Exception):
762 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800763 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
764 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700765
766 def test_pickle_enum_function(self):
767 if isinstance(Answer, Exception):
768 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800769 test_pickle_dump_load(self.assertIs, Answer.him)
770 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700771
772 def test_pickle_enum_function_with_module(self):
773 if isinstance(Question, Exception):
774 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800775 test_pickle_dump_load(self.assertIs, Question.who)
776 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700777
Ethan Furmanca1b7942014-02-08 11:36:27 -0800778 def test_enum_function_with_qualname(self):
779 if isinstance(Theory, Exception):
780 raise Theory
781 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
782
783 def test_class_nested_enum_and_pickle_protocol_four(self):
784 # would normally just have this directly in the class namespace
785 class NestedEnum(Enum):
786 twigs = 'common'
787 shiny = 'rare'
788
789 self.__class__.NestedEnum = NestedEnum
790 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300791 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800792
Ethan Furman24e837f2015-03-18 17:27:57 -0700793 def test_pickle_by_name(self):
794 class ReplaceGlobalInt(IntEnum):
795 ONE = 1
796 TWO = 2
797 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
798 for proto in range(HIGHEST_PROTOCOL):
799 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
800
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700801 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800802 BadPickle = Enum(
803 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700804 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800805 # now break BadPickle to test exception raising
806 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800807 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
808 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700809
810 def test_string_enum(self):
811 class SkillLevel(str, Enum):
812 master = 'what is the sound of one hand clapping?'
813 journeyman = 'why did the chicken cross the road?'
814 apprentice = 'knock, knock!'
815 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
816
817 def test_getattr_getitem(self):
818 class Period(Enum):
819 morning = 1
820 noon = 2
821 evening = 3
822 night = 4
823 self.assertIs(Period(2), Period.noon)
824 self.assertIs(getattr(Period, 'night'), Period.night)
825 self.assertIs(Period['morning'], Period.morning)
826
827 def test_getattr_dunder(self):
828 Season = self.Season
829 self.assertTrue(getattr(Season, '__eq__'))
830
831 def test_iteration_order(self):
832 class Season(Enum):
833 SUMMER = 2
834 WINTER = 4
835 AUTUMN = 3
836 SPRING = 1
837 self.assertEqual(
838 list(Season),
839 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
840 )
841
Ethan Furman2131a4a2013-09-14 18:11:24 -0700842 def test_reversed_iteration_order(self):
843 self.assertEqual(
844 list(reversed(self.Season)),
845 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
846 self.Season.SPRING]
847 )
848
Martin Pantereb995702016-07-28 01:11:04 +0000849 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700850 SummerMonth = Enum('SummerMonth', 'june july august')
851 lst = list(SummerMonth)
852 self.assertEqual(len(lst), len(SummerMonth))
853 self.assertEqual(len(SummerMonth), 3, SummerMonth)
854 self.assertEqual(
855 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
856 lst,
857 )
858 for i, month in enumerate('june july august'.split(), 1):
859 e = SummerMonth(i)
860 self.assertEqual(int(e.value), i)
861 self.assertNotEqual(e, i)
862 self.assertEqual(e.name, month)
863 self.assertIn(e, SummerMonth)
864 self.assertIs(type(e), SummerMonth)
865
Martin Pantereb995702016-07-28 01:11:04 +0000866 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700867 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
868 lst = list(SummerMonth)
869 self.assertEqual(len(lst), len(SummerMonth))
870 self.assertEqual(len(SummerMonth), 3, SummerMonth)
871 self.assertEqual(
872 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
873 lst,
874 )
875 for i, month in enumerate('june july august'.split(), 10):
876 e = SummerMonth(i)
877 self.assertEqual(int(e.value), i)
878 self.assertNotEqual(e, i)
879 self.assertEqual(e.name, month)
880 self.assertIn(e, SummerMonth)
881 self.assertIs(type(e), SummerMonth)
882
Martin Pantereb995702016-07-28 01:11:04 +0000883 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700884 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
885 lst = list(SummerMonth)
886 self.assertEqual(len(lst), len(SummerMonth))
887 self.assertEqual(len(SummerMonth), 3, SummerMonth)
888 self.assertEqual(
889 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
890 lst,
891 )
892 for i, month in enumerate('june july august'.split(), 1):
893 e = SummerMonth(i)
894 self.assertEqual(int(e.value), i)
895 self.assertNotEqual(e, i)
896 self.assertEqual(e.name, month)
897 self.assertIn(e, SummerMonth)
898 self.assertIs(type(e), SummerMonth)
899
Martin Pantereb995702016-07-28 01:11:04 +0000900 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700901 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
902 lst = list(SummerMonth)
903 self.assertEqual(len(lst), len(SummerMonth))
904 self.assertEqual(len(SummerMonth), 3, SummerMonth)
905 self.assertEqual(
906 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
907 lst,
908 )
909 for i, month in enumerate('june july august'.split(), 20):
910 e = SummerMonth(i)
911 self.assertEqual(int(e.value), i)
912 self.assertNotEqual(e, i)
913 self.assertEqual(e.name, month)
914 self.assertIn(e, SummerMonth)
915 self.assertIs(type(e), SummerMonth)
916
Martin Pantereb995702016-07-28 01:11:04 +0000917 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700918 SummerMonth = Enum(
919 'SummerMonth',
920 (('june', 1), ('july', 2), ('august', 3))
921 )
922 lst = list(SummerMonth)
923 self.assertEqual(len(lst), len(SummerMonth))
924 self.assertEqual(len(SummerMonth), 3, SummerMonth)
925 self.assertEqual(
926 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
927 lst,
928 )
929 for i, month in enumerate('june july august'.split(), 1):
930 e = SummerMonth(i)
931 self.assertEqual(int(e.value), i)
932 self.assertNotEqual(e, i)
933 self.assertEqual(e.name, month)
934 self.assertIn(e, SummerMonth)
935 self.assertIs(type(e), SummerMonth)
936
Martin Pantereb995702016-07-28 01:11:04 +0000937 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700938 SummerMonth = Enum(
939 'SummerMonth',
940 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
941 )
942 lst = list(SummerMonth)
943 self.assertEqual(len(lst), len(SummerMonth))
944 self.assertEqual(len(SummerMonth), 3, SummerMonth)
945 self.assertEqual(
946 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
947 lst,
948 )
949 for i, month in enumerate('june july august'.split(), 1):
950 e = SummerMonth(i)
951 self.assertEqual(int(e.value), i)
952 self.assertNotEqual(e, i)
953 self.assertEqual(e.name, month)
954 self.assertIn(e, SummerMonth)
955 self.assertIs(type(e), SummerMonth)
956
Martin Pantereb995702016-07-28 01:11:04 +0000957 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700958 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
959 lst = list(SummerMonth)
960 self.assertEqual(len(lst), len(SummerMonth))
961 self.assertEqual(len(SummerMonth), 3, SummerMonth)
962 self.assertEqual(
963 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
964 lst,
965 )
966 for i, month in enumerate('june july august'.split(), 1):
967 e = SummerMonth(i)
968 self.assertEqual(e, i)
969 self.assertEqual(e.name, month)
970 self.assertIn(e, SummerMonth)
971 self.assertIs(type(e), SummerMonth)
972
Martin Pantereb995702016-07-28 01:11:04 +0000973 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700974 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
975 lst = list(SummerMonth)
976 self.assertEqual(len(lst), len(SummerMonth))
977 self.assertEqual(len(SummerMonth), 3, SummerMonth)
978 self.assertEqual(
979 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
980 lst,
981 )
982 for i, month in enumerate('june july august'.split(), 30):
983 e = SummerMonth(i)
984 self.assertEqual(e, i)
985 self.assertEqual(e.name, month)
986 self.assertIn(e, SummerMonth)
987 self.assertIs(type(e), SummerMonth)
988
Martin Pantereb995702016-07-28 01:11:04 +0000989 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700990 SummerMonth = IntEnum('SummerMonth', 'june july august')
991 lst = list(SummerMonth)
992 self.assertEqual(len(lst), len(SummerMonth))
993 self.assertEqual(len(SummerMonth), 3, SummerMonth)
994 self.assertEqual(
995 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
996 lst,
997 )
998 for i, month in enumerate('june july august'.split(), 1):
999 e = SummerMonth(i)
1000 self.assertEqual(e, i)
1001 self.assertEqual(e.name, month)
1002 self.assertIn(e, SummerMonth)
1003 self.assertIs(type(e), SummerMonth)
1004
Martin Pantereb995702016-07-28 01:11:04 +00001005 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001006 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1007 lst = list(SummerMonth)
1008 self.assertEqual(len(lst), len(SummerMonth))
1009 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1010 self.assertEqual(
1011 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1012 lst,
1013 )
1014 for i, month in enumerate('june july august'.split(), 40):
1015 e = SummerMonth(i)
1016 self.assertEqual(e, i)
1017 self.assertEqual(e.name, month)
1018 self.assertIn(e, SummerMonth)
1019 self.assertIs(type(e), SummerMonth)
1020
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001021 def test_subclassing(self):
1022 if isinstance(Name, Exception):
1023 raise Name
1024 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1025 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1026 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001027 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001028
1029 def test_extending(self):
1030 class Color(Enum):
1031 red = 1
1032 green = 2
1033 blue = 3
1034 with self.assertRaises(TypeError):
1035 class MoreColor(Color):
1036 cyan = 4
1037 magenta = 5
1038 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001039 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1040 class EvenMoreColor(Color, IntEnum):
1041 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001042
1043 def test_exclude_methods(self):
1044 class whatever(Enum):
1045 this = 'that'
1046 these = 'those'
1047 def really(self):
1048 return 'no, not %s' % self.value
1049 self.assertIsNot(type(whatever.really), whatever)
1050 self.assertEqual(whatever.this.really(), 'no, not that')
1051
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001052 def test_wrong_inheritance_order(self):
1053 with self.assertRaises(TypeError):
1054 class Wrong(Enum, str):
1055 NotHere = 'error before this point'
1056
1057 def test_intenum_transitivity(self):
1058 class number(IntEnum):
1059 one = 1
1060 two = 2
1061 three = 3
1062 class numero(IntEnum):
1063 uno = 1
1064 dos = 2
1065 tres = 3
1066 self.assertEqual(number.one, numero.uno)
1067 self.assertEqual(number.two, numero.dos)
1068 self.assertEqual(number.three, numero.tres)
1069
1070 def test_wrong_enum_in_call(self):
1071 class Monochrome(Enum):
1072 black = 0
1073 white = 1
1074 class Gender(Enum):
1075 male = 0
1076 female = 1
1077 self.assertRaises(ValueError, Monochrome, Gender.male)
1078
1079 def test_wrong_enum_in_mixed_call(self):
1080 class Monochrome(IntEnum):
1081 black = 0
1082 white = 1
1083 class Gender(Enum):
1084 male = 0
1085 female = 1
1086 self.assertRaises(ValueError, Monochrome, Gender.male)
1087
1088 def test_mixed_enum_in_call_1(self):
1089 class Monochrome(IntEnum):
1090 black = 0
1091 white = 1
1092 class Gender(IntEnum):
1093 male = 0
1094 female = 1
1095 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1096
1097 def test_mixed_enum_in_call_2(self):
1098 class Monochrome(Enum):
1099 black = 0
1100 white = 1
1101 class Gender(IntEnum):
1102 male = 0
1103 female = 1
1104 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1105
1106 def test_flufl_enum(self):
1107 class Fluflnum(Enum):
1108 def __int__(self):
1109 return int(self.value)
1110 class MailManOptions(Fluflnum):
1111 option1 = 1
1112 option2 = 2
1113 option3 = 3
1114 self.assertEqual(int(MailManOptions.option1), 1)
1115
Ethan Furman5e5a8232013-08-04 08:42:23 -07001116 def test_introspection(self):
1117 class Number(IntEnum):
1118 one = 100
1119 two = 200
1120 self.assertIs(Number.one._member_type_, int)
1121 self.assertIs(Number._member_type_, int)
1122 class String(str, Enum):
1123 yarn = 'soft'
1124 rope = 'rough'
1125 wire = 'hard'
1126 self.assertIs(String.yarn._member_type_, str)
1127 self.assertIs(String._member_type_, str)
1128 class Plain(Enum):
1129 vanilla = 'white'
1130 one = 1
1131 self.assertIs(Plain.vanilla._member_type_, object)
1132 self.assertIs(Plain._member_type_, object)
1133
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001134 def test_no_such_enum_member(self):
1135 class Color(Enum):
1136 red = 1
1137 green = 2
1138 blue = 3
1139 with self.assertRaises(ValueError):
1140 Color(4)
1141 with self.assertRaises(KeyError):
1142 Color['chartreuse']
1143
1144 def test_new_repr(self):
1145 class Color(Enum):
1146 red = 1
1147 green = 2
1148 blue = 3
1149 def __repr__(self):
1150 return "don't you just love shades of %s?" % self.name
1151 self.assertEqual(
1152 repr(Color.blue),
1153 "don't you just love shades of blue?",
1154 )
1155
1156 def test_inherited_repr(self):
1157 class MyEnum(Enum):
1158 def __repr__(self):
1159 return "My name is %s." % self.name
1160 class MyIntEnum(int, MyEnum):
1161 this = 1
1162 that = 2
1163 theother = 3
1164 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1165
1166 def test_multiple_mixin_mro(self):
1167 class auto_enum(type(Enum)):
1168 def __new__(metacls, cls, bases, classdict):
1169 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001170 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001171 names = set(classdict._member_names)
1172 i = 0
1173 for k in classdict._member_names:
1174 v = classdict[k]
1175 if v is Ellipsis:
1176 v = i
1177 else:
1178 i = v
1179 i += 1
1180 temp[k] = v
1181 for k, v in classdict.items():
1182 if k not in names:
1183 temp[k] = v
1184 return super(auto_enum, metacls).__new__(
1185 metacls, cls, bases, temp)
1186
1187 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1188 pass
1189
1190 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1191 pass
1192
1193 class TestAutoNumber(AutoNumberedEnum):
1194 a = ...
1195 b = 3
1196 c = ...
1197
1198 class TestAutoInt(AutoIntEnum):
1199 a = ...
1200 b = 3
1201 c = ...
1202
1203 def test_subclasses_with_getnewargs(self):
1204 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001205 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001206 def __new__(cls, *args):
1207 _args = args
1208 name, *args = args
1209 if len(args) == 0:
1210 raise TypeError("name and value must be specified")
1211 self = int.__new__(cls, *args)
1212 self._intname = name
1213 self._args = _args
1214 return self
1215 def __getnewargs__(self):
1216 return self._args
1217 @property
1218 def __name__(self):
1219 return self._intname
1220 def __repr__(self):
1221 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001222 return "{}({!r}, {})".format(
1223 type(self).__name__,
1224 self.__name__,
1225 int.__repr__(self),
1226 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001227 def __str__(self):
1228 # str() is unchanged, even if it relies on the repr() fallback
1229 base = int
1230 base_str = base.__str__
1231 if base_str.__objclass__ is object:
1232 return base.__repr__(self)
1233 return base_str(self)
1234 # for simplicity, we only define one operator that
1235 # propagates expressions
1236 def __add__(self, other):
1237 temp = int(self) + int( other)
1238 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1239 return NamedInt(
1240 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001241 temp,
1242 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243 else:
1244 return temp
1245
1246 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001247 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001248 x = ('the-x', 1)
1249 y = ('the-y', 2)
1250
Ethan Furman2aa27322013-07-19 19:35:56 -07001251
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001252 self.assertIs(NEI.__new__, Enum.__new__)
1253 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1254 globals()['NamedInt'] = NamedInt
1255 globals()['NEI'] = NEI
1256 NI5 = NamedInt('test', 5)
1257 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001258 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001259 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001260 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001261 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001262
Ethan Furmanca1b7942014-02-08 11:36:27 -08001263 def test_subclasses_with_getnewargs_ex(self):
1264 class NamedInt(int):
1265 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1266 def __new__(cls, *args):
1267 _args = args
1268 name, *args = args
1269 if len(args) == 0:
1270 raise TypeError("name and value must be specified")
1271 self = int.__new__(cls, *args)
1272 self._intname = name
1273 self._args = _args
1274 return self
1275 def __getnewargs_ex__(self):
1276 return self._args, {}
1277 @property
1278 def __name__(self):
1279 return self._intname
1280 def __repr__(self):
1281 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001282 return "{}({!r}, {})".format(
1283 type(self).__name__,
1284 self.__name__,
1285 int.__repr__(self),
1286 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001287 def __str__(self):
1288 # str() is unchanged, even if it relies on the repr() fallback
1289 base = int
1290 base_str = base.__str__
1291 if base_str.__objclass__ is object:
1292 return base.__repr__(self)
1293 return base_str(self)
1294 # for simplicity, we only define one operator that
1295 # propagates expressions
1296 def __add__(self, other):
1297 temp = int(self) + int( other)
1298 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1299 return NamedInt(
1300 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001301 temp,
1302 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001303 else:
1304 return temp
1305
1306 class NEI(NamedInt, Enum):
1307 __qualname__ = 'NEI' # needed for pickle protocol 4
1308 x = ('the-x', 1)
1309 y = ('the-y', 2)
1310
1311
1312 self.assertIs(NEI.__new__, Enum.__new__)
1313 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1314 globals()['NamedInt'] = NamedInt
1315 globals()['NEI'] = NEI
1316 NI5 = NamedInt('test', 5)
1317 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001318 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001319 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001320 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001321 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001322
1323 def test_subclasses_with_reduce(self):
1324 class NamedInt(int):
1325 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1326 def __new__(cls, *args):
1327 _args = args
1328 name, *args = args
1329 if len(args) == 0:
1330 raise TypeError("name and value must be specified")
1331 self = int.__new__(cls, *args)
1332 self._intname = name
1333 self._args = _args
1334 return self
1335 def __reduce__(self):
1336 return self.__class__, self._args
1337 @property
1338 def __name__(self):
1339 return self._intname
1340 def __repr__(self):
1341 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001342 return "{}({!r}, {})".format(
1343 type(self).__name__,
1344 self.__name__,
1345 int.__repr__(self),
1346 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001347 def __str__(self):
1348 # str() is unchanged, even if it relies on the repr() fallback
1349 base = int
1350 base_str = base.__str__
1351 if base_str.__objclass__ is object:
1352 return base.__repr__(self)
1353 return base_str(self)
1354 # for simplicity, we only define one operator that
1355 # propagates expressions
1356 def __add__(self, other):
1357 temp = int(self) + int( other)
1358 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1359 return NamedInt(
1360 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001361 temp,
1362 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001363 else:
1364 return temp
1365
1366 class NEI(NamedInt, Enum):
1367 __qualname__ = 'NEI' # needed for pickle protocol 4
1368 x = ('the-x', 1)
1369 y = ('the-y', 2)
1370
1371
1372 self.assertIs(NEI.__new__, Enum.__new__)
1373 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1374 globals()['NamedInt'] = NamedInt
1375 globals()['NEI'] = NEI
1376 NI5 = NamedInt('test', 5)
1377 self.assertEqual(NI5, 5)
1378 test_pickle_dump_load(self.assertEqual, NI5, 5)
1379 self.assertEqual(NEI.y.value, 2)
1380 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001381 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001382
1383 def test_subclasses_with_reduce_ex(self):
1384 class NamedInt(int):
1385 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1386 def __new__(cls, *args):
1387 _args = args
1388 name, *args = args
1389 if len(args) == 0:
1390 raise TypeError("name and value must be specified")
1391 self = int.__new__(cls, *args)
1392 self._intname = name
1393 self._args = _args
1394 return self
1395 def __reduce_ex__(self, proto):
1396 return self.__class__, self._args
1397 @property
1398 def __name__(self):
1399 return self._intname
1400 def __repr__(self):
1401 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001402 return "{}({!r}, {})".format(
1403 type(self).__name__,
1404 self.__name__,
1405 int.__repr__(self),
1406 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001407 def __str__(self):
1408 # str() is unchanged, even if it relies on the repr() fallback
1409 base = int
1410 base_str = base.__str__
1411 if base_str.__objclass__ is object:
1412 return base.__repr__(self)
1413 return base_str(self)
1414 # for simplicity, we only define one operator that
1415 # propagates expressions
1416 def __add__(self, other):
1417 temp = int(self) + int( other)
1418 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1419 return NamedInt(
1420 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001421 temp,
1422 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001423 else:
1424 return temp
1425
1426 class NEI(NamedInt, Enum):
1427 __qualname__ = 'NEI' # needed for pickle protocol 4
1428 x = ('the-x', 1)
1429 y = ('the-y', 2)
1430
Ethan Furmanca1b7942014-02-08 11:36:27 -08001431 self.assertIs(NEI.__new__, Enum.__new__)
1432 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1433 globals()['NamedInt'] = NamedInt
1434 globals()['NEI'] = NEI
1435 NI5 = NamedInt('test', 5)
1436 self.assertEqual(NI5, 5)
1437 test_pickle_dump_load(self.assertEqual, NI5, 5)
1438 self.assertEqual(NEI.y.value, 2)
1439 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001440 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001441
Ethan Furmandc870522014-02-18 12:37:12 -08001442 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001443 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001444 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001445 def __new__(cls, *args):
1446 _args = args
1447 name, *args = args
1448 if len(args) == 0:
1449 raise TypeError("name and value must be specified")
1450 self = int.__new__(cls, *args)
1451 self._intname = name
1452 self._args = _args
1453 return self
1454 @property
1455 def __name__(self):
1456 return self._intname
1457 def __repr__(self):
1458 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001459 return "{}({!r}, {})".format(
1460 type(self).__name__,
1461 self.__name__,
1462 int.__repr__(self),
1463 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001464 def __str__(self):
1465 # str() is unchanged, even if it relies on the repr() fallback
1466 base = int
1467 base_str = base.__str__
1468 if base_str.__objclass__ is object:
1469 return base.__repr__(self)
1470 return base_str(self)
1471 # for simplicity, we only define one operator that
1472 # propagates expressions
1473 def __add__(self, other):
1474 temp = int(self) + int( other)
1475 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1476 return NamedInt(
1477 '({0} + {1})'.format(self.__name__, other.__name__),
1478 temp )
1479 else:
1480 return temp
1481
1482 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001483 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001484 x = ('the-x', 1)
1485 y = ('the-y', 2)
1486
1487 self.assertIs(NEI.__new__, Enum.__new__)
1488 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1489 globals()['NamedInt'] = NamedInt
1490 globals()['NEI'] = NEI
1491 NI5 = NamedInt('test', 5)
1492 self.assertEqual(NI5, 5)
1493 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001494 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1495 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001496
Ethan Furmandc870522014-02-18 12:37:12 -08001497 def test_subclasses_without_direct_pickle_support_using_name(self):
1498 class NamedInt(int):
1499 __qualname__ = 'NamedInt'
1500 def __new__(cls, *args):
1501 _args = args
1502 name, *args = args
1503 if len(args) == 0:
1504 raise TypeError("name and value must be specified")
1505 self = int.__new__(cls, *args)
1506 self._intname = name
1507 self._args = _args
1508 return self
1509 @property
1510 def __name__(self):
1511 return self._intname
1512 def __repr__(self):
1513 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001514 return "{}({!r}, {})".format(
1515 type(self).__name__,
1516 self.__name__,
1517 int.__repr__(self),
1518 )
Ethan Furmandc870522014-02-18 12:37:12 -08001519 def __str__(self):
1520 # str() is unchanged, even if it relies on the repr() fallback
1521 base = int
1522 base_str = base.__str__
1523 if base_str.__objclass__ is object:
1524 return base.__repr__(self)
1525 return base_str(self)
1526 # for simplicity, we only define one operator that
1527 # propagates expressions
1528 def __add__(self, other):
1529 temp = int(self) + int( other)
1530 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1531 return NamedInt(
1532 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001533 temp,
1534 )
Ethan Furmandc870522014-02-18 12:37:12 -08001535 else:
1536 return temp
1537
1538 class NEI(NamedInt, Enum):
1539 __qualname__ = 'NEI'
1540 x = ('the-x', 1)
1541 y = ('the-y', 2)
1542 def __reduce_ex__(self, proto):
1543 return getattr, (self.__class__, self._name_)
1544
1545 self.assertIs(NEI.__new__, Enum.__new__)
1546 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1547 globals()['NamedInt'] = NamedInt
1548 globals()['NEI'] = NEI
1549 NI5 = NamedInt('test', 5)
1550 self.assertEqual(NI5, 5)
1551 self.assertEqual(NEI.y.value, 2)
1552 test_pickle_dump_load(self.assertIs, NEI.y)
1553 test_pickle_dump_load(self.assertIs, NEI)
1554
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001555 def test_tuple_subclass(self):
1556 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001557 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558 first = (1, 'for the money')
1559 second = (2, 'for the show')
1560 third = (3, 'for the music')
1561 self.assertIs(type(SomeTuple.first), SomeTuple)
1562 self.assertIsInstance(SomeTuple.second, tuple)
1563 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1564 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001565 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001566
1567 def test_duplicate_values_give_unique_enum_items(self):
1568 class AutoNumber(Enum):
1569 first = ()
1570 second = ()
1571 third = ()
1572 def __new__(cls):
1573 value = len(cls.__members__) + 1
1574 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001575 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001576 return obj
1577 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001578 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001579 self.assertEqual(
1580 list(AutoNumber),
1581 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1582 )
1583 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001584 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001585 self.assertIs(AutoNumber(1), AutoNumber.first)
1586
1587 def test_inherited_new_from_enhanced_enum(self):
1588 class AutoNumber(Enum):
1589 def __new__(cls):
1590 value = len(cls.__members__) + 1
1591 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001592 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001593 return obj
1594 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001595 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001596 class Color(AutoNumber):
1597 red = ()
1598 green = ()
1599 blue = ()
1600 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1601 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1602
1603 def test_inherited_new_from_mixed_enum(self):
1604 class AutoNumber(IntEnum):
1605 def __new__(cls):
1606 value = len(cls.__members__) + 1
1607 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001608 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001609 return obj
1610 class Color(AutoNumber):
1611 red = ()
1612 green = ()
1613 blue = ()
1614 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1615 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1616
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001617 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001618 class OrdinaryEnum(Enum):
1619 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001620 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1621 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001622
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001623 def test_ordered_mixin(self):
1624 class OrderedEnum(Enum):
1625 def __ge__(self, other):
1626 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001627 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001628 return NotImplemented
1629 def __gt__(self, other):
1630 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001631 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001632 return NotImplemented
1633 def __le__(self, other):
1634 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001635 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001636 return NotImplemented
1637 def __lt__(self, other):
1638 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001639 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001640 return NotImplemented
1641 class Grade(OrderedEnum):
1642 A = 5
1643 B = 4
1644 C = 3
1645 D = 2
1646 F = 1
1647 self.assertGreater(Grade.A, Grade.B)
1648 self.assertLessEqual(Grade.F, Grade.C)
1649 self.assertLess(Grade.D, Grade.A)
1650 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001651 self.assertEqual(Grade.B, Grade.B)
1652 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001653
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001654 def test_extending2(self):
1655 class Shade(Enum):
1656 def shade(self):
1657 print(self.name)
1658 class Color(Shade):
1659 red = 1
1660 green = 2
1661 blue = 3
1662 with self.assertRaises(TypeError):
1663 class MoreColor(Color):
1664 cyan = 4
1665 magenta = 5
1666 yellow = 6
1667
1668 def test_extending3(self):
1669 class Shade(Enum):
1670 def shade(self):
1671 return self.name
1672 class Color(Shade):
1673 def hex(self):
1674 return '%s hexlified!' % self.value
1675 class MoreColor(Color):
1676 cyan = 4
1677 magenta = 5
1678 yellow = 6
1679 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1680
orlnub1230fb9fad2018-09-12 20:28:53 +03001681 def test_subclass_duplicate_name(self):
1682 class Base(Enum):
1683 def test(self):
1684 pass
1685 class Test(Base):
1686 test = 1
1687 self.assertIs(type(Test.test), Test)
1688
1689 def test_subclass_duplicate_name_dynamic(self):
1690 from types import DynamicClassAttribute
1691 class Base(Enum):
1692 @DynamicClassAttribute
1693 def test(self):
1694 return 'dynamic'
1695 class Test(Base):
1696 test = 1
1697 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001698 class Base2(Enum):
1699 @enum.property
1700 def flash(self):
1701 return 'flashy dynamic'
1702 class Test(Base2):
1703 flash = 1
1704 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001705
1706 def test_no_duplicates(self):
1707 class UniqueEnum(Enum):
1708 def __init__(self, *args):
1709 cls = self.__class__
1710 if any(self.value == e.value for e in cls):
1711 a = self.name
1712 e = cls(self.value).name
1713 raise ValueError(
1714 "aliases not allowed in UniqueEnum: %r --> %r"
1715 % (a, e)
1716 )
1717 class Color(UniqueEnum):
1718 red = 1
1719 green = 2
1720 blue = 3
1721 with self.assertRaises(ValueError):
1722 class Color(UniqueEnum):
1723 red = 1
1724 green = 2
1725 blue = 3
1726 grene = 2
1727
1728 def test_init(self):
1729 class Planet(Enum):
1730 MERCURY = (3.303e+23, 2.4397e6)
1731 VENUS = (4.869e+24, 6.0518e6)
1732 EARTH = (5.976e+24, 6.37814e6)
1733 MARS = (6.421e+23, 3.3972e6)
1734 JUPITER = (1.9e+27, 7.1492e7)
1735 SATURN = (5.688e+26, 6.0268e7)
1736 URANUS = (8.686e+25, 2.5559e7)
1737 NEPTUNE = (1.024e+26, 2.4746e7)
1738 def __init__(self, mass, radius):
1739 self.mass = mass # in kilograms
1740 self.radius = radius # in meters
1741 @property
1742 def surface_gravity(self):
1743 # universal gravitational constant (m3 kg-1 s-2)
1744 G = 6.67300E-11
1745 return G * self.mass / (self.radius * self.radius)
1746 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1747 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1748
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001749 def test_ignore(self):
1750 class Period(timedelta, Enum):
1751 '''
1752 different lengths of time
1753 '''
1754 def __new__(cls, value, period):
1755 obj = timedelta.__new__(cls, value)
1756 obj._value_ = value
1757 obj.period = period
1758 return obj
1759 _ignore_ = 'Period i'
1760 Period = vars()
1761 for i in range(13):
1762 Period['month_%d' % i] = i*30, 'month'
1763 for i in range(53):
1764 Period['week_%d' % i] = i*7, 'week'
1765 for i in range(32):
1766 Period['day_%d' % i] = i, 'day'
1767 OneDay = day_1
1768 OneWeek = week_1
1769 OneMonth = month_1
1770 self.assertFalse(hasattr(Period, '_ignore_'))
1771 self.assertFalse(hasattr(Period, 'Period'))
1772 self.assertFalse(hasattr(Period, 'i'))
1773 self.assertTrue(isinstance(Period.day_1, timedelta))
1774 self.assertTrue(Period.month_1 is Period.day_30)
1775 self.assertTrue(Period.week_4 is Period.day_28)
1776
Ethan Furman2aa27322013-07-19 19:35:56 -07001777 def test_nonhash_value(self):
1778 class AutoNumberInAList(Enum):
1779 def __new__(cls):
1780 value = [len(cls.__members__) + 1]
1781 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001782 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001783 return obj
1784 class ColorInAList(AutoNumberInAList):
1785 red = ()
1786 green = ()
1787 blue = ()
1788 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001789 for enum, value in zip(ColorInAList, range(3)):
1790 value += 1
1791 self.assertEqual(enum.value, [value])
1792 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001793
Ethan Furmanb41803e2013-07-25 13:50:45 -07001794 def test_conflicting_types_resolved_in_new(self):
1795 class LabelledIntEnum(int, Enum):
1796 def __new__(cls, *args):
1797 value, label = args
1798 obj = int.__new__(cls, value)
1799 obj.label = label
1800 obj._value_ = value
1801 return obj
1802
1803 class LabelledList(LabelledIntEnum):
1804 unprocessed = (1, "Unprocessed")
1805 payment_complete = (2, "Payment Complete")
1806
1807 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1808 self.assertEqual(LabelledList.unprocessed, 1)
1809 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001810
Ethan Furmanc16595e2016-09-10 23:36:59 -07001811 def test_auto_number(self):
1812 class Color(Enum):
1813 red = auto()
1814 blue = auto()
1815 green = auto()
1816
1817 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1818 self.assertEqual(Color.red.value, 1)
1819 self.assertEqual(Color.blue.value, 2)
1820 self.assertEqual(Color.green.value, 3)
1821
1822 def test_auto_name(self):
1823 class Color(Enum):
1824 def _generate_next_value_(name, start, count, last):
1825 return name
1826 red = auto()
1827 blue = auto()
1828 green = auto()
1829
1830 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1831 self.assertEqual(Color.red.value, 'red')
1832 self.assertEqual(Color.blue.value, 'blue')
1833 self.assertEqual(Color.green.value, 'green')
1834
1835 def test_auto_name_inherit(self):
1836 class AutoNameEnum(Enum):
1837 def _generate_next_value_(name, start, count, last):
1838 return name
1839 class Color(AutoNameEnum):
1840 red = auto()
1841 blue = auto()
1842 green = auto()
1843
1844 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1845 self.assertEqual(Color.red.value, 'red')
1846 self.assertEqual(Color.blue.value, 'blue')
1847 self.assertEqual(Color.green.value, 'green')
1848
1849 def test_auto_garbage(self):
1850 class Color(Enum):
1851 red = 'red'
1852 blue = auto()
1853 self.assertEqual(Color.blue.value, 1)
1854
1855 def test_auto_garbage_corrected(self):
1856 class Color(Enum):
1857 red = 'red'
1858 blue = 2
1859 green = auto()
1860
1861 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1862 self.assertEqual(Color.red.value, 'red')
1863 self.assertEqual(Color.blue.value, 2)
1864 self.assertEqual(Color.green.value, 3)
1865
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001866 def test_auto_order(self):
1867 with self.assertRaises(TypeError):
1868 class Color(Enum):
1869 red = auto()
1870 green = auto()
1871 blue = auto()
1872 def _generate_next_value_(name, start, count, last):
1873 return name
1874
Ethan Furmanfc23a942020-09-16 12:37:54 -07001875 def test_auto_order_wierd(self):
1876 weird_auto = auto()
1877 weird_auto.value = 'pathological case'
1878 class Color(Enum):
1879 red = weird_auto
1880 def _generate_next_value_(name, start, count, last):
1881 return name
1882 blue = auto()
1883 self.assertEqual(list(Color), [Color.red, Color.blue])
1884 self.assertEqual(Color.red.value, 'pathological case')
1885 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001886
Ethan Furman3515dcc2016-09-18 13:15:41 -07001887 def test_duplicate_auto(self):
1888 class Dupes(Enum):
1889 first = primero = auto()
1890 second = auto()
1891 third = auto()
1892 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1893
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001894 def test_default_missing(self):
1895 class Color(Enum):
1896 RED = 1
1897 GREEN = 2
1898 BLUE = 3
1899 try:
1900 Color(7)
1901 except ValueError as exc:
1902 self.assertTrue(exc.__context__ is None)
1903 else:
1904 raise Exception('Exception not raised.')
1905
Ethan Furman019f0a02018-09-12 11:43:34 -07001906 def test_missing(self):
1907 class Color(Enum):
1908 red = 1
1909 green = 2
1910 blue = 3
1911 @classmethod
1912 def _missing_(cls, item):
1913 if item == 'three':
1914 return cls.blue
1915 elif item == 'bad return':
1916 # trigger internal error
1917 return 5
1918 elif item == 'error out':
1919 raise ZeroDivisionError
1920 else:
1921 # trigger not found
1922 return None
1923 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001924 try:
1925 Color(7)
1926 except ValueError as exc:
1927 self.assertTrue(exc.__context__ is None)
1928 else:
1929 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001930 try:
1931 Color('bad return')
1932 except TypeError as exc:
1933 self.assertTrue(isinstance(exc.__context__, ValueError))
1934 else:
1935 raise Exception('Exception not raised.')
1936 try:
1937 Color('error out')
1938 except ZeroDivisionError as exc:
1939 self.assertTrue(isinstance(exc.__context__, ValueError))
1940 else:
1941 raise Exception('Exception not raised.')
1942
Ethan Furman8c14f5a2021-04-12 08:51:20 -07001943 def test_missing_exceptions_reset(self):
1944 import weakref
1945 #
1946 class TestEnum(enum.Enum):
1947 VAL1 = 'val1'
1948 VAL2 = 'val2'
1949 #
1950 class Class1:
1951 def __init__(self):
1952 # Gracefully handle an exception of our own making
1953 try:
1954 raise ValueError()
1955 except ValueError:
1956 pass
1957 #
1958 class Class2:
1959 def __init__(self):
1960 # Gracefully handle an exception of Enum's making
1961 try:
1962 TestEnum('invalid_value')
1963 except ValueError:
1964 pass
1965 # No strong refs here so these are free to die.
1966 class_1_ref = weakref.ref(Class1())
1967 class_2_ref = weakref.ref(Class2())
1968 #
1969 # The exception raised by Enum creates a reference loop and thus
1970 # Class2 instances will stick around until the next gargage collection
1971 # cycle, unlike Class1.
1972 self.assertIs(class_1_ref(), None)
1973 self.assertIs(class_2_ref(), None)
1974
Ethan Furman5bdab642018-09-21 19:03:09 -07001975 def test_multiple_mixin(self):
1976 class MaxMixin:
1977 @classproperty
1978 def MAX(cls):
1979 max = len(cls)
1980 cls.MAX = max
1981 return max
1982 class StrMixin:
1983 def __str__(self):
1984 return self._name_.lower()
1985 class SomeEnum(Enum):
1986 def behavior(self):
1987 return 'booyah'
1988 class AnotherEnum(Enum):
1989 def behavior(self):
1990 return 'nuhuh!'
1991 def social(self):
1992 return "what's up?"
1993 class Color(MaxMixin, Enum):
1994 RED = auto()
1995 GREEN = auto()
1996 BLUE = auto()
1997 self.assertEqual(Color.RED.value, 1)
1998 self.assertEqual(Color.GREEN.value, 2)
1999 self.assertEqual(Color.BLUE.value, 3)
2000 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002001 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002002 class Color(MaxMixin, StrMixin, Enum):
2003 RED = auto()
2004 GREEN = auto()
2005 BLUE = auto()
2006 self.assertEqual(Color.RED.value, 1)
2007 self.assertEqual(Color.GREEN.value, 2)
2008 self.assertEqual(Color.BLUE.value, 3)
2009 self.assertEqual(Color.MAX, 3)
2010 self.assertEqual(str(Color.BLUE), 'blue')
2011 class Color(StrMixin, MaxMixin, Enum):
2012 RED = auto()
2013 GREEN = auto()
2014 BLUE = auto()
2015 self.assertEqual(Color.RED.value, 1)
2016 self.assertEqual(Color.GREEN.value, 2)
2017 self.assertEqual(Color.BLUE.value, 3)
2018 self.assertEqual(Color.MAX, 3)
2019 self.assertEqual(str(Color.BLUE), 'blue')
2020 class CoolColor(StrMixin, SomeEnum, Enum):
2021 RED = auto()
2022 GREEN = auto()
2023 BLUE = auto()
2024 self.assertEqual(CoolColor.RED.value, 1)
2025 self.assertEqual(CoolColor.GREEN.value, 2)
2026 self.assertEqual(CoolColor.BLUE.value, 3)
2027 self.assertEqual(str(CoolColor.BLUE), 'blue')
2028 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2029 class CoolerColor(StrMixin, AnotherEnum, Enum):
2030 RED = auto()
2031 GREEN = auto()
2032 BLUE = auto()
2033 self.assertEqual(CoolerColor.RED.value, 1)
2034 self.assertEqual(CoolerColor.GREEN.value, 2)
2035 self.assertEqual(CoolerColor.BLUE.value, 3)
2036 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2037 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2038 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2039 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2040 RED = auto()
2041 GREEN = auto()
2042 BLUE = auto()
2043 self.assertEqual(CoolestColor.RED.value, 1)
2044 self.assertEqual(CoolestColor.GREEN.value, 2)
2045 self.assertEqual(CoolestColor.BLUE.value, 3)
2046 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2047 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2048 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2049 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2050 RED = auto()
2051 GREEN = auto()
2052 BLUE = auto()
2053 self.assertEqual(ConfusedColor.RED.value, 1)
2054 self.assertEqual(ConfusedColor.GREEN.value, 2)
2055 self.assertEqual(ConfusedColor.BLUE.value, 3)
2056 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2057 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2058 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2059 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2060 RED = auto()
2061 GREEN = auto()
2062 BLUE = auto()
2063 self.assertEqual(ReformedColor.RED.value, 1)
2064 self.assertEqual(ReformedColor.GREEN.value, 2)
2065 self.assertEqual(ReformedColor.BLUE.value, 3)
2066 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2067 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2068 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2069 self.assertTrue(issubclass(ReformedColor, int))
2070
Ethan Furmancd453852018-10-05 23:29:36 -07002071 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002072 @unique
2073 class Decision1(StrEnum):
2074 REVERT = "REVERT"
2075 REVERT_ALL = "REVERT_ALL"
2076 RETRY = "RETRY"
2077 class MyEnum(StrEnum):
2078 pass
2079 @unique
2080 class Decision2(MyEnum):
2081 REVERT = "REVERT"
2082 REVERT_ALL = "REVERT_ALL"
2083 RETRY = "RETRY"
2084
Ethan Furmanc2667362020-12-07 00:17:31 -08002085 def test_multiple_mixin_inherited(self):
2086 class MyInt(int):
2087 def __new__(cls, value):
2088 return super().__new__(cls, value)
2089
2090 class HexMixin:
2091 def __repr__(self):
2092 return hex(self)
2093
2094 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2095 pass
2096
2097 class Foo(MyIntEnum):
2098 TEST = 1
2099 self.assertTrue(isinstance(Foo.TEST, MyInt))
2100 self.assertEqual(repr(Foo.TEST), "0x1")
2101
2102 class Fee(MyIntEnum):
2103 TEST = 1
2104 def __new__(cls, value):
2105 value += 1
2106 member = int.__new__(cls, value)
2107 member._value_ = value
2108 return member
2109 self.assertEqual(Fee.TEST, 2)
2110
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002111 def test_empty_globals(self):
2112 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2113 # when using compile and exec because f_globals is empty
2114 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2115 code = compile(code, "<string>", "exec")
2116 global_ns = {}
2117 local_ls = {}
2118 exec(code, global_ns, local_ls)
2119
Ethan Furman0063ff42020-09-21 17:23:13 -07002120 def test_strenum(self):
2121 class GoodStrEnum(StrEnum):
2122 one = '1'
2123 two = '2'
2124 three = b'3', 'ascii'
2125 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002126 self.assertEqual(GoodStrEnum.one, '1')
2127 self.assertEqual(str(GoodStrEnum.one), '1')
2128 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2129 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2130 #
2131 class DumbMixin:
2132 def __str__(self):
2133 return "don't do this"
2134 class DumbStrEnum(DumbMixin, StrEnum):
2135 five = '5'
2136 six = '6'
2137 seven = '7'
2138 self.assertEqual(DumbStrEnum.seven, '7')
2139 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2140 #
2141 class EnumMixin(Enum):
2142 def hello(self):
2143 print('hello from %s' % (self, ))
2144 class HelloEnum(EnumMixin, StrEnum):
2145 eight = '8'
2146 self.assertEqual(HelloEnum.eight, '8')
2147 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2148 #
2149 class GoodbyeMixin:
2150 def goodbye(self):
2151 print('%s wishes you a fond farewell')
2152 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2153 nine = '9'
2154 self.assertEqual(GoodbyeEnum.nine, '9')
2155 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2156 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002157 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2158 class FirstFailedStrEnum(StrEnum):
2159 one = 1
2160 two = '2'
2161 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2162 class SecondFailedStrEnum(StrEnum):
2163 one = '1'
2164 two = 2,
2165 three = '3'
2166 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2167 class ThirdFailedStrEnum(StrEnum):
2168 one = '1'
2169 two = 2
2170 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2171 class ThirdFailedStrEnum(StrEnum):
2172 one = '1'
2173 two = b'2', sys.getdefaultencoding
2174 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2175 class ThirdFailedStrEnum(StrEnum):
2176 one = '1'
2177 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002178
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002179 def test_missing_value_error(self):
2180 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2181 class Combined(str, Enum):
2182 #
2183 def __new__(cls, value, sequence):
2184 enum = str.__new__(cls, value)
2185 if '(' in value:
2186 fis_name, segment = value.split('(', 1)
2187 segment = segment.strip(' )')
2188 else:
2189 fis_name = value
2190 segment = None
2191 enum.fis_name = fis_name
2192 enum.segment = segment
2193 enum.sequence = sequence
2194 return enum
2195 #
2196 def __repr__(self):
2197 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2198 #
2199 key_type = 'An$(1,2)', 0
2200 company_id = 'An$(3,2)', 1
2201 code = 'An$(5,1)', 2
2202 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002203
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002204 @unittest.skipUnless(
2205 sys.version_info[:2] == (3, 9),
2206 'private variables are now normal attributes',
2207 )
2208 def test_warning_for_private_variables(self):
2209 with self.assertWarns(DeprecationWarning):
2210 class Private(Enum):
2211 __corporal = 'Radar'
2212 self.assertEqual(Private._Private__corporal.value, 'Radar')
2213 try:
2214 with self.assertWarns(DeprecationWarning):
2215 class Private(Enum):
2216 __major_ = 'Hoolihan'
2217 except ValueError:
2218 pass
2219
2220 def test_private_variable_is_normal_attribute(self):
2221 class Private(Enum):
2222 __corporal = 'Radar'
2223 __major_ = 'Hoolihan'
2224 self.assertEqual(Private._Private__corporal, 'Radar')
2225 self.assertEqual(Private._Private__major_, 'Hoolihan')
2226
Ethan Furmand65b9032021-02-08 17:32:38 -08002227 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002228 sys.version_info[:2] < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002229 'member-member access now raises an exception',
2230 )
2231 def test_warning_for_member_from_member_access(self):
2232 with self.assertWarns(DeprecationWarning):
2233 class Di(Enum):
2234 YES = 1
2235 NO = 0
2236 nope = Di.YES.NO
2237 self.assertIs(Di.NO, nope)
2238
2239 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002240 sys.version_info[:2] >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002241 'member-member access currently issues a warning',
2242 )
2243 def test_exception_for_member_from_member_access(self):
2244 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2245 class Di(Enum):
2246 YES = 1
2247 NO = 0
2248 nope = Di.YES.NO
2249
Ethan Furmanefb13be2020-12-10 12:20:06 -08002250 def test_strenum_auto(self):
2251 class Strings(StrEnum):
2252 ONE = auto()
2253 TWO = auto()
2254 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2255
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002256
Ethan Furmana6582872020-12-10 13:07:00 -08002257 def test_dynamic_members_with_static_methods(self):
2258 #
2259 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2260 class Foo(Enum):
2261 vars().update({
2262 k: v
2263 for k, v in foo_defines.items()
2264 if k.startswith('FOO_')
2265 })
2266 def upper(self):
2267 return self.value.upper()
2268 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2269 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2270 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2271 #
2272 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2273 class FooBar(Enum):
2274 vars().update({
2275 k: v
2276 for k, v in foo_defines.items()
2277 if k.startswith('FOO_')
2278 },
2279 **{'FOO_CAT': 'small'},
2280 )
2281 def upper(self):
2282 return self.value.upper()
2283
2284
Ethan Furmane8e61272016-08-20 07:19:31 -07002285class TestOrder(unittest.TestCase):
2286
2287 def test_same_members(self):
2288 class Color(Enum):
2289 _order_ = 'red green blue'
2290 red = 1
2291 green = 2
2292 blue = 3
2293
2294 def test_same_members_with_aliases(self):
2295 class Color(Enum):
2296 _order_ = 'red green blue'
2297 red = 1
2298 green = 2
2299 blue = 3
2300 verde = green
2301
2302 def test_same_members_wrong_order(self):
2303 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2304 class Color(Enum):
2305 _order_ = 'red green blue'
2306 red = 1
2307 blue = 3
2308 green = 2
2309
2310 def test_order_has_extra_members(self):
2311 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2312 class Color(Enum):
2313 _order_ = 'red green blue purple'
2314 red = 1
2315 green = 2
2316 blue = 3
2317
2318 def test_order_has_extra_members_with_aliases(self):
2319 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2320 class Color(Enum):
2321 _order_ = 'red green blue purple'
2322 red = 1
2323 green = 2
2324 blue = 3
2325 verde = green
2326
2327 def test_enum_has_extra_members(self):
2328 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2329 class Color(Enum):
2330 _order_ = 'red green blue'
2331 red = 1
2332 green = 2
2333 blue = 3
2334 purple = 4
2335
2336 def test_enum_has_extra_members_with_aliases(self):
2337 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2338 class Color(Enum):
2339 _order_ = 'red green blue'
2340 red = 1
2341 green = 2
2342 blue = 3
2343 purple = 4
2344 verde = green
2345
2346
Ethan Furman65a5a472016-09-01 23:55:19 -07002347class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002348 """Tests of the Flags."""
2349
Ethan Furman65a5a472016-09-01 23:55:19 -07002350 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002351 R, W, X = 4, 2, 1
2352
Ethan Furman65a5a472016-09-01 23:55:19 -07002353 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002354 RO = 0
2355 WO = 1
2356 RW = 2
2357 AC = 3
2358 CE = 1<<19
2359
Rahul Jha94306522018-09-10 23:51:04 +05302360 class Color(Flag):
2361 BLACK = 0
2362 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002363 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302364 GREEN = 2
2365 BLUE = 4
2366 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002367 WHITE = RED|GREEN|BLUE
2368 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302369
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002370 def test_str(self):
2371 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002372 self.assertEqual(str(Perm.R), 'R')
2373 self.assertEqual(str(Perm.W), 'W')
2374 self.assertEqual(str(Perm.X), 'X')
2375 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2376 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002377 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002378 self.assertEqual(str(~Perm.R), 'W|X')
2379 self.assertEqual(str(~Perm.W), 'R|X')
2380 self.assertEqual(str(~Perm.X), 'R|W')
2381 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002382 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002383 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002384
2385 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002386 self.assertEqual(str(Open.RO), 'RO')
2387 self.assertEqual(str(Open.WO), 'WO')
2388 self.assertEqual(str(Open.AC), 'AC')
2389 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2390 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2391 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2392 self.assertEqual(str(~Open.WO), 'RW|CE')
2393 self.assertEqual(str(~Open.AC), 'CE')
2394 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2395 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002396
2397 def test_repr(self):
2398 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002399 self.assertEqual(repr(Perm.R), 'Perm.R')
2400 self.assertEqual(repr(Perm.W), 'Perm.W')
2401 self.assertEqual(repr(Perm.X), 'Perm.X')
2402 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2403 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2404 self.assertEqual(repr(Perm(0)), '0x0')
2405 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2406 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2407 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2408 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2409 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2410 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002411
2412 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002413 self.assertEqual(repr(Open.RO), 'Open.RO')
2414 self.assertEqual(repr(Open.WO), 'Open.WO')
2415 self.assertEqual(repr(Open.AC), 'Open.AC')
2416 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2417 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2418 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2419 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2420 self.assertEqual(repr(~Open.AC), 'Open.CE')
2421 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2422 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002423
Ethan Furman37440ee2020-12-08 11:14:10 -08002424 def test_format(self):
2425 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002426 self.assertEqual(format(Perm.R, ''), 'R')
2427 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002428
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002429 def test_or(self):
2430 Perm = self.Perm
2431 for i in Perm:
2432 for j in Perm:
2433 self.assertEqual((i | j), Perm(i.value | j.value))
2434 self.assertEqual((i | j).value, i.value | j.value)
2435 self.assertIs(type(i | j), Perm)
2436 for i in Perm:
2437 self.assertIs(i | i, i)
2438 Open = self.Open
2439 self.assertIs(Open.RO | Open.CE, Open.CE)
2440
2441 def test_and(self):
2442 Perm = self.Perm
2443 RW = Perm.R | Perm.W
2444 RX = Perm.R | Perm.X
2445 WX = Perm.W | Perm.X
2446 RWX = Perm.R | Perm.W | Perm.X
2447 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2448 for i in values:
2449 for j in values:
2450 self.assertEqual((i & j).value, i.value & j.value)
2451 self.assertIs(type(i & j), Perm)
2452 for i in Perm:
2453 self.assertIs(i & i, i)
2454 self.assertIs(i & RWX, i)
2455 self.assertIs(RWX & i, i)
2456 Open = self.Open
2457 self.assertIs(Open.RO & Open.CE, Open.RO)
2458
2459 def test_xor(self):
2460 Perm = self.Perm
2461 for i in Perm:
2462 for j in Perm:
2463 self.assertEqual((i ^ j).value, i.value ^ j.value)
2464 self.assertIs(type(i ^ j), Perm)
2465 for i in Perm:
2466 self.assertIs(i ^ Perm(0), i)
2467 self.assertIs(Perm(0) ^ i, i)
2468 Open = self.Open
2469 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2470 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2471
2472 def test_invert(self):
2473 Perm = self.Perm
2474 RW = Perm.R | Perm.W
2475 RX = Perm.R | Perm.X
2476 WX = Perm.W | Perm.X
2477 RWX = Perm.R | Perm.W | Perm.X
2478 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2479 for i in values:
2480 self.assertIs(type(~i), Perm)
2481 self.assertEqual(~~i, i)
2482 for i in Perm:
2483 self.assertIs(~~i, i)
2484 Open = self.Open
2485 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2486 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2487
Ethan Furman25d94bb2016-09-02 16:32:32 -07002488 def test_bool(self):
2489 Perm = self.Perm
2490 for f in Perm:
2491 self.assertTrue(f)
2492 Open = self.Open
2493 for f in Open:
2494 self.assertEqual(bool(f.value), bool(f))
2495
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002496 def test_boundary(self):
2497 self.assertIs(enum.Flag._boundary_, STRICT)
2498 class Iron(Flag, boundary=STRICT):
2499 ONE = 1
2500 TWO = 2
2501 EIGHT = 8
2502 self.assertIs(Iron._boundary_, STRICT)
2503 #
2504 class Water(Flag, boundary=CONFORM):
2505 ONE = 1
2506 TWO = 2
2507 EIGHT = 8
2508 self.assertIs(Water._boundary_, CONFORM)
2509 #
2510 class Space(Flag, boundary=EJECT):
2511 ONE = 1
2512 TWO = 2
2513 EIGHT = 8
2514 self.assertIs(Space._boundary_, EJECT)
2515 #
2516 class Bizarre(Flag, boundary=KEEP):
2517 b = 3
2518 c = 4
2519 d = 6
2520 #
2521 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002522 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002523 self.assertIs(Water(7), Water.ONE|Water.TWO)
2524 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002525 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002526 self.assertEqual(Space(7), 7)
2527 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002528 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002529 self.assertEqual(list(Bizarre), [Bizarre.c])
2530 self.assertIs(Bizarre(3), Bizarre.b)
2531 self.assertIs(Bizarre(6), Bizarre.d)
2532
2533 def test_iter(self):
2534 Color = self.Color
2535 Open = self.Open
2536 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2537 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2538
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002539 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002540 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002541 lst = list(Perm)
2542 self.assertEqual(len(lst), len(Perm))
2543 self.assertEqual(len(Perm), 3, Perm)
2544 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2545 for i, n in enumerate('R W X'.split()):
2546 v = 1<<i
2547 e = Perm(v)
2548 self.assertEqual(e.value, v)
2549 self.assertEqual(type(e.value), int)
2550 self.assertEqual(e.name, n)
2551 self.assertIn(e, Perm)
2552 self.assertIs(type(e), Perm)
2553
2554 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002555 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002556 lst = list(Perm)
2557 self.assertEqual(len(lst), len(Perm))
2558 self.assertEqual(len(Perm), 3, Perm)
2559 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2560 for i, n in enumerate('R W X'.split()):
2561 v = 8<<i
2562 e = Perm(v)
2563 self.assertEqual(e.value, v)
2564 self.assertEqual(type(e.value), int)
2565 self.assertEqual(e.name, n)
2566 self.assertIn(e, Perm)
2567 self.assertIs(type(e), Perm)
2568
2569 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002570 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002571 lst = list(Perm)
2572 self.assertEqual(len(lst), len(Perm))
2573 self.assertEqual(len(Perm), 3, Perm)
2574 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2575 for i, n in enumerate('R W X'.split()):
2576 v = 1<<i
2577 e = Perm(v)
2578 self.assertEqual(e.value, v)
2579 self.assertEqual(type(e.value), int)
2580 self.assertEqual(e.name, n)
2581 self.assertIn(e, Perm)
2582 self.assertIs(type(e), Perm)
2583
2584 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002585 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002586 lst = list(Perm)
2587 self.assertEqual(len(lst), len(Perm))
2588 self.assertEqual(len(Perm), 3, Perm)
2589 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2590 for i, n in enumerate('R W X'.split()):
2591 v = 1<<(2*i+1)
2592 e = Perm(v)
2593 self.assertEqual(e.value, v)
2594 self.assertEqual(type(e.value), int)
2595 self.assertEqual(e.name, n)
2596 self.assertIn(e, Perm)
2597 self.assertIs(type(e), Perm)
2598
2599 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002600 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002601 lst = list(Perm)
2602 self.assertEqual(len(lst), len(Perm))
2603 self.assertEqual(len(Perm), 3, Perm)
2604 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2605 for i, n in enumerate('R W X'.split()):
2606 v = 1<<(2*i+1)
2607 e = Perm(v)
2608 self.assertEqual(e.value, v)
2609 self.assertEqual(type(e.value), int)
2610 self.assertEqual(e.name, n)
2611 self.assertIn(e, Perm)
2612 self.assertIs(type(e), Perm)
2613
Ethan Furman65a5a472016-09-01 23:55:19 -07002614 def test_pickle(self):
2615 if isinstance(FlagStooges, Exception):
2616 raise FlagStooges
2617 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2618 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002619
Rahul Jha94306522018-09-10 23:51:04 +05302620 def test_contains(self):
2621 Open = self.Open
2622 Color = self.Color
2623 self.assertFalse(Color.BLACK in Open)
2624 self.assertFalse(Open.RO in Color)
2625 with self.assertRaises(TypeError):
2626 'BLACK' in Color
2627 with self.assertRaises(TypeError):
2628 'RO' in Open
2629 with self.assertRaises(TypeError):
2630 1 in Color
2631 with self.assertRaises(TypeError):
2632 1 in Open
2633
2634 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002635 Perm = self.Perm
2636 R, W, X = Perm
2637 RW = R | W
2638 RX = R | X
2639 WX = W | X
2640 RWX = R | W | X
2641 self.assertTrue(R in RW)
2642 self.assertTrue(R in RX)
2643 self.assertTrue(R in RWX)
2644 self.assertTrue(W in RW)
2645 self.assertTrue(W in WX)
2646 self.assertTrue(W in RWX)
2647 self.assertTrue(X in RX)
2648 self.assertTrue(X in WX)
2649 self.assertTrue(X in RWX)
2650 self.assertFalse(R in WX)
2651 self.assertFalse(W in RX)
2652 self.assertFalse(X in RW)
2653
Ethan Furman7219e272020-09-16 13:01:00 -07002654 def test_member_iter(self):
2655 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002656 self.assertEqual(list(Color.BLACK), [])
2657 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002658 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2659 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002660 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2661 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2662
2663 def test_member_length(self):
2664 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2665 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2666 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2667 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2668
2669 def test_number_reset_and_order_cleanup(self):
2670 class Confused(Flag):
2671 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2672 ONE = auto()
2673 TWO = auto()
2674 FOUR = auto()
2675 DOS = 2
2676 EIGHT = auto()
2677 SIXTEEN = auto()
2678 self.assertEqual(
2679 list(Confused),
2680 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2681 self.assertIs(Confused.TWO, Confused.DOS)
2682 self.assertEqual(Confused.DOS._value_, 2)
2683 self.assertEqual(Confused.EIGHT._value_, 8)
2684 self.assertEqual(Confused.SIXTEEN._value_, 16)
2685
2686 def test_aliases(self):
2687 Color = self.Color
2688 self.assertEqual(Color(1).name, 'RED')
2689 self.assertEqual(Color['ROJO'].name, 'RED')
2690 self.assertEqual(Color(7).name, 'WHITE')
2691 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2692 self.assertIs(Color.BLANCO, Color.WHITE)
2693 Open = self.Open
2694 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002695
Ethan Furmanc16595e2016-09-10 23:36:59 -07002696 def test_auto_number(self):
2697 class Color(Flag):
2698 red = auto()
2699 blue = auto()
2700 green = auto()
2701
2702 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2703 self.assertEqual(Color.red.value, 1)
2704 self.assertEqual(Color.blue.value, 2)
2705 self.assertEqual(Color.green.value, 4)
2706
2707 def test_auto_number_garbage(self):
2708 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2709 class Color(Flag):
2710 red = 'not an int'
2711 blue = auto()
2712
Ethan Furman3515dcc2016-09-18 13:15:41 -07002713 def test_duplicate_auto(self):
2714 class Dupes(Enum):
2715 first = primero = auto()
2716 second = auto()
2717 third = auto()
2718 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2719
2720 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002721 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2722 class Bizarre(Flag):
2723 b = 3
2724 c = 4
2725 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002726
Ethan Furman5bdab642018-09-21 19:03:09 -07002727 def test_multiple_mixin(self):
2728 class AllMixin:
2729 @classproperty
2730 def ALL(cls):
2731 members = list(cls)
2732 all_value = None
2733 if members:
2734 all_value = members[0]
2735 for member in members[1:]:
2736 all_value |= member
2737 cls.ALL = all_value
2738 return all_value
2739 class StrMixin:
2740 def __str__(self):
2741 return self._name_.lower()
2742 class Color(AllMixin, Flag):
2743 RED = auto()
2744 GREEN = auto()
2745 BLUE = auto()
2746 self.assertEqual(Color.RED.value, 1)
2747 self.assertEqual(Color.GREEN.value, 2)
2748 self.assertEqual(Color.BLUE.value, 4)
2749 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002750 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002751 class Color(AllMixin, StrMixin, Flag):
2752 RED = auto()
2753 GREEN = auto()
2754 BLUE = auto()
2755 self.assertEqual(Color.RED.value, 1)
2756 self.assertEqual(Color.GREEN.value, 2)
2757 self.assertEqual(Color.BLUE.value, 4)
2758 self.assertEqual(Color.ALL.value, 7)
2759 self.assertEqual(str(Color.BLUE), 'blue')
2760 class Color(StrMixin, AllMixin, Flag):
2761 RED = auto()
2762 GREEN = auto()
2763 BLUE = auto()
2764 self.assertEqual(Color.RED.value, 1)
2765 self.assertEqual(Color.GREEN.value, 2)
2766 self.assertEqual(Color.BLUE.value, 4)
2767 self.assertEqual(Color.ALL.value, 7)
2768 self.assertEqual(str(Color.BLUE), 'blue')
2769
Hai Shie80697d2020-05-28 06:10:27 +08002770 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002771 def test_unique_composite(self):
2772 # override __eq__ to be identity only
2773 class TestFlag(Flag):
2774 one = auto()
2775 two = auto()
2776 three = auto()
2777 four = auto()
2778 five = auto()
2779 six = auto()
2780 seven = auto()
2781 eight = auto()
2782 def __eq__(self, other):
2783 return self is other
2784 def __hash__(self):
2785 return hash(self._value_)
2786 # have multiple threads competing to complete the composite members
2787 seen = set()
2788 failed = False
2789 def cycle_enum():
2790 nonlocal failed
2791 try:
2792 for i in range(256):
2793 seen.add(TestFlag(i))
2794 except Exception:
2795 failed = True
2796 threads = [
2797 threading.Thread(target=cycle_enum)
2798 for _ in range(8)
2799 ]
Hai Shie80697d2020-05-28 06:10:27 +08002800 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002801 pass
2802 # check that only 248 members were created
2803 self.assertFalse(
2804 failed,
2805 'at least one thread failed while creating composite members')
2806 self.assertEqual(256, len(seen), 'too many composite members created')
2807
Ethan Furman6bd94de2020-12-09 16:41:22 -08002808 def test_init_subclass(self):
2809 class MyEnum(Flag):
2810 def __init_subclass__(cls, **kwds):
2811 super().__init_subclass__(**kwds)
2812 self.assertFalse(cls.__dict__.get('_test', False))
2813 cls._test1 = 'MyEnum'
2814 #
2815 class TheirEnum(MyEnum):
2816 def __init_subclass__(cls, **kwds):
2817 super(TheirEnum, cls).__init_subclass__(**kwds)
2818 cls._test2 = 'TheirEnum'
2819 class WhoseEnum(TheirEnum):
2820 def __init_subclass__(cls, **kwds):
2821 pass
2822 class NoEnum(WhoseEnum):
2823 ONE = 1
2824 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2825 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2826 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2827 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2828 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2829 #
2830 class OurEnum(MyEnum):
2831 def __init_subclass__(cls, **kwds):
2832 cls._test2 = 'OurEnum'
2833 class WhereEnum(OurEnum):
2834 def __init_subclass__(cls, **kwds):
2835 pass
2836 class NeverEnum(WhereEnum):
2837 ONE = 1
2838 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2839 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2840 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2841 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2842 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2843
Ethan Furmanc16595e2016-09-10 23:36:59 -07002844
Ethan Furman65a5a472016-09-01 23:55:19 -07002845class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002846 """Tests of the IntFlags."""
2847
Ethan Furman65a5a472016-09-01 23:55:19 -07002848 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002849 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002850 W = 1 << 1
2851 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002852
Ethan Furman65a5a472016-09-01 23:55:19 -07002853 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002854 RO = 0
2855 WO = 1
2856 RW = 2
2857 AC = 3
2858 CE = 1<<19
2859
Rahul Jha94306522018-09-10 23:51:04 +05302860 class Color(IntFlag):
2861 BLACK = 0
2862 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002863 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302864 GREEN = 2
2865 BLUE = 4
2866 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002867 WHITE = RED|GREEN|BLUE
2868 BLANCO = RED|GREEN|BLUE
2869
2870 class Skip(IntFlag):
2871 FIRST = 1
2872 SECOND = 2
2873 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302874
Ethan Furman3515dcc2016-09-18 13:15:41 -07002875 def test_type(self):
2876 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002877 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002878 Open = self.Open
2879 for f in Perm:
2880 self.assertTrue(isinstance(f, Perm))
2881 self.assertEqual(f, f.value)
2882 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2883 self.assertEqual(Perm.W | Perm.X, 3)
2884 for f in Open:
2885 self.assertTrue(isinstance(f, Open))
2886 self.assertEqual(f, f.value)
2887 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2888 self.assertEqual(Open.WO | Open.RW, 3)
2889
2890
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002891 def test_str(self):
2892 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002893 self.assertEqual(str(Perm.R), 'R')
2894 self.assertEqual(str(Perm.W), 'W')
2895 self.assertEqual(str(Perm.X), 'X')
2896 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2897 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002898 self.assertEqual(str(Perm.R | 8), '12')
2899 self.assertEqual(str(Perm(0)), 'Perm(0)')
2900 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002901 self.assertEqual(str(~Perm.R), 'W|X')
2902 self.assertEqual(str(~Perm.W), 'R|X')
2903 self.assertEqual(str(~Perm.X), 'R|W')
2904 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002905 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2906 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002907 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002908 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002909
2910 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002911 self.assertEqual(str(Open.RO), 'RO')
2912 self.assertEqual(str(Open.WO), 'WO')
2913 self.assertEqual(str(Open.AC), 'AC')
2914 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2915 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002916 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002917 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2918 self.assertEqual(str(~Open.WO), 'RW|CE')
2919 self.assertEqual(str(~Open.AC), 'CE')
2920 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2921 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002922 self.assertEqual(str(Open(~4)), '-5')
2923
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002924 def test_repr(self):
2925 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002926 self.assertEqual(repr(Perm.R), 'Perm.R')
2927 self.assertEqual(repr(Perm.W), 'Perm.W')
2928 self.assertEqual(repr(Perm.X), 'Perm.X')
2929 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2930 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002931 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07002932 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002933 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002934 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2935 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2936 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2937 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2938 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002939 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002940 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002941 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002942
2943 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002944 self.assertEqual(repr(Open.RO), 'Open.RO')
2945 self.assertEqual(repr(Open.WO), 'Open.WO')
2946 self.assertEqual(repr(Open.AC), 'Open.AC')
2947 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2948 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002949 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002950 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2951 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2952 self.assertEqual(repr(~Open.AC), 'Open.CE')
2953 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2954 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002955 self.assertEqual(repr(Open(~4)), '-5')
2956
Ethan Furman37440ee2020-12-08 11:14:10 -08002957 def test_format(self):
2958 Perm = self.Perm
2959 self.assertEqual(format(Perm.R, ''), '4')
2960 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2961
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002962 def test_or(self):
2963 Perm = self.Perm
2964 for i in Perm:
2965 for j in Perm:
2966 self.assertEqual(i | j, i.value | j.value)
2967 self.assertEqual((i | j).value, i.value | j.value)
2968 self.assertIs(type(i | j), Perm)
2969 for j in range(8):
2970 self.assertEqual(i | j, i.value | j)
2971 self.assertEqual((i | j).value, i.value | j)
2972 self.assertIs(type(i | j), Perm)
2973 self.assertEqual(j | i, j | i.value)
2974 self.assertEqual((j | i).value, j | i.value)
2975 self.assertIs(type(j | i), Perm)
2976 for i in Perm:
2977 self.assertIs(i | i, i)
2978 self.assertIs(i | 0, i)
2979 self.assertIs(0 | i, i)
2980 Open = self.Open
2981 self.assertIs(Open.RO | Open.CE, Open.CE)
2982
2983 def test_and(self):
2984 Perm = self.Perm
2985 RW = Perm.R | Perm.W
2986 RX = Perm.R | Perm.X
2987 WX = Perm.W | Perm.X
2988 RWX = Perm.R | Perm.W | Perm.X
2989 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2990 for i in values:
2991 for j in values:
2992 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2993 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2994 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2995 for j in range(8):
2996 self.assertEqual(i & j, i.value & j)
2997 self.assertEqual((i & j).value, i.value & j)
2998 self.assertIs(type(i & j), Perm)
2999 self.assertEqual(j & i, j & i.value)
3000 self.assertEqual((j & i).value, j & i.value)
3001 self.assertIs(type(j & i), Perm)
3002 for i in Perm:
3003 self.assertIs(i & i, i)
3004 self.assertIs(i & 7, i)
3005 self.assertIs(7 & i, i)
3006 Open = self.Open
3007 self.assertIs(Open.RO & Open.CE, Open.RO)
3008
3009 def test_xor(self):
3010 Perm = self.Perm
3011 for i in Perm:
3012 for j in Perm:
3013 self.assertEqual(i ^ j, i.value ^ j.value)
3014 self.assertEqual((i ^ j).value, i.value ^ j.value)
3015 self.assertIs(type(i ^ j), Perm)
3016 for j in range(8):
3017 self.assertEqual(i ^ j, i.value ^ j)
3018 self.assertEqual((i ^ j).value, i.value ^ j)
3019 self.assertIs(type(i ^ j), Perm)
3020 self.assertEqual(j ^ i, j ^ i.value)
3021 self.assertEqual((j ^ i).value, j ^ i.value)
3022 self.assertIs(type(j ^ i), Perm)
3023 for i in Perm:
3024 self.assertIs(i ^ 0, i)
3025 self.assertIs(0 ^ i, i)
3026 Open = self.Open
3027 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3028 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3029
3030 def test_invert(self):
3031 Perm = self.Perm
3032 RW = Perm.R | Perm.W
3033 RX = Perm.R | Perm.X
3034 WX = Perm.W | Perm.X
3035 RWX = Perm.R | Perm.W | Perm.X
3036 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3037 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003038 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003039 self.assertIs(type(~i), Perm)
3040 self.assertEqual(~~i, i)
3041 for i in Perm:
3042 self.assertIs(~~i, i)
3043 Open = self.Open
3044 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3045 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3046
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003047 def test_boundary(self):
3048 self.assertIs(enum.IntFlag._boundary_, EJECT)
3049 class Iron(IntFlag, boundary=STRICT):
3050 ONE = 1
3051 TWO = 2
3052 EIGHT = 8
3053 self.assertIs(Iron._boundary_, STRICT)
3054 #
3055 class Water(IntFlag, boundary=CONFORM):
3056 ONE = 1
3057 TWO = 2
3058 EIGHT = 8
3059 self.assertIs(Water._boundary_, CONFORM)
3060 #
3061 class Space(IntFlag, boundary=EJECT):
3062 ONE = 1
3063 TWO = 2
3064 EIGHT = 8
3065 self.assertIs(Space._boundary_, EJECT)
3066 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003067 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003068 class Bizarre(IntFlag, boundary=KEEP):
3069 b = 3
3070 c = 4
3071 d = 6
3072 #
3073 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003074 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003075 self.assertIs(Water(7), Water.ONE|Water.TWO)
3076 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003077 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003078 self.assertEqual(Space(7), 7)
3079 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003080 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003081 self.assertEqual(list(Bizarre), [Bizarre.c])
3082 self.assertIs(Bizarre(3), Bizarre.b)
3083 self.assertIs(Bizarre(6), Bizarre.d)
3084
3085 def test_iter(self):
3086 Color = self.Color
3087 Open = self.Open
3088 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3089 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3090
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003091 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003092 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003093 lst = list(Perm)
3094 self.assertEqual(len(lst), len(Perm))
3095 self.assertEqual(len(Perm), 3, Perm)
3096 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3097 for i, n in enumerate('R W X'.split()):
3098 v = 1<<i
3099 e = Perm(v)
3100 self.assertEqual(e.value, v)
3101 self.assertEqual(type(e.value), int)
3102 self.assertEqual(e, v)
3103 self.assertEqual(e.name, n)
3104 self.assertIn(e, Perm)
3105 self.assertIs(type(e), Perm)
3106
3107 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003108 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003109 lst = list(Perm)
3110 self.assertEqual(len(lst), len(Perm))
3111 self.assertEqual(len(Perm), 3, Perm)
3112 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3113 for i, n in enumerate('R W X'.split()):
3114 v = 8<<i
3115 e = Perm(v)
3116 self.assertEqual(e.value, v)
3117 self.assertEqual(type(e.value), int)
3118 self.assertEqual(e, v)
3119 self.assertEqual(e.name, n)
3120 self.assertIn(e, Perm)
3121 self.assertIs(type(e), Perm)
3122
3123 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003124 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003125 lst = list(Perm)
3126 self.assertEqual(len(lst), len(Perm))
3127 self.assertEqual(len(Perm), 3, Perm)
3128 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3129 for i, n in enumerate('R W X'.split()):
3130 v = 1<<i
3131 e = Perm(v)
3132 self.assertEqual(e.value, v)
3133 self.assertEqual(type(e.value), int)
3134 self.assertEqual(e, v)
3135 self.assertEqual(e.name, n)
3136 self.assertIn(e, Perm)
3137 self.assertIs(type(e), Perm)
3138
3139 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003140 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003141 lst = list(Perm)
3142 self.assertEqual(len(lst), len(Perm))
3143 self.assertEqual(len(Perm), 3, Perm)
3144 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3145 for i, n in enumerate('R W X'.split()):
3146 v = 1<<(2*i+1)
3147 e = Perm(v)
3148 self.assertEqual(e.value, v)
3149 self.assertEqual(type(e.value), int)
3150 self.assertEqual(e, v)
3151 self.assertEqual(e.name, n)
3152 self.assertIn(e, Perm)
3153 self.assertIs(type(e), Perm)
3154
3155 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003156 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003157 lst = list(Perm)
3158 self.assertEqual(len(lst), len(Perm))
3159 self.assertEqual(len(Perm), 3, Perm)
3160 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3161 for i, n in enumerate('R W X'.split()):
3162 v = 1<<(2*i+1)
3163 e = Perm(v)
3164 self.assertEqual(e.value, v)
3165 self.assertEqual(type(e.value), int)
3166 self.assertEqual(e, v)
3167 self.assertEqual(e.name, n)
3168 self.assertIn(e, Perm)
3169 self.assertIs(type(e), Perm)
3170
3171
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003172 def test_programatic_function_from_empty_list(self):
3173 Perm = enum.IntFlag('Perm', [])
3174 lst = list(Perm)
3175 self.assertEqual(len(lst), len(Perm))
3176 self.assertEqual(len(Perm), 0, Perm)
3177 Thing = enum.Enum('Thing', [])
3178 lst = list(Thing)
3179 self.assertEqual(len(lst), len(Thing))
3180 self.assertEqual(len(Thing), 0, Thing)
3181
3182
3183 def test_programatic_function_from_empty_tuple(self):
3184 Perm = enum.IntFlag('Perm', ())
3185 lst = list(Perm)
3186 self.assertEqual(len(lst), len(Perm))
3187 self.assertEqual(len(Perm), 0, Perm)
3188 Thing = enum.Enum('Thing', ())
3189 self.assertEqual(len(lst), len(Thing))
3190 self.assertEqual(len(Thing), 0, Thing)
3191
Rahul Jha94306522018-09-10 23:51:04 +05303192 def test_contains(self):
3193 Open = self.Open
3194 Color = self.Color
3195 self.assertTrue(Color.GREEN in Color)
3196 self.assertTrue(Open.RW in Open)
3197 self.assertFalse(Color.GREEN in Open)
3198 self.assertFalse(Open.RW in Color)
3199 with self.assertRaises(TypeError):
3200 'GREEN' in Color
3201 with self.assertRaises(TypeError):
3202 'RW' in Open
3203 with self.assertRaises(TypeError):
3204 2 in Color
3205 with self.assertRaises(TypeError):
3206 2 in Open
3207
3208 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003209 Perm = self.Perm
3210 R, W, X = Perm
3211 RW = R | W
3212 RX = R | X
3213 WX = W | X
3214 RWX = R | W | X
3215 self.assertTrue(R in RW)
3216 self.assertTrue(R in RX)
3217 self.assertTrue(R in RWX)
3218 self.assertTrue(W in RW)
3219 self.assertTrue(W in WX)
3220 self.assertTrue(W in RWX)
3221 self.assertTrue(X in RX)
3222 self.assertTrue(X in WX)
3223 self.assertTrue(X in RWX)
3224 self.assertFalse(R in WX)
3225 self.assertFalse(W in RX)
3226 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303227 with self.assertRaises(TypeError):
3228 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003229
Ethan Furman7219e272020-09-16 13:01:00 -07003230 def test_member_iter(self):
3231 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003232 self.assertEqual(list(Color.BLACK), [])
3233 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003234 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3235 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003236 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3237
3238 def test_member_length(self):
3239 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3240 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3241 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3242 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3243
3244 def test_aliases(self):
3245 Color = self.Color
3246 self.assertEqual(Color(1).name, 'RED')
3247 self.assertEqual(Color['ROJO'].name, 'RED')
3248 self.assertEqual(Color(7).name, 'WHITE')
3249 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3250 self.assertIs(Color.BLANCO, Color.WHITE)
3251 Open = self.Open
3252 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003253
Ethan Furman25d94bb2016-09-02 16:32:32 -07003254 def test_bool(self):
3255 Perm = self.Perm
3256 for f in Perm:
3257 self.assertTrue(f)
3258 Open = self.Open
3259 for f in Open:
3260 self.assertEqual(bool(f.value), bool(f))
3261
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003262 def test_bizarre(self):
3263 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3264 class Bizarre(IntFlag):
3265 b = 3
3266 c = 4
3267 d = 6
3268
Ethan Furman5bdab642018-09-21 19:03:09 -07003269 def test_multiple_mixin(self):
3270 class AllMixin:
3271 @classproperty
3272 def ALL(cls):
3273 members = list(cls)
3274 all_value = None
3275 if members:
3276 all_value = members[0]
3277 for member in members[1:]:
3278 all_value |= member
3279 cls.ALL = all_value
3280 return all_value
3281 class StrMixin:
3282 def __str__(self):
3283 return self._name_.lower()
3284 class Color(AllMixin, IntFlag):
3285 RED = auto()
3286 GREEN = auto()
3287 BLUE = auto()
3288 self.assertEqual(Color.RED.value, 1)
3289 self.assertEqual(Color.GREEN.value, 2)
3290 self.assertEqual(Color.BLUE.value, 4)
3291 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003292 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003293 class Color(AllMixin, StrMixin, IntFlag):
3294 RED = auto()
3295 GREEN = auto()
3296 BLUE = auto()
3297 self.assertEqual(Color.RED.value, 1)
3298 self.assertEqual(Color.GREEN.value, 2)
3299 self.assertEqual(Color.BLUE.value, 4)
3300 self.assertEqual(Color.ALL.value, 7)
3301 self.assertEqual(str(Color.BLUE), 'blue')
3302 class Color(StrMixin, AllMixin, IntFlag):
3303 RED = auto()
3304 GREEN = auto()
3305 BLUE = auto()
3306 self.assertEqual(Color.RED.value, 1)
3307 self.assertEqual(Color.GREEN.value, 2)
3308 self.assertEqual(Color.BLUE.value, 4)
3309 self.assertEqual(Color.ALL.value, 7)
3310 self.assertEqual(str(Color.BLUE), 'blue')
3311
Hai Shie80697d2020-05-28 06:10:27 +08003312 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003313 def test_unique_composite(self):
3314 # override __eq__ to be identity only
3315 class TestFlag(IntFlag):
3316 one = auto()
3317 two = auto()
3318 three = auto()
3319 four = auto()
3320 five = auto()
3321 six = auto()
3322 seven = auto()
3323 eight = auto()
3324 def __eq__(self, other):
3325 return self is other
3326 def __hash__(self):
3327 return hash(self._value_)
3328 # have multiple threads competing to complete the composite members
3329 seen = set()
3330 failed = False
3331 def cycle_enum():
3332 nonlocal failed
3333 try:
3334 for i in range(256):
3335 seen.add(TestFlag(i))
3336 except Exception:
3337 failed = True
3338 threads = [
3339 threading.Thread(target=cycle_enum)
3340 for _ in range(8)
3341 ]
Hai Shie80697d2020-05-28 06:10:27 +08003342 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003343 pass
3344 # check that only 248 members were created
3345 self.assertFalse(
3346 failed,
3347 'at least one thread failed while creating composite members')
3348 self.assertEqual(256, len(seen), 'too many composite members created')
3349
3350
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003351class TestEmptyAndNonLatinStrings(unittest.TestCase):
3352
3353 def test_empty_string(self):
3354 with self.assertRaises(ValueError):
3355 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3356
3357 def test_non_latin_character_string(self):
3358 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3359 item = getattr(greek_abc, '\u03B1')
3360 self.assertEqual(item.value, 1)
3361
3362 def test_non_latin_number_string(self):
3363 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3364 item = getattr(hebrew_123, '\u05D0')
3365 self.assertEqual(item.value, 1)
3366
3367
Ethan Furmanf24bb352013-07-18 17:05:39 -07003368class TestUnique(unittest.TestCase):
3369
3370 def test_unique_clean(self):
3371 @unique
3372 class Clean(Enum):
3373 one = 1
3374 two = 'dos'
3375 tres = 4.0
3376 @unique
3377 class Cleaner(IntEnum):
3378 single = 1
3379 double = 2
3380 triple = 3
3381
3382 def test_unique_dirty(self):
3383 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3384 @unique
3385 class Dirty(Enum):
3386 one = 1
3387 two = 'dos'
3388 tres = 1
3389 with self.assertRaisesRegex(
3390 ValueError,
3391 'double.*single.*turkey.*triple',
3392 ):
3393 @unique
3394 class Dirtier(IntEnum):
3395 single = 1
3396 double = 1
3397 triple = 3
3398 turkey = 3
3399
Ethan Furman3803ad42016-05-01 10:03:53 -07003400 def test_unique_with_name(self):
3401 @unique
3402 class Silly(Enum):
3403 one = 1
3404 two = 'dos'
3405 name = 3
3406 @unique
3407 class Sillier(IntEnum):
3408 single = 1
3409 name = 2
3410 triple = 3
3411 value = 4
3412
Ethan Furmanec099732021-04-15 06:58:33 -07003413class TestHelpers(unittest.TestCase):
3414
3415 sunder_names = '_bad_', '_good_', '_what_ho_'
3416 dunder_names = '__mal__', '__bien__', '__que_que__'
3417 private_names = '_MyEnum__private', '_MyEnum__still_private'
3418 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3419 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3420
3421 def test_sunder(self):
3422 for name in self.sunder_names + self.private_and_sunder_names:
3423 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3424 for name in self.dunder_names + self.private_names + self.random_names:
3425 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3426
3427 def test_dunder(self):
3428 for name in self.dunder_names:
3429 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3430 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3431 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3432
3433 def test_is_private(self):
3434 for name in self.private_names + self.private_and_sunder_names:
3435 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3436 for name in self.sunder_names + self.dunder_names + self.random_names:
3437 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003438
Ethan Furmanb7751062021-03-30 21:17:26 -07003439class TestEnumTypeSubclassing(unittest.TestCase):
3440 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003441
Ethan Furman3323da92015-04-11 09:39:59 -07003442expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003443Help on class Color in module %s:
3444
3445class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003446 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003447 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003448 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003449 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003450 | Method resolution order:
3451 | Color
3452 | enum.Enum
3453 | builtins.object
3454 |\x20\x20
3455 | Data and other attributes defined here:
3456 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003457 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003458 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003459 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003460 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003461 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003462 |\x20\x20
3463 | ----------------------------------------------------------------------
3464 | Data descriptors inherited from enum.Enum:
3465 |\x20\x20
3466 | name
3467 | The name of the Enum member.
3468 |\x20\x20
3469 | value
3470 | The value of the Enum member.
3471 |\x20\x20
3472 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003473 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003474 |\x20\x20
3475 | __members__
3476 | Returns a mapping of member name->value.
3477 |\x20\x20\x20\x20\x20\x20
3478 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003479 | is a read-only view of the internal mapping."""
3480
3481expected_help_output_without_docs = """\
3482Help on class Color in module %s:
3483
3484class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003485 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3486 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003487 | Method resolution order:
3488 | Color
3489 | enum.Enum
3490 | builtins.object
3491 |\x20\x20
3492 | Data and other attributes defined here:
3493 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003494 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003495 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003496 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003497 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003498 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003499 |\x20\x20
3500 | ----------------------------------------------------------------------
3501 | Data descriptors inherited from enum.Enum:
3502 |\x20\x20
3503 | name
3504 |\x20\x20
3505 | value
3506 |\x20\x20
3507 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003508 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003509 |\x20\x20
3510 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003511
3512class TestStdLib(unittest.TestCase):
3513
Ethan Furman48a724f2015-04-11 23:23:06 -07003514 maxDiff = None
3515
Ethan Furman5875d742013-10-21 20:45:55 -07003516 class Color(Enum):
3517 red = 1
3518 green = 2
3519 blue = 3
3520
3521 def test_pydoc(self):
3522 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003523 if StrEnum.__doc__ is None:
3524 expected_text = expected_help_output_without_docs % __name__
3525 else:
3526 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003527 output = StringIO()
3528 helper = pydoc.Helper(output=output)
3529 helper(self.Color)
3530 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003531 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003532
3533 def test_inspect_getmembers(self):
3534 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003535 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003536 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003537 ('__members__', self.Color.__members__),
3538 ('__module__', __name__),
3539 ('blue', self.Color.blue),
3540 ('green', self.Color.green),
3541 ('name', Enum.__dict__['name']),
3542 ('red', self.Color.red),
3543 ('value', Enum.__dict__['value']),
3544 ))
3545 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003546 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003547 failed = False
3548 for k in values.keys():
3549 if result[k] != values[k]:
3550 print()
3551 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3552 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3553 failed = True
3554 if failed:
3555 self.fail("result does not equal expected, see print above")
3556
3557 def test_inspect_classify_class_attrs(self):
3558 # indirectly test __objclass__
3559 from inspect import Attribute
3560 values = [
3561 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003562 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003563 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003564 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003565 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003566 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003567 Attribute(name='__module__', kind='data',
3568 defining_class=self.Color, object=__name__),
3569 Attribute(name='blue', kind='data',
3570 defining_class=self.Color, object=self.Color.blue),
3571 Attribute(name='green', kind='data',
3572 defining_class=self.Color, object=self.Color.green),
3573 Attribute(name='red', kind='data',
3574 defining_class=self.Color, object=self.Color.red),
3575 Attribute(name='name', kind='data',
3576 defining_class=Enum, object=Enum.__dict__['name']),
3577 Attribute(name='value', kind='data',
3578 defining_class=Enum, object=Enum.__dict__['value']),
3579 ]
3580 values.sort(key=lambda item: item.name)
3581 result = list(inspect.classify_class_attrs(self.Color))
3582 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003583 self.assertEqual(
3584 len(values), len(result),
3585 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3586 )
Ethan Furman5875d742013-10-21 20:45:55 -07003587 failed = False
3588 for v, r in zip(values, result):
3589 if r != v:
3590 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3591 failed = True
3592 if failed:
3593 self.fail("result does not equal expected, see print above")
3594
Ethan Furmana02cb472021-04-21 10:20:44 -07003595 def test_test_simple_enum(self):
3596 @_simple_enum(Enum)
3597 class SimpleColor:
3598 RED = 1
3599 GREEN = 2
3600 BLUE = 3
3601 class CheckedColor(Enum):
3602 RED = 1
3603 GREEN = 2
3604 BLUE = 3
3605 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3606 SimpleColor.GREEN._value_ = 9
3607 self.assertRaisesRegex(
3608 TypeError, "enum mismatch",
3609 _test_simple_enum, CheckedColor, SimpleColor,
3610 )
3611 class CheckedMissing(IntFlag, boundary=KEEP):
3612 SIXTY_FOUR = 64
3613 ONE_TWENTY_EIGHT = 128
3614 TWENTY_FORTY_EIGHT = 2048
3615 ALL = 2048 + 128 + 64 + 12
3616 CM = CheckedMissing
3617 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3618 #
3619 @_simple_enum(IntFlag, boundary=KEEP)
3620 class Missing:
3621 SIXTY_FOUR = 64
3622 ONE_TWENTY_EIGHT = 128
3623 TWENTY_FORTY_EIGHT = 2048
3624 ALL = 2048 + 128 + 64 + 12
3625 M = Missing
3626 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3627 #
3628 _test_simple_enum(CheckedMissing, Missing)
3629
Martin Panter19e69c52015-11-14 12:46:42 +00003630
3631class MiscTestCase(unittest.TestCase):
3632 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003633 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003634
3635
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003636# These are unordered here on purpose to ensure that declaration order
3637# makes no difference.
3638CONVERT_TEST_NAME_D = 5
3639CONVERT_TEST_NAME_C = 5
3640CONVERT_TEST_NAME_B = 5
3641CONVERT_TEST_NAME_A = 5 # This one should sort first.
3642CONVERT_TEST_NAME_E = 5
3643CONVERT_TEST_NAME_F = 5
3644
Ethan Furmana02cb472021-04-21 10:20:44 -07003645CONVERT_STRING_TEST_NAME_D = 5
3646CONVERT_STRING_TEST_NAME_C = 5
3647CONVERT_STRING_TEST_NAME_B = 5
3648CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3649CONVERT_STRING_TEST_NAME_E = 5
3650CONVERT_STRING_TEST_NAME_F = 5
3651
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003652class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003653 def setUp(self):
3654 # Reset the module-level test variables to their original integer
3655 # values, otherwise the already created enum values get converted
3656 # instead.
3657 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3658 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3659 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3660
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003661 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003662 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003663 'UnittestConvert',
3664 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003665 filter=lambda x: x.startswith('CONVERT_TEST_'))
3666 # We don't want the reverse lookup value to vary when there are
3667 # multiple possible names for a given value. It should always
3668 # report the first lexigraphical name in that case.
3669 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3670
3671 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003672 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003673 'UnittestConvert',
3674 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003675 filter=lambda x: x.startswith('CONVERT_TEST_'))
3676 # Ensure that test_type has all of the desired names and values.
3677 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3678 test_type.CONVERT_TEST_NAME_A)
3679 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3680 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3681 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3682 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3683 # Ensure that test_type only picked up names matching the filter.
3684 self.assertEqual([name for name in dir(test_type)
3685 if name[0:2] not in ('CO', '__')],
3686 [], msg='Names other than CONVERT_TEST_* found.')
3687
orlnub1230fb9fad2018-09-12 20:28:53 +03003688 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3689 '_convert was deprecated in 3.8')
3690 def test_convert_warn(self):
3691 with self.assertWarns(DeprecationWarning):
3692 enum.IntEnum._convert(
3693 'UnittestConvert',
3694 ('test.test_enum', '__main__')[__name__=='__main__'],
3695 filter=lambda x: x.startswith('CONVERT_TEST_'))
3696
3697 @unittest.skipUnless(sys.version_info >= (3, 9),
3698 '_convert was removed in 3.9')
3699 def test_convert_raise(self):
3700 with self.assertRaises(AttributeError):
3701 enum.IntEnum._convert(
3702 'UnittestConvert',
3703 ('test.test_enum', '__main__')[__name__=='__main__'],
3704 filter=lambda x: x.startswith('CONVERT_TEST_'))
3705
Ethan Furmanb7751062021-03-30 21:17:26 -07003706 def test_convert_repr_and_str(self):
3707 module = ('test.test_enum', '__main__')[__name__=='__main__']
3708 test_type = enum.IntEnum._convert_(
3709 'UnittestConvert',
3710 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003711 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3712 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3713 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
3714 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003715
3716# global names for StrEnum._convert_ test
3717CONVERT_STR_TEST_2 = 'goodbye'
3718CONVERT_STR_TEST_1 = 'hello'
3719
3720class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003721 def setUp(self):
3722 global CONVERT_STR_TEST_1
3723 global CONVERT_STR_TEST_2
3724 CONVERT_STR_TEST_2 = 'goodbye'
3725 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07003726
3727 def test_convert(self):
3728 test_type = enum.StrEnum._convert_(
3729 'UnittestConvert',
3730 ('test.test_enum', '__main__')[__name__=='__main__'],
3731 filter=lambda x: x.startswith('CONVERT_STR_'))
3732 # Ensure that test_type has all of the desired names and values.
3733 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3734 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3735 # Ensure that test_type only picked up names matching the filter.
3736 self.assertEqual([name for name in dir(test_type)
3737 if name[0:2] not in ('CO', '__')],
3738 [], msg='Names other than CONVERT_STR_* found.')
3739
3740 def test_convert_repr_and_str(self):
3741 module = ('test.test_enum', '__main__')[__name__=='__main__']
3742 test_type = enum.StrEnum._convert_(
3743 'UnittestConvert',
3744 module,
3745 filter=lambda x: x.startswith('CONVERT_STR_'))
3746 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3747 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
3748 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
3749
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003750
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003751if __name__ == '__main__':
3752 unittest.main()