blob: d946dd520da95c73313871dfd2ebd139fae303dc [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
531 def assertFormatIsValue(self, spec, member):
532 self.assertEqual(spec.format(member), spec.format(member.value))
533
534 def test_format_enum_date(self):
535 Holiday = self.Holiday
536 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
537 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
538 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
539 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
540 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
541 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
542 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
543 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
544
545 def test_format_enum_float(self):
546 Konstants = self.Konstants
547 self.assertFormatIsValue('{}', Konstants.TAU)
548 self.assertFormatIsValue('{:}', Konstants.TAU)
549 self.assertFormatIsValue('{:20}', Konstants.TAU)
550 self.assertFormatIsValue('{:^20}', Konstants.TAU)
551 self.assertFormatIsValue('{:>20}', Konstants.TAU)
552 self.assertFormatIsValue('{:<20}', Konstants.TAU)
553 self.assertFormatIsValue('{:n}', Konstants.TAU)
554 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
555 self.assertFormatIsValue('{:f}', Konstants.TAU)
556
557 def test_format_enum_int(self):
558 Grades = self.Grades
559 self.assertFormatIsValue('{}', Grades.C)
560 self.assertFormatIsValue('{:}', Grades.C)
561 self.assertFormatIsValue('{:20}', Grades.C)
562 self.assertFormatIsValue('{:^20}', Grades.C)
563 self.assertFormatIsValue('{:>20}', Grades.C)
564 self.assertFormatIsValue('{:<20}', Grades.C)
565 self.assertFormatIsValue('{:+}', Grades.C)
566 self.assertFormatIsValue('{:08X}', Grades.C)
567 self.assertFormatIsValue('{:b}', Grades.C)
568
569 def test_format_enum_str(self):
570 Directional = self.Directional
571 self.assertFormatIsValue('{}', Directional.WEST)
572 self.assertFormatIsValue('{:}', Directional.WEST)
573 self.assertFormatIsValue('{:20}', Directional.WEST)
574 self.assertFormatIsValue('{:^20}', Directional.WEST)
575 self.assertFormatIsValue('{:>20}', Directional.WEST)
576 self.assertFormatIsValue('{:<20}', Directional.WEST)
577
Ethan Furman22415ad2020-09-15 16:28:25 -0700578 def test_object_str_override(self):
579 class Colors(Enum):
580 RED, GREEN, BLUE = 1, 2, 3
581 def __repr__(self):
582 return "test.%s" % (self._name_, )
583 __str__ = object.__str__
584 self.assertEqual(str(Colors.RED), 'test.RED')
585
Ethan Furmanbff01f32020-09-15 15:56:26 -0700586 def test_enum_str_override(self):
587 class MyStrEnum(Enum):
588 def __str__(self):
589 return 'MyStr'
590 class MyMethodEnum(Enum):
591 def hello(self):
592 return 'Hello! My name is %s' % self.name
593 class Test1Enum(MyMethodEnum, int, MyStrEnum):
594 One = 1
595 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800596 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800598 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700599 #
600 class Test2Enum(MyStrEnum, MyMethodEnum):
601 One = 1
602 Two = 2
603 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800604 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700605
606 def test_inherited_data_type(self):
607 class HexInt(int):
608 def __repr__(self):
609 return hex(self)
610 class MyEnum(HexInt, enum.Enum):
611 A = 1
612 B = 2
613 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700614 def __repr__(self):
615 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700616 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
617
618 def test_too_many_data_types(self):
619 with self.assertRaisesRegex(TypeError, 'too many data types'):
620 class Huh(str, int, Enum):
621 One = 1
622
623 class MyStr(str):
624 def hello(self):
625 return 'hello, %s' % self
626 class MyInt(int):
627 def repr(self):
628 return hex(self)
629 with self.assertRaisesRegex(TypeError, 'too many data types'):
630 class Huh(MyStr, MyInt, Enum):
631 One = 1
632
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700633 def test_hash(self):
634 Season = self.Season
635 dates = {}
636 dates[Season.WINTER] = '1225'
637 dates[Season.SPRING] = '0315'
638 dates[Season.SUMMER] = '0704'
639 dates[Season.AUTUMN] = '1031'
640 self.assertEqual(dates[Season.AUTUMN], '1031')
641
642 def test_intenum_from_scratch(self):
643 class phy(int, Enum):
644 pi = 3
645 tau = 2 * pi
646 self.assertTrue(phy.pi < phy.tau)
647
648 def test_intenum_inherited(self):
649 class IntEnum(int, Enum):
650 pass
651 class phy(IntEnum):
652 pi = 3
653 tau = 2 * pi
654 self.assertTrue(phy.pi < phy.tau)
655
656 def test_floatenum_from_scratch(self):
657 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700658 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700659 tau = 2 * pi
660 self.assertTrue(phy.pi < phy.tau)
661
662 def test_floatenum_inherited(self):
663 class FloatEnum(float, Enum):
664 pass
665 class phy(FloatEnum):
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_strenum_from_scratch(self):
671 class phy(str, Enum):
672 pi = 'Pi'
673 tau = 'Tau'
674 self.assertTrue(phy.pi < phy.tau)
675
Ethan Furman0063ff42020-09-21 17:23:13 -0700676 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700677 class phy(StrEnum):
678 pi = 'Pi'
679 tau = 'Tau'
680 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700681 self.assertEqual(phy.pi.upper(), 'PI')
682 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700683
684 def test_intenum(self):
685 class WeekDay(IntEnum):
686 SUNDAY = 1
687 MONDAY = 2
688 TUESDAY = 3
689 WEDNESDAY = 4
690 THURSDAY = 5
691 FRIDAY = 6
692 SATURDAY = 7
693
694 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
695 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
696
697 lst = list(WeekDay)
698 self.assertEqual(len(lst), len(WeekDay))
699 self.assertEqual(len(WeekDay), 7)
700 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
701 target = target.split()
702 for i, weekday in enumerate(target, 1):
703 e = WeekDay(i)
704 self.assertEqual(e, i)
705 self.assertEqual(int(e), i)
706 self.assertEqual(e.name, weekday)
707 self.assertIn(e, WeekDay)
708 self.assertEqual(lst.index(e)+1, i)
709 self.assertTrue(0 < e < 8)
710 self.assertIs(type(e), WeekDay)
711 self.assertIsInstance(e, int)
712 self.assertIsInstance(e, Enum)
713
714 def test_intenum_duplicates(self):
715 class WeekDay(IntEnum):
716 SUNDAY = 1
717 MONDAY = 2
718 TUESDAY = TEUSDAY = 3
719 WEDNESDAY = 4
720 THURSDAY = 5
721 FRIDAY = 6
722 SATURDAY = 7
723 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
724 self.assertEqual(WeekDay(3).name, 'TUESDAY')
725 self.assertEqual([k for k,v in WeekDay.__members__.items()
726 if v.name != k], ['TEUSDAY', ])
727
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300728 def test_intenum_from_bytes(self):
729 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
730 with self.assertRaises(ValueError):
731 IntStooges.from_bytes(b'\x00\x05', 'big')
732
733 def test_floatenum_fromhex(self):
734 h = float.hex(FloatStooges.MOE.value)
735 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
736 h = float.hex(FloatStooges.MOE.value + 0.01)
737 with self.assertRaises(ValueError):
738 FloatStooges.fromhex(h)
739
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700740 def test_pickle_enum(self):
741 if isinstance(Stooges, Exception):
742 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800743 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
744 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700745
746 def test_pickle_int(self):
747 if isinstance(IntStooges, Exception):
748 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800749 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
750 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700751
752 def test_pickle_float(self):
753 if isinstance(FloatStooges, Exception):
754 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800755 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
756 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700757
758 def test_pickle_enum_function(self):
759 if isinstance(Answer, Exception):
760 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800761 test_pickle_dump_load(self.assertIs, Answer.him)
762 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700763
764 def test_pickle_enum_function_with_module(self):
765 if isinstance(Question, Exception):
766 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800767 test_pickle_dump_load(self.assertIs, Question.who)
768 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700769
Ethan Furmanca1b7942014-02-08 11:36:27 -0800770 def test_enum_function_with_qualname(self):
771 if isinstance(Theory, Exception):
772 raise Theory
773 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
774
775 def test_class_nested_enum_and_pickle_protocol_four(self):
776 # would normally just have this directly in the class namespace
777 class NestedEnum(Enum):
778 twigs = 'common'
779 shiny = 'rare'
780
781 self.__class__.NestedEnum = NestedEnum
782 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300783 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784
Ethan Furman24e837f2015-03-18 17:27:57 -0700785 def test_pickle_by_name(self):
786 class ReplaceGlobalInt(IntEnum):
787 ONE = 1
788 TWO = 2
789 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
790 for proto in range(HIGHEST_PROTOCOL):
791 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
792
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700793 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800794 BadPickle = Enum(
795 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700796 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800797 # now break BadPickle to test exception raising
798 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800799 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
800 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700801
802 def test_string_enum(self):
803 class SkillLevel(str, Enum):
804 master = 'what is the sound of one hand clapping?'
805 journeyman = 'why did the chicken cross the road?'
806 apprentice = 'knock, knock!'
807 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
808
809 def test_getattr_getitem(self):
810 class Period(Enum):
811 morning = 1
812 noon = 2
813 evening = 3
814 night = 4
815 self.assertIs(Period(2), Period.noon)
816 self.assertIs(getattr(Period, 'night'), Period.night)
817 self.assertIs(Period['morning'], Period.morning)
818
819 def test_getattr_dunder(self):
820 Season = self.Season
821 self.assertTrue(getattr(Season, '__eq__'))
822
823 def test_iteration_order(self):
824 class Season(Enum):
825 SUMMER = 2
826 WINTER = 4
827 AUTUMN = 3
828 SPRING = 1
829 self.assertEqual(
830 list(Season),
831 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
832 )
833
Ethan Furman2131a4a2013-09-14 18:11:24 -0700834 def test_reversed_iteration_order(self):
835 self.assertEqual(
836 list(reversed(self.Season)),
837 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
838 self.Season.SPRING]
839 )
840
Martin Pantereb995702016-07-28 01:11:04 +0000841 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700842 SummerMonth = Enum('SummerMonth', 'june july august')
843 lst = list(SummerMonth)
844 self.assertEqual(len(lst), len(SummerMonth))
845 self.assertEqual(len(SummerMonth), 3, SummerMonth)
846 self.assertEqual(
847 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
848 lst,
849 )
850 for i, month in enumerate('june july august'.split(), 1):
851 e = SummerMonth(i)
852 self.assertEqual(int(e.value), i)
853 self.assertNotEqual(e, i)
854 self.assertEqual(e.name, month)
855 self.assertIn(e, SummerMonth)
856 self.assertIs(type(e), SummerMonth)
857
Martin Pantereb995702016-07-28 01:11:04 +0000858 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700859 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
860 lst = list(SummerMonth)
861 self.assertEqual(len(lst), len(SummerMonth))
862 self.assertEqual(len(SummerMonth), 3, SummerMonth)
863 self.assertEqual(
864 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
865 lst,
866 )
867 for i, month in enumerate('june july august'.split(), 10):
868 e = SummerMonth(i)
869 self.assertEqual(int(e.value), i)
870 self.assertNotEqual(e, i)
871 self.assertEqual(e.name, month)
872 self.assertIn(e, SummerMonth)
873 self.assertIs(type(e), SummerMonth)
874
Martin Pantereb995702016-07-28 01:11:04 +0000875 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700876 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
877 lst = list(SummerMonth)
878 self.assertEqual(len(lst), len(SummerMonth))
879 self.assertEqual(len(SummerMonth), 3, SummerMonth)
880 self.assertEqual(
881 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
882 lst,
883 )
884 for i, month in enumerate('june july august'.split(), 1):
885 e = SummerMonth(i)
886 self.assertEqual(int(e.value), i)
887 self.assertNotEqual(e, i)
888 self.assertEqual(e.name, month)
889 self.assertIn(e, SummerMonth)
890 self.assertIs(type(e), SummerMonth)
891
Martin Pantereb995702016-07-28 01:11:04 +0000892 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700893 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
894 lst = list(SummerMonth)
895 self.assertEqual(len(lst), len(SummerMonth))
896 self.assertEqual(len(SummerMonth), 3, SummerMonth)
897 self.assertEqual(
898 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
899 lst,
900 )
901 for i, month in enumerate('june july august'.split(), 20):
902 e = SummerMonth(i)
903 self.assertEqual(int(e.value), i)
904 self.assertNotEqual(e, i)
905 self.assertEqual(e.name, month)
906 self.assertIn(e, SummerMonth)
907 self.assertIs(type(e), SummerMonth)
908
Martin Pantereb995702016-07-28 01:11:04 +0000909 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700910 SummerMonth = Enum(
911 'SummerMonth',
912 (('june', 1), ('july', 2), ('august', 3))
913 )
914 lst = list(SummerMonth)
915 self.assertEqual(len(lst), len(SummerMonth))
916 self.assertEqual(len(SummerMonth), 3, SummerMonth)
917 self.assertEqual(
918 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
919 lst,
920 )
921 for i, month in enumerate('june july august'.split(), 1):
922 e = SummerMonth(i)
923 self.assertEqual(int(e.value), i)
924 self.assertNotEqual(e, i)
925 self.assertEqual(e.name, month)
926 self.assertIn(e, SummerMonth)
927 self.assertIs(type(e), SummerMonth)
928
Martin Pantereb995702016-07-28 01:11:04 +0000929 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700930 SummerMonth = Enum(
931 'SummerMonth',
932 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
933 )
934 lst = list(SummerMonth)
935 self.assertEqual(len(lst), len(SummerMonth))
936 self.assertEqual(len(SummerMonth), 3, SummerMonth)
937 self.assertEqual(
938 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
939 lst,
940 )
941 for i, month in enumerate('june july august'.split(), 1):
942 e = SummerMonth(i)
943 self.assertEqual(int(e.value), i)
944 self.assertNotEqual(e, i)
945 self.assertEqual(e.name, month)
946 self.assertIn(e, SummerMonth)
947 self.assertIs(type(e), SummerMonth)
948
Martin Pantereb995702016-07-28 01:11:04 +0000949 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700950 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
951 lst = list(SummerMonth)
952 self.assertEqual(len(lst), len(SummerMonth))
953 self.assertEqual(len(SummerMonth), 3, SummerMonth)
954 self.assertEqual(
955 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
956 lst,
957 )
958 for i, month in enumerate('june july august'.split(), 1):
959 e = SummerMonth(i)
960 self.assertEqual(e, i)
961 self.assertEqual(e.name, month)
962 self.assertIn(e, SummerMonth)
963 self.assertIs(type(e), SummerMonth)
964
Martin Pantereb995702016-07-28 01:11:04 +0000965 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700966 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
967 lst = list(SummerMonth)
968 self.assertEqual(len(lst), len(SummerMonth))
969 self.assertEqual(len(SummerMonth), 3, SummerMonth)
970 self.assertEqual(
971 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
972 lst,
973 )
974 for i, month in enumerate('june july august'.split(), 30):
975 e = SummerMonth(i)
976 self.assertEqual(e, i)
977 self.assertEqual(e.name, month)
978 self.assertIn(e, SummerMonth)
979 self.assertIs(type(e), SummerMonth)
980
Martin Pantereb995702016-07-28 01:11:04 +0000981 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700982 SummerMonth = IntEnum('SummerMonth', 'june july august')
983 lst = list(SummerMonth)
984 self.assertEqual(len(lst), len(SummerMonth))
985 self.assertEqual(len(SummerMonth), 3, SummerMonth)
986 self.assertEqual(
987 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
988 lst,
989 )
990 for i, month in enumerate('june july august'.split(), 1):
991 e = SummerMonth(i)
992 self.assertEqual(e, i)
993 self.assertEqual(e.name, month)
994 self.assertIn(e, SummerMonth)
995 self.assertIs(type(e), SummerMonth)
996
Martin Pantereb995702016-07-28 01:11:04 +0000997 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700998 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
999 lst = list(SummerMonth)
1000 self.assertEqual(len(lst), len(SummerMonth))
1001 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1002 self.assertEqual(
1003 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1004 lst,
1005 )
1006 for i, month in enumerate('june july august'.split(), 40):
1007 e = SummerMonth(i)
1008 self.assertEqual(e, i)
1009 self.assertEqual(e.name, month)
1010 self.assertIn(e, SummerMonth)
1011 self.assertIs(type(e), SummerMonth)
1012
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001013 def test_subclassing(self):
1014 if isinstance(Name, Exception):
1015 raise Name
1016 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1017 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1018 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001019 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001020
1021 def test_extending(self):
1022 class Color(Enum):
1023 red = 1
1024 green = 2
1025 blue = 3
1026 with self.assertRaises(TypeError):
1027 class MoreColor(Color):
1028 cyan = 4
1029 magenta = 5
1030 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001031 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1032 class EvenMoreColor(Color, IntEnum):
1033 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034
1035 def test_exclude_methods(self):
1036 class whatever(Enum):
1037 this = 'that'
1038 these = 'those'
1039 def really(self):
1040 return 'no, not %s' % self.value
1041 self.assertIsNot(type(whatever.really), whatever)
1042 self.assertEqual(whatever.this.really(), 'no, not that')
1043
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001044 def test_wrong_inheritance_order(self):
1045 with self.assertRaises(TypeError):
1046 class Wrong(Enum, str):
1047 NotHere = 'error before this point'
1048
1049 def test_intenum_transitivity(self):
1050 class number(IntEnum):
1051 one = 1
1052 two = 2
1053 three = 3
1054 class numero(IntEnum):
1055 uno = 1
1056 dos = 2
1057 tres = 3
1058 self.assertEqual(number.one, numero.uno)
1059 self.assertEqual(number.two, numero.dos)
1060 self.assertEqual(number.three, numero.tres)
1061
1062 def test_wrong_enum_in_call(self):
1063 class Monochrome(Enum):
1064 black = 0
1065 white = 1
1066 class Gender(Enum):
1067 male = 0
1068 female = 1
1069 self.assertRaises(ValueError, Monochrome, Gender.male)
1070
1071 def test_wrong_enum_in_mixed_call(self):
1072 class Monochrome(IntEnum):
1073 black = 0
1074 white = 1
1075 class Gender(Enum):
1076 male = 0
1077 female = 1
1078 self.assertRaises(ValueError, Monochrome, Gender.male)
1079
1080 def test_mixed_enum_in_call_1(self):
1081 class Monochrome(IntEnum):
1082 black = 0
1083 white = 1
1084 class Gender(IntEnum):
1085 male = 0
1086 female = 1
1087 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1088
1089 def test_mixed_enum_in_call_2(self):
1090 class Monochrome(Enum):
1091 black = 0
1092 white = 1
1093 class Gender(IntEnum):
1094 male = 0
1095 female = 1
1096 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1097
1098 def test_flufl_enum(self):
1099 class Fluflnum(Enum):
1100 def __int__(self):
1101 return int(self.value)
1102 class MailManOptions(Fluflnum):
1103 option1 = 1
1104 option2 = 2
1105 option3 = 3
1106 self.assertEqual(int(MailManOptions.option1), 1)
1107
Ethan Furman5e5a8232013-08-04 08:42:23 -07001108 def test_introspection(self):
1109 class Number(IntEnum):
1110 one = 100
1111 two = 200
1112 self.assertIs(Number.one._member_type_, int)
1113 self.assertIs(Number._member_type_, int)
1114 class String(str, Enum):
1115 yarn = 'soft'
1116 rope = 'rough'
1117 wire = 'hard'
1118 self.assertIs(String.yarn._member_type_, str)
1119 self.assertIs(String._member_type_, str)
1120 class Plain(Enum):
1121 vanilla = 'white'
1122 one = 1
1123 self.assertIs(Plain.vanilla._member_type_, object)
1124 self.assertIs(Plain._member_type_, object)
1125
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001126 def test_no_such_enum_member(self):
1127 class Color(Enum):
1128 red = 1
1129 green = 2
1130 blue = 3
1131 with self.assertRaises(ValueError):
1132 Color(4)
1133 with self.assertRaises(KeyError):
1134 Color['chartreuse']
1135
1136 def test_new_repr(self):
1137 class Color(Enum):
1138 red = 1
1139 green = 2
1140 blue = 3
1141 def __repr__(self):
1142 return "don't you just love shades of %s?" % self.name
1143 self.assertEqual(
1144 repr(Color.blue),
1145 "don't you just love shades of blue?",
1146 )
1147
1148 def test_inherited_repr(self):
1149 class MyEnum(Enum):
1150 def __repr__(self):
1151 return "My name is %s." % self.name
1152 class MyIntEnum(int, MyEnum):
1153 this = 1
1154 that = 2
1155 theother = 3
1156 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1157
1158 def test_multiple_mixin_mro(self):
1159 class auto_enum(type(Enum)):
1160 def __new__(metacls, cls, bases, classdict):
1161 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001162 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001163 names = set(classdict._member_names)
1164 i = 0
1165 for k in classdict._member_names:
1166 v = classdict[k]
1167 if v is Ellipsis:
1168 v = i
1169 else:
1170 i = v
1171 i += 1
1172 temp[k] = v
1173 for k, v in classdict.items():
1174 if k not in names:
1175 temp[k] = v
1176 return super(auto_enum, metacls).__new__(
1177 metacls, cls, bases, temp)
1178
1179 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1180 pass
1181
1182 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1183 pass
1184
1185 class TestAutoNumber(AutoNumberedEnum):
1186 a = ...
1187 b = 3
1188 c = ...
1189
1190 class TestAutoInt(AutoIntEnum):
1191 a = ...
1192 b = 3
1193 c = ...
1194
1195 def test_subclasses_with_getnewargs(self):
1196 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001197 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001198 def __new__(cls, *args):
1199 _args = args
1200 name, *args = args
1201 if len(args) == 0:
1202 raise TypeError("name and value must be specified")
1203 self = int.__new__(cls, *args)
1204 self._intname = name
1205 self._args = _args
1206 return self
1207 def __getnewargs__(self):
1208 return self._args
1209 @property
1210 def __name__(self):
1211 return self._intname
1212 def __repr__(self):
1213 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001214 return "{}({!r}, {})".format(
1215 type(self).__name__,
1216 self.__name__,
1217 int.__repr__(self),
1218 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001219 def __str__(self):
1220 # str() is unchanged, even if it relies on the repr() fallback
1221 base = int
1222 base_str = base.__str__
1223 if base_str.__objclass__ is object:
1224 return base.__repr__(self)
1225 return base_str(self)
1226 # for simplicity, we only define one operator that
1227 # propagates expressions
1228 def __add__(self, other):
1229 temp = int(self) + int( other)
1230 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1231 return NamedInt(
1232 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001233 temp,
1234 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001235 else:
1236 return temp
1237
1238 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001239 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240 x = ('the-x', 1)
1241 y = ('the-y', 2)
1242
Ethan Furman2aa27322013-07-19 19:35:56 -07001243
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001244 self.assertIs(NEI.__new__, Enum.__new__)
1245 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1246 globals()['NamedInt'] = NamedInt
1247 globals()['NEI'] = NEI
1248 NI5 = NamedInt('test', 5)
1249 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001250 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001251 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001252 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001253 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001254
Ethan Furmanca1b7942014-02-08 11:36:27 -08001255 def test_subclasses_with_getnewargs_ex(self):
1256 class NamedInt(int):
1257 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1258 def __new__(cls, *args):
1259 _args = args
1260 name, *args = args
1261 if len(args) == 0:
1262 raise TypeError("name and value must be specified")
1263 self = int.__new__(cls, *args)
1264 self._intname = name
1265 self._args = _args
1266 return self
1267 def __getnewargs_ex__(self):
1268 return self._args, {}
1269 @property
1270 def __name__(self):
1271 return self._intname
1272 def __repr__(self):
1273 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001274 return "{}({!r}, {})".format(
1275 type(self).__name__,
1276 self.__name__,
1277 int.__repr__(self),
1278 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001279 def __str__(self):
1280 # str() is unchanged, even if it relies on the repr() fallback
1281 base = int
1282 base_str = base.__str__
1283 if base_str.__objclass__ is object:
1284 return base.__repr__(self)
1285 return base_str(self)
1286 # for simplicity, we only define one operator that
1287 # propagates expressions
1288 def __add__(self, other):
1289 temp = int(self) + int( other)
1290 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1291 return NamedInt(
1292 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001293 temp,
1294 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001295 else:
1296 return temp
1297
1298 class NEI(NamedInt, Enum):
1299 __qualname__ = 'NEI' # needed for pickle protocol 4
1300 x = ('the-x', 1)
1301 y = ('the-y', 2)
1302
1303
1304 self.assertIs(NEI.__new__, Enum.__new__)
1305 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1306 globals()['NamedInt'] = NamedInt
1307 globals()['NEI'] = NEI
1308 NI5 = NamedInt('test', 5)
1309 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001310 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001311 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001312 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001313 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001314
1315 def test_subclasses_with_reduce(self):
1316 class NamedInt(int):
1317 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1318 def __new__(cls, *args):
1319 _args = args
1320 name, *args = args
1321 if len(args) == 0:
1322 raise TypeError("name and value must be specified")
1323 self = int.__new__(cls, *args)
1324 self._intname = name
1325 self._args = _args
1326 return self
1327 def __reduce__(self):
1328 return self.__class__, self._args
1329 @property
1330 def __name__(self):
1331 return self._intname
1332 def __repr__(self):
1333 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001334 return "{}({!r}, {})".format(
1335 type(self).__name__,
1336 self.__name__,
1337 int.__repr__(self),
1338 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001339 def __str__(self):
1340 # str() is unchanged, even if it relies on the repr() fallback
1341 base = int
1342 base_str = base.__str__
1343 if base_str.__objclass__ is object:
1344 return base.__repr__(self)
1345 return base_str(self)
1346 # for simplicity, we only define one operator that
1347 # propagates expressions
1348 def __add__(self, other):
1349 temp = int(self) + int( other)
1350 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1351 return NamedInt(
1352 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001353 temp,
1354 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001355 else:
1356 return temp
1357
1358 class NEI(NamedInt, Enum):
1359 __qualname__ = 'NEI' # needed for pickle protocol 4
1360 x = ('the-x', 1)
1361 y = ('the-y', 2)
1362
1363
1364 self.assertIs(NEI.__new__, Enum.__new__)
1365 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1366 globals()['NamedInt'] = NamedInt
1367 globals()['NEI'] = NEI
1368 NI5 = NamedInt('test', 5)
1369 self.assertEqual(NI5, 5)
1370 test_pickle_dump_load(self.assertEqual, NI5, 5)
1371 self.assertEqual(NEI.y.value, 2)
1372 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001373 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001374
1375 def test_subclasses_with_reduce_ex(self):
1376 class NamedInt(int):
1377 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1378 def __new__(cls, *args):
1379 _args = args
1380 name, *args = args
1381 if len(args) == 0:
1382 raise TypeError("name and value must be specified")
1383 self = int.__new__(cls, *args)
1384 self._intname = name
1385 self._args = _args
1386 return self
1387 def __reduce_ex__(self, proto):
1388 return self.__class__, self._args
1389 @property
1390 def __name__(self):
1391 return self._intname
1392 def __repr__(self):
1393 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001394 return "{}({!r}, {})".format(
1395 type(self).__name__,
1396 self.__name__,
1397 int.__repr__(self),
1398 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001399 def __str__(self):
1400 # str() is unchanged, even if it relies on the repr() fallback
1401 base = int
1402 base_str = base.__str__
1403 if base_str.__objclass__ is object:
1404 return base.__repr__(self)
1405 return base_str(self)
1406 # for simplicity, we only define one operator that
1407 # propagates expressions
1408 def __add__(self, other):
1409 temp = int(self) + int( other)
1410 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1411 return NamedInt(
1412 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001413 temp,
1414 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001415 else:
1416 return temp
1417
1418 class NEI(NamedInt, Enum):
1419 __qualname__ = 'NEI' # needed for pickle protocol 4
1420 x = ('the-x', 1)
1421 y = ('the-y', 2)
1422
Ethan Furmanca1b7942014-02-08 11:36:27 -08001423 self.assertIs(NEI.__new__, Enum.__new__)
1424 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1425 globals()['NamedInt'] = NamedInt
1426 globals()['NEI'] = NEI
1427 NI5 = NamedInt('test', 5)
1428 self.assertEqual(NI5, 5)
1429 test_pickle_dump_load(self.assertEqual, NI5, 5)
1430 self.assertEqual(NEI.y.value, 2)
1431 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001432 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001433
Ethan Furmandc870522014-02-18 12:37:12 -08001434 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001435 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001436 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001437 def __new__(cls, *args):
1438 _args = args
1439 name, *args = args
1440 if len(args) == 0:
1441 raise TypeError("name and value must be specified")
1442 self = int.__new__(cls, *args)
1443 self._intname = name
1444 self._args = _args
1445 return self
1446 @property
1447 def __name__(self):
1448 return self._intname
1449 def __repr__(self):
1450 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001451 return "{}({!r}, {})".format(
1452 type(self).__name__,
1453 self.__name__,
1454 int.__repr__(self),
1455 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 def __str__(self):
1457 # str() is unchanged, even if it relies on the repr() fallback
1458 base = int
1459 base_str = base.__str__
1460 if base_str.__objclass__ is object:
1461 return base.__repr__(self)
1462 return base_str(self)
1463 # for simplicity, we only define one operator that
1464 # propagates expressions
1465 def __add__(self, other):
1466 temp = int(self) + int( other)
1467 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1468 return NamedInt(
1469 '({0} + {1})'.format(self.__name__, other.__name__),
1470 temp )
1471 else:
1472 return temp
1473
1474 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001475 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001476 x = ('the-x', 1)
1477 y = ('the-y', 2)
1478
1479 self.assertIs(NEI.__new__, Enum.__new__)
1480 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1481 globals()['NamedInt'] = NamedInt
1482 globals()['NEI'] = NEI
1483 NI5 = NamedInt('test', 5)
1484 self.assertEqual(NI5, 5)
1485 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001486 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1487 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001488
Ethan Furmandc870522014-02-18 12:37:12 -08001489 def test_subclasses_without_direct_pickle_support_using_name(self):
1490 class NamedInt(int):
1491 __qualname__ = 'NamedInt'
1492 def __new__(cls, *args):
1493 _args = args
1494 name, *args = args
1495 if len(args) == 0:
1496 raise TypeError("name and value must be specified")
1497 self = int.__new__(cls, *args)
1498 self._intname = name
1499 self._args = _args
1500 return self
1501 @property
1502 def __name__(self):
1503 return self._intname
1504 def __repr__(self):
1505 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001506 return "{}({!r}, {})".format(
1507 type(self).__name__,
1508 self.__name__,
1509 int.__repr__(self),
1510 )
Ethan Furmandc870522014-02-18 12:37:12 -08001511 def __str__(self):
1512 # str() is unchanged, even if it relies on the repr() fallback
1513 base = int
1514 base_str = base.__str__
1515 if base_str.__objclass__ is object:
1516 return base.__repr__(self)
1517 return base_str(self)
1518 # for simplicity, we only define one operator that
1519 # propagates expressions
1520 def __add__(self, other):
1521 temp = int(self) + int( other)
1522 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1523 return NamedInt(
1524 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001525 temp,
1526 )
Ethan Furmandc870522014-02-18 12:37:12 -08001527 else:
1528 return temp
1529
1530 class NEI(NamedInt, Enum):
1531 __qualname__ = 'NEI'
1532 x = ('the-x', 1)
1533 y = ('the-y', 2)
1534 def __reduce_ex__(self, proto):
1535 return getattr, (self.__class__, self._name_)
1536
1537 self.assertIs(NEI.__new__, Enum.__new__)
1538 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1539 globals()['NamedInt'] = NamedInt
1540 globals()['NEI'] = NEI
1541 NI5 = NamedInt('test', 5)
1542 self.assertEqual(NI5, 5)
1543 self.assertEqual(NEI.y.value, 2)
1544 test_pickle_dump_load(self.assertIs, NEI.y)
1545 test_pickle_dump_load(self.assertIs, NEI)
1546
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 def test_tuple_subclass(self):
1548 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001549 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001550 first = (1, 'for the money')
1551 second = (2, 'for the show')
1552 third = (3, 'for the music')
1553 self.assertIs(type(SomeTuple.first), SomeTuple)
1554 self.assertIsInstance(SomeTuple.second, tuple)
1555 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1556 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001557 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558
1559 def test_duplicate_values_give_unique_enum_items(self):
1560 class AutoNumber(Enum):
1561 first = ()
1562 second = ()
1563 third = ()
1564 def __new__(cls):
1565 value = len(cls.__members__) + 1
1566 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001567 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001568 return obj
1569 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001570 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001571 self.assertEqual(
1572 list(AutoNumber),
1573 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1574 )
1575 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001576 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 self.assertIs(AutoNumber(1), AutoNumber.first)
1578
1579 def test_inherited_new_from_enhanced_enum(self):
1580 class AutoNumber(Enum):
1581 def __new__(cls):
1582 value = len(cls.__members__) + 1
1583 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001584 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001585 return obj
1586 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001587 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001588 class Color(AutoNumber):
1589 red = ()
1590 green = ()
1591 blue = ()
1592 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1593 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1594
1595 def test_inherited_new_from_mixed_enum(self):
1596 class AutoNumber(IntEnum):
1597 def __new__(cls):
1598 value = len(cls.__members__) + 1
1599 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001600 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001601 return obj
1602 class Color(AutoNumber):
1603 red = ()
1604 green = ()
1605 blue = ()
1606 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1607 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1608
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001609 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001610 class OrdinaryEnum(Enum):
1611 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001612 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1613 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001614
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001615 def test_ordered_mixin(self):
1616 class OrderedEnum(Enum):
1617 def __ge__(self, other):
1618 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001619 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001620 return NotImplemented
1621 def __gt__(self, other):
1622 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001623 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001624 return NotImplemented
1625 def __le__(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 __lt__(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 class Grade(OrderedEnum):
1634 A = 5
1635 B = 4
1636 C = 3
1637 D = 2
1638 F = 1
1639 self.assertGreater(Grade.A, Grade.B)
1640 self.assertLessEqual(Grade.F, Grade.C)
1641 self.assertLess(Grade.D, Grade.A)
1642 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001643 self.assertEqual(Grade.B, Grade.B)
1644 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001645
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001646 def test_extending2(self):
1647 class Shade(Enum):
1648 def shade(self):
1649 print(self.name)
1650 class Color(Shade):
1651 red = 1
1652 green = 2
1653 blue = 3
1654 with self.assertRaises(TypeError):
1655 class MoreColor(Color):
1656 cyan = 4
1657 magenta = 5
1658 yellow = 6
1659
1660 def test_extending3(self):
1661 class Shade(Enum):
1662 def shade(self):
1663 return self.name
1664 class Color(Shade):
1665 def hex(self):
1666 return '%s hexlified!' % self.value
1667 class MoreColor(Color):
1668 cyan = 4
1669 magenta = 5
1670 yellow = 6
1671 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1672
orlnub1230fb9fad2018-09-12 20:28:53 +03001673 def test_subclass_duplicate_name(self):
1674 class Base(Enum):
1675 def test(self):
1676 pass
1677 class Test(Base):
1678 test = 1
1679 self.assertIs(type(Test.test), Test)
1680
1681 def test_subclass_duplicate_name_dynamic(self):
1682 from types import DynamicClassAttribute
1683 class Base(Enum):
1684 @DynamicClassAttribute
1685 def test(self):
1686 return 'dynamic'
1687 class Test(Base):
1688 test = 1
1689 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001690 class Base2(Enum):
1691 @enum.property
1692 def flash(self):
1693 return 'flashy dynamic'
1694 class Test(Base2):
1695 flash = 1
1696 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001697
1698 def test_no_duplicates(self):
1699 class UniqueEnum(Enum):
1700 def __init__(self, *args):
1701 cls = self.__class__
1702 if any(self.value == e.value for e in cls):
1703 a = self.name
1704 e = cls(self.value).name
1705 raise ValueError(
1706 "aliases not allowed in UniqueEnum: %r --> %r"
1707 % (a, e)
1708 )
1709 class Color(UniqueEnum):
1710 red = 1
1711 green = 2
1712 blue = 3
1713 with self.assertRaises(ValueError):
1714 class Color(UniqueEnum):
1715 red = 1
1716 green = 2
1717 blue = 3
1718 grene = 2
1719
1720 def test_init(self):
1721 class Planet(Enum):
1722 MERCURY = (3.303e+23, 2.4397e6)
1723 VENUS = (4.869e+24, 6.0518e6)
1724 EARTH = (5.976e+24, 6.37814e6)
1725 MARS = (6.421e+23, 3.3972e6)
1726 JUPITER = (1.9e+27, 7.1492e7)
1727 SATURN = (5.688e+26, 6.0268e7)
1728 URANUS = (8.686e+25, 2.5559e7)
1729 NEPTUNE = (1.024e+26, 2.4746e7)
1730 def __init__(self, mass, radius):
1731 self.mass = mass # in kilograms
1732 self.radius = radius # in meters
1733 @property
1734 def surface_gravity(self):
1735 # universal gravitational constant (m3 kg-1 s-2)
1736 G = 6.67300E-11
1737 return G * self.mass / (self.radius * self.radius)
1738 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1739 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1740
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001741 def test_ignore(self):
1742 class Period(timedelta, Enum):
1743 '''
1744 different lengths of time
1745 '''
1746 def __new__(cls, value, period):
1747 obj = timedelta.__new__(cls, value)
1748 obj._value_ = value
1749 obj.period = period
1750 return obj
1751 _ignore_ = 'Period i'
1752 Period = vars()
1753 for i in range(13):
1754 Period['month_%d' % i] = i*30, 'month'
1755 for i in range(53):
1756 Period['week_%d' % i] = i*7, 'week'
1757 for i in range(32):
1758 Period['day_%d' % i] = i, 'day'
1759 OneDay = day_1
1760 OneWeek = week_1
1761 OneMonth = month_1
1762 self.assertFalse(hasattr(Period, '_ignore_'))
1763 self.assertFalse(hasattr(Period, 'Period'))
1764 self.assertFalse(hasattr(Period, 'i'))
1765 self.assertTrue(isinstance(Period.day_1, timedelta))
1766 self.assertTrue(Period.month_1 is Period.day_30)
1767 self.assertTrue(Period.week_4 is Period.day_28)
1768
Ethan Furman2aa27322013-07-19 19:35:56 -07001769 def test_nonhash_value(self):
1770 class AutoNumberInAList(Enum):
1771 def __new__(cls):
1772 value = [len(cls.__members__) + 1]
1773 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001774 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001775 return obj
1776 class ColorInAList(AutoNumberInAList):
1777 red = ()
1778 green = ()
1779 blue = ()
1780 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001781 for enum, value in zip(ColorInAList, range(3)):
1782 value += 1
1783 self.assertEqual(enum.value, [value])
1784 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001785
Ethan Furmanb41803e2013-07-25 13:50:45 -07001786 def test_conflicting_types_resolved_in_new(self):
1787 class LabelledIntEnum(int, Enum):
1788 def __new__(cls, *args):
1789 value, label = args
1790 obj = int.__new__(cls, value)
1791 obj.label = label
1792 obj._value_ = value
1793 return obj
1794
1795 class LabelledList(LabelledIntEnum):
1796 unprocessed = (1, "Unprocessed")
1797 payment_complete = (2, "Payment Complete")
1798
1799 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1800 self.assertEqual(LabelledList.unprocessed, 1)
1801 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001802
Ethan Furmanc16595e2016-09-10 23:36:59 -07001803 def test_auto_number(self):
1804 class Color(Enum):
1805 red = auto()
1806 blue = auto()
1807 green = auto()
1808
1809 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1810 self.assertEqual(Color.red.value, 1)
1811 self.assertEqual(Color.blue.value, 2)
1812 self.assertEqual(Color.green.value, 3)
1813
1814 def test_auto_name(self):
1815 class Color(Enum):
1816 def _generate_next_value_(name, start, count, last):
1817 return name
1818 red = auto()
1819 blue = auto()
1820 green = auto()
1821
1822 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1823 self.assertEqual(Color.red.value, 'red')
1824 self.assertEqual(Color.blue.value, 'blue')
1825 self.assertEqual(Color.green.value, 'green')
1826
1827 def test_auto_name_inherit(self):
1828 class AutoNameEnum(Enum):
1829 def _generate_next_value_(name, start, count, last):
1830 return name
1831 class Color(AutoNameEnum):
1832 red = auto()
1833 blue = auto()
1834 green = auto()
1835
1836 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1837 self.assertEqual(Color.red.value, 'red')
1838 self.assertEqual(Color.blue.value, 'blue')
1839 self.assertEqual(Color.green.value, 'green')
1840
1841 def test_auto_garbage(self):
1842 class Color(Enum):
1843 red = 'red'
1844 blue = auto()
1845 self.assertEqual(Color.blue.value, 1)
1846
1847 def test_auto_garbage_corrected(self):
1848 class Color(Enum):
1849 red = 'red'
1850 blue = 2
1851 green = auto()
1852
1853 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1854 self.assertEqual(Color.red.value, 'red')
1855 self.assertEqual(Color.blue.value, 2)
1856 self.assertEqual(Color.green.value, 3)
1857
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001858 def test_auto_order(self):
1859 with self.assertRaises(TypeError):
1860 class Color(Enum):
1861 red = auto()
1862 green = auto()
1863 blue = auto()
1864 def _generate_next_value_(name, start, count, last):
1865 return name
1866
Ethan Furmanfc23a942020-09-16 12:37:54 -07001867 def test_auto_order_wierd(self):
1868 weird_auto = auto()
1869 weird_auto.value = 'pathological case'
1870 class Color(Enum):
1871 red = weird_auto
1872 def _generate_next_value_(name, start, count, last):
1873 return name
1874 blue = auto()
1875 self.assertEqual(list(Color), [Color.red, Color.blue])
1876 self.assertEqual(Color.red.value, 'pathological case')
1877 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001878
Ethan Furman3515dcc2016-09-18 13:15:41 -07001879 def test_duplicate_auto(self):
1880 class Dupes(Enum):
1881 first = primero = auto()
1882 second = auto()
1883 third = auto()
1884 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1885
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001886 def test_default_missing(self):
1887 class Color(Enum):
1888 RED = 1
1889 GREEN = 2
1890 BLUE = 3
1891 try:
1892 Color(7)
1893 except ValueError as exc:
1894 self.assertTrue(exc.__context__ is None)
1895 else:
1896 raise Exception('Exception not raised.')
1897
Ethan Furman019f0a02018-09-12 11:43:34 -07001898 def test_missing(self):
1899 class Color(Enum):
1900 red = 1
1901 green = 2
1902 blue = 3
1903 @classmethod
1904 def _missing_(cls, item):
1905 if item == 'three':
1906 return cls.blue
1907 elif item == 'bad return':
1908 # trigger internal error
1909 return 5
1910 elif item == 'error out':
1911 raise ZeroDivisionError
1912 else:
1913 # trigger not found
1914 return None
1915 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001916 try:
1917 Color(7)
1918 except ValueError as exc:
1919 self.assertTrue(exc.__context__ is None)
1920 else:
1921 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001922 try:
1923 Color('bad return')
1924 except TypeError as exc:
1925 self.assertTrue(isinstance(exc.__context__, ValueError))
1926 else:
1927 raise Exception('Exception not raised.')
1928 try:
1929 Color('error out')
1930 except ZeroDivisionError as exc:
1931 self.assertTrue(isinstance(exc.__context__, ValueError))
1932 else:
1933 raise Exception('Exception not raised.')
1934
Ethan Furman8c14f5a2021-04-12 08:51:20 -07001935 def test_missing_exceptions_reset(self):
1936 import weakref
1937 #
1938 class TestEnum(enum.Enum):
1939 VAL1 = 'val1'
1940 VAL2 = 'val2'
1941 #
1942 class Class1:
1943 def __init__(self):
1944 # Gracefully handle an exception of our own making
1945 try:
1946 raise ValueError()
1947 except ValueError:
1948 pass
1949 #
1950 class Class2:
1951 def __init__(self):
1952 # Gracefully handle an exception of Enum's making
1953 try:
1954 TestEnum('invalid_value')
1955 except ValueError:
1956 pass
1957 # No strong refs here so these are free to die.
1958 class_1_ref = weakref.ref(Class1())
1959 class_2_ref = weakref.ref(Class2())
1960 #
1961 # The exception raised by Enum creates a reference loop and thus
1962 # Class2 instances will stick around until the next gargage collection
1963 # cycle, unlike Class1.
1964 self.assertIs(class_1_ref(), None)
1965 self.assertIs(class_2_ref(), None)
1966
Ethan Furman5bdab642018-09-21 19:03:09 -07001967 def test_multiple_mixin(self):
1968 class MaxMixin:
1969 @classproperty
1970 def MAX(cls):
1971 max = len(cls)
1972 cls.MAX = max
1973 return max
1974 class StrMixin:
1975 def __str__(self):
1976 return self._name_.lower()
1977 class SomeEnum(Enum):
1978 def behavior(self):
1979 return 'booyah'
1980 class AnotherEnum(Enum):
1981 def behavior(self):
1982 return 'nuhuh!'
1983 def social(self):
1984 return "what's up?"
1985 class Color(MaxMixin, Enum):
1986 RED = auto()
1987 GREEN = auto()
1988 BLUE = auto()
1989 self.assertEqual(Color.RED.value, 1)
1990 self.assertEqual(Color.GREEN.value, 2)
1991 self.assertEqual(Color.BLUE.value, 3)
1992 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07001993 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07001994 class Color(MaxMixin, StrMixin, Enum):
1995 RED = auto()
1996 GREEN = auto()
1997 BLUE = auto()
1998 self.assertEqual(Color.RED.value, 1)
1999 self.assertEqual(Color.GREEN.value, 2)
2000 self.assertEqual(Color.BLUE.value, 3)
2001 self.assertEqual(Color.MAX, 3)
2002 self.assertEqual(str(Color.BLUE), 'blue')
2003 class Color(StrMixin, MaxMixin, Enum):
2004 RED = auto()
2005 GREEN = auto()
2006 BLUE = auto()
2007 self.assertEqual(Color.RED.value, 1)
2008 self.assertEqual(Color.GREEN.value, 2)
2009 self.assertEqual(Color.BLUE.value, 3)
2010 self.assertEqual(Color.MAX, 3)
2011 self.assertEqual(str(Color.BLUE), 'blue')
2012 class CoolColor(StrMixin, SomeEnum, Enum):
2013 RED = auto()
2014 GREEN = auto()
2015 BLUE = auto()
2016 self.assertEqual(CoolColor.RED.value, 1)
2017 self.assertEqual(CoolColor.GREEN.value, 2)
2018 self.assertEqual(CoolColor.BLUE.value, 3)
2019 self.assertEqual(str(CoolColor.BLUE), 'blue')
2020 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2021 class CoolerColor(StrMixin, AnotherEnum, Enum):
2022 RED = auto()
2023 GREEN = auto()
2024 BLUE = auto()
2025 self.assertEqual(CoolerColor.RED.value, 1)
2026 self.assertEqual(CoolerColor.GREEN.value, 2)
2027 self.assertEqual(CoolerColor.BLUE.value, 3)
2028 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2029 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2030 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2031 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2032 RED = auto()
2033 GREEN = auto()
2034 BLUE = auto()
2035 self.assertEqual(CoolestColor.RED.value, 1)
2036 self.assertEqual(CoolestColor.GREEN.value, 2)
2037 self.assertEqual(CoolestColor.BLUE.value, 3)
2038 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2039 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2040 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2041 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2042 RED = auto()
2043 GREEN = auto()
2044 BLUE = auto()
2045 self.assertEqual(ConfusedColor.RED.value, 1)
2046 self.assertEqual(ConfusedColor.GREEN.value, 2)
2047 self.assertEqual(ConfusedColor.BLUE.value, 3)
2048 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2049 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2050 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2051 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2052 RED = auto()
2053 GREEN = auto()
2054 BLUE = auto()
2055 self.assertEqual(ReformedColor.RED.value, 1)
2056 self.assertEqual(ReformedColor.GREEN.value, 2)
2057 self.assertEqual(ReformedColor.BLUE.value, 3)
2058 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2059 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2060 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2061 self.assertTrue(issubclass(ReformedColor, int))
2062
Ethan Furmancd453852018-10-05 23:29:36 -07002063 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002064 @unique
2065 class Decision1(StrEnum):
2066 REVERT = "REVERT"
2067 REVERT_ALL = "REVERT_ALL"
2068 RETRY = "RETRY"
2069 class MyEnum(StrEnum):
2070 pass
2071 @unique
2072 class Decision2(MyEnum):
2073 REVERT = "REVERT"
2074 REVERT_ALL = "REVERT_ALL"
2075 RETRY = "RETRY"
2076
Ethan Furmanc2667362020-12-07 00:17:31 -08002077 def test_multiple_mixin_inherited(self):
2078 class MyInt(int):
2079 def __new__(cls, value):
2080 return super().__new__(cls, value)
2081
2082 class HexMixin:
2083 def __repr__(self):
2084 return hex(self)
2085
2086 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2087 pass
2088
2089 class Foo(MyIntEnum):
2090 TEST = 1
2091 self.assertTrue(isinstance(Foo.TEST, MyInt))
2092 self.assertEqual(repr(Foo.TEST), "0x1")
2093
2094 class Fee(MyIntEnum):
2095 TEST = 1
2096 def __new__(cls, value):
2097 value += 1
2098 member = int.__new__(cls, value)
2099 member._value_ = value
2100 return member
2101 self.assertEqual(Fee.TEST, 2)
2102
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002103 def test_empty_globals(self):
2104 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2105 # when using compile and exec because f_globals is empty
2106 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2107 code = compile(code, "<string>", "exec")
2108 global_ns = {}
2109 local_ls = {}
2110 exec(code, global_ns, local_ls)
2111
Ethan Furman0063ff42020-09-21 17:23:13 -07002112 def test_strenum(self):
2113 class GoodStrEnum(StrEnum):
2114 one = '1'
2115 two = '2'
2116 three = b'3', 'ascii'
2117 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002118 self.assertEqual(GoodStrEnum.one, '1')
2119 self.assertEqual(str(GoodStrEnum.one), '1')
2120 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2121 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2122 #
2123 class DumbMixin:
2124 def __str__(self):
2125 return "don't do this"
2126 class DumbStrEnum(DumbMixin, StrEnum):
2127 five = '5'
2128 six = '6'
2129 seven = '7'
2130 self.assertEqual(DumbStrEnum.seven, '7')
2131 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2132 #
2133 class EnumMixin(Enum):
2134 def hello(self):
2135 print('hello from %s' % (self, ))
2136 class HelloEnum(EnumMixin, StrEnum):
2137 eight = '8'
2138 self.assertEqual(HelloEnum.eight, '8')
2139 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2140 #
2141 class GoodbyeMixin:
2142 def goodbye(self):
2143 print('%s wishes you a fond farewell')
2144 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2145 nine = '9'
2146 self.assertEqual(GoodbyeEnum.nine, '9')
2147 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2148 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002149 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2150 class FirstFailedStrEnum(StrEnum):
2151 one = 1
2152 two = '2'
2153 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2154 class SecondFailedStrEnum(StrEnum):
2155 one = '1'
2156 two = 2,
2157 three = '3'
2158 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2159 class ThirdFailedStrEnum(StrEnum):
2160 one = '1'
2161 two = 2
2162 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2163 class ThirdFailedStrEnum(StrEnum):
2164 one = '1'
2165 two = b'2', sys.getdefaultencoding
2166 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2167 class ThirdFailedStrEnum(StrEnum):
2168 one = '1'
2169 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002170
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002171 def test_missing_value_error(self):
2172 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2173 class Combined(str, Enum):
2174 #
2175 def __new__(cls, value, sequence):
2176 enum = str.__new__(cls, value)
2177 if '(' in value:
2178 fis_name, segment = value.split('(', 1)
2179 segment = segment.strip(' )')
2180 else:
2181 fis_name = value
2182 segment = None
2183 enum.fis_name = fis_name
2184 enum.segment = segment
2185 enum.sequence = sequence
2186 return enum
2187 #
2188 def __repr__(self):
2189 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2190 #
2191 key_type = 'An$(1,2)', 0
2192 company_id = 'An$(3,2)', 1
2193 code = 'An$(5,1)', 2
2194 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002195
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002196 @unittest.skipUnless(
2197 sys.version_info[:2] == (3, 9),
2198 'private variables are now normal attributes',
2199 )
2200 def test_warning_for_private_variables(self):
2201 with self.assertWarns(DeprecationWarning):
2202 class Private(Enum):
2203 __corporal = 'Radar'
2204 self.assertEqual(Private._Private__corporal.value, 'Radar')
2205 try:
2206 with self.assertWarns(DeprecationWarning):
2207 class Private(Enum):
2208 __major_ = 'Hoolihan'
2209 except ValueError:
2210 pass
2211
2212 def test_private_variable_is_normal_attribute(self):
2213 class Private(Enum):
2214 __corporal = 'Radar'
2215 __major_ = 'Hoolihan'
2216 self.assertEqual(Private._Private__corporal, 'Radar')
2217 self.assertEqual(Private._Private__major_, 'Hoolihan')
2218
Ethan Furmand65b9032021-02-08 17:32:38 -08002219 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002220 sys.version_info[:2] < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002221 'member-member access now raises an exception',
2222 )
2223 def test_warning_for_member_from_member_access(self):
2224 with self.assertWarns(DeprecationWarning):
2225 class Di(Enum):
2226 YES = 1
2227 NO = 0
2228 nope = Di.YES.NO
2229 self.assertIs(Di.NO, nope)
2230
2231 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002232 sys.version_info[:2] >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002233 'member-member access currently issues a warning',
2234 )
2235 def test_exception_for_member_from_member_access(self):
2236 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2237 class Di(Enum):
2238 YES = 1
2239 NO = 0
2240 nope = Di.YES.NO
2241
Ethan Furmanefb13be2020-12-10 12:20:06 -08002242 def test_strenum_auto(self):
2243 class Strings(StrEnum):
2244 ONE = auto()
2245 TWO = auto()
2246 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2247
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002248
Ethan Furmana6582872020-12-10 13:07:00 -08002249 def test_dynamic_members_with_static_methods(self):
2250 #
2251 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2252 class Foo(Enum):
2253 vars().update({
2254 k: v
2255 for k, v in foo_defines.items()
2256 if k.startswith('FOO_')
2257 })
2258 def upper(self):
2259 return self.value.upper()
2260 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2261 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2262 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2263 #
2264 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2265 class FooBar(Enum):
2266 vars().update({
2267 k: v
2268 for k, v in foo_defines.items()
2269 if k.startswith('FOO_')
2270 },
2271 **{'FOO_CAT': 'small'},
2272 )
2273 def upper(self):
2274 return self.value.upper()
2275
2276
Ethan Furmane8e61272016-08-20 07:19:31 -07002277class TestOrder(unittest.TestCase):
2278
2279 def test_same_members(self):
2280 class Color(Enum):
2281 _order_ = 'red green blue'
2282 red = 1
2283 green = 2
2284 blue = 3
2285
2286 def test_same_members_with_aliases(self):
2287 class Color(Enum):
2288 _order_ = 'red green blue'
2289 red = 1
2290 green = 2
2291 blue = 3
2292 verde = green
2293
2294 def test_same_members_wrong_order(self):
2295 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2296 class Color(Enum):
2297 _order_ = 'red green blue'
2298 red = 1
2299 blue = 3
2300 green = 2
2301
2302 def test_order_has_extra_members(self):
2303 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2304 class Color(Enum):
2305 _order_ = 'red green blue purple'
2306 red = 1
2307 green = 2
2308 blue = 3
2309
2310 def test_order_has_extra_members_with_aliases(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 verde = green
2318
2319 def test_enum_has_extra_members(self):
2320 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2321 class Color(Enum):
2322 _order_ = 'red green blue'
2323 red = 1
2324 green = 2
2325 blue = 3
2326 purple = 4
2327
2328 def test_enum_has_extra_members_with_aliases(self):
2329 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2330 class Color(Enum):
2331 _order_ = 'red green blue'
2332 red = 1
2333 green = 2
2334 blue = 3
2335 purple = 4
2336 verde = green
2337
2338
Ethan Furman65a5a472016-09-01 23:55:19 -07002339class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002340 """Tests of the Flags."""
2341
Ethan Furman65a5a472016-09-01 23:55:19 -07002342 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002343 R, W, X = 4, 2, 1
2344
Ethan Furman65a5a472016-09-01 23:55:19 -07002345 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002346 RO = 0
2347 WO = 1
2348 RW = 2
2349 AC = 3
2350 CE = 1<<19
2351
Rahul Jha94306522018-09-10 23:51:04 +05302352 class Color(Flag):
2353 BLACK = 0
2354 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002355 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302356 GREEN = 2
2357 BLUE = 4
2358 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002359 WHITE = RED|GREEN|BLUE
2360 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302361
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002362 def test_str(self):
2363 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002364 self.assertEqual(str(Perm.R), 'R')
2365 self.assertEqual(str(Perm.W), 'W')
2366 self.assertEqual(str(Perm.X), 'X')
2367 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2368 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002369 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002370 self.assertEqual(str(~Perm.R), 'W|X')
2371 self.assertEqual(str(~Perm.W), 'R|X')
2372 self.assertEqual(str(~Perm.X), 'R|W')
2373 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002374 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002375 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002376
2377 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002378 self.assertEqual(str(Open.RO), 'RO')
2379 self.assertEqual(str(Open.WO), 'WO')
2380 self.assertEqual(str(Open.AC), 'AC')
2381 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2382 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2383 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2384 self.assertEqual(str(~Open.WO), 'RW|CE')
2385 self.assertEqual(str(~Open.AC), 'CE')
2386 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2387 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002388
2389 def test_repr(self):
2390 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002391 self.assertEqual(repr(Perm.R), 'Perm.R')
2392 self.assertEqual(repr(Perm.W), 'Perm.W')
2393 self.assertEqual(repr(Perm.X), 'Perm.X')
2394 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2395 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2396 self.assertEqual(repr(Perm(0)), '0x0')
2397 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2398 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2399 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2400 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2401 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2402 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002403
2404 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002405 self.assertEqual(repr(Open.RO), 'Open.RO')
2406 self.assertEqual(repr(Open.WO), 'Open.WO')
2407 self.assertEqual(repr(Open.AC), 'Open.AC')
2408 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2409 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2410 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2411 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2412 self.assertEqual(repr(~Open.AC), 'Open.CE')
2413 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2414 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002415
Ethan Furman37440ee2020-12-08 11:14:10 -08002416 def test_format(self):
2417 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002418 self.assertEqual(format(Perm.R, ''), 'R')
2419 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002420
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002421 def test_or(self):
2422 Perm = self.Perm
2423 for i in Perm:
2424 for j in Perm:
2425 self.assertEqual((i | j), Perm(i.value | j.value))
2426 self.assertEqual((i | j).value, i.value | j.value)
2427 self.assertIs(type(i | j), Perm)
2428 for i in Perm:
2429 self.assertIs(i | i, i)
2430 Open = self.Open
2431 self.assertIs(Open.RO | Open.CE, Open.CE)
2432
2433 def test_and(self):
2434 Perm = self.Perm
2435 RW = Perm.R | Perm.W
2436 RX = Perm.R | Perm.X
2437 WX = Perm.W | Perm.X
2438 RWX = Perm.R | Perm.W | Perm.X
2439 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2440 for i in values:
2441 for j in values:
2442 self.assertEqual((i & j).value, i.value & j.value)
2443 self.assertIs(type(i & j), Perm)
2444 for i in Perm:
2445 self.assertIs(i & i, i)
2446 self.assertIs(i & RWX, i)
2447 self.assertIs(RWX & i, i)
2448 Open = self.Open
2449 self.assertIs(Open.RO & Open.CE, Open.RO)
2450
2451 def test_xor(self):
2452 Perm = self.Perm
2453 for i in Perm:
2454 for j in Perm:
2455 self.assertEqual((i ^ j).value, i.value ^ j.value)
2456 self.assertIs(type(i ^ j), Perm)
2457 for i in Perm:
2458 self.assertIs(i ^ Perm(0), i)
2459 self.assertIs(Perm(0) ^ i, i)
2460 Open = self.Open
2461 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2462 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2463
2464 def test_invert(self):
2465 Perm = self.Perm
2466 RW = Perm.R | Perm.W
2467 RX = Perm.R | Perm.X
2468 WX = Perm.W | Perm.X
2469 RWX = Perm.R | Perm.W | Perm.X
2470 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2471 for i in values:
2472 self.assertIs(type(~i), Perm)
2473 self.assertEqual(~~i, i)
2474 for i in Perm:
2475 self.assertIs(~~i, i)
2476 Open = self.Open
2477 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2478 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2479
Ethan Furman25d94bb2016-09-02 16:32:32 -07002480 def test_bool(self):
2481 Perm = self.Perm
2482 for f in Perm:
2483 self.assertTrue(f)
2484 Open = self.Open
2485 for f in Open:
2486 self.assertEqual(bool(f.value), bool(f))
2487
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002488 def test_boundary(self):
2489 self.assertIs(enum.Flag._boundary_, STRICT)
2490 class Iron(Flag, boundary=STRICT):
2491 ONE = 1
2492 TWO = 2
2493 EIGHT = 8
2494 self.assertIs(Iron._boundary_, STRICT)
2495 #
2496 class Water(Flag, boundary=CONFORM):
2497 ONE = 1
2498 TWO = 2
2499 EIGHT = 8
2500 self.assertIs(Water._boundary_, CONFORM)
2501 #
2502 class Space(Flag, boundary=EJECT):
2503 ONE = 1
2504 TWO = 2
2505 EIGHT = 8
2506 self.assertIs(Space._boundary_, EJECT)
2507 #
2508 class Bizarre(Flag, boundary=KEEP):
2509 b = 3
2510 c = 4
2511 d = 6
2512 #
2513 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002514 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002515 self.assertIs(Water(7), Water.ONE|Water.TWO)
2516 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002517 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002518 self.assertEqual(Space(7), 7)
2519 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002520 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002521 self.assertEqual(list(Bizarre), [Bizarre.c])
2522 self.assertIs(Bizarre(3), Bizarre.b)
2523 self.assertIs(Bizarre(6), Bizarre.d)
2524
2525 def test_iter(self):
2526 Color = self.Color
2527 Open = self.Open
2528 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2529 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2530
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002531 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002532 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002533 lst = list(Perm)
2534 self.assertEqual(len(lst), len(Perm))
2535 self.assertEqual(len(Perm), 3, Perm)
2536 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2537 for i, n in enumerate('R W X'.split()):
2538 v = 1<<i
2539 e = Perm(v)
2540 self.assertEqual(e.value, v)
2541 self.assertEqual(type(e.value), int)
2542 self.assertEqual(e.name, n)
2543 self.assertIn(e, Perm)
2544 self.assertIs(type(e), Perm)
2545
2546 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002547 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002548 lst = list(Perm)
2549 self.assertEqual(len(lst), len(Perm))
2550 self.assertEqual(len(Perm), 3, Perm)
2551 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2552 for i, n in enumerate('R W X'.split()):
2553 v = 8<<i
2554 e = Perm(v)
2555 self.assertEqual(e.value, v)
2556 self.assertEqual(type(e.value), int)
2557 self.assertEqual(e.name, n)
2558 self.assertIn(e, Perm)
2559 self.assertIs(type(e), Perm)
2560
2561 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002562 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002563 lst = list(Perm)
2564 self.assertEqual(len(lst), len(Perm))
2565 self.assertEqual(len(Perm), 3, Perm)
2566 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2567 for i, n in enumerate('R W X'.split()):
2568 v = 1<<i
2569 e = Perm(v)
2570 self.assertEqual(e.value, v)
2571 self.assertEqual(type(e.value), int)
2572 self.assertEqual(e.name, n)
2573 self.assertIn(e, Perm)
2574 self.assertIs(type(e), Perm)
2575
2576 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002577 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002578 lst = list(Perm)
2579 self.assertEqual(len(lst), len(Perm))
2580 self.assertEqual(len(Perm), 3, Perm)
2581 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2582 for i, n in enumerate('R W X'.split()):
2583 v = 1<<(2*i+1)
2584 e = Perm(v)
2585 self.assertEqual(e.value, v)
2586 self.assertEqual(type(e.value), int)
2587 self.assertEqual(e.name, n)
2588 self.assertIn(e, Perm)
2589 self.assertIs(type(e), Perm)
2590
2591 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002592 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002593 lst = list(Perm)
2594 self.assertEqual(len(lst), len(Perm))
2595 self.assertEqual(len(Perm), 3, Perm)
2596 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2597 for i, n in enumerate('R W X'.split()):
2598 v = 1<<(2*i+1)
2599 e = Perm(v)
2600 self.assertEqual(e.value, v)
2601 self.assertEqual(type(e.value), int)
2602 self.assertEqual(e.name, n)
2603 self.assertIn(e, Perm)
2604 self.assertIs(type(e), Perm)
2605
Ethan Furman65a5a472016-09-01 23:55:19 -07002606 def test_pickle(self):
2607 if isinstance(FlagStooges, Exception):
2608 raise FlagStooges
2609 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2610 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002611
Rahul Jha94306522018-09-10 23:51:04 +05302612 def test_contains(self):
2613 Open = self.Open
2614 Color = self.Color
2615 self.assertFalse(Color.BLACK in Open)
2616 self.assertFalse(Open.RO in Color)
2617 with self.assertRaises(TypeError):
2618 'BLACK' in Color
2619 with self.assertRaises(TypeError):
2620 'RO' in Open
2621 with self.assertRaises(TypeError):
2622 1 in Color
2623 with self.assertRaises(TypeError):
2624 1 in Open
2625
2626 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002627 Perm = self.Perm
2628 R, W, X = Perm
2629 RW = R | W
2630 RX = R | X
2631 WX = W | X
2632 RWX = R | W | X
2633 self.assertTrue(R in RW)
2634 self.assertTrue(R in RX)
2635 self.assertTrue(R in RWX)
2636 self.assertTrue(W in RW)
2637 self.assertTrue(W in WX)
2638 self.assertTrue(W in RWX)
2639 self.assertTrue(X in RX)
2640 self.assertTrue(X in WX)
2641 self.assertTrue(X in RWX)
2642 self.assertFalse(R in WX)
2643 self.assertFalse(W in RX)
2644 self.assertFalse(X in RW)
2645
Ethan Furman7219e272020-09-16 13:01:00 -07002646 def test_member_iter(self):
2647 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002648 self.assertEqual(list(Color.BLACK), [])
2649 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002650 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2651 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002652 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2653 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2654
2655 def test_member_length(self):
2656 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2657 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2658 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2659 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2660
2661 def test_number_reset_and_order_cleanup(self):
2662 class Confused(Flag):
2663 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2664 ONE = auto()
2665 TWO = auto()
2666 FOUR = auto()
2667 DOS = 2
2668 EIGHT = auto()
2669 SIXTEEN = auto()
2670 self.assertEqual(
2671 list(Confused),
2672 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2673 self.assertIs(Confused.TWO, Confused.DOS)
2674 self.assertEqual(Confused.DOS._value_, 2)
2675 self.assertEqual(Confused.EIGHT._value_, 8)
2676 self.assertEqual(Confused.SIXTEEN._value_, 16)
2677
2678 def test_aliases(self):
2679 Color = self.Color
2680 self.assertEqual(Color(1).name, 'RED')
2681 self.assertEqual(Color['ROJO'].name, 'RED')
2682 self.assertEqual(Color(7).name, 'WHITE')
2683 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2684 self.assertIs(Color.BLANCO, Color.WHITE)
2685 Open = self.Open
2686 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002687
Ethan Furmanc16595e2016-09-10 23:36:59 -07002688 def test_auto_number(self):
2689 class Color(Flag):
2690 red = auto()
2691 blue = auto()
2692 green = auto()
2693
2694 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2695 self.assertEqual(Color.red.value, 1)
2696 self.assertEqual(Color.blue.value, 2)
2697 self.assertEqual(Color.green.value, 4)
2698
2699 def test_auto_number_garbage(self):
2700 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2701 class Color(Flag):
2702 red = 'not an int'
2703 blue = auto()
2704
Ethan Furman3515dcc2016-09-18 13:15:41 -07002705 def test_duplicate_auto(self):
2706 class Dupes(Enum):
2707 first = primero = auto()
2708 second = auto()
2709 third = auto()
2710 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2711
2712 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002713 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2714 class Bizarre(Flag):
2715 b = 3
2716 c = 4
2717 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002718
Ethan Furman5bdab642018-09-21 19:03:09 -07002719 def test_multiple_mixin(self):
2720 class AllMixin:
2721 @classproperty
2722 def ALL(cls):
2723 members = list(cls)
2724 all_value = None
2725 if members:
2726 all_value = members[0]
2727 for member in members[1:]:
2728 all_value |= member
2729 cls.ALL = all_value
2730 return all_value
2731 class StrMixin:
2732 def __str__(self):
2733 return self._name_.lower()
2734 class Color(AllMixin, Flag):
2735 RED = auto()
2736 GREEN = auto()
2737 BLUE = auto()
2738 self.assertEqual(Color.RED.value, 1)
2739 self.assertEqual(Color.GREEN.value, 2)
2740 self.assertEqual(Color.BLUE.value, 4)
2741 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002742 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002743 class Color(AllMixin, StrMixin, Flag):
2744 RED = auto()
2745 GREEN = auto()
2746 BLUE = auto()
2747 self.assertEqual(Color.RED.value, 1)
2748 self.assertEqual(Color.GREEN.value, 2)
2749 self.assertEqual(Color.BLUE.value, 4)
2750 self.assertEqual(Color.ALL.value, 7)
2751 self.assertEqual(str(Color.BLUE), 'blue')
2752 class Color(StrMixin, AllMixin, Flag):
2753 RED = auto()
2754 GREEN = auto()
2755 BLUE = auto()
2756 self.assertEqual(Color.RED.value, 1)
2757 self.assertEqual(Color.GREEN.value, 2)
2758 self.assertEqual(Color.BLUE.value, 4)
2759 self.assertEqual(Color.ALL.value, 7)
2760 self.assertEqual(str(Color.BLUE), 'blue')
2761
Hai Shie80697d2020-05-28 06:10:27 +08002762 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002763 def test_unique_composite(self):
2764 # override __eq__ to be identity only
2765 class TestFlag(Flag):
2766 one = auto()
2767 two = auto()
2768 three = auto()
2769 four = auto()
2770 five = auto()
2771 six = auto()
2772 seven = auto()
2773 eight = auto()
2774 def __eq__(self, other):
2775 return self is other
2776 def __hash__(self):
2777 return hash(self._value_)
2778 # have multiple threads competing to complete the composite members
2779 seen = set()
2780 failed = False
2781 def cycle_enum():
2782 nonlocal failed
2783 try:
2784 for i in range(256):
2785 seen.add(TestFlag(i))
2786 except Exception:
2787 failed = True
2788 threads = [
2789 threading.Thread(target=cycle_enum)
2790 for _ in range(8)
2791 ]
Hai Shie80697d2020-05-28 06:10:27 +08002792 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002793 pass
2794 # check that only 248 members were created
2795 self.assertFalse(
2796 failed,
2797 'at least one thread failed while creating composite members')
2798 self.assertEqual(256, len(seen), 'too many composite members created')
2799
Ethan Furman6bd94de2020-12-09 16:41:22 -08002800 def test_init_subclass(self):
2801 class MyEnum(Flag):
2802 def __init_subclass__(cls, **kwds):
2803 super().__init_subclass__(**kwds)
2804 self.assertFalse(cls.__dict__.get('_test', False))
2805 cls._test1 = 'MyEnum'
2806 #
2807 class TheirEnum(MyEnum):
2808 def __init_subclass__(cls, **kwds):
2809 super(TheirEnum, cls).__init_subclass__(**kwds)
2810 cls._test2 = 'TheirEnum'
2811 class WhoseEnum(TheirEnum):
2812 def __init_subclass__(cls, **kwds):
2813 pass
2814 class NoEnum(WhoseEnum):
2815 ONE = 1
2816 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2817 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2818 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2819 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2820 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2821 #
2822 class OurEnum(MyEnum):
2823 def __init_subclass__(cls, **kwds):
2824 cls._test2 = 'OurEnum'
2825 class WhereEnum(OurEnum):
2826 def __init_subclass__(cls, **kwds):
2827 pass
2828 class NeverEnum(WhereEnum):
2829 ONE = 1
2830 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2831 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2832 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2833 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2834 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2835
Ethan Furmanc16595e2016-09-10 23:36:59 -07002836
Ethan Furman65a5a472016-09-01 23:55:19 -07002837class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002838 """Tests of the IntFlags."""
2839
Ethan Furman65a5a472016-09-01 23:55:19 -07002840 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002841 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002842 W = 1 << 1
2843 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002844
Ethan Furman65a5a472016-09-01 23:55:19 -07002845 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002846 RO = 0
2847 WO = 1
2848 RW = 2
2849 AC = 3
2850 CE = 1<<19
2851
Rahul Jha94306522018-09-10 23:51:04 +05302852 class Color(IntFlag):
2853 BLACK = 0
2854 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002855 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302856 GREEN = 2
2857 BLUE = 4
2858 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002859 WHITE = RED|GREEN|BLUE
2860 BLANCO = RED|GREEN|BLUE
2861
2862 class Skip(IntFlag):
2863 FIRST = 1
2864 SECOND = 2
2865 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302866
Ethan Furman3515dcc2016-09-18 13:15:41 -07002867 def test_type(self):
2868 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002869 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002870 Open = self.Open
2871 for f in Perm:
2872 self.assertTrue(isinstance(f, Perm))
2873 self.assertEqual(f, f.value)
2874 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2875 self.assertEqual(Perm.W | Perm.X, 3)
2876 for f in Open:
2877 self.assertTrue(isinstance(f, Open))
2878 self.assertEqual(f, f.value)
2879 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2880 self.assertEqual(Open.WO | Open.RW, 3)
2881
2882
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002883 def test_str(self):
2884 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002885 self.assertEqual(str(Perm.R), 'R')
2886 self.assertEqual(str(Perm.W), 'W')
2887 self.assertEqual(str(Perm.X), 'X')
2888 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2889 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002890 self.assertEqual(str(Perm.R | 8), '12')
2891 self.assertEqual(str(Perm(0)), 'Perm(0)')
2892 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002893 self.assertEqual(str(~Perm.R), 'W|X')
2894 self.assertEqual(str(~Perm.W), 'R|X')
2895 self.assertEqual(str(~Perm.X), 'R|W')
2896 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002897 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2898 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002899 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002900 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002901
2902 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002903 self.assertEqual(str(Open.RO), 'RO')
2904 self.assertEqual(str(Open.WO), 'WO')
2905 self.assertEqual(str(Open.AC), 'AC')
2906 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2907 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002908 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002909 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2910 self.assertEqual(str(~Open.WO), 'RW|CE')
2911 self.assertEqual(str(~Open.AC), 'CE')
2912 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2913 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002914 self.assertEqual(str(Open(~4)), '-5')
2915
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002916 def test_repr(self):
2917 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002918 self.assertEqual(repr(Perm.R), 'Perm.R')
2919 self.assertEqual(repr(Perm.W), 'Perm.W')
2920 self.assertEqual(repr(Perm.X), 'Perm.X')
2921 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2922 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002923 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07002924 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002925 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002926 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2927 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2928 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2929 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2930 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002931 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002932 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002933 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002934
2935 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002936 self.assertEqual(repr(Open.RO), 'Open.RO')
2937 self.assertEqual(repr(Open.WO), 'Open.WO')
2938 self.assertEqual(repr(Open.AC), 'Open.AC')
2939 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2940 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002941 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002942 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2943 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2944 self.assertEqual(repr(~Open.AC), 'Open.CE')
2945 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2946 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002947 self.assertEqual(repr(Open(~4)), '-5')
2948
Ethan Furman37440ee2020-12-08 11:14:10 -08002949 def test_format(self):
2950 Perm = self.Perm
2951 self.assertEqual(format(Perm.R, ''), '4')
2952 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2953
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002954 def test_or(self):
2955 Perm = self.Perm
2956 for i in Perm:
2957 for j in Perm:
2958 self.assertEqual(i | j, i.value | j.value)
2959 self.assertEqual((i | j).value, i.value | j.value)
2960 self.assertIs(type(i | j), Perm)
2961 for j in range(8):
2962 self.assertEqual(i | j, i.value | j)
2963 self.assertEqual((i | j).value, i.value | j)
2964 self.assertIs(type(i | j), Perm)
2965 self.assertEqual(j | i, j | i.value)
2966 self.assertEqual((j | i).value, j | i.value)
2967 self.assertIs(type(j | i), Perm)
2968 for i in Perm:
2969 self.assertIs(i | i, i)
2970 self.assertIs(i | 0, i)
2971 self.assertIs(0 | i, i)
2972 Open = self.Open
2973 self.assertIs(Open.RO | Open.CE, Open.CE)
2974
2975 def test_and(self):
2976 Perm = self.Perm
2977 RW = Perm.R | Perm.W
2978 RX = Perm.R | Perm.X
2979 WX = Perm.W | Perm.X
2980 RWX = Perm.R | Perm.W | Perm.X
2981 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2982 for i in values:
2983 for j in values:
2984 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2985 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2986 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2987 for j in range(8):
2988 self.assertEqual(i & j, i.value & j)
2989 self.assertEqual((i & j).value, i.value & j)
2990 self.assertIs(type(i & j), Perm)
2991 self.assertEqual(j & i, j & i.value)
2992 self.assertEqual((j & i).value, j & i.value)
2993 self.assertIs(type(j & i), Perm)
2994 for i in Perm:
2995 self.assertIs(i & i, i)
2996 self.assertIs(i & 7, i)
2997 self.assertIs(7 & i, i)
2998 Open = self.Open
2999 self.assertIs(Open.RO & Open.CE, Open.RO)
3000
3001 def test_xor(self):
3002 Perm = self.Perm
3003 for i in Perm:
3004 for j in Perm:
3005 self.assertEqual(i ^ j, i.value ^ j.value)
3006 self.assertEqual((i ^ j).value, i.value ^ j.value)
3007 self.assertIs(type(i ^ j), Perm)
3008 for j in range(8):
3009 self.assertEqual(i ^ j, i.value ^ j)
3010 self.assertEqual((i ^ j).value, i.value ^ j)
3011 self.assertIs(type(i ^ j), Perm)
3012 self.assertEqual(j ^ i, j ^ i.value)
3013 self.assertEqual((j ^ i).value, j ^ i.value)
3014 self.assertIs(type(j ^ i), Perm)
3015 for i in Perm:
3016 self.assertIs(i ^ 0, i)
3017 self.assertIs(0 ^ i, i)
3018 Open = self.Open
3019 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3020 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3021
3022 def test_invert(self):
3023 Perm = self.Perm
3024 RW = Perm.R | Perm.W
3025 RX = Perm.R | Perm.X
3026 WX = Perm.W | Perm.X
3027 RWX = Perm.R | Perm.W | Perm.X
3028 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3029 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003030 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003031 self.assertIs(type(~i), Perm)
3032 self.assertEqual(~~i, i)
3033 for i in Perm:
3034 self.assertIs(~~i, i)
3035 Open = self.Open
3036 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3037 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3038
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003039 def test_boundary(self):
3040 self.assertIs(enum.IntFlag._boundary_, EJECT)
3041 class Iron(IntFlag, boundary=STRICT):
3042 ONE = 1
3043 TWO = 2
3044 EIGHT = 8
3045 self.assertIs(Iron._boundary_, STRICT)
3046 #
3047 class Water(IntFlag, boundary=CONFORM):
3048 ONE = 1
3049 TWO = 2
3050 EIGHT = 8
3051 self.assertIs(Water._boundary_, CONFORM)
3052 #
3053 class Space(IntFlag, boundary=EJECT):
3054 ONE = 1
3055 TWO = 2
3056 EIGHT = 8
3057 self.assertIs(Space._boundary_, EJECT)
3058 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003059 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003060 class Bizarre(IntFlag, boundary=KEEP):
3061 b = 3
3062 c = 4
3063 d = 6
3064 #
3065 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003066 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003067 self.assertIs(Water(7), Water.ONE|Water.TWO)
3068 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003069 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003070 self.assertEqual(Space(7), 7)
3071 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003072 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003073 self.assertEqual(list(Bizarre), [Bizarre.c])
3074 self.assertIs(Bizarre(3), Bizarre.b)
3075 self.assertIs(Bizarre(6), Bizarre.d)
3076
3077 def test_iter(self):
3078 Color = self.Color
3079 Open = self.Open
3080 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3081 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3082
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003083 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003084 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003085 lst = list(Perm)
3086 self.assertEqual(len(lst), len(Perm))
3087 self.assertEqual(len(Perm), 3, Perm)
3088 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3089 for i, n in enumerate('R W X'.split()):
3090 v = 1<<i
3091 e = Perm(v)
3092 self.assertEqual(e.value, v)
3093 self.assertEqual(type(e.value), int)
3094 self.assertEqual(e, v)
3095 self.assertEqual(e.name, n)
3096 self.assertIn(e, Perm)
3097 self.assertIs(type(e), Perm)
3098
3099 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003100 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003101 lst = list(Perm)
3102 self.assertEqual(len(lst), len(Perm))
3103 self.assertEqual(len(Perm), 3, Perm)
3104 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3105 for i, n in enumerate('R W X'.split()):
3106 v = 8<<i
3107 e = Perm(v)
3108 self.assertEqual(e.value, v)
3109 self.assertEqual(type(e.value), int)
3110 self.assertEqual(e, v)
3111 self.assertEqual(e.name, n)
3112 self.assertIn(e, Perm)
3113 self.assertIs(type(e), Perm)
3114
3115 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003116 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003117 lst = list(Perm)
3118 self.assertEqual(len(lst), len(Perm))
3119 self.assertEqual(len(Perm), 3, Perm)
3120 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3121 for i, n in enumerate('R W X'.split()):
3122 v = 1<<i
3123 e = Perm(v)
3124 self.assertEqual(e.value, v)
3125 self.assertEqual(type(e.value), int)
3126 self.assertEqual(e, v)
3127 self.assertEqual(e.name, n)
3128 self.assertIn(e, Perm)
3129 self.assertIs(type(e), Perm)
3130
3131 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003132 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003133 lst = list(Perm)
3134 self.assertEqual(len(lst), len(Perm))
3135 self.assertEqual(len(Perm), 3, Perm)
3136 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3137 for i, n in enumerate('R W X'.split()):
3138 v = 1<<(2*i+1)
3139 e = Perm(v)
3140 self.assertEqual(e.value, v)
3141 self.assertEqual(type(e.value), int)
3142 self.assertEqual(e, v)
3143 self.assertEqual(e.name, n)
3144 self.assertIn(e, Perm)
3145 self.assertIs(type(e), Perm)
3146
3147 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003148 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003149 lst = list(Perm)
3150 self.assertEqual(len(lst), len(Perm))
3151 self.assertEqual(len(Perm), 3, Perm)
3152 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3153 for i, n in enumerate('R W X'.split()):
3154 v = 1<<(2*i+1)
3155 e = Perm(v)
3156 self.assertEqual(e.value, v)
3157 self.assertEqual(type(e.value), int)
3158 self.assertEqual(e, v)
3159 self.assertEqual(e.name, n)
3160 self.assertIn(e, Perm)
3161 self.assertIs(type(e), Perm)
3162
3163
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003164 def test_programatic_function_from_empty_list(self):
3165 Perm = enum.IntFlag('Perm', [])
3166 lst = list(Perm)
3167 self.assertEqual(len(lst), len(Perm))
3168 self.assertEqual(len(Perm), 0, Perm)
3169 Thing = enum.Enum('Thing', [])
3170 lst = list(Thing)
3171 self.assertEqual(len(lst), len(Thing))
3172 self.assertEqual(len(Thing), 0, Thing)
3173
3174
3175 def test_programatic_function_from_empty_tuple(self):
3176 Perm = enum.IntFlag('Perm', ())
3177 lst = list(Perm)
3178 self.assertEqual(len(lst), len(Perm))
3179 self.assertEqual(len(Perm), 0, Perm)
3180 Thing = enum.Enum('Thing', ())
3181 self.assertEqual(len(lst), len(Thing))
3182 self.assertEqual(len(Thing), 0, Thing)
3183
Rahul Jha94306522018-09-10 23:51:04 +05303184 def test_contains(self):
3185 Open = self.Open
3186 Color = self.Color
3187 self.assertTrue(Color.GREEN in Color)
3188 self.assertTrue(Open.RW in Open)
3189 self.assertFalse(Color.GREEN in Open)
3190 self.assertFalse(Open.RW in Color)
3191 with self.assertRaises(TypeError):
3192 'GREEN' in Color
3193 with self.assertRaises(TypeError):
3194 'RW' in Open
3195 with self.assertRaises(TypeError):
3196 2 in Color
3197 with self.assertRaises(TypeError):
3198 2 in Open
3199
3200 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003201 Perm = self.Perm
3202 R, W, X = Perm
3203 RW = R | W
3204 RX = R | X
3205 WX = W | X
3206 RWX = R | W | X
3207 self.assertTrue(R in RW)
3208 self.assertTrue(R in RX)
3209 self.assertTrue(R in RWX)
3210 self.assertTrue(W in RW)
3211 self.assertTrue(W in WX)
3212 self.assertTrue(W in RWX)
3213 self.assertTrue(X in RX)
3214 self.assertTrue(X in WX)
3215 self.assertTrue(X in RWX)
3216 self.assertFalse(R in WX)
3217 self.assertFalse(W in RX)
3218 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303219 with self.assertRaises(TypeError):
3220 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003221
Ethan Furman7219e272020-09-16 13:01:00 -07003222 def test_member_iter(self):
3223 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003224 self.assertEqual(list(Color.BLACK), [])
3225 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003226 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3227 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003228 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3229
3230 def test_member_length(self):
3231 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3232 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3233 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3234 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3235
3236 def test_aliases(self):
3237 Color = self.Color
3238 self.assertEqual(Color(1).name, 'RED')
3239 self.assertEqual(Color['ROJO'].name, 'RED')
3240 self.assertEqual(Color(7).name, 'WHITE')
3241 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3242 self.assertIs(Color.BLANCO, Color.WHITE)
3243 Open = self.Open
3244 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003245
Ethan Furman25d94bb2016-09-02 16:32:32 -07003246 def test_bool(self):
3247 Perm = self.Perm
3248 for f in Perm:
3249 self.assertTrue(f)
3250 Open = self.Open
3251 for f in Open:
3252 self.assertEqual(bool(f.value), bool(f))
3253
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003254 def test_bizarre(self):
3255 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3256 class Bizarre(IntFlag):
3257 b = 3
3258 c = 4
3259 d = 6
3260
Ethan Furman5bdab642018-09-21 19:03:09 -07003261 def test_multiple_mixin(self):
3262 class AllMixin:
3263 @classproperty
3264 def ALL(cls):
3265 members = list(cls)
3266 all_value = None
3267 if members:
3268 all_value = members[0]
3269 for member in members[1:]:
3270 all_value |= member
3271 cls.ALL = all_value
3272 return all_value
3273 class StrMixin:
3274 def __str__(self):
3275 return self._name_.lower()
3276 class Color(AllMixin, IntFlag):
3277 RED = auto()
3278 GREEN = auto()
3279 BLUE = auto()
3280 self.assertEqual(Color.RED.value, 1)
3281 self.assertEqual(Color.GREEN.value, 2)
3282 self.assertEqual(Color.BLUE.value, 4)
3283 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003284 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003285 class Color(AllMixin, StrMixin, IntFlag):
3286 RED = auto()
3287 GREEN = auto()
3288 BLUE = auto()
3289 self.assertEqual(Color.RED.value, 1)
3290 self.assertEqual(Color.GREEN.value, 2)
3291 self.assertEqual(Color.BLUE.value, 4)
3292 self.assertEqual(Color.ALL.value, 7)
3293 self.assertEqual(str(Color.BLUE), 'blue')
3294 class Color(StrMixin, AllMixin, IntFlag):
3295 RED = auto()
3296 GREEN = auto()
3297 BLUE = auto()
3298 self.assertEqual(Color.RED.value, 1)
3299 self.assertEqual(Color.GREEN.value, 2)
3300 self.assertEqual(Color.BLUE.value, 4)
3301 self.assertEqual(Color.ALL.value, 7)
3302 self.assertEqual(str(Color.BLUE), 'blue')
3303
Hai Shie80697d2020-05-28 06:10:27 +08003304 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003305 def test_unique_composite(self):
3306 # override __eq__ to be identity only
3307 class TestFlag(IntFlag):
3308 one = auto()
3309 two = auto()
3310 three = auto()
3311 four = auto()
3312 five = auto()
3313 six = auto()
3314 seven = auto()
3315 eight = auto()
3316 def __eq__(self, other):
3317 return self is other
3318 def __hash__(self):
3319 return hash(self._value_)
3320 # have multiple threads competing to complete the composite members
3321 seen = set()
3322 failed = False
3323 def cycle_enum():
3324 nonlocal failed
3325 try:
3326 for i in range(256):
3327 seen.add(TestFlag(i))
3328 except Exception:
3329 failed = True
3330 threads = [
3331 threading.Thread(target=cycle_enum)
3332 for _ in range(8)
3333 ]
Hai Shie80697d2020-05-28 06:10:27 +08003334 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003335 pass
3336 # check that only 248 members were created
3337 self.assertFalse(
3338 failed,
3339 'at least one thread failed while creating composite members')
3340 self.assertEqual(256, len(seen), 'too many composite members created')
3341
3342
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003343class TestEmptyAndNonLatinStrings(unittest.TestCase):
3344
3345 def test_empty_string(self):
3346 with self.assertRaises(ValueError):
3347 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3348
3349 def test_non_latin_character_string(self):
3350 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3351 item = getattr(greek_abc, '\u03B1')
3352 self.assertEqual(item.value, 1)
3353
3354 def test_non_latin_number_string(self):
3355 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3356 item = getattr(hebrew_123, '\u05D0')
3357 self.assertEqual(item.value, 1)
3358
3359
Ethan Furmanf24bb352013-07-18 17:05:39 -07003360class TestUnique(unittest.TestCase):
3361
3362 def test_unique_clean(self):
3363 @unique
3364 class Clean(Enum):
3365 one = 1
3366 two = 'dos'
3367 tres = 4.0
3368 @unique
3369 class Cleaner(IntEnum):
3370 single = 1
3371 double = 2
3372 triple = 3
3373
3374 def test_unique_dirty(self):
3375 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3376 @unique
3377 class Dirty(Enum):
3378 one = 1
3379 two = 'dos'
3380 tres = 1
3381 with self.assertRaisesRegex(
3382 ValueError,
3383 'double.*single.*turkey.*triple',
3384 ):
3385 @unique
3386 class Dirtier(IntEnum):
3387 single = 1
3388 double = 1
3389 triple = 3
3390 turkey = 3
3391
Ethan Furman3803ad42016-05-01 10:03:53 -07003392 def test_unique_with_name(self):
3393 @unique
3394 class Silly(Enum):
3395 one = 1
3396 two = 'dos'
3397 name = 3
3398 @unique
3399 class Sillier(IntEnum):
3400 single = 1
3401 name = 2
3402 triple = 3
3403 value = 4
3404
Ethan Furmanec099732021-04-15 06:58:33 -07003405class TestHelpers(unittest.TestCase):
3406
3407 sunder_names = '_bad_', '_good_', '_what_ho_'
3408 dunder_names = '__mal__', '__bien__', '__que_que__'
3409 private_names = '_MyEnum__private', '_MyEnum__still_private'
3410 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3411 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3412
3413 def test_sunder(self):
3414 for name in self.sunder_names + self.private_and_sunder_names:
3415 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3416 for name in self.dunder_names + self.private_names + self.random_names:
3417 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3418
3419 def test_dunder(self):
3420 for name in self.dunder_names:
3421 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3422 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3423 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3424
3425 def test_is_private(self):
3426 for name in self.private_names + self.private_and_sunder_names:
3427 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3428 for name in self.sunder_names + self.dunder_names + self.random_names:
3429 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003430
Ethan Furmanb7751062021-03-30 21:17:26 -07003431class TestEnumTypeSubclassing(unittest.TestCase):
3432 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003433
Ethan Furman3323da92015-04-11 09:39:59 -07003434expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003435Help on class Color in module %s:
3436
3437class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003438 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003439 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003440 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003441 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003442 | Method resolution order:
3443 | Color
3444 | enum.Enum
3445 | builtins.object
3446 |\x20\x20
3447 | Data and other attributes defined here:
3448 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003449 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003450 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003451 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003452 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003453 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003454 |\x20\x20
3455 | ----------------------------------------------------------------------
3456 | Data descriptors inherited from enum.Enum:
3457 |\x20\x20
3458 | name
3459 | The name of the Enum member.
3460 |\x20\x20
3461 | value
3462 | The value of the Enum member.
3463 |\x20\x20
3464 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003465 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003466 |\x20\x20
3467 | __members__
3468 | Returns a mapping of member name->value.
3469 |\x20\x20\x20\x20\x20\x20
3470 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003471 | is a read-only view of the internal mapping."""
3472
3473expected_help_output_without_docs = """\
3474Help on class Color in module %s:
3475
3476class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003477 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3478 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003479 | Method resolution order:
3480 | Color
3481 | enum.Enum
3482 | builtins.object
3483 |\x20\x20
3484 | Data and other attributes defined here:
3485 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003486 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003487 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003488 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003489 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003490 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003491 |\x20\x20
3492 | ----------------------------------------------------------------------
3493 | Data descriptors inherited from enum.Enum:
3494 |\x20\x20
3495 | name
3496 |\x20\x20
3497 | value
3498 |\x20\x20
3499 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003500 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003501 |\x20\x20
3502 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003503
3504class TestStdLib(unittest.TestCase):
3505
Ethan Furman48a724f2015-04-11 23:23:06 -07003506 maxDiff = None
3507
Ethan Furman5875d742013-10-21 20:45:55 -07003508 class Color(Enum):
3509 red = 1
3510 green = 2
3511 blue = 3
3512
3513 def test_pydoc(self):
3514 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003515 if StrEnum.__doc__ is None:
3516 expected_text = expected_help_output_without_docs % __name__
3517 else:
3518 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003519 output = StringIO()
3520 helper = pydoc.Helper(output=output)
3521 helper(self.Color)
3522 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003523 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003524
3525 def test_inspect_getmembers(self):
3526 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003527 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003528 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003529 ('__members__', self.Color.__members__),
3530 ('__module__', __name__),
3531 ('blue', self.Color.blue),
3532 ('green', self.Color.green),
3533 ('name', Enum.__dict__['name']),
3534 ('red', self.Color.red),
3535 ('value', Enum.__dict__['value']),
3536 ))
3537 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003538 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003539 failed = False
3540 for k in values.keys():
3541 if result[k] != values[k]:
3542 print()
3543 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3544 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3545 failed = True
3546 if failed:
3547 self.fail("result does not equal expected, see print above")
3548
3549 def test_inspect_classify_class_attrs(self):
3550 # indirectly test __objclass__
3551 from inspect import Attribute
3552 values = [
3553 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003554 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003555 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003556 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003557 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003558 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003559 Attribute(name='__module__', kind='data',
3560 defining_class=self.Color, object=__name__),
3561 Attribute(name='blue', kind='data',
3562 defining_class=self.Color, object=self.Color.blue),
3563 Attribute(name='green', kind='data',
3564 defining_class=self.Color, object=self.Color.green),
3565 Attribute(name='red', kind='data',
3566 defining_class=self.Color, object=self.Color.red),
3567 Attribute(name='name', kind='data',
3568 defining_class=Enum, object=Enum.__dict__['name']),
3569 Attribute(name='value', kind='data',
3570 defining_class=Enum, object=Enum.__dict__['value']),
3571 ]
3572 values.sort(key=lambda item: item.name)
3573 result = list(inspect.classify_class_attrs(self.Color))
3574 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003575 self.assertEqual(
3576 len(values), len(result),
3577 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3578 )
Ethan Furman5875d742013-10-21 20:45:55 -07003579 failed = False
3580 for v, r in zip(values, result):
3581 if r != v:
3582 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3583 failed = True
3584 if failed:
3585 self.fail("result does not equal expected, see print above")
3586
Ethan Furmana02cb472021-04-21 10:20:44 -07003587 def test_test_simple_enum(self):
3588 @_simple_enum(Enum)
3589 class SimpleColor:
3590 RED = 1
3591 GREEN = 2
3592 BLUE = 3
3593 class CheckedColor(Enum):
3594 RED = 1
3595 GREEN = 2
3596 BLUE = 3
3597 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3598 SimpleColor.GREEN._value_ = 9
3599 self.assertRaisesRegex(
3600 TypeError, "enum mismatch",
3601 _test_simple_enum, CheckedColor, SimpleColor,
3602 )
3603 class CheckedMissing(IntFlag, boundary=KEEP):
3604 SIXTY_FOUR = 64
3605 ONE_TWENTY_EIGHT = 128
3606 TWENTY_FORTY_EIGHT = 2048
3607 ALL = 2048 + 128 + 64 + 12
3608 CM = CheckedMissing
3609 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3610 #
3611 @_simple_enum(IntFlag, boundary=KEEP)
3612 class Missing:
3613 SIXTY_FOUR = 64
3614 ONE_TWENTY_EIGHT = 128
3615 TWENTY_FORTY_EIGHT = 2048
3616 ALL = 2048 + 128 + 64 + 12
3617 M = Missing
3618 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3619 #
3620 _test_simple_enum(CheckedMissing, Missing)
3621
Martin Panter19e69c52015-11-14 12:46:42 +00003622
3623class MiscTestCase(unittest.TestCase):
3624 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003625 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003626
3627
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003628# These are unordered here on purpose to ensure that declaration order
3629# makes no difference.
3630CONVERT_TEST_NAME_D = 5
3631CONVERT_TEST_NAME_C = 5
3632CONVERT_TEST_NAME_B = 5
3633CONVERT_TEST_NAME_A = 5 # This one should sort first.
3634CONVERT_TEST_NAME_E = 5
3635CONVERT_TEST_NAME_F = 5
3636
Ethan Furmana02cb472021-04-21 10:20:44 -07003637CONVERT_STRING_TEST_NAME_D = 5
3638CONVERT_STRING_TEST_NAME_C = 5
3639CONVERT_STRING_TEST_NAME_B = 5
3640CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3641CONVERT_STRING_TEST_NAME_E = 5
3642CONVERT_STRING_TEST_NAME_F = 5
3643
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003644class TestIntEnumConvert(unittest.TestCase):
3645 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003646 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003647 'UnittestConvert',
3648 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003649 filter=lambda x: x.startswith('CONVERT_TEST_'))
3650 # We don't want the reverse lookup value to vary when there are
3651 # multiple possible names for a given value. It should always
3652 # report the first lexigraphical name in that case.
3653 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3654
3655 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003656 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003657 'UnittestConvert',
3658 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003659 filter=lambda x: x.startswith('CONVERT_TEST_'))
3660 # Ensure that test_type has all of the desired names and values.
3661 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3662 test_type.CONVERT_TEST_NAME_A)
3663 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3664 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3665 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3666 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3667 # Ensure that test_type only picked up names matching the filter.
3668 self.assertEqual([name for name in dir(test_type)
3669 if name[0:2] not in ('CO', '__')],
3670 [], msg='Names other than CONVERT_TEST_* found.')
3671
orlnub1230fb9fad2018-09-12 20:28:53 +03003672 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3673 '_convert was deprecated in 3.8')
3674 def test_convert_warn(self):
3675 with self.assertWarns(DeprecationWarning):
3676 enum.IntEnum._convert(
3677 'UnittestConvert',
3678 ('test.test_enum', '__main__')[__name__=='__main__'],
3679 filter=lambda x: x.startswith('CONVERT_TEST_'))
3680
3681 @unittest.skipUnless(sys.version_info >= (3, 9),
3682 '_convert was removed in 3.9')
3683 def test_convert_raise(self):
3684 with self.assertRaises(AttributeError):
3685 enum.IntEnum._convert(
3686 'UnittestConvert',
3687 ('test.test_enum', '__main__')[__name__=='__main__'],
3688 filter=lambda x: x.startswith('CONVERT_TEST_'))
3689
Ethan Furmanb7751062021-03-30 21:17:26 -07003690 def test_convert_repr_and_str(self):
Ethan Furmana02cb472021-04-21 10:20:44 -07003691 # reset global constants, as previous tests could have converted the
3692 # integer values to enums
Ethan Furmanb7751062021-03-30 21:17:26 -07003693 module = ('test.test_enum', '__main__')[__name__=='__main__']
3694 test_type = enum.IntEnum._convert_(
3695 'UnittestConvert',
3696 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003697 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3698 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3699 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
3700 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003701
3702# global names for StrEnum._convert_ test
3703CONVERT_STR_TEST_2 = 'goodbye'
3704CONVERT_STR_TEST_1 = 'hello'
3705
3706class TestStrEnumConvert(unittest.TestCase):
3707
3708 def test_convert(self):
3709 test_type = enum.StrEnum._convert_(
3710 'UnittestConvert',
3711 ('test.test_enum', '__main__')[__name__=='__main__'],
3712 filter=lambda x: x.startswith('CONVERT_STR_'))
3713 # Ensure that test_type has all of the desired names and values.
3714 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3715 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3716 # Ensure that test_type only picked up names matching the filter.
3717 self.assertEqual([name for name in dir(test_type)
3718 if name[0:2] not in ('CO', '__')],
3719 [], msg='Names other than CONVERT_STR_* found.')
3720
3721 def test_convert_repr_and_str(self):
3722 module = ('test.test_enum', '__main__')[__name__=='__main__']
3723 test_type = enum.StrEnum._convert_(
3724 'UnittestConvert',
3725 module,
3726 filter=lambda x: x.startswith('CONVERT_STR_'))
3727 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3728 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
3729 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
3730
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003731
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003732if __name__ == '__main__':
3733 unittest.main()