blob: 03cf3533fc62d6deeeba2a17c89a45c22204a12f [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07008from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Ethan Furman9bf7c2d2021-07-03 21:08:42 -070011from test.support import ALWAYS_EQ, check__all__, threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080012from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080013
Ethan Furman2a9ab752021-10-20 19:48:37 -070014python_version = sys.version_info[:2]
Ethan Furman6b3d64a2013-06-14 16:55:46 -070015
16# for pickle tests
17try:
18 class Stooges(Enum):
19 LARRY = 1
20 CURLY = 2
21 MOE = 3
22except Exception as exc:
23 Stooges = exc
24
25try:
26 class IntStooges(int, Enum):
27 LARRY = 1
28 CURLY = 2
29 MOE = 3
30except Exception as exc:
31 IntStooges = exc
32
33try:
34 class FloatStooges(float, Enum):
35 LARRY = 1.39
36 CURLY = 2.72
37 MOE = 3.142596
38except Exception as exc:
39 FloatStooges = exc
40
Ethan Furman65a5a472016-09-01 23:55:19 -070041try:
42 class FlagStooges(Flag):
43 LARRY = 1
44 CURLY = 2
45 MOE = 3
46except Exception as exc:
47 FlagStooges = exc
48
Ethan Furman6b3d64a2013-06-14 16:55:46 -070049# for pickle test and subclass tests
Ethan Furman9bf7c2d2021-07-03 21:08:42 -070050try:
51 class StrEnum(str, Enum):
52 'accepts only string values'
53 class Name(StrEnum):
54 BDFL = 'Guido van Rossum'
55 FLUFL = 'Barry Warsaw'
56except Exception as exc:
57 Name = exc
Ethan Furman6b3d64a2013-06-14 16:55:46 -070058
59try:
60 Question = Enum('Question', 'who what when where why', module=__name__)
61except Exception as exc:
62 Question = exc
63
64try:
65 Answer = Enum('Answer', 'him this then there because')
66except Exception as exc:
67 Answer = exc
68
Ethan Furmanca1b7942014-02-08 11:36:27 -080069try:
70 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
71except Exception as exc:
72 Theory = exc
73
Ethan Furman6b3d64a2013-06-14 16:55:46 -070074# for doctests
75try:
76 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080077 TOMATO = 1
78 BANANA = 2
79 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070080except Exception:
81 pass
82
Serhiy Storchakae50e7802015-03-31 16:56:49 +030083def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080084 if target is None:
85 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030086 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 assertion(loads(dumps(source, protocol=protocol)), target)
88
Serhiy Storchakae50e7802015-03-31 16:56:49 +030089def test_pickle_exception(assertion, exception, obj):
90 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 with assertion(exception):
92 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070093
94class TestHelpers(unittest.TestCase):
95 # _is_descriptor, _is_sunder, _is_dunder
96
97 def test_is_descriptor(self):
98 class foo:
99 pass
100 for attr in ('__get__','__set__','__delete__'):
101 obj = foo()
102 self.assertFalse(enum._is_descriptor(obj))
103 setattr(obj, attr, 1)
104 self.assertTrue(enum._is_descriptor(obj))
105
106 def test_is_sunder(self):
107 for s in ('_a_', '_aa_'):
108 self.assertTrue(enum._is_sunder(s))
109
110 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
111 '__', '___', '____', '_____',):
112 self.assertFalse(enum._is_sunder(s))
113
114 def test_is_dunder(self):
115 for s in ('__a__', '__aa__'):
116 self.assertTrue(enum._is_dunder(s))
117 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_dunder(s))
120
Ethan Furman5bdab642018-09-21 19:03:09 -0700121# for subclassing tests
122
123class classproperty:
124
125 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
126 self.fget = fget
127 self.fset = fset
128 self.fdel = fdel
129 if doc is None and fget is not None:
130 doc = fget.__doc__
131 self.__doc__ = doc
132
133 def __get__(self, instance, ownerclass):
134 return self.fget(ownerclass)
135
136
Ethan Furmanc16595e2016-09-10 23:36:59 -0700137# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700138
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700139class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800140
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700141 def setUp(self):
142 class Season(Enum):
143 SPRING = 1
144 SUMMER = 2
145 AUTUMN = 3
146 WINTER = 4
147 self.Season = Season
148
Ethan Furmanec15a822013-08-31 19:17:41 -0700149 class Konstants(float, Enum):
150 E = 2.7182818
151 PI = 3.1415926
152 TAU = 2 * PI
153 self.Konstants = Konstants
154
155 class Grades(IntEnum):
156 A = 5
157 B = 4
158 C = 3
159 D = 2
160 F = 0
161 self.Grades = Grades
162
163 class Directional(str, Enum):
164 EAST = 'east'
165 WEST = 'west'
166 NORTH = 'north'
167 SOUTH = 'south'
168 self.Directional = Directional
169
170 from datetime import date
171 class Holiday(date, Enum):
172 NEW_YEAR = 2013, 1, 1
173 IDES_OF_MARCH = 2013, 3, 15
174 self.Holiday = Holiday
175
Ethan Furman388a3922013-08-12 06:51:41 -0700176 def test_dir_on_class(self):
177 Season = self.Season
178 self.assertEqual(
179 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700180 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700181 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
182 )
183
184 def test_dir_on_item(self):
185 Season = self.Season
186 self.assertEqual(
187 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700188 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700189 )
190
Ethan Furmanc850f342013-09-15 16:59:35 -0700191 def test_dir_with_added_behavior(self):
192 class Test(Enum):
193 this = 'that'
194 these = 'those'
195 def wowser(self):
196 return ("Wowser! I'm %s!" % self.name)
197 self.assertEqual(
198 set(dir(Test)),
199 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
200 )
201 self.assertEqual(
202 set(dir(Test.this)),
203 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
204 )
205
Ethan Furman0ae550b2014-10-14 08:58:32 -0700206 def test_dir_on_sub_with_behavior_on_super(self):
207 # see issue22506
208 class SuperEnum(Enum):
209 def invisible(self):
210 return "did you see me?"
211 class SubEnum(SuperEnum):
212 sample = 5
213 self.assertEqual(
214 set(dir(SubEnum.sample)),
215 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
216 )
217
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200218 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
219 # see issue40084
220 class SuperEnum(IntEnum):
221 def __new__(cls, value, description=""):
222 obj = int.__new__(cls, value)
223 obj._value_ = value
224 obj.description = description
225 return obj
226 class SubEnum(SuperEnum):
227 sample = 5
228 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
229
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700230 def test_enum_in_enum_out(self):
231 Season = self.Season
232 self.assertIs(Season(Season.WINTER), Season.WINTER)
233
234 def test_enum_value(self):
235 Season = self.Season
236 self.assertEqual(Season.SPRING.value, 1)
237
238 def test_intenum_value(self):
239 self.assertEqual(IntStooges.CURLY.value, 2)
240
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700241 def test_enum(self):
242 Season = self.Season
243 lst = list(Season)
244 self.assertEqual(len(lst), len(Season))
245 self.assertEqual(len(Season), 4, Season)
246 self.assertEqual(
247 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
248
249 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
250 e = Season(i)
251 self.assertEqual(e, getattr(Season, season))
252 self.assertEqual(e.value, i)
253 self.assertNotEqual(e, i)
254 self.assertEqual(e.name, season)
255 self.assertIn(e, Season)
256 self.assertIs(type(e), Season)
257 self.assertIsInstance(e, Season)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700258 self.assertEqual(str(e), 'Season.' + season)
259 self.assertEqual(
260 repr(e),
261 '<Season.{0}: {1}>'.format(season, i),
262 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700263
264 def test_value_name(self):
265 Season = self.Season
266 self.assertEqual(Season.SPRING.name, 'SPRING')
267 self.assertEqual(Season.SPRING.value, 1)
268 with self.assertRaises(AttributeError):
269 Season.SPRING.name = 'invierno'
270 with self.assertRaises(AttributeError):
271 Season.SPRING.value = 2
272
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700273 def test_changing_member(self):
274 Season = self.Season
275 with self.assertRaises(AttributeError):
276 Season.WINTER = 'really cold'
277
Ethan Furman64a99722013-09-22 16:18:19 -0700278 def test_attribute_deletion(self):
279 class Season(Enum):
280 SPRING = 1
281 SUMMER = 2
282 AUTUMN = 3
283 WINTER = 4
284
285 def spam(cls):
286 pass
287
288 self.assertTrue(hasattr(Season, 'spam'))
289 del Season.spam
290 self.assertFalse(hasattr(Season, 'spam'))
291
292 with self.assertRaises(AttributeError):
293 del Season.SPRING
294 with self.assertRaises(AttributeError):
295 del Season.DRY
296 with self.assertRaises(AttributeError):
297 del Season.SPRING.name
298
Ethan Furman5de67b12016-04-13 23:52:09 -0700299 def test_bool_of_class(self):
300 class Empty(Enum):
301 pass
302 self.assertTrue(bool(Empty))
303
304 def test_bool_of_member(self):
305 class Count(Enum):
306 zero = 0
307 one = 1
308 two = 2
309 for member in Count:
310 self.assertTrue(bool(member))
311
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700312 def test_invalid_names(self):
313 with self.assertRaises(ValueError):
314 class Wrong(Enum):
315 mro = 9
316 with self.assertRaises(ValueError):
317 class Wrong(Enum):
318 _create_= 11
319 with self.assertRaises(ValueError):
320 class Wrong(Enum):
321 _get_mixins_ = 9
322 with self.assertRaises(ValueError):
323 class Wrong(Enum):
324 _find_new_ = 1
325 with self.assertRaises(ValueError):
326 class Wrong(Enum):
327 _any_name_ = 9
328
Ethan Furman6db1fd52015-09-17 21:49:12 -0700329 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800330 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700331 class Logic(Enum):
332 true = True
333 false = False
334 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800335 self.assertTrue(Logic.false)
336 # unless overridden
337 class RealLogic(Enum):
338 true = True
339 false = False
340 def __bool__(self):
341 return bool(self._value_)
342 self.assertTrue(RealLogic.true)
343 self.assertFalse(RealLogic.false)
344 # mixed Enums depend on mixed-in type
345 class IntLogic(int, Enum):
346 true = 1
347 false = 0
348 self.assertTrue(IntLogic.true)
349 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700350
Ethan Furman2a9ab752021-10-20 19:48:37 -0700351 @unittest.skipIf(
352 python_version >= (3, 12),
353 '__contains__ now returns True/False for all inputs',
354 )
355 def test_contains_er(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700356 Season = self.Season
357 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530358 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -0700359 with self.assertWarns(DeprecationWarning):
360 3 in Season
Rahul Jha94306522018-09-10 23:51:04 +0530361 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -0700362 with self.assertWarns(DeprecationWarning):
363 'AUTUMN' in Season
Ethan Furman6bd92882021-04-27 13:05:08 -0700364 val = Season(3)
365 self.assertIn(val, Season)
Ethan Furman2a9ab752021-10-20 19:48:37 -0700366 #
367 class OtherEnum(Enum):
368 one = 1; two = 2
369 self.assertNotIn(OtherEnum.two, Season)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700370
Ethan Furman2a9ab752021-10-20 19:48:37 -0700371 @unittest.skipIf(
372 python_version < (3, 12),
373 '__contains__ only works with enum memmbers before 3.12',
374 )
375 def test_contains_tf(self):
376 Season = self.Season
377 self.assertIn(Season.AUTUMN, Season)
378 self.assertTrue(3 in Season)
379 self.assertFalse('AUTUMN' in Season)
380 val = Season(3)
381 self.assertIn(val, Season)
382 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700383 class OtherEnum(Enum):
384 one = 1; two = 2
385 self.assertNotIn(OtherEnum.two, Season)
386
387 def test_comparisons(self):
388 Season = self.Season
389 with self.assertRaises(TypeError):
390 Season.SPRING < Season.WINTER
391 with self.assertRaises(TypeError):
392 Season.SPRING > 4
393
394 self.assertNotEqual(Season.SPRING, 1)
395
396 class Part(Enum):
397 SPRING = 1
398 CLIP = 2
399 BARREL = 3
400
401 self.assertNotEqual(Season.SPRING, Part.SPRING)
402 with self.assertRaises(TypeError):
403 Season.SPRING < Part.CLIP
404
405 def test_enum_duplicates(self):
406 class Season(Enum):
407 SPRING = 1
408 SUMMER = 2
409 AUTUMN = FALL = 3
410 WINTER = 4
411 ANOTHER_SPRING = 1
412 lst = list(Season)
413 self.assertEqual(
414 lst,
415 [Season.SPRING, Season.SUMMER,
416 Season.AUTUMN, Season.WINTER,
417 ])
418 self.assertIs(Season.FALL, Season.AUTUMN)
419 self.assertEqual(Season.FALL.value, 3)
420 self.assertEqual(Season.AUTUMN.value, 3)
421 self.assertIs(Season(3), Season.AUTUMN)
422 self.assertIs(Season(1), Season.SPRING)
423 self.assertEqual(Season.FALL.name, 'AUTUMN')
424 self.assertEqual(
425 [k for k,v in Season.__members__.items() if v.name != k],
426 ['FALL', 'ANOTHER_SPRING'],
427 )
428
Ethan Furman101e0742013-09-15 12:34:36 -0700429 def test_duplicate_name(self):
430 with self.assertRaises(TypeError):
431 class Color(Enum):
432 red = 1
433 green = 2
434 blue = 3
435 red = 4
436
437 with self.assertRaises(TypeError):
438 class Color(Enum):
439 red = 1
440 green = 2
441 blue = 3
442 def red(self):
443 return 'red'
444
445 with self.assertRaises(TypeError):
446 class Color(Enum):
447 @property
448 def red(self):
449 return 'redder'
450 red = 1
451 green = 2
452 blue = 3
453
454
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700455 def test_enum_with_value_name(self):
456 class Huh(Enum):
457 name = 1
458 value = 2
459 self.assertEqual(
460 list(Huh),
461 [Huh.name, Huh.value],
462 )
463 self.assertIs(type(Huh.name), Huh)
464 self.assertEqual(Huh.name.name, 'name')
465 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700466
467 def test_format_enum(self):
468 Season = self.Season
469 self.assertEqual('{}'.format(Season.SPRING),
470 '{}'.format(str(Season.SPRING)))
471 self.assertEqual( '{:}'.format(Season.SPRING),
472 '{:}'.format(str(Season.SPRING)))
473 self.assertEqual('{:20}'.format(Season.SPRING),
474 '{:20}'.format(str(Season.SPRING)))
475 self.assertEqual('{:^20}'.format(Season.SPRING),
476 '{:^20}'.format(str(Season.SPRING)))
477 self.assertEqual('{:>20}'.format(Season.SPRING),
478 '{:>20}'.format(str(Season.SPRING)))
479 self.assertEqual('{:<20}'.format(Season.SPRING),
480 '{:<20}'.format(str(Season.SPRING)))
481
thatneat2f19e822019-07-04 11:28:37 -0700482 def test_str_override_enum(self):
483 class EnumWithStrOverrides(Enum):
484 one = auto()
485 two = auto()
486
487 def __str__(self):
488 return 'Str!'
489 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
490 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
491
492 def test_format_override_enum(self):
493 class EnumWithFormatOverride(Enum):
494 one = 1.0
495 two = 2.0
496 def __format__(self, spec):
497 return 'Format!!'
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700498 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
thatneat2f19e822019-07-04 11:28:37 -0700499 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
500
501 def test_str_and_format_override_enum(self):
502 class EnumWithStrFormatOverrides(Enum):
503 one = auto()
504 two = auto()
505 def __str__(self):
506 return 'Str!'
507 def __format__(self, spec):
508 return 'Format!'
509 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
510 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
511
512 def test_str_override_mixin(self):
513 class MixinEnumWithStrOverride(float, Enum):
514 one = 1.0
515 two = 2.0
516 def __str__(self):
517 return 'Overridden!'
518 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
519 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
520
521 def test_str_and_format_override_mixin(self):
522 class MixinWithStrFormatOverrides(float, Enum):
523 one = 1.0
524 two = 2.0
525 def __str__(self):
526 return 'Str!'
527 def __format__(self, spec):
528 return 'Format!'
529 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
530 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
531
532 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700533 class TestFloat(float, Enum):
534 one = 1.0
535 two = 2.0
536 def __format__(self, spec):
537 return 'TestFloat success!'
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700538 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700539 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
540
541 def assertFormatIsValue(self, spec, member):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700542 self.assertEqual(spec.format(member), spec.format(member.value))
Ethan Furmanec15a822013-08-31 19:17:41 -0700543
544 def test_format_enum_date(self):
545 Holiday = self.Holiday
546 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
547 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
548 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
549 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
550 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
551 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
552 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
553 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
554
555 def test_format_enum_float(self):
556 Konstants = self.Konstants
557 self.assertFormatIsValue('{}', Konstants.TAU)
558 self.assertFormatIsValue('{:}', Konstants.TAU)
559 self.assertFormatIsValue('{:20}', Konstants.TAU)
560 self.assertFormatIsValue('{:^20}', Konstants.TAU)
561 self.assertFormatIsValue('{:>20}', Konstants.TAU)
562 self.assertFormatIsValue('{:<20}', Konstants.TAU)
563 self.assertFormatIsValue('{:n}', Konstants.TAU)
564 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
565 self.assertFormatIsValue('{:f}', Konstants.TAU)
566
567 def test_format_enum_int(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700568 Grades = self.Grades
Ethan Furmanec15a822013-08-31 19:17:41 -0700569 self.assertFormatIsValue('{}', Grades.C)
570 self.assertFormatIsValue('{:}', Grades.C)
571 self.assertFormatIsValue('{:20}', Grades.C)
572 self.assertFormatIsValue('{:^20}', Grades.C)
573 self.assertFormatIsValue('{:>20}', Grades.C)
574 self.assertFormatIsValue('{:<20}', Grades.C)
575 self.assertFormatIsValue('{:+}', Grades.C)
576 self.assertFormatIsValue('{:08X}', Grades.C)
577 self.assertFormatIsValue('{:b}', Grades.C)
578
579 def test_format_enum_str(self):
580 Directional = self.Directional
581 self.assertFormatIsValue('{}', Directional.WEST)
582 self.assertFormatIsValue('{:}', Directional.WEST)
583 self.assertFormatIsValue('{:20}', Directional.WEST)
584 self.assertFormatIsValue('{:^20}', Directional.WEST)
585 self.assertFormatIsValue('{:>20}', Directional.WEST)
586 self.assertFormatIsValue('{:<20}', Directional.WEST)
587
Ethan Furman22415ad2020-09-15 16:28:25 -0700588 def test_object_str_override(self):
589 class Colors(Enum):
590 RED, GREEN, BLUE = 1, 2, 3
591 def __repr__(self):
592 return "test.%s" % (self._name_, )
593 __str__ = object.__str__
594 self.assertEqual(str(Colors.RED), 'test.RED')
595
Ethan Furmanbff01f32020-09-15 15:56:26 -0700596 def test_enum_str_override(self):
597 class MyStrEnum(Enum):
598 def __str__(self):
599 return 'MyStr'
600 class MyMethodEnum(Enum):
601 def hello(self):
602 return 'Hello! My name is %s' % self.name
603 class Test1Enum(MyMethodEnum, int, MyStrEnum):
604 One = 1
605 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800606 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700607 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800608 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700609 #
610 class Test2Enum(MyStrEnum, MyMethodEnum):
611 One = 1
612 Two = 2
613 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800614 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700615
616 def test_inherited_data_type(self):
617 class HexInt(int):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700618 __qualname__ = 'HexInt'
Ethan Furmanbff01f32020-09-15 15:56:26 -0700619 def __repr__(self):
620 return hex(self)
621 class MyEnum(HexInt, enum.Enum):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700622 __qualname__ = 'MyEnum'
Ethan Furmanbff01f32020-09-15 15:56:26 -0700623 A = 1
624 B = 2
625 C = 3
626 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700627 globals()['HexInt'] = HexInt
628 globals()['MyEnum'] = MyEnum
629 test_pickle_dump_load(self.assertIs, MyEnum.A)
630 test_pickle_dump_load(self.assertIs, MyEnum)
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700631 #
632 class SillyInt(HexInt):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700633 __qualname__ = 'SillyInt'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700634 pass
635 class MyOtherEnum(SillyInt, enum.Enum):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700636 __qualname__ = 'MyOtherEnum'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700637 D = 4
638 E = 5
639 F = 6
640 self.assertIs(MyOtherEnum._member_type_, SillyInt)
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700641 globals()['SillyInt'] = SillyInt
642 globals()['MyOtherEnum'] = MyOtherEnum
643 test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
644 test_pickle_dump_load(self.assertIs, MyOtherEnum)
645 #
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700646 class BrokenInt(int):
647 __qualname__ = 'BrokenInt'
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700648 def __new__(cls, value):
649 return int.__new__(cls, value)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700650 class MyBrokenEnum(BrokenInt, Enum):
651 __qualname__ = 'MyBrokenEnum'
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700652 G = 7
653 H = 8
654 I = 9
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700655 self.assertIs(MyBrokenEnum._member_type_, BrokenInt)
656 self.assertIs(MyBrokenEnum(7), MyBrokenEnum.G)
657 globals()['BrokenInt'] = BrokenInt
658 globals()['MyBrokenEnum'] = MyBrokenEnum
659 test_pickle_exception(self.assertRaises, TypeError, MyBrokenEnum.G)
660 test_pickle_exception(self.assertRaises, PicklingError, MyBrokenEnum)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700661
662 def test_too_many_data_types(self):
663 with self.assertRaisesRegex(TypeError, 'too many data types'):
664 class Huh(str, int, Enum):
665 One = 1
666
667 class MyStr(str):
668 def hello(self):
669 return 'hello, %s' % self
670 class MyInt(int):
671 def repr(self):
672 return hex(self)
673 with self.assertRaisesRegex(TypeError, 'too many data types'):
674 class Huh(MyStr, MyInt, Enum):
675 One = 1
676
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700677 def test_hash(self):
678 Season = self.Season
679 dates = {}
680 dates[Season.WINTER] = '1225'
681 dates[Season.SPRING] = '0315'
682 dates[Season.SUMMER] = '0704'
683 dates[Season.AUTUMN] = '1031'
684 self.assertEqual(dates[Season.AUTUMN], '1031')
685
686 def test_intenum_from_scratch(self):
687 class phy(int, Enum):
688 pi = 3
689 tau = 2 * pi
690 self.assertTrue(phy.pi < phy.tau)
691
692 def test_intenum_inherited(self):
693 class IntEnum(int, Enum):
694 pass
695 class phy(IntEnum):
696 pi = 3
697 tau = 2 * pi
698 self.assertTrue(phy.pi < phy.tau)
699
700 def test_floatenum_from_scratch(self):
701 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700702 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700703 tau = 2 * pi
704 self.assertTrue(phy.pi < phy.tau)
705
706 def test_floatenum_inherited(self):
707 class FloatEnum(float, Enum):
708 pass
709 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700710 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700711 tau = 2 * pi
712 self.assertTrue(phy.pi < phy.tau)
713
714 def test_strenum_from_scratch(self):
715 class phy(str, Enum):
716 pi = 'Pi'
717 tau = 'Tau'
718 self.assertTrue(phy.pi < phy.tau)
719
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700720 def test_strenum_inherited(self):
721 class StrEnum(str, Enum):
722 pass
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700723 class phy(StrEnum):
724 pi = 'Pi'
725 tau = 'Tau'
726 self.assertTrue(phy.pi < phy.tau)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700727
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700728
729 def test_intenum(self):
730 class WeekDay(IntEnum):
731 SUNDAY = 1
732 MONDAY = 2
733 TUESDAY = 3
734 WEDNESDAY = 4
735 THURSDAY = 5
736 FRIDAY = 6
737 SATURDAY = 7
738
739 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
740 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
741
742 lst = list(WeekDay)
743 self.assertEqual(len(lst), len(WeekDay))
744 self.assertEqual(len(WeekDay), 7)
745 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
746 target = target.split()
747 for i, weekday in enumerate(target, 1):
748 e = WeekDay(i)
749 self.assertEqual(e, i)
750 self.assertEqual(int(e), i)
751 self.assertEqual(e.name, weekday)
752 self.assertIn(e, WeekDay)
753 self.assertEqual(lst.index(e)+1, i)
754 self.assertTrue(0 < e < 8)
755 self.assertIs(type(e), WeekDay)
756 self.assertIsInstance(e, int)
757 self.assertIsInstance(e, Enum)
758
759 def test_intenum_duplicates(self):
760 class WeekDay(IntEnum):
761 SUNDAY = 1
762 MONDAY = 2
763 TUESDAY = TEUSDAY = 3
764 WEDNESDAY = 4
765 THURSDAY = 5
766 FRIDAY = 6
767 SATURDAY = 7
768 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
769 self.assertEqual(WeekDay(3).name, 'TUESDAY')
770 self.assertEqual([k for k,v in WeekDay.__members__.items()
771 if v.name != k], ['TEUSDAY', ])
772
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300773 def test_intenum_from_bytes(self):
774 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
775 with self.assertRaises(ValueError):
776 IntStooges.from_bytes(b'\x00\x05', 'big')
777
778 def test_floatenum_fromhex(self):
779 h = float.hex(FloatStooges.MOE.value)
780 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
781 h = float.hex(FloatStooges.MOE.value + 0.01)
782 with self.assertRaises(ValueError):
783 FloatStooges.fromhex(h)
784
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700785 def test_pickle_enum(self):
786 if isinstance(Stooges, Exception):
787 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800788 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
789 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700790
791 def test_pickle_int(self):
792 if isinstance(IntStooges, Exception):
793 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800794 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
795 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700796
797 def test_pickle_float(self):
798 if isinstance(FloatStooges, Exception):
799 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800800 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
801 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700802
803 def test_pickle_enum_function(self):
804 if isinstance(Answer, Exception):
805 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800806 test_pickle_dump_load(self.assertIs, Answer.him)
807 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700808
809 def test_pickle_enum_function_with_module(self):
810 if isinstance(Question, Exception):
811 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800812 test_pickle_dump_load(self.assertIs, Question.who)
813 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700814
Ethan Furmanca1b7942014-02-08 11:36:27 -0800815 def test_enum_function_with_qualname(self):
816 if isinstance(Theory, Exception):
817 raise Theory
818 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
819
820 def test_class_nested_enum_and_pickle_protocol_four(self):
821 # would normally just have this directly in the class namespace
822 class NestedEnum(Enum):
823 twigs = 'common'
824 shiny = 'rare'
825
826 self.__class__.NestedEnum = NestedEnum
827 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300828 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800829
Ethan Furman24e837f2015-03-18 17:27:57 -0700830 def test_pickle_by_name(self):
831 class ReplaceGlobalInt(IntEnum):
832 ONE = 1
833 TWO = 2
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700834 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700835 for proto in range(HIGHEST_PROTOCOL):
836 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
837
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700838 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800839 BadPickle = Enum(
840 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700841 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800842 # now break BadPickle to test exception raising
843 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800844 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
845 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700846
847 def test_string_enum(self):
848 class SkillLevel(str, Enum):
849 master = 'what is the sound of one hand clapping?'
850 journeyman = 'why did the chicken cross the road?'
851 apprentice = 'knock, knock!'
852 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
853
854 def test_getattr_getitem(self):
855 class Period(Enum):
856 morning = 1
857 noon = 2
858 evening = 3
859 night = 4
860 self.assertIs(Period(2), Period.noon)
861 self.assertIs(getattr(Period, 'night'), Period.night)
862 self.assertIs(Period['morning'], Period.morning)
863
864 def test_getattr_dunder(self):
865 Season = self.Season
866 self.assertTrue(getattr(Season, '__eq__'))
867
868 def test_iteration_order(self):
869 class Season(Enum):
870 SUMMER = 2
871 WINTER = 4
872 AUTUMN = 3
873 SPRING = 1
874 self.assertEqual(
875 list(Season),
876 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
877 )
878
Ethan Furman2131a4a2013-09-14 18:11:24 -0700879 def test_reversed_iteration_order(self):
880 self.assertEqual(
881 list(reversed(self.Season)),
882 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
883 self.Season.SPRING]
884 )
885
Martin Pantereb995702016-07-28 01:11:04 +0000886 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700887 SummerMonth = Enum('SummerMonth', 'june july august')
888 lst = list(SummerMonth)
889 self.assertEqual(len(lst), len(SummerMonth))
890 self.assertEqual(len(SummerMonth), 3, SummerMonth)
891 self.assertEqual(
892 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
893 lst,
894 )
895 for i, month in enumerate('june july august'.split(), 1):
896 e = SummerMonth(i)
897 self.assertEqual(int(e.value), i)
898 self.assertNotEqual(e, i)
899 self.assertEqual(e.name, month)
900 self.assertIn(e, SummerMonth)
901 self.assertIs(type(e), SummerMonth)
902
Martin Pantereb995702016-07-28 01:11:04 +0000903 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700904 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
905 lst = list(SummerMonth)
906 self.assertEqual(len(lst), len(SummerMonth))
907 self.assertEqual(len(SummerMonth), 3, SummerMonth)
908 self.assertEqual(
909 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
910 lst,
911 )
912 for i, month in enumerate('june july august'.split(), 10):
913 e = SummerMonth(i)
914 self.assertEqual(int(e.value), i)
915 self.assertNotEqual(e, i)
916 self.assertEqual(e.name, month)
917 self.assertIn(e, SummerMonth)
918 self.assertIs(type(e), SummerMonth)
919
Martin Pantereb995702016-07-28 01:11:04 +0000920 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700921 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
922 lst = list(SummerMonth)
923 self.assertEqual(len(lst), len(SummerMonth))
924 self.assertEqual(len(SummerMonth), 3, SummerMonth)
925 self.assertEqual(
926 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
927 lst,
928 )
929 for i, month in enumerate('june july august'.split(), 1):
930 e = SummerMonth(i)
931 self.assertEqual(int(e.value), i)
932 self.assertNotEqual(e, i)
933 self.assertEqual(e.name, month)
934 self.assertIn(e, SummerMonth)
935 self.assertIs(type(e), SummerMonth)
936
Martin Pantereb995702016-07-28 01:11:04 +0000937 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700938 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
939 lst = list(SummerMonth)
940 self.assertEqual(len(lst), len(SummerMonth))
941 self.assertEqual(len(SummerMonth), 3, SummerMonth)
942 self.assertEqual(
943 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
944 lst,
945 )
946 for i, month in enumerate('june july august'.split(), 20):
947 e = SummerMonth(i)
948 self.assertEqual(int(e.value), i)
949 self.assertNotEqual(e, i)
950 self.assertEqual(e.name, month)
951 self.assertIn(e, SummerMonth)
952 self.assertIs(type(e), SummerMonth)
953
Martin Pantereb995702016-07-28 01:11:04 +0000954 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700955 SummerMonth = Enum(
956 'SummerMonth',
957 (('june', 1), ('july', 2), ('august', 3))
958 )
959 lst = list(SummerMonth)
960 self.assertEqual(len(lst), len(SummerMonth))
961 self.assertEqual(len(SummerMonth), 3, SummerMonth)
962 self.assertEqual(
963 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
964 lst,
965 )
966 for i, month in enumerate('june july august'.split(), 1):
967 e = SummerMonth(i)
968 self.assertEqual(int(e.value), i)
969 self.assertNotEqual(e, i)
970 self.assertEqual(e.name, month)
971 self.assertIn(e, SummerMonth)
972 self.assertIs(type(e), SummerMonth)
973
Martin Pantereb995702016-07-28 01:11:04 +0000974 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700975 SummerMonth = Enum(
976 'SummerMonth',
977 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
978 )
979 lst = list(SummerMonth)
980 self.assertEqual(len(lst), len(SummerMonth))
981 self.assertEqual(len(SummerMonth), 3, SummerMonth)
982 self.assertEqual(
983 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
984 lst,
985 )
986 for i, month in enumerate('june july august'.split(), 1):
987 e = SummerMonth(i)
988 self.assertEqual(int(e.value), i)
989 self.assertNotEqual(e, i)
990 self.assertEqual(e.name, month)
991 self.assertIn(e, SummerMonth)
992 self.assertIs(type(e), SummerMonth)
993
Martin Pantereb995702016-07-28 01:11:04 +0000994 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700995 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
996 lst = list(SummerMonth)
997 self.assertEqual(len(lst), len(SummerMonth))
998 self.assertEqual(len(SummerMonth), 3, SummerMonth)
999 self.assertEqual(
1000 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1001 lst,
1002 )
1003 for i, month in enumerate('june july august'.split(), 1):
1004 e = SummerMonth(i)
1005 self.assertEqual(e, i)
1006 self.assertEqual(e.name, month)
1007 self.assertIn(e, SummerMonth)
1008 self.assertIs(type(e), SummerMonth)
1009
Martin Pantereb995702016-07-28 01:11:04 +00001010 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001011 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1012 lst = list(SummerMonth)
1013 self.assertEqual(len(lst), len(SummerMonth))
1014 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1015 self.assertEqual(
1016 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1017 lst,
1018 )
1019 for i, month in enumerate('june july august'.split(), 30):
1020 e = SummerMonth(i)
1021 self.assertEqual(e, i)
1022 self.assertEqual(e.name, month)
1023 self.assertIn(e, SummerMonth)
1024 self.assertIs(type(e), SummerMonth)
1025
Martin Pantereb995702016-07-28 01:11:04 +00001026 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001027 SummerMonth = IntEnum('SummerMonth', 'june july august')
1028 lst = list(SummerMonth)
1029 self.assertEqual(len(lst), len(SummerMonth))
1030 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1031 self.assertEqual(
1032 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1033 lst,
1034 )
1035 for i, month in enumerate('june july august'.split(), 1):
1036 e = SummerMonth(i)
1037 self.assertEqual(e, i)
1038 self.assertEqual(e.name, month)
1039 self.assertIn(e, SummerMonth)
1040 self.assertIs(type(e), SummerMonth)
1041
Martin Pantereb995702016-07-28 01:11:04 +00001042 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001043 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1044 lst = list(SummerMonth)
1045 self.assertEqual(len(lst), len(SummerMonth))
1046 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1047 self.assertEqual(
1048 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1049 lst,
1050 )
1051 for i, month in enumerate('june july august'.split(), 40):
1052 e = SummerMonth(i)
1053 self.assertEqual(e, i)
1054 self.assertEqual(e.name, month)
1055 self.assertIn(e, SummerMonth)
1056 self.assertIs(type(e), SummerMonth)
1057
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001058 def test_subclassing(self):
1059 if isinstance(Name, Exception):
1060 raise Name
1061 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1062 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1063 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001064 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001065
1066 def test_extending(self):
1067 class Color(Enum):
1068 red = 1
1069 green = 2
1070 blue = 3
1071 with self.assertRaises(TypeError):
1072 class MoreColor(Color):
1073 cyan = 4
1074 magenta = 5
1075 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001076 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1077 class EvenMoreColor(Color, IntEnum):
1078 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001079
1080 def test_exclude_methods(self):
1081 class whatever(Enum):
1082 this = 'that'
1083 these = 'those'
1084 def really(self):
1085 return 'no, not %s' % self.value
1086 self.assertIsNot(type(whatever.really), whatever)
1087 self.assertEqual(whatever.this.really(), 'no, not that')
1088
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001089 def test_wrong_inheritance_order(self):
1090 with self.assertRaises(TypeError):
1091 class Wrong(Enum, str):
1092 NotHere = 'error before this point'
1093
1094 def test_intenum_transitivity(self):
1095 class number(IntEnum):
1096 one = 1
1097 two = 2
1098 three = 3
1099 class numero(IntEnum):
1100 uno = 1
1101 dos = 2
1102 tres = 3
1103 self.assertEqual(number.one, numero.uno)
1104 self.assertEqual(number.two, numero.dos)
1105 self.assertEqual(number.three, numero.tres)
1106
1107 def test_wrong_enum_in_call(self):
1108 class Monochrome(Enum):
1109 black = 0
1110 white = 1
1111 class Gender(Enum):
1112 male = 0
1113 female = 1
1114 self.assertRaises(ValueError, Monochrome, Gender.male)
1115
1116 def test_wrong_enum_in_mixed_call(self):
1117 class Monochrome(IntEnum):
1118 black = 0
1119 white = 1
1120 class Gender(Enum):
1121 male = 0
1122 female = 1
1123 self.assertRaises(ValueError, Monochrome, Gender.male)
1124
1125 def test_mixed_enum_in_call_1(self):
1126 class Monochrome(IntEnum):
1127 black = 0
1128 white = 1
1129 class Gender(IntEnum):
1130 male = 0
1131 female = 1
1132 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1133
1134 def test_mixed_enum_in_call_2(self):
1135 class Monochrome(Enum):
1136 black = 0
1137 white = 1
1138 class Gender(IntEnum):
1139 male = 0
1140 female = 1
1141 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1142
1143 def test_flufl_enum(self):
1144 class Fluflnum(Enum):
1145 def __int__(self):
1146 return int(self.value)
1147 class MailManOptions(Fluflnum):
1148 option1 = 1
1149 option2 = 2
1150 option3 = 3
1151 self.assertEqual(int(MailManOptions.option1), 1)
1152
Ethan Furman5e5a8232013-08-04 08:42:23 -07001153 def test_introspection(self):
1154 class Number(IntEnum):
1155 one = 100
1156 two = 200
1157 self.assertIs(Number.one._member_type_, int)
1158 self.assertIs(Number._member_type_, int)
1159 class String(str, Enum):
1160 yarn = 'soft'
1161 rope = 'rough'
1162 wire = 'hard'
1163 self.assertIs(String.yarn._member_type_, str)
1164 self.assertIs(String._member_type_, str)
1165 class Plain(Enum):
1166 vanilla = 'white'
1167 one = 1
1168 self.assertIs(Plain.vanilla._member_type_, object)
1169 self.assertIs(Plain._member_type_, object)
1170
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001171 def test_no_such_enum_member(self):
1172 class Color(Enum):
1173 red = 1
1174 green = 2
1175 blue = 3
1176 with self.assertRaises(ValueError):
1177 Color(4)
1178 with self.assertRaises(KeyError):
1179 Color['chartreuse']
1180
1181 def test_new_repr(self):
1182 class Color(Enum):
1183 red = 1
1184 green = 2
1185 blue = 3
1186 def __repr__(self):
1187 return "don't you just love shades of %s?" % self.name
1188 self.assertEqual(
1189 repr(Color.blue),
1190 "don't you just love shades of blue?",
1191 )
1192
1193 def test_inherited_repr(self):
1194 class MyEnum(Enum):
1195 def __repr__(self):
1196 return "My name is %s." % self.name
1197 class MyIntEnum(int, MyEnum):
1198 this = 1
1199 that = 2
1200 theother = 3
1201 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1202
1203 def test_multiple_mixin_mro(self):
1204 class auto_enum(type(Enum)):
1205 def __new__(metacls, cls, bases, classdict):
1206 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001207 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001208 names = set(classdict._member_names)
1209 i = 0
1210 for k in classdict._member_names:
1211 v = classdict[k]
1212 if v is Ellipsis:
1213 v = i
1214 else:
1215 i = v
1216 i += 1
1217 temp[k] = v
1218 for k, v in classdict.items():
1219 if k not in names:
1220 temp[k] = v
1221 return super(auto_enum, metacls).__new__(
1222 metacls, cls, bases, temp)
1223
1224 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1225 pass
1226
1227 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1228 pass
1229
1230 class TestAutoNumber(AutoNumberedEnum):
1231 a = ...
1232 b = 3
1233 c = ...
1234
1235 class TestAutoInt(AutoIntEnum):
1236 a = ...
1237 b = 3
1238 c = ...
1239
1240 def test_subclasses_with_getnewargs(self):
1241 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001242 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243 def __new__(cls, *args):
1244 _args = args
1245 name, *args = args
1246 if len(args) == 0:
1247 raise TypeError("name and value must be specified")
1248 self = int.__new__(cls, *args)
1249 self._intname = name
1250 self._args = _args
1251 return self
1252 def __getnewargs__(self):
1253 return self._args
1254 @property
1255 def __name__(self):
1256 return self._intname
1257 def __repr__(self):
1258 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001259 return "{}({!r}, {})".format(type(self).__name__,
1260 self.__name__,
1261 int.__repr__(self))
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001262 def __str__(self):
1263 # str() is unchanged, even if it relies on the repr() fallback
1264 base = int
1265 base_str = base.__str__
1266 if base_str.__objclass__ is object:
1267 return base.__repr__(self)
1268 return base_str(self)
1269 # for simplicity, we only define one operator that
1270 # propagates expressions
1271 def __add__(self, other):
1272 temp = int(self) + int( other)
1273 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1274 return NamedInt(
1275 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001276 temp )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001277 else:
1278 return temp
1279
1280 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001281 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001282 x = ('the-x', 1)
1283 y = ('the-y', 2)
1284
Ethan Furman2aa27322013-07-19 19:35:56 -07001285
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001286 self.assertIs(NEI.__new__, Enum.__new__)
1287 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1288 globals()['NamedInt'] = NamedInt
1289 globals()['NEI'] = NEI
1290 NI5 = NamedInt('test', 5)
1291 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001292 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001293 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001294 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001295 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001296
Ethan Furmanca1b7942014-02-08 11:36:27 -08001297 def test_subclasses_with_getnewargs_ex(self):
1298 class NamedInt(int):
1299 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1300 def __new__(cls, *args):
1301 _args = args
1302 name, *args = args
1303 if len(args) == 0:
1304 raise TypeError("name and value must be specified")
1305 self = int.__new__(cls, *args)
1306 self._intname = name
1307 self._args = _args
1308 return self
1309 def __getnewargs_ex__(self):
1310 return self._args, {}
1311 @property
1312 def __name__(self):
1313 return self._intname
1314 def __repr__(self):
1315 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001316 return "{}({!r}, {})".format(type(self).__name__,
1317 self.__name__,
1318 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001319 def __str__(self):
1320 # str() is unchanged, even if it relies on the repr() fallback
1321 base = int
1322 base_str = base.__str__
1323 if base_str.__objclass__ is object:
1324 return base.__repr__(self)
1325 return base_str(self)
1326 # for simplicity, we only define one operator that
1327 # propagates expressions
1328 def __add__(self, other):
1329 temp = int(self) + int( other)
1330 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1331 return NamedInt(
1332 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001333 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001334 else:
1335 return temp
1336
1337 class NEI(NamedInt, Enum):
1338 __qualname__ = 'NEI' # needed for pickle protocol 4
1339 x = ('the-x', 1)
1340 y = ('the-y', 2)
1341
1342
1343 self.assertIs(NEI.__new__, Enum.__new__)
1344 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1345 globals()['NamedInt'] = NamedInt
1346 globals()['NEI'] = NEI
1347 NI5 = NamedInt('test', 5)
1348 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001349 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001350 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001351 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001352 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001353
1354 def test_subclasses_with_reduce(self):
1355 class NamedInt(int):
1356 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1357 def __new__(cls, *args):
1358 _args = args
1359 name, *args = args
1360 if len(args) == 0:
1361 raise TypeError("name and value must be specified")
1362 self = int.__new__(cls, *args)
1363 self._intname = name
1364 self._args = _args
1365 return self
1366 def __reduce__(self):
1367 return self.__class__, self._args
1368 @property
1369 def __name__(self):
1370 return self._intname
1371 def __repr__(self):
1372 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001373 return "{}({!r}, {})".format(type(self).__name__,
1374 self.__name__,
1375 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001376 def __str__(self):
1377 # str() is unchanged, even if it relies on the repr() fallback
1378 base = int
1379 base_str = base.__str__
1380 if base_str.__objclass__ is object:
1381 return base.__repr__(self)
1382 return base_str(self)
1383 # for simplicity, we only define one operator that
1384 # propagates expressions
1385 def __add__(self, other):
1386 temp = int(self) + int( other)
1387 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1388 return NamedInt(
1389 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001390 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001391 else:
1392 return temp
1393
1394 class NEI(NamedInt, Enum):
1395 __qualname__ = 'NEI' # needed for pickle protocol 4
1396 x = ('the-x', 1)
1397 y = ('the-y', 2)
1398
1399
1400 self.assertIs(NEI.__new__, Enum.__new__)
1401 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1402 globals()['NamedInt'] = NamedInt
1403 globals()['NEI'] = NEI
1404 NI5 = NamedInt('test', 5)
1405 self.assertEqual(NI5, 5)
1406 test_pickle_dump_load(self.assertEqual, NI5, 5)
1407 self.assertEqual(NEI.y.value, 2)
1408 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001409 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001410
1411 def test_subclasses_with_reduce_ex(self):
1412 class NamedInt(int):
1413 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1414 def __new__(cls, *args):
1415 _args = args
1416 name, *args = args
1417 if len(args) == 0:
1418 raise TypeError("name and value must be specified")
1419 self = int.__new__(cls, *args)
1420 self._intname = name
1421 self._args = _args
1422 return self
1423 def __reduce_ex__(self, proto):
1424 return self.__class__, self._args
1425 @property
1426 def __name__(self):
1427 return self._intname
1428 def __repr__(self):
1429 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001430 return "{}({!r}, {})".format(type(self).__name__,
1431 self.__name__,
1432 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001433 def __str__(self):
1434 # str() is unchanged, even if it relies on the repr() fallback
1435 base = int
1436 base_str = base.__str__
1437 if base_str.__objclass__ is object:
1438 return base.__repr__(self)
1439 return base_str(self)
1440 # for simplicity, we only define one operator that
1441 # propagates expressions
1442 def __add__(self, other):
1443 temp = int(self) + int( other)
1444 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1445 return NamedInt(
1446 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001447 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001448 else:
1449 return temp
1450
1451 class NEI(NamedInt, Enum):
1452 __qualname__ = 'NEI' # needed for pickle protocol 4
1453 x = ('the-x', 1)
1454 y = ('the-y', 2)
1455
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001456
Ethan Furmanca1b7942014-02-08 11:36:27 -08001457 self.assertIs(NEI.__new__, Enum.__new__)
1458 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1459 globals()['NamedInt'] = NamedInt
1460 globals()['NEI'] = NEI
1461 NI5 = NamedInt('test', 5)
1462 self.assertEqual(NI5, 5)
1463 test_pickle_dump_load(self.assertEqual, NI5, 5)
1464 self.assertEqual(NEI.y.value, 2)
1465 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001466 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001467
Ethan Furmandc870522014-02-18 12:37:12 -08001468 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001469 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001470 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001471 def __new__(cls, *args):
1472 _args = args
1473 name, *args = args
1474 if len(args) == 0:
1475 raise TypeError("name and value must be specified")
1476 self = int.__new__(cls, *args)
1477 self._intname = name
1478 self._args = _args
1479 return self
1480 @property
1481 def __name__(self):
1482 return self._intname
1483 def __repr__(self):
1484 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001485 return "{}({!r}, {})".format(type(self).__name__,
1486 self.__name__,
1487 int.__repr__(self))
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001488 def __str__(self):
1489 # str() is unchanged, even if it relies on the repr() fallback
1490 base = int
1491 base_str = base.__str__
1492 if base_str.__objclass__ is object:
1493 return base.__repr__(self)
1494 return base_str(self)
1495 # for simplicity, we only define one operator that
1496 # propagates expressions
1497 def __add__(self, other):
1498 temp = int(self) + int( other)
1499 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1500 return NamedInt(
1501 '({0} + {1})'.format(self.__name__, other.__name__),
1502 temp )
1503 else:
1504 return temp
1505
1506 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001507 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001508 x = ('the-x', 1)
1509 y = ('the-y', 2)
1510
1511 self.assertIs(NEI.__new__, Enum.__new__)
1512 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1513 globals()['NamedInt'] = NamedInt
1514 globals()['NEI'] = NEI
1515 NI5 = NamedInt('test', 5)
1516 self.assertEqual(NI5, 5)
1517 self.assertEqual(NEI.y.value, 2)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001518 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1519 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001520
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001521 def test_subclasses_without_direct_pickle_support_using_name(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001522 class NamedInt(int):
1523 __qualname__ = 'NamedInt'
1524 def __new__(cls, *args):
1525 _args = args
1526 name, *args = args
1527 if len(args) == 0:
1528 raise TypeError("name and value must be specified")
1529 self = int.__new__(cls, *args)
1530 self._intname = name
1531 self._args = _args
1532 return self
1533 @property
1534 def __name__(self):
1535 return self._intname
1536 def __repr__(self):
1537 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001538 return "{}({!r}, {})".format(type(self).__name__,
1539 self.__name__,
1540 int.__repr__(self))
Ethan Furmandc870522014-02-18 12:37:12 -08001541 def __str__(self):
1542 # str() is unchanged, even if it relies on the repr() fallback
1543 base = int
1544 base_str = base.__str__
1545 if base_str.__objclass__ is object:
1546 return base.__repr__(self)
1547 return base_str(self)
1548 # for simplicity, we only define one operator that
1549 # propagates expressions
1550 def __add__(self, other):
1551 temp = int(self) + int( other)
1552 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1553 return NamedInt(
1554 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001555 temp )
Ethan Furmandc870522014-02-18 12:37:12 -08001556 else:
1557 return temp
1558
1559 class NEI(NamedInt, Enum):
1560 __qualname__ = 'NEI'
1561 x = ('the-x', 1)
1562 y = ('the-y', 2)
1563 def __reduce_ex__(self, proto):
1564 return getattr, (self.__class__, self._name_)
1565
1566 self.assertIs(NEI.__new__, Enum.__new__)
1567 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1568 globals()['NamedInt'] = NamedInt
1569 globals()['NEI'] = NEI
1570 NI5 = NamedInt('test', 5)
1571 self.assertEqual(NI5, 5)
1572 self.assertEqual(NEI.y.value, 2)
1573 test_pickle_dump_load(self.assertIs, NEI.y)
1574 test_pickle_dump_load(self.assertIs, NEI)
1575
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001576 def test_tuple_subclass(self):
1577 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001578 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001579 first = (1, 'for the money')
1580 second = (2, 'for the show')
1581 third = (3, 'for the music')
1582 self.assertIs(type(SomeTuple.first), SomeTuple)
1583 self.assertIsInstance(SomeTuple.second, tuple)
1584 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1585 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001586 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001587
1588 def test_duplicate_values_give_unique_enum_items(self):
1589 class AutoNumber(Enum):
1590 first = ()
1591 second = ()
1592 third = ()
1593 def __new__(cls):
1594 value = len(cls.__members__) + 1
1595 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001596 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001597 return obj
1598 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001599 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001600 self.assertEqual(
1601 list(AutoNumber),
1602 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1603 )
1604 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001605 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001606 self.assertIs(AutoNumber(1), AutoNumber.first)
1607
1608 def test_inherited_new_from_enhanced_enum(self):
1609 class AutoNumber(Enum):
1610 def __new__(cls):
1611 value = len(cls.__members__) + 1
1612 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001613 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 return obj
1615 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001616 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001617 class Color(AutoNumber):
1618 red = ()
1619 green = ()
1620 blue = ()
1621 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1622 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1623
1624 def test_inherited_new_from_mixed_enum(self):
1625 class AutoNumber(IntEnum):
1626 def __new__(cls):
1627 value = len(cls.__members__) + 1
1628 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001629 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001630 return obj
1631 class Color(AutoNumber):
1632 red = ()
1633 green = ()
1634 blue = ()
1635 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1636 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1637
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001638 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001639 class OrdinaryEnum(Enum):
1640 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001641 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1642 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001643
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001644 def test_ordered_mixin(self):
1645 class OrderedEnum(Enum):
1646 def __ge__(self, other):
1647 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001648 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001649 return NotImplemented
1650 def __gt__(self, other):
1651 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001652 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001653 return NotImplemented
1654 def __le__(self, other):
1655 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001656 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001657 return NotImplemented
1658 def __lt__(self, other):
1659 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001660 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001661 return NotImplemented
1662 class Grade(OrderedEnum):
1663 A = 5
1664 B = 4
1665 C = 3
1666 D = 2
1667 F = 1
1668 self.assertGreater(Grade.A, Grade.B)
1669 self.assertLessEqual(Grade.F, Grade.C)
1670 self.assertLess(Grade.D, Grade.A)
1671 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001672 self.assertEqual(Grade.B, Grade.B)
1673 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001674
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001675 def test_extending2(self):
1676 class Shade(Enum):
1677 def shade(self):
1678 print(self.name)
1679 class Color(Shade):
1680 red = 1
1681 green = 2
1682 blue = 3
1683 with self.assertRaises(TypeError):
1684 class MoreColor(Color):
1685 cyan = 4
1686 magenta = 5
1687 yellow = 6
1688
1689 def test_extending3(self):
1690 class Shade(Enum):
1691 def shade(self):
1692 return self.name
1693 class Color(Shade):
1694 def hex(self):
1695 return '%s hexlified!' % self.value
1696 class MoreColor(Color):
1697 cyan = 4
1698 magenta = 5
1699 yellow = 6
1700 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1701
orlnub1230fb9fad2018-09-12 20:28:53 +03001702 def test_subclass_duplicate_name(self):
1703 class Base(Enum):
1704 def test(self):
1705 pass
1706 class Test(Base):
1707 test = 1
1708 self.assertIs(type(Test.test), Test)
1709
1710 def test_subclass_duplicate_name_dynamic(self):
1711 from types import DynamicClassAttribute
1712 class Base(Enum):
1713 @DynamicClassAttribute
1714 def test(self):
1715 return 'dynamic'
1716 class Test(Base):
1717 test = 1
1718 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001719
1720 def test_no_duplicates(self):
1721 class UniqueEnum(Enum):
1722 def __init__(self, *args):
1723 cls = self.__class__
1724 if any(self.value == e.value for e in cls):
1725 a = self.name
1726 e = cls(self.value).name
1727 raise ValueError(
1728 "aliases not allowed in UniqueEnum: %r --> %r"
1729 % (a, e)
1730 )
1731 class Color(UniqueEnum):
1732 red = 1
1733 green = 2
1734 blue = 3
1735 with self.assertRaises(ValueError):
1736 class Color(UniqueEnum):
1737 red = 1
1738 green = 2
1739 blue = 3
1740 grene = 2
1741
1742 def test_init(self):
1743 class Planet(Enum):
1744 MERCURY = (3.303e+23, 2.4397e6)
1745 VENUS = (4.869e+24, 6.0518e6)
1746 EARTH = (5.976e+24, 6.37814e6)
1747 MARS = (6.421e+23, 3.3972e6)
1748 JUPITER = (1.9e+27, 7.1492e7)
1749 SATURN = (5.688e+26, 6.0268e7)
1750 URANUS = (8.686e+25, 2.5559e7)
1751 NEPTUNE = (1.024e+26, 2.4746e7)
1752 def __init__(self, mass, radius):
1753 self.mass = mass # in kilograms
1754 self.radius = radius # in meters
1755 @property
1756 def surface_gravity(self):
1757 # universal gravitational constant (m3 kg-1 s-2)
1758 G = 6.67300E-11
1759 return G * self.mass / (self.radius * self.radius)
1760 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1761 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1762
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001763 def test_ignore(self):
1764 class Period(timedelta, Enum):
1765 '''
1766 different lengths of time
1767 '''
1768 def __new__(cls, value, period):
1769 obj = timedelta.__new__(cls, value)
1770 obj._value_ = value
1771 obj.period = period
1772 return obj
1773 _ignore_ = 'Period i'
1774 Period = vars()
1775 for i in range(13):
1776 Period['month_%d' % i] = i*30, 'month'
1777 for i in range(53):
1778 Period['week_%d' % i] = i*7, 'week'
1779 for i in range(32):
1780 Period['day_%d' % i] = i, 'day'
1781 OneDay = day_1
1782 OneWeek = week_1
1783 OneMonth = month_1
1784 self.assertFalse(hasattr(Period, '_ignore_'))
1785 self.assertFalse(hasattr(Period, 'Period'))
1786 self.assertFalse(hasattr(Period, 'i'))
1787 self.assertTrue(isinstance(Period.day_1, timedelta))
1788 self.assertTrue(Period.month_1 is Period.day_30)
1789 self.assertTrue(Period.week_4 is Period.day_28)
1790
Ethan Furman2aa27322013-07-19 19:35:56 -07001791 def test_nonhash_value(self):
1792 class AutoNumberInAList(Enum):
1793 def __new__(cls):
1794 value = [len(cls.__members__) + 1]
1795 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001796 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001797 return obj
1798 class ColorInAList(AutoNumberInAList):
1799 red = ()
1800 green = ()
1801 blue = ()
1802 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001803 for enum, value in zip(ColorInAList, range(3)):
1804 value += 1
1805 self.assertEqual(enum.value, [value])
1806 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001807
Ethan Furmanb41803e2013-07-25 13:50:45 -07001808 def test_conflicting_types_resolved_in_new(self):
1809 class LabelledIntEnum(int, Enum):
1810 def __new__(cls, *args):
1811 value, label = args
1812 obj = int.__new__(cls, value)
1813 obj.label = label
1814 obj._value_ = value
1815 return obj
1816
1817 class LabelledList(LabelledIntEnum):
1818 unprocessed = (1, "Unprocessed")
1819 payment_complete = (2, "Payment Complete")
1820
1821 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1822 self.assertEqual(LabelledList.unprocessed, 1)
1823 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001824
Ethan Furmanc16595e2016-09-10 23:36:59 -07001825 def test_auto_number(self):
1826 class Color(Enum):
1827 red = auto()
1828 blue = auto()
1829 green = auto()
1830
1831 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1832 self.assertEqual(Color.red.value, 1)
1833 self.assertEqual(Color.blue.value, 2)
1834 self.assertEqual(Color.green.value, 3)
1835
1836 def test_auto_name(self):
1837 class Color(Enum):
1838 def _generate_next_value_(name, start, count, last):
1839 return name
1840 red = auto()
1841 blue = auto()
1842 green = auto()
1843
1844 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1845 self.assertEqual(Color.red.value, 'red')
1846 self.assertEqual(Color.blue.value, 'blue')
1847 self.assertEqual(Color.green.value, 'green')
1848
1849 def test_auto_name_inherit(self):
1850 class AutoNameEnum(Enum):
1851 def _generate_next_value_(name, start, count, last):
1852 return name
1853 class Color(AutoNameEnum):
1854 red = auto()
1855 blue = auto()
1856 green = auto()
1857
1858 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1859 self.assertEqual(Color.red.value, 'red')
1860 self.assertEqual(Color.blue.value, 'blue')
1861 self.assertEqual(Color.green.value, 'green')
1862
1863 def test_auto_garbage(self):
1864 class Color(Enum):
1865 red = 'red'
1866 blue = auto()
1867 self.assertEqual(Color.blue.value, 1)
1868
1869 def test_auto_garbage_corrected(self):
1870 class Color(Enum):
1871 red = 'red'
1872 blue = 2
1873 green = auto()
1874
1875 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1876 self.assertEqual(Color.red.value, 'red')
1877 self.assertEqual(Color.blue.value, 2)
1878 self.assertEqual(Color.green.value, 3)
1879
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001880 def test_auto_order(self):
1881 with self.assertRaises(TypeError):
1882 class Color(Enum):
1883 red = auto()
1884 green = auto()
1885 blue = auto()
1886 def _generate_next_value_(name, start, count, last):
1887 return name
1888
Ethan Furmanfc23a942020-09-16 12:37:54 -07001889 def test_auto_order_wierd(self):
1890 weird_auto = auto()
1891 weird_auto.value = 'pathological case'
1892 class Color(Enum):
1893 red = weird_auto
1894 def _generate_next_value_(name, start, count, last):
1895 return name
1896 blue = auto()
1897 self.assertEqual(list(Color), [Color.red, Color.blue])
1898 self.assertEqual(Color.red.value, 'pathological case')
1899 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001900
Ethan Furman3515dcc2016-09-18 13:15:41 -07001901 def test_duplicate_auto(self):
1902 class Dupes(Enum):
1903 first = primero = auto()
1904 second = auto()
1905 third = auto()
1906 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1907
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001908 def test_default_missing(self):
1909 class Color(Enum):
1910 RED = 1
1911 GREEN = 2
1912 BLUE = 3
1913 try:
1914 Color(7)
1915 except ValueError as exc:
1916 self.assertTrue(exc.__context__ is None)
1917 else:
1918 raise Exception('Exception not raised.')
1919
Ethan Furman019f0a02018-09-12 11:43:34 -07001920 def test_missing(self):
1921 class Color(Enum):
1922 red = 1
1923 green = 2
1924 blue = 3
1925 @classmethod
1926 def _missing_(cls, item):
1927 if item == 'three':
1928 return cls.blue
1929 elif item == 'bad return':
1930 # trigger internal error
1931 return 5
1932 elif item == 'error out':
1933 raise ZeroDivisionError
1934 else:
1935 # trigger not found
1936 return None
1937 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001938 try:
1939 Color(7)
1940 except ValueError as exc:
1941 self.assertTrue(exc.__context__ is None)
1942 else:
1943 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001944 try:
1945 Color('bad return')
1946 except TypeError as exc:
1947 self.assertTrue(isinstance(exc.__context__, ValueError))
1948 else:
1949 raise Exception('Exception not raised.')
1950 try:
1951 Color('error out')
1952 except ZeroDivisionError as exc:
1953 self.assertTrue(isinstance(exc.__context__, ValueError))
1954 else:
1955 raise Exception('Exception not raised.')
1956
Ethan Furman2a9ab752021-10-20 19:48:37 -07001957 def test_missing_exceptions_reset(self):
1958 import weakref
1959 #
1960 class TestEnum(enum.Enum):
1961 VAL1 = 'val1'
1962 VAL2 = 'val2'
1963 #
1964 class Class1:
1965 def __init__(self):
1966 # Gracefully handle an exception of our own making
1967 try:
1968 raise ValueError()
1969 except ValueError:
1970 pass
1971 #
1972 class Class2:
1973 def __init__(self):
1974 # Gracefully handle an exception of Enum's making
1975 try:
1976 TestEnum('invalid_value')
1977 except ValueError:
1978 pass
1979 # No strong refs here so these are free to die.
1980 class_1_ref = weakref.ref(Class1())
1981 class_2_ref = weakref.ref(Class2())
1982 #
1983 # The exception raised by Enum creates a reference loop and thus
1984 # Class2 instances will stick around until the next gargage collection
1985 # cycle, unlike Class1.
1986 self.assertIs(class_1_ref(), None)
1987 self.assertIs(class_2_ref(), None)
1988
Ethan Furman5bdab642018-09-21 19:03:09 -07001989 def test_multiple_mixin(self):
1990 class MaxMixin:
1991 @classproperty
1992 def MAX(cls):
1993 max = len(cls)
1994 cls.MAX = max
1995 return max
1996 class StrMixin:
1997 def __str__(self):
1998 return self._name_.lower()
1999 class SomeEnum(Enum):
2000 def behavior(self):
2001 return 'booyah'
2002 class AnotherEnum(Enum):
2003 def behavior(self):
2004 return 'nuhuh!'
2005 def social(self):
2006 return "what's up?"
2007 class Color(MaxMixin, Enum):
2008 RED = auto()
2009 GREEN = auto()
2010 BLUE = auto()
2011 self.assertEqual(Color.RED.value, 1)
2012 self.assertEqual(Color.GREEN.value, 2)
2013 self.assertEqual(Color.BLUE.value, 3)
2014 self.assertEqual(Color.MAX, 3)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002015 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002016 class Color(MaxMixin, StrMixin, Enum):
2017 RED = auto()
2018 GREEN = auto()
2019 BLUE = auto()
2020 self.assertEqual(Color.RED.value, 1)
2021 self.assertEqual(Color.GREEN.value, 2)
2022 self.assertEqual(Color.BLUE.value, 3)
2023 self.assertEqual(Color.MAX, 3)
2024 self.assertEqual(str(Color.BLUE), 'blue')
2025 class Color(StrMixin, MaxMixin, Enum):
2026 RED = auto()
2027 GREEN = auto()
2028 BLUE = auto()
2029 self.assertEqual(Color.RED.value, 1)
2030 self.assertEqual(Color.GREEN.value, 2)
2031 self.assertEqual(Color.BLUE.value, 3)
2032 self.assertEqual(Color.MAX, 3)
2033 self.assertEqual(str(Color.BLUE), 'blue')
2034 class CoolColor(StrMixin, SomeEnum, Enum):
2035 RED = auto()
2036 GREEN = auto()
2037 BLUE = auto()
2038 self.assertEqual(CoolColor.RED.value, 1)
2039 self.assertEqual(CoolColor.GREEN.value, 2)
2040 self.assertEqual(CoolColor.BLUE.value, 3)
2041 self.assertEqual(str(CoolColor.BLUE), 'blue')
2042 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2043 class CoolerColor(StrMixin, AnotherEnum, Enum):
2044 RED = auto()
2045 GREEN = auto()
2046 BLUE = auto()
2047 self.assertEqual(CoolerColor.RED.value, 1)
2048 self.assertEqual(CoolerColor.GREEN.value, 2)
2049 self.assertEqual(CoolerColor.BLUE.value, 3)
2050 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2051 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2052 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2053 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2054 RED = auto()
2055 GREEN = auto()
2056 BLUE = auto()
2057 self.assertEqual(CoolestColor.RED.value, 1)
2058 self.assertEqual(CoolestColor.GREEN.value, 2)
2059 self.assertEqual(CoolestColor.BLUE.value, 3)
2060 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2061 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2062 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2063 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2064 RED = auto()
2065 GREEN = auto()
2066 BLUE = auto()
2067 self.assertEqual(ConfusedColor.RED.value, 1)
2068 self.assertEqual(ConfusedColor.GREEN.value, 2)
2069 self.assertEqual(ConfusedColor.BLUE.value, 3)
2070 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2071 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2072 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2073 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2074 RED = auto()
2075 GREEN = auto()
2076 BLUE = auto()
2077 self.assertEqual(ReformedColor.RED.value, 1)
2078 self.assertEqual(ReformedColor.GREEN.value, 2)
2079 self.assertEqual(ReformedColor.BLUE.value, 3)
2080 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2081 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2082 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2083 self.assertTrue(issubclass(ReformedColor, int))
2084
Ethan Furmancd453852018-10-05 23:29:36 -07002085 def test_multiple_inherited_mixin(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002086 class StrEnum(str, Enum):
2087 def __new__(cls, *args, **kwargs):
2088 for a in args:
2089 if not isinstance(a, str):
2090 raise TypeError("Enumeration '%s' (%s) is not"
2091 " a string" % (a, type(a).__name__))
2092 return str.__new__(cls, *args, **kwargs)
Ethan Furmancd453852018-10-05 23:29:36 -07002093 @unique
2094 class Decision1(StrEnum):
2095 REVERT = "REVERT"
2096 REVERT_ALL = "REVERT_ALL"
2097 RETRY = "RETRY"
2098 class MyEnum(StrEnum):
2099 pass
2100 @unique
2101 class Decision2(MyEnum):
2102 REVERT = "REVERT"
2103 REVERT_ALL = "REVERT_ALL"
2104 RETRY = "RETRY"
2105
Ethan Furmanc2667362020-12-07 00:17:31 -08002106 def test_multiple_mixin_inherited(self):
2107 class MyInt(int):
2108 def __new__(cls, value):
2109 return super().__new__(cls, value)
2110
2111 class HexMixin:
2112 def __repr__(self):
2113 return hex(self)
2114
2115 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2116 pass
2117
2118 class Foo(MyIntEnum):
2119 TEST = 1
2120 self.assertTrue(isinstance(Foo.TEST, MyInt))
2121 self.assertEqual(repr(Foo.TEST), "0x1")
2122
2123 class Fee(MyIntEnum):
2124 TEST = 1
2125 def __new__(cls, value):
2126 value += 1
2127 member = int.__new__(cls, value)
2128 member._value_ = value
2129 return member
2130 self.assertEqual(Fee.TEST, 2)
2131
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002132 def test_empty_globals(self):
2133 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2134 # when using compile and exec because f_globals is empty
2135 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2136 code = compile(code, "<string>", "exec")
2137 global_ns = {}
2138 local_ls = {}
2139 exec(code, global_ns, local_ls)
2140
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002141 @unittest.skipUnless(
Ethan Furman2a9ab752021-10-20 19:48:37 -07002142 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002143 'private variables are now normal attributes',
2144 )
2145 def test_warning_for_private_variables(self):
2146 with self.assertWarns(DeprecationWarning):
2147 class Private(Enum):
2148 __corporal = 'Radar'
2149 self.assertEqual(Private._Private__corporal.value, 'Radar')
2150 try:
2151 with self.assertWarns(DeprecationWarning):
2152 class Private(Enum):
2153 __major_ = 'Hoolihan'
2154 except ValueError:
2155 pass
2156
Ethan Furmana6582872020-12-10 13:07:00 -08002157
Ethan Furmane8e61272016-08-20 07:19:31 -07002158class TestOrder(unittest.TestCase):
2159
2160 def test_same_members(self):
2161 class Color(Enum):
2162 _order_ = 'red green blue'
2163 red = 1
2164 green = 2
2165 blue = 3
2166
2167 def test_same_members_with_aliases(self):
2168 class Color(Enum):
2169 _order_ = 'red green blue'
2170 red = 1
2171 green = 2
2172 blue = 3
2173 verde = green
2174
2175 def test_same_members_wrong_order(self):
2176 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2177 class Color(Enum):
2178 _order_ = 'red green blue'
2179 red = 1
2180 blue = 3
2181 green = 2
2182
2183 def test_order_has_extra_members(self):
2184 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2185 class Color(Enum):
2186 _order_ = 'red green blue purple'
2187 red = 1
2188 green = 2
2189 blue = 3
2190
2191 def test_order_has_extra_members_with_aliases(self):
2192 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2193 class Color(Enum):
2194 _order_ = 'red green blue purple'
2195 red = 1
2196 green = 2
2197 blue = 3
2198 verde = green
2199
2200 def test_enum_has_extra_members(self):
2201 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2202 class Color(Enum):
2203 _order_ = 'red green blue'
2204 red = 1
2205 green = 2
2206 blue = 3
2207 purple = 4
2208
2209 def test_enum_has_extra_members_with_aliases(self):
2210 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2211 class Color(Enum):
2212 _order_ = 'red green blue'
2213 red = 1
2214 green = 2
2215 blue = 3
2216 purple = 4
2217 verde = green
2218
2219
Ethan Furman65a5a472016-09-01 23:55:19 -07002220class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002221 """Tests of the Flags."""
2222
Ethan Furman65a5a472016-09-01 23:55:19 -07002223 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002224 R, W, X = 4, 2, 1
2225
Ethan Furman65a5a472016-09-01 23:55:19 -07002226 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002227 RO = 0
2228 WO = 1
2229 RW = 2
2230 AC = 3
2231 CE = 1<<19
2232
Rahul Jha94306522018-09-10 23:51:04 +05302233 class Color(Flag):
2234 BLACK = 0
2235 RED = 1
2236 GREEN = 2
2237 BLUE = 4
2238 PURPLE = RED|BLUE
2239
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002240 def test_str(self):
2241 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002242 self.assertEqual(str(Perm.R), 'Perm.R')
2243 self.assertEqual(str(Perm.W), 'Perm.W')
2244 self.assertEqual(str(Perm.X), 'Perm.X')
2245 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2246 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2247 self.assertEqual(str(Perm(0)), 'Perm.0')
2248 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2249 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2250 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2251 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2252 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2253 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002254
2255 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002256 self.assertEqual(str(Open.RO), 'Open.RO')
2257 self.assertEqual(str(Open.WO), 'Open.WO')
2258 self.assertEqual(str(Open.AC), 'Open.AC')
2259 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2260 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2261 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2262 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2263 self.assertEqual(str(~Open.AC), 'Open.CE')
2264 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2265 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002266
2267 def test_repr(self):
2268 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002269 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2270 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2271 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2272 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2273 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2274 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2275 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2276 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2277 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2278 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2279 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
2280 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002281
2282 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002283 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2284 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2285 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2286 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2287 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2288 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
2289 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2290 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2291 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2292 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002293
Ethan Furman37440ee2020-12-08 11:14:10 -08002294 def test_format(self):
2295 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002296 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2297 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002298
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002299 def test_or(self):
2300 Perm = self.Perm
2301 for i in Perm:
2302 for j in Perm:
2303 self.assertEqual((i | j), Perm(i.value | j.value))
2304 self.assertEqual((i | j).value, i.value | j.value)
2305 self.assertIs(type(i | j), Perm)
2306 for i in Perm:
2307 self.assertIs(i | i, i)
2308 Open = self.Open
2309 self.assertIs(Open.RO | Open.CE, Open.CE)
2310
2311 def test_and(self):
2312 Perm = self.Perm
2313 RW = Perm.R | Perm.W
2314 RX = Perm.R | Perm.X
2315 WX = Perm.W | Perm.X
2316 RWX = Perm.R | Perm.W | Perm.X
2317 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2318 for i in values:
2319 for j in values:
2320 self.assertEqual((i & j).value, i.value & j.value)
2321 self.assertIs(type(i & j), Perm)
2322 for i in Perm:
2323 self.assertIs(i & i, i)
2324 self.assertIs(i & RWX, i)
2325 self.assertIs(RWX & i, i)
2326 Open = self.Open
2327 self.assertIs(Open.RO & Open.CE, Open.RO)
2328
2329 def test_xor(self):
2330 Perm = self.Perm
2331 for i in Perm:
2332 for j in Perm:
2333 self.assertEqual((i ^ j).value, i.value ^ j.value)
2334 self.assertIs(type(i ^ j), Perm)
2335 for i in Perm:
2336 self.assertIs(i ^ Perm(0), i)
2337 self.assertIs(Perm(0) ^ i, i)
2338 Open = self.Open
2339 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2340 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2341
2342 def test_invert(self):
2343 Perm = self.Perm
2344 RW = Perm.R | Perm.W
2345 RX = Perm.R | Perm.X
2346 WX = Perm.W | Perm.X
2347 RWX = Perm.R | Perm.W | Perm.X
2348 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2349 for i in values:
2350 self.assertIs(type(~i), Perm)
2351 self.assertEqual(~~i, i)
2352 for i in Perm:
2353 self.assertIs(~~i, i)
2354 Open = self.Open
2355 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2356 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2357
Ethan Furman25d94bb2016-09-02 16:32:32 -07002358 def test_bool(self):
2359 Perm = self.Perm
2360 for f in Perm:
2361 self.assertTrue(f)
2362 Open = self.Open
2363 for f in Open:
2364 self.assertEqual(bool(f.value), bool(f))
2365
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002366 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002367 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002368 lst = list(Perm)
2369 self.assertEqual(len(lst), len(Perm))
2370 self.assertEqual(len(Perm), 3, Perm)
2371 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2372 for i, n in enumerate('R W X'.split()):
2373 v = 1<<i
2374 e = Perm(v)
2375 self.assertEqual(e.value, v)
2376 self.assertEqual(type(e.value), int)
2377 self.assertEqual(e.name, n)
2378 self.assertIn(e, Perm)
2379 self.assertIs(type(e), Perm)
2380
2381 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002382 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383 lst = list(Perm)
2384 self.assertEqual(len(lst), len(Perm))
2385 self.assertEqual(len(Perm), 3, Perm)
2386 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2387 for i, n in enumerate('R W X'.split()):
2388 v = 8<<i
2389 e = Perm(v)
2390 self.assertEqual(e.value, v)
2391 self.assertEqual(type(e.value), int)
2392 self.assertEqual(e.name, n)
2393 self.assertIn(e, Perm)
2394 self.assertIs(type(e), Perm)
2395
2396 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002397 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002398 lst = list(Perm)
2399 self.assertEqual(len(lst), len(Perm))
2400 self.assertEqual(len(Perm), 3, Perm)
2401 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2402 for i, n in enumerate('R W X'.split()):
2403 v = 1<<i
2404 e = Perm(v)
2405 self.assertEqual(e.value, v)
2406 self.assertEqual(type(e.value), int)
2407 self.assertEqual(e.name, n)
2408 self.assertIn(e, Perm)
2409 self.assertIs(type(e), Perm)
2410
2411 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002412 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002413 lst = list(Perm)
2414 self.assertEqual(len(lst), len(Perm))
2415 self.assertEqual(len(Perm), 3, Perm)
2416 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2417 for i, n in enumerate('R W X'.split()):
2418 v = 1<<(2*i+1)
2419 e = Perm(v)
2420 self.assertEqual(e.value, v)
2421 self.assertEqual(type(e.value), int)
2422 self.assertEqual(e.name, n)
2423 self.assertIn(e, Perm)
2424 self.assertIs(type(e), Perm)
2425
2426 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002427 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002428 lst = list(Perm)
2429 self.assertEqual(len(lst), len(Perm))
2430 self.assertEqual(len(Perm), 3, Perm)
2431 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2432 for i, n in enumerate('R W X'.split()):
2433 v = 1<<(2*i+1)
2434 e = Perm(v)
2435 self.assertEqual(e.value, v)
2436 self.assertEqual(type(e.value), int)
2437 self.assertEqual(e.name, n)
2438 self.assertIn(e, Perm)
2439 self.assertIs(type(e), Perm)
2440
Ethan Furman65a5a472016-09-01 23:55:19 -07002441 def test_pickle(self):
2442 if isinstance(FlagStooges, Exception):
2443 raise FlagStooges
2444 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2445 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002446
Ethan Furman2a9ab752021-10-20 19:48:37 -07002447 @unittest.skipIf(
2448 python_version >= (3, 12),
2449 '__contains__ now returns True/False for all inputs',
2450 )
2451 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302452 Open = self.Open
2453 Color = self.Color
2454 self.assertFalse(Color.BLACK in Open)
2455 self.assertFalse(Open.RO in Color)
2456 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002457 with self.assertWarns(DeprecationWarning):
2458 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302459 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002460 with self.assertWarns(DeprecationWarning):
2461 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302462 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002463 with self.assertWarns(DeprecationWarning):
2464 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302465 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002466 with self.assertWarns(DeprecationWarning):
2467 1 in Open
2468
2469 @unittest.skipIf(
2470 python_version < (3, 12),
2471 '__contains__ only works with enum memmbers before 3.12',
2472 )
2473 def test_contains_tf(self):
2474 Open = self.Open
2475 Color = self.Color
2476 self.assertFalse(Color.BLACK in Open)
2477 self.assertFalse(Open.RO in Color)
2478 self.assertFalse('BLACK' in Color)
2479 self.assertFalse('RO' in Open)
2480 self.assertTrue(1 in Color)
2481 self.assertTrue(1 in Open)
2482
Rahul Jha94306522018-09-10 23:51:04 +05302483
2484 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002485 Perm = self.Perm
2486 R, W, X = Perm
2487 RW = R | W
2488 RX = R | X
2489 WX = W | X
2490 RWX = R | W | X
2491 self.assertTrue(R in RW)
2492 self.assertTrue(R in RX)
2493 self.assertTrue(R in RWX)
2494 self.assertTrue(W in RW)
2495 self.assertTrue(W in WX)
2496 self.assertTrue(W in RWX)
2497 self.assertTrue(X in RX)
2498 self.assertTrue(X in WX)
2499 self.assertTrue(X in RWX)
2500 self.assertFalse(R in WX)
2501 self.assertFalse(W in RX)
2502 self.assertFalse(X in RW)
2503
Ethan Furmanc16595e2016-09-10 23:36:59 -07002504 def test_auto_number(self):
2505 class Color(Flag):
2506 red = auto()
2507 blue = auto()
2508 green = auto()
2509
2510 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2511 self.assertEqual(Color.red.value, 1)
2512 self.assertEqual(Color.blue.value, 2)
2513 self.assertEqual(Color.green.value, 4)
2514
2515 def test_auto_number_garbage(self):
2516 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2517 class Color(Flag):
2518 red = 'not an int'
2519 blue = auto()
2520
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002521 def test_cascading_failure(self):
2522 class Bizarre(Flag):
2523 c = 3
2524 d = 4
2525 f = 6
2526 # Bizarre.c | Bizarre.d
2527 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2528 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2529 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2530 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2531 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2532 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2533 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2534
Ethan Furman3515dcc2016-09-18 13:15:41 -07002535 def test_duplicate_auto(self):
2536 class Dupes(Enum):
2537 first = primero = auto()
2538 second = auto()
2539 third = auto()
2540 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2541
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002542 def test_bizarre(self):
2543 class Bizarre(Flag):
2544 b = 3
2545 c = 4
2546 d = 6
2547 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2548
Ethan Furman5bdab642018-09-21 19:03:09 -07002549 def test_multiple_mixin(self):
2550 class AllMixin:
2551 @classproperty
2552 def ALL(cls):
2553 members = list(cls)
2554 all_value = None
2555 if members:
2556 all_value = members[0]
2557 for member in members[1:]:
2558 all_value |= member
2559 cls.ALL = all_value
2560 return all_value
2561 class StrMixin:
2562 def __str__(self):
2563 return self._name_.lower()
2564 class Color(AllMixin, Flag):
2565 RED = auto()
2566 GREEN = auto()
2567 BLUE = auto()
2568 self.assertEqual(Color.RED.value, 1)
2569 self.assertEqual(Color.GREEN.value, 2)
2570 self.assertEqual(Color.BLUE.value, 4)
2571 self.assertEqual(Color.ALL.value, 7)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002572 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002573 class Color(AllMixin, StrMixin, Flag):
2574 RED = auto()
2575 GREEN = auto()
2576 BLUE = auto()
2577 self.assertEqual(Color.RED.value, 1)
2578 self.assertEqual(Color.GREEN.value, 2)
2579 self.assertEqual(Color.BLUE.value, 4)
2580 self.assertEqual(Color.ALL.value, 7)
2581 self.assertEqual(str(Color.BLUE), 'blue')
2582 class Color(StrMixin, AllMixin, Flag):
2583 RED = auto()
2584 GREEN = auto()
2585 BLUE = auto()
2586 self.assertEqual(Color.RED.value, 1)
2587 self.assertEqual(Color.GREEN.value, 2)
2588 self.assertEqual(Color.BLUE.value, 4)
2589 self.assertEqual(Color.ALL.value, 7)
2590 self.assertEqual(str(Color.BLUE), 'blue')
2591
Hai Shie80697d2020-05-28 06:10:27 +08002592 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002593 def test_unique_composite(self):
2594 # override __eq__ to be identity only
2595 class TestFlag(Flag):
2596 one = auto()
2597 two = auto()
2598 three = auto()
2599 four = auto()
2600 five = auto()
2601 six = auto()
2602 seven = auto()
2603 eight = auto()
2604 def __eq__(self, other):
2605 return self is other
2606 def __hash__(self):
2607 return hash(self._value_)
2608 # have multiple threads competing to complete the composite members
2609 seen = set()
2610 failed = False
2611 def cycle_enum():
2612 nonlocal failed
2613 try:
2614 for i in range(256):
2615 seen.add(TestFlag(i))
2616 except Exception:
2617 failed = True
2618 threads = [
2619 threading.Thread(target=cycle_enum)
2620 for _ in range(8)
2621 ]
Hai Shie80697d2020-05-28 06:10:27 +08002622 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002623 pass
2624 # check that only 248 members were created
2625 self.assertFalse(
2626 failed,
2627 'at least one thread failed while creating composite members')
2628 self.assertEqual(256, len(seen), 'too many composite members created')
2629
Ethan Furman6bd94de2020-12-09 16:41:22 -08002630 def test_init_subclass(self):
2631 class MyEnum(Flag):
2632 def __init_subclass__(cls, **kwds):
2633 super().__init_subclass__(**kwds)
2634 self.assertFalse(cls.__dict__.get('_test', False))
2635 cls._test1 = 'MyEnum'
2636 #
2637 class TheirEnum(MyEnum):
2638 def __init_subclass__(cls, **kwds):
2639 super(TheirEnum, cls).__init_subclass__(**kwds)
2640 cls._test2 = 'TheirEnum'
2641 class WhoseEnum(TheirEnum):
2642 def __init_subclass__(cls, **kwds):
2643 pass
2644 class NoEnum(WhoseEnum):
2645 ONE = 1
2646 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2647 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2648 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2649 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2650 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2651 #
2652 class OurEnum(MyEnum):
2653 def __init_subclass__(cls, **kwds):
2654 cls._test2 = 'OurEnum'
2655 class WhereEnum(OurEnum):
2656 def __init_subclass__(cls, **kwds):
2657 pass
2658 class NeverEnum(WhereEnum):
2659 ONE = 1
2660 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2661 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2662 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2663 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2664 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2665
Ethan Furmanc16595e2016-09-10 23:36:59 -07002666
Ethan Furman65a5a472016-09-01 23:55:19 -07002667class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002668 """Tests of the IntFlags."""
2669
Ethan Furman65a5a472016-09-01 23:55:19 -07002670 class Perm(IntFlag):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002671 X = 1 << 0
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002672 W = 1 << 1
2673 R = 1 << 2
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002674
Ethan Furman65a5a472016-09-01 23:55:19 -07002675 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002676 RO = 0
2677 WO = 1
2678 RW = 2
2679 AC = 3
2680 CE = 1<<19
2681
Rahul Jha94306522018-09-10 23:51:04 +05302682 class Color(IntFlag):
2683 BLACK = 0
2684 RED = 1
2685 GREEN = 2
2686 BLUE = 4
2687 PURPLE = RED|BLUE
2688
Ethan Furman3515dcc2016-09-18 13:15:41 -07002689 def test_type(self):
2690 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002691 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002692 Open = self.Open
2693 for f in Perm:
2694 self.assertTrue(isinstance(f, Perm))
2695 self.assertEqual(f, f.value)
2696 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2697 self.assertEqual(Perm.W | Perm.X, 3)
2698 for f in Open:
2699 self.assertTrue(isinstance(f, Open))
2700 self.assertEqual(f, f.value)
2701 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2702 self.assertEqual(Open.WO | Open.RW, 3)
2703
2704
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002705 def test_str(self):
2706 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002707 self.assertEqual(str(Perm.R), 'Perm.R')
2708 self.assertEqual(str(Perm.W), 'Perm.W')
2709 self.assertEqual(str(Perm.X), 'Perm.X')
2710 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2711 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2712 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2713 self.assertEqual(str(Perm(0)), 'Perm.0')
2714 self.assertEqual(str(Perm(8)), 'Perm.8')
2715 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2716 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2717 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2718 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2719 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
2720 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2721 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2722 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002723
2724 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002725 self.assertEqual(str(Open.RO), 'Open.RO')
2726 self.assertEqual(str(Open.WO), 'Open.WO')
2727 self.assertEqual(str(Open.AC), 'Open.AC')
2728 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2729 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2730 self.assertEqual(str(Open(4)), 'Open.4')
2731 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2732 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2733 self.assertEqual(str(~Open.AC), 'Open.CE')
2734 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2735 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2736 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002737
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002738 def test_repr(self):
2739 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002740 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2741 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2742 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2743 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2744 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2745 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
2746 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2747 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
2748 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2749 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2750 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2751 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
2752 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
2753 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2754 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2755 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002756
2757 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002758 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2759 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2760 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2761 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2762 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2763 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
2764 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2765 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2766 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2767 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2768 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2769 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002770
Ethan Furman37440ee2020-12-08 11:14:10 -08002771 def test_format(self):
Ethan Furman1b4addf2021-06-18 14:25:42 -07002772 Perm = self.Perm
2773 self.assertEqual(format(Perm.R, ''), '4')
2774 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08002775
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002776 def test_or(self):
2777 Perm = self.Perm
2778 for i in Perm:
2779 for j in Perm:
2780 self.assertEqual(i | j, i.value | j.value)
2781 self.assertEqual((i | j).value, i.value | j.value)
2782 self.assertIs(type(i | j), Perm)
2783 for j in range(8):
2784 self.assertEqual(i | j, i.value | j)
2785 self.assertEqual((i | j).value, i.value | j)
2786 self.assertIs(type(i | j), Perm)
2787 self.assertEqual(j | i, j | i.value)
2788 self.assertEqual((j | i).value, j | i.value)
2789 self.assertIs(type(j | i), Perm)
2790 for i in Perm:
2791 self.assertIs(i | i, i)
2792 self.assertIs(i | 0, i)
2793 self.assertIs(0 | i, i)
2794 Open = self.Open
2795 self.assertIs(Open.RO | Open.CE, Open.CE)
2796
2797 def test_and(self):
2798 Perm = self.Perm
2799 RW = Perm.R | Perm.W
2800 RX = Perm.R | Perm.X
2801 WX = Perm.W | Perm.X
2802 RWX = Perm.R | Perm.W | Perm.X
2803 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2804 for i in values:
2805 for j in values:
2806 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2807 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2808 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2809 for j in range(8):
2810 self.assertEqual(i & j, i.value & j)
2811 self.assertEqual((i & j).value, i.value & j)
2812 self.assertIs(type(i & j), Perm)
2813 self.assertEqual(j & i, j & i.value)
2814 self.assertEqual((j & i).value, j & i.value)
2815 self.assertIs(type(j & i), Perm)
2816 for i in Perm:
2817 self.assertIs(i & i, i)
2818 self.assertIs(i & 7, i)
2819 self.assertIs(7 & i, i)
2820 Open = self.Open
2821 self.assertIs(Open.RO & Open.CE, Open.RO)
2822
2823 def test_xor(self):
2824 Perm = self.Perm
2825 for i in Perm:
2826 for j in Perm:
2827 self.assertEqual(i ^ j, i.value ^ j.value)
2828 self.assertEqual((i ^ j).value, i.value ^ j.value)
2829 self.assertIs(type(i ^ j), Perm)
2830 for j in range(8):
2831 self.assertEqual(i ^ j, i.value ^ j)
2832 self.assertEqual((i ^ j).value, i.value ^ j)
2833 self.assertIs(type(i ^ j), Perm)
2834 self.assertEqual(j ^ i, j ^ i.value)
2835 self.assertEqual((j ^ i).value, j ^ i.value)
2836 self.assertIs(type(j ^ i), Perm)
2837 for i in Perm:
2838 self.assertIs(i ^ 0, i)
2839 self.assertIs(0 ^ i, i)
2840 Open = self.Open
2841 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2842 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2843
2844 def test_invert(self):
2845 Perm = self.Perm
2846 RW = Perm.R | Perm.W
2847 RX = Perm.R | Perm.X
2848 WX = Perm.W | Perm.X
2849 RWX = Perm.R | Perm.W | Perm.X
2850 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2851 for i in values:
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002852 self.assertEqual(~i, ~i.value)
2853 self.assertEqual((~i).value, ~i.value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002854 self.assertIs(type(~i), Perm)
2855 self.assertEqual(~~i, i)
2856 for i in Perm:
2857 self.assertIs(~~i, i)
2858 Open = self.Open
2859 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2860 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2861
2862 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002863 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002864 lst = list(Perm)
2865 self.assertEqual(len(lst), len(Perm))
2866 self.assertEqual(len(Perm), 3, Perm)
2867 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2868 for i, n in enumerate('R W X'.split()):
2869 v = 1<<i
2870 e = Perm(v)
2871 self.assertEqual(e.value, v)
2872 self.assertEqual(type(e.value), int)
2873 self.assertEqual(e, v)
2874 self.assertEqual(e.name, n)
2875 self.assertIn(e, Perm)
2876 self.assertIs(type(e), Perm)
2877
2878 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002879 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002880 lst = list(Perm)
2881 self.assertEqual(len(lst), len(Perm))
2882 self.assertEqual(len(Perm), 3, Perm)
2883 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2884 for i, n in enumerate('R W X'.split()):
2885 v = 8<<i
2886 e = Perm(v)
2887 self.assertEqual(e.value, v)
2888 self.assertEqual(type(e.value), int)
2889 self.assertEqual(e, v)
2890 self.assertEqual(e.name, n)
2891 self.assertIn(e, Perm)
2892 self.assertIs(type(e), Perm)
2893
2894 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002895 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002896 lst = list(Perm)
2897 self.assertEqual(len(lst), len(Perm))
2898 self.assertEqual(len(Perm), 3, Perm)
2899 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2900 for i, n in enumerate('R W X'.split()):
2901 v = 1<<i
2902 e = Perm(v)
2903 self.assertEqual(e.value, v)
2904 self.assertEqual(type(e.value), int)
2905 self.assertEqual(e, v)
2906 self.assertEqual(e.name, n)
2907 self.assertIn(e, Perm)
2908 self.assertIs(type(e), Perm)
2909
2910 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002911 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002912 lst = list(Perm)
2913 self.assertEqual(len(lst), len(Perm))
2914 self.assertEqual(len(Perm), 3, Perm)
2915 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2916 for i, n in enumerate('R W X'.split()):
2917 v = 1<<(2*i+1)
2918 e = Perm(v)
2919 self.assertEqual(e.value, v)
2920 self.assertEqual(type(e.value), int)
2921 self.assertEqual(e, v)
2922 self.assertEqual(e.name, n)
2923 self.assertIn(e, Perm)
2924 self.assertIs(type(e), Perm)
2925
2926 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002927 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002928 lst = list(Perm)
2929 self.assertEqual(len(lst), len(Perm))
2930 self.assertEqual(len(Perm), 3, Perm)
2931 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2932 for i, n in enumerate('R W X'.split()):
2933 v = 1<<(2*i+1)
2934 e = Perm(v)
2935 self.assertEqual(e.value, v)
2936 self.assertEqual(type(e.value), int)
2937 self.assertEqual(e, v)
2938 self.assertEqual(e.name, n)
2939 self.assertIn(e, Perm)
2940 self.assertIs(type(e), Perm)
2941
2942
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002943 def test_programatic_function_from_empty_list(self):
2944 Perm = enum.IntFlag('Perm', [])
2945 lst = list(Perm)
2946 self.assertEqual(len(lst), len(Perm))
2947 self.assertEqual(len(Perm), 0, Perm)
2948 Thing = enum.Enum('Thing', [])
2949 lst = list(Thing)
2950 self.assertEqual(len(lst), len(Thing))
2951 self.assertEqual(len(Thing), 0, Thing)
2952
2953
2954 def test_programatic_function_from_empty_tuple(self):
2955 Perm = enum.IntFlag('Perm', ())
2956 lst = list(Perm)
2957 self.assertEqual(len(lst), len(Perm))
2958 self.assertEqual(len(Perm), 0, Perm)
2959 Thing = enum.Enum('Thing', ())
2960 self.assertEqual(len(lst), len(Thing))
2961 self.assertEqual(len(Thing), 0, Thing)
2962
Ethan Furman2a9ab752021-10-20 19:48:37 -07002963 @unittest.skipIf(
2964 python_version >= (3, 12),
2965 '__contains__ now returns True/False for all inputs',
2966 )
2967 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302968 Open = self.Open
2969 Color = self.Color
2970 self.assertTrue(Color.GREEN in Color)
2971 self.assertTrue(Open.RW in Open)
2972 self.assertFalse(Color.GREEN in Open)
2973 self.assertFalse(Open.RW in Color)
2974 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002975 with self.assertWarns(DeprecationWarning):
2976 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302977 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002978 with self.assertWarns(DeprecationWarning):
2979 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302980 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002981 with self.assertWarns(DeprecationWarning):
2982 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302983 with self.assertRaises(TypeError):
Ethan Furman2a9ab752021-10-20 19:48:37 -07002984 with self.assertWarns(DeprecationWarning):
2985 2 in Open
2986
2987 @unittest.skipIf(
2988 python_version < (3, 12),
2989 '__contains__ only works with enum memmbers before 3.12',
2990 )
2991 def test_contains_tf(self):
2992 Open = self.Open
2993 Color = self.Color
2994 self.assertTrue(Color.GREEN in Color)
2995 self.assertTrue(Open.RW in Open)
2996 self.assertTrue(Color.GREEN in Open)
2997 self.assertTrue(Open.RW in Color)
2998 self.assertFalse('GREEN' in Color)
2999 self.assertFalse('RW' in Open)
3000 self.assertTrue(2 in Color)
3001 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303002
3003 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003004 Perm = self.Perm
3005 R, W, X = Perm
3006 RW = R | W
3007 RX = R | X
3008 WX = W | X
3009 RWX = R | W | X
3010 self.assertTrue(R in RW)
3011 self.assertTrue(R in RX)
3012 self.assertTrue(R in RWX)
3013 self.assertTrue(W in RW)
3014 self.assertTrue(W in WX)
3015 self.assertTrue(W in RWX)
3016 self.assertTrue(X in RX)
3017 self.assertTrue(X in WX)
3018 self.assertTrue(X in RWX)
3019 self.assertFalse(R in WX)
3020 self.assertFalse(W in RX)
3021 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303022 with self.assertRaises(TypeError):
3023 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003024
Ethan Furman25d94bb2016-09-02 16:32:32 -07003025 def test_bool(self):
3026 Perm = self.Perm
3027 for f in Perm:
3028 self.assertTrue(f)
3029 Open = self.Open
3030 for f in Open:
3031 self.assertEqual(bool(f.value), bool(f))
3032
Ethan Furman5bdab642018-09-21 19:03:09 -07003033 def test_multiple_mixin(self):
3034 class AllMixin:
3035 @classproperty
3036 def ALL(cls):
3037 members = list(cls)
3038 all_value = None
3039 if members:
3040 all_value = members[0]
3041 for member in members[1:]:
3042 all_value |= member
3043 cls.ALL = all_value
3044 return all_value
3045 class StrMixin:
3046 def __str__(self):
3047 return self._name_.lower()
3048 class Color(AllMixin, IntFlag):
3049 RED = auto()
3050 GREEN = auto()
3051 BLUE = auto()
3052 self.assertEqual(Color.RED.value, 1)
3053 self.assertEqual(Color.GREEN.value, 2)
3054 self.assertEqual(Color.BLUE.value, 4)
3055 self.assertEqual(Color.ALL.value, 7)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003056 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003057 class Color(AllMixin, StrMixin, IntFlag):
3058 RED = auto()
3059 GREEN = auto()
3060 BLUE = auto()
3061 self.assertEqual(Color.RED.value, 1)
3062 self.assertEqual(Color.GREEN.value, 2)
3063 self.assertEqual(Color.BLUE.value, 4)
3064 self.assertEqual(Color.ALL.value, 7)
3065 self.assertEqual(str(Color.BLUE), 'blue')
3066 class Color(StrMixin, AllMixin, IntFlag):
3067 RED = auto()
3068 GREEN = auto()
3069 BLUE = auto()
3070 self.assertEqual(Color.RED.value, 1)
3071 self.assertEqual(Color.GREEN.value, 2)
3072 self.assertEqual(Color.BLUE.value, 4)
3073 self.assertEqual(Color.ALL.value, 7)
3074 self.assertEqual(str(Color.BLUE), 'blue')
3075
Hai Shie80697d2020-05-28 06:10:27 +08003076 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003077 def test_unique_composite(self):
3078 # override __eq__ to be identity only
3079 class TestFlag(IntFlag):
3080 one = auto()
3081 two = auto()
3082 three = auto()
3083 four = auto()
3084 five = auto()
3085 six = auto()
3086 seven = auto()
3087 eight = auto()
3088 def __eq__(self, other):
3089 return self is other
3090 def __hash__(self):
3091 return hash(self._value_)
3092 # have multiple threads competing to complete the composite members
3093 seen = set()
3094 failed = False
3095 def cycle_enum():
3096 nonlocal failed
3097 try:
3098 for i in range(256):
3099 seen.add(TestFlag(i))
3100 except Exception:
3101 failed = True
3102 threads = [
3103 threading.Thread(target=cycle_enum)
3104 for _ in range(8)
3105 ]
Hai Shie80697d2020-05-28 06:10:27 +08003106 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003107 pass
3108 # check that only 248 members were created
3109 self.assertFalse(
3110 failed,
3111 'at least one thread failed while creating composite members')
3112 self.assertEqual(256, len(seen), 'too many composite members created')
3113
3114
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003115class TestEmptyAndNonLatinStrings(unittest.TestCase):
3116
3117 def test_empty_string(self):
3118 with self.assertRaises(ValueError):
3119 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3120
3121 def test_non_latin_character_string(self):
3122 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3123 item = getattr(greek_abc, '\u03B1')
3124 self.assertEqual(item.value, 1)
3125
3126 def test_non_latin_number_string(self):
3127 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3128 item = getattr(hebrew_123, '\u05D0')
3129 self.assertEqual(item.value, 1)
3130
3131
Ethan Furmanf24bb352013-07-18 17:05:39 -07003132class TestUnique(unittest.TestCase):
3133
3134 def test_unique_clean(self):
3135 @unique
3136 class Clean(Enum):
3137 one = 1
3138 two = 'dos'
3139 tres = 4.0
3140 @unique
3141 class Cleaner(IntEnum):
3142 single = 1
3143 double = 2
3144 triple = 3
3145
3146 def test_unique_dirty(self):
3147 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3148 @unique
3149 class Dirty(Enum):
3150 one = 1
3151 two = 'dos'
3152 tres = 1
3153 with self.assertRaisesRegex(
3154 ValueError,
3155 'double.*single.*turkey.*triple',
3156 ):
3157 @unique
3158 class Dirtier(IntEnum):
3159 single = 1
3160 double = 1
3161 triple = 3
3162 turkey = 3
3163
Ethan Furman3803ad42016-05-01 10:03:53 -07003164 def test_unique_with_name(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003165 @unique
Ethan Furman3803ad42016-05-01 10:03:53 -07003166 class Silly(Enum):
3167 one = 1
3168 two = 'dos'
3169 name = 3
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003170 @unique
Ethan Furman74964862021-06-10 07:24:20 -07003171 class Sillier(IntEnum):
3172 single = 1
3173 name = 2
3174 triple = 3
3175 value = 4
3176
Ethan Furman74964862021-06-10 07:24:20 -07003177
Ethan Furman5bdab642018-09-21 19:03:09 -07003178
Ethan Furman3323da92015-04-11 09:39:59 -07003179expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003180Help on class Color in module %s:
3181
3182class Color(enum.Enum)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003183 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003184 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003185 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003186 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003187 | Method resolution order:
3188 | Color
3189 | enum.Enum
3190 | builtins.object
3191 |\x20\x20
3192 | Data and other attributes defined here:
3193 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003194 | blue = <Color.blue: 3>
Ethan Furman5875d742013-10-21 20:45:55 -07003195 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003196 | green = <Color.green: 2>
Ethan Furman5875d742013-10-21 20:45:55 -07003197 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003198 | red = <Color.red: 1>
Ethan Furman5875d742013-10-21 20:45:55 -07003199 |\x20\x20
3200 | ----------------------------------------------------------------------
3201 | Data descriptors inherited from enum.Enum:
3202 |\x20\x20
3203 | name
3204 | The name of the Enum member.
3205 |\x20\x20
3206 | value
3207 | The value of the Enum member.
3208 |\x20\x20
3209 | ----------------------------------------------------------------------
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003210 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003211 |\x20\x20
3212 | __members__
3213 | Returns a mapping of member name->value.
3214 |\x20\x20\x20\x20\x20\x20
3215 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003216 | is a read-only view of the internal mapping."""
3217
3218expected_help_output_without_docs = """\
3219Help on class Color in module %s:
3220
3221class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003222 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3223 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003224 | Method resolution order:
3225 | Color
3226 | enum.Enum
3227 | builtins.object
3228 |\x20\x20
3229 | Data and other attributes defined here:
3230 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003231 | blue = <Color.blue: 3>
Ethan Furman3323da92015-04-11 09:39:59 -07003232 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003233 | green = <Color.green: 2>
Ethan Furman3323da92015-04-11 09:39:59 -07003234 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003235 | red = <Color.red: 1>
Ethan Furman3323da92015-04-11 09:39:59 -07003236 |\x20\x20
3237 | ----------------------------------------------------------------------
3238 | Data descriptors inherited from enum.Enum:
3239 |\x20\x20
3240 | name
3241 |\x20\x20
3242 | value
3243 |\x20\x20
3244 | ----------------------------------------------------------------------
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003245 | Data descriptors inherited from enum.EnumMeta:
Ethan Furman3323da92015-04-11 09:39:59 -07003246 |\x20\x20
3247 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003248
3249class TestStdLib(unittest.TestCase):
3250
Ethan Furman48a724f2015-04-11 23:23:06 -07003251 maxDiff = None
3252
Ethan Furman5875d742013-10-21 20:45:55 -07003253 class Color(Enum):
3254 red = 1
3255 green = 2
3256 blue = 3
3257
3258 def test_pydoc(self):
3259 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003260 if StrEnum.__doc__ is None:
3261 expected_text = expected_help_output_without_docs % __name__
3262 else:
3263 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003264 output = StringIO()
3265 helper = pydoc.Helper(output=output)
3266 helper(self.Color)
3267 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003268 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003269
3270 def test_inspect_getmembers(self):
3271 values = dict((
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003272 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003273 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003274 ('__members__', self.Color.__members__),
3275 ('__module__', __name__),
3276 ('blue', self.Color.blue),
3277 ('green', self.Color.green),
3278 ('name', Enum.__dict__['name']),
3279 ('red', self.Color.red),
3280 ('value', Enum.__dict__['value']),
3281 ))
3282 result = dict(inspect.getmembers(self.Color))
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003283 self.assertEqual(values.keys(), result.keys())
Ethan Furman5875d742013-10-21 20:45:55 -07003284 failed = False
3285 for k in values.keys():
3286 if result[k] != values[k]:
3287 print()
3288 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3289 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3290 failed = True
3291 if failed:
3292 self.fail("result does not equal expected, see print above")
3293
3294 def test_inspect_classify_class_attrs(self):
3295 # indirectly test __objclass__
3296 from inspect import Attribute
3297 values = [
3298 Attribute(name='__class__', kind='data',
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003299 defining_class=object, object=EnumMeta),
Ethan Furman5875d742013-10-21 20:45:55 -07003300 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003301 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003302 Attribute(name='__members__', kind='property',
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003303 defining_class=EnumMeta, object=EnumMeta.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003304 Attribute(name='__module__', kind='data',
3305 defining_class=self.Color, object=__name__),
3306 Attribute(name='blue', kind='data',
3307 defining_class=self.Color, object=self.Color.blue),
3308 Attribute(name='green', kind='data',
3309 defining_class=self.Color, object=self.Color.green),
3310 Attribute(name='red', kind='data',
3311 defining_class=self.Color, object=self.Color.red),
3312 Attribute(name='name', kind='data',
3313 defining_class=Enum, object=Enum.__dict__['name']),
3314 Attribute(name='value', kind='data',
3315 defining_class=Enum, object=Enum.__dict__['value']),
3316 ]
3317 values.sort(key=lambda item: item.name)
3318 result = list(inspect.classify_class_attrs(self.Color))
3319 result.sort(key=lambda item: item.name)
3320 failed = False
3321 for v, r in zip(values, result):
3322 if r != v:
3323 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3324 failed = True
3325 if failed:
3326 self.fail("result does not equal expected, see print above")
3327
Martin Panter19e69c52015-11-14 12:46:42 +00003328
3329class MiscTestCase(unittest.TestCase):
3330 def test__all__(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003331 check__all__(self, enum)
Martin Panter19e69c52015-11-14 12:46:42 +00003332
3333
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003334# These are unordered here on purpose to ensure that declaration order
3335# makes no difference.
3336CONVERT_TEST_NAME_D = 5
3337CONVERT_TEST_NAME_C = 5
3338CONVERT_TEST_NAME_B = 5
3339CONVERT_TEST_NAME_A = 5 # This one should sort first.
3340CONVERT_TEST_NAME_E = 5
3341CONVERT_TEST_NAME_F = 5
3342
3343class TestIntEnumConvert(unittest.TestCase):
3344 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003345 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003346 'UnittestConvert',
3347 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003348 filter=lambda x: x.startswith('CONVERT_TEST_'))
3349 # We don't want the reverse lookup value to vary when there are
3350 # multiple possible names for a given value. It should always
3351 # report the first lexigraphical name in that case.
3352 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3353
3354 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003355 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003356 'UnittestConvert',
3357 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003358 filter=lambda x: x.startswith('CONVERT_TEST_'))
3359 # Ensure that test_type has all of the desired names and values.
3360 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3361 test_type.CONVERT_TEST_NAME_A)
3362 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3363 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3364 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3365 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3366 # Ensure that test_type only picked up names matching the filter.
3367 self.assertEqual([name for name in dir(test_type)
3368 if name[0:2] not in ('CO', '__')],
3369 [], msg='Names other than CONVERT_TEST_* found.')
3370
Ethan Furman2a9ab752021-10-20 19:48:37 -07003371 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003372 '_convert was deprecated in 3.8')
3373 def test_convert_warn(self):
3374 with self.assertWarns(DeprecationWarning):
3375 enum.IntEnum._convert(
3376 'UnittestConvert',
3377 ('test.test_enum', '__main__')[__name__=='__main__'],
3378 filter=lambda x: x.startswith('CONVERT_TEST_'))
3379
Ethan Furman2a9ab752021-10-20 19:48:37 -07003380 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003381 '_convert was removed in 3.9')
3382 def test_convert_raise(self):
3383 with self.assertRaises(AttributeError):
3384 enum.IntEnum._convert(
3385 'UnittestConvert',
3386 ('test.test_enum', '__main__')[__name__=='__main__'],
3387 filter=lambda x: x.startswith('CONVERT_TEST_'))
3388
Ethan Furman2a9ab752021-10-20 19:48:37 -07003389class TestHelpers(unittest.TestCase):
3390
3391 sunder_names = '_bad_', '_good_', '_what_ho_'
3392 dunder_names = '__mal__', '__bien__', '__que_que__'
3393 private_names = '_MyEnum__private', '_MyEnum__still_private'
3394 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3395 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3396
3397 def test_sunder(self):
3398 for name in self.sunder_names + self.private_and_sunder_names:
3399 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3400 for name in self.dunder_names + self.private_names + self.random_names:
3401 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3402
3403 def test_dunder(self):
3404 for name in self.dunder_names:
3405 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3406 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3407 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3408
3409 def test_is_private(self):
3410 for name in self.private_names + self.private_and_sunder_names:
3411 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3412 for name in self.sunder_names + self.dunder_names + self.random_names:
3413 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
3414
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003415
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003416if __name__ == '__main__':
3417 unittest.main()
Ethan Furman2a9ab752021-10-20 19:48:37 -07003418