blob: daca2e3c83f2711212b031e0f682430a65ce7a0b [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002import doctest
Ethan Furman5875d742013-10-21 20:45:55 -07003import inspect
4import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03005import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07006import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02007import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07008from collections import OrderedDict
Ethan Furman0063ff42020-09-21 17:23:13 -07009from enum import Enum, IntEnum, StrEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080010from enum import STRICT, CONFORM, EJECT, KEEP
Ethan Furman5875d742013-10-21 20:45:55 -070011from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080012from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000013from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030014from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080015from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080016from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080017
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080018def load_tests(loader, tests, ignore):
19 tests.addTests(doctest.DocTestSuite(enum))
20 tests.addTests(doctest.DocFileSuite(
21 '../../Doc/library/enum.rst',
22 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
23 ))
24 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070025
26# for pickle tests
27try:
28 class Stooges(Enum):
29 LARRY = 1
30 CURLY = 2
31 MOE = 3
32except Exception as exc:
33 Stooges = exc
34
35try:
36 class IntStooges(int, Enum):
37 LARRY = 1
38 CURLY = 2
39 MOE = 3
40except Exception as exc:
41 IntStooges = exc
42
43try:
44 class FloatStooges(float, Enum):
45 LARRY = 1.39
46 CURLY = 2.72
47 MOE = 3.142596
48except Exception as exc:
49 FloatStooges = exc
50
Ethan Furman65a5a472016-09-01 23:55:19 -070051try:
52 class FlagStooges(Flag):
53 LARRY = 1
54 CURLY = 2
55 MOE = 3
56except Exception as exc:
57 FlagStooges = exc
58
Ethan Furman6b3d64a2013-06-14 16:55:46 -070059# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070060class Name(StrEnum):
61 BDFL = 'Guido van Rossum'
62 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070063
64try:
65 Question = Enum('Question', 'who what when where why', module=__name__)
66except Exception as exc:
67 Question = exc
68
69try:
70 Answer = Enum('Answer', 'him this then there because')
71except Exception as exc:
72 Answer = exc
73
Ethan Furmanca1b7942014-02-08 11:36:27 -080074try:
75 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
76except Exception as exc:
77 Theory = exc
78
Ethan Furman6b3d64a2013-06-14 16:55:46 -070079# for doctests
80try:
81 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080082 TOMATO = 1
83 BANANA = 2
84 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070085except Exception:
86 pass
87
Serhiy Storchakae50e7802015-03-31 16:56:49 +030088def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080089 if target is None:
90 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030091 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080092 assertion(loads(dumps(source, protocol=protocol)), target)
93
Serhiy Storchakae50e7802015-03-31 16:56:49 +030094def test_pickle_exception(assertion, exception, obj):
95 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080096 with assertion(exception):
97 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070098
99class TestHelpers(unittest.TestCase):
100 # _is_descriptor, _is_sunder, _is_dunder
101
102 def test_is_descriptor(self):
103 class foo:
104 pass
105 for attr in ('__get__','__set__','__delete__'):
106 obj = foo()
107 self.assertFalse(enum._is_descriptor(obj))
108 setattr(obj, attr, 1)
109 self.assertTrue(enum._is_descriptor(obj))
110
111 def test_is_sunder(self):
112 for s in ('_a_', '_aa_'):
113 self.assertTrue(enum._is_sunder(s))
114
115 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
116 '__', '___', '____', '_____',):
117 self.assertFalse(enum._is_sunder(s))
118
119 def test_is_dunder(self):
120 for s in ('__a__', '__aa__'):
121 self.assertTrue(enum._is_dunder(s))
122 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
123 '__', '___', '____', '_____',):
124 self.assertFalse(enum._is_dunder(s))
125
Ethan Furman5bdab642018-09-21 19:03:09 -0700126# for subclassing tests
127
128class classproperty:
129
130 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
131 self.fget = fget
132 self.fset = fset
133 self.fdel = fdel
134 if doc is None and fget is not None:
135 doc = fget.__doc__
136 self.__doc__ = doc
137
138 def __get__(self, instance, ownerclass):
139 return self.fget(ownerclass)
140
141
Ethan Furmanc16595e2016-09-10 23:36:59 -0700142# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700143
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700144class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800145
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700146 def setUp(self):
147 class Season(Enum):
148 SPRING = 1
149 SUMMER = 2
150 AUTUMN = 3
151 WINTER = 4
152 self.Season = Season
153
Ethan Furmanec15a822013-08-31 19:17:41 -0700154 class Konstants(float, Enum):
155 E = 2.7182818
156 PI = 3.1415926
157 TAU = 2 * PI
158 self.Konstants = Konstants
159
160 class Grades(IntEnum):
161 A = 5
162 B = 4
163 C = 3
164 D = 2
165 F = 0
166 self.Grades = Grades
167
168 class Directional(str, Enum):
169 EAST = 'east'
170 WEST = 'west'
171 NORTH = 'north'
172 SOUTH = 'south'
173 self.Directional = Directional
174
175 from datetime import date
176 class Holiday(date, Enum):
177 NEW_YEAR = 2013, 1, 1
178 IDES_OF_MARCH = 2013, 3, 15
179 self.Holiday = Holiday
180
Ethan Furman388a3922013-08-12 06:51:41 -0700181 def test_dir_on_class(self):
182 Season = self.Season
183 self.assertEqual(
184 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700185 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700186 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
187 )
188
189 def test_dir_on_item(self):
190 Season = self.Season
191 self.assertEqual(
192 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700193 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700194 )
195
Ethan Furmanc850f342013-09-15 16:59:35 -0700196 def test_dir_with_added_behavior(self):
197 class Test(Enum):
198 this = 'that'
199 these = 'those'
200 def wowser(self):
201 return ("Wowser! I'm %s!" % self.name)
202 self.assertEqual(
203 set(dir(Test)),
204 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
205 )
206 self.assertEqual(
207 set(dir(Test.this)),
208 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
209 )
210
Ethan Furman0ae550b2014-10-14 08:58:32 -0700211 def test_dir_on_sub_with_behavior_on_super(self):
212 # see issue22506
213 class SuperEnum(Enum):
214 def invisible(self):
215 return "did you see me?"
216 class SubEnum(SuperEnum):
217 sample = 5
218 self.assertEqual(
219 set(dir(SubEnum.sample)),
220 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
221 )
222
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200223 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
224 # see issue40084
225 class SuperEnum(IntEnum):
226 def __new__(cls, value, description=""):
227 obj = int.__new__(cls, value)
228 obj._value_ = value
229 obj.description = description
230 return obj
231 class SubEnum(SuperEnum):
232 sample = 5
233 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
234
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700235 def test_enum_in_enum_out(self):
236 Season = self.Season
237 self.assertIs(Season(Season.WINTER), Season.WINTER)
238
239 def test_enum_value(self):
240 Season = self.Season
241 self.assertEqual(Season.SPRING.value, 1)
242
243 def test_intenum_value(self):
244 self.assertEqual(IntStooges.CURLY.value, 2)
245
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700246 def test_enum(self):
247 Season = self.Season
248 lst = list(Season)
249 self.assertEqual(len(lst), len(Season))
250 self.assertEqual(len(Season), 4, Season)
251 self.assertEqual(
252 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
253
254 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
255 e = Season(i)
256 self.assertEqual(e, getattr(Season, season))
257 self.assertEqual(e.value, i)
258 self.assertNotEqual(e, i)
259 self.assertEqual(e.name, season)
260 self.assertIn(e, Season)
261 self.assertIs(type(e), Season)
262 self.assertIsInstance(e, Season)
263 self.assertEqual(str(e), 'Season.' + season)
264 self.assertEqual(
265 repr(e),
266 '<Season.{0}: {1}>'.format(season, i),
267 )
268
269 def test_value_name(self):
270 Season = self.Season
271 self.assertEqual(Season.SPRING.name, 'SPRING')
272 self.assertEqual(Season.SPRING.value, 1)
273 with self.assertRaises(AttributeError):
274 Season.SPRING.name = 'invierno'
275 with self.assertRaises(AttributeError):
276 Season.SPRING.value = 2
277
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700278 def test_changing_member(self):
279 Season = self.Season
280 with self.assertRaises(AttributeError):
281 Season.WINTER = 'really cold'
282
Ethan Furman64a99722013-09-22 16:18:19 -0700283 def test_attribute_deletion(self):
284 class Season(Enum):
285 SPRING = 1
286 SUMMER = 2
287 AUTUMN = 3
288 WINTER = 4
289
290 def spam(cls):
291 pass
292
293 self.assertTrue(hasattr(Season, 'spam'))
294 del Season.spam
295 self.assertFalse(hasattr(Season, 'spam'))
296
297 with self.assertRaises(AttributeError):
298 del Season.SPRING
299 with self.assertRaises(AttributeError):
300 del Season.DRY
301 with self.assertRaises(AttributeError):
302 del Season.SPRING.name
303
Ethan Furman5de67b12016-04-13 23:52:09 -0700304 def test_bool_of_class(self):
305 class Empty(Enum):
306 pass
307 self.assertTrue(bool(Empty))
308
309 def test_bool_of_member(self):
310 class Count(Enum):
311 zero = 0
312 one = 1
313 two = 2
314 for member in Count:
315 self.assertTrue(bool(member))
316
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700317 def test_invalid_names(self):
318 with self.assertRaises(ValueError):
319 class Wrong(Enum):
320 mro = 9
321 with self.assertRaises(ValueError):
322 class Wrong(Enum):
323 _create_= 11
324 with self.assertRaises(ValueError):
325 class Wrong(Enum):
326 _get_mixins_ = 9
327 with self.assertRaises(ValueError):
328 class Wrong(Enum):
329 _find_new_ = 1
330 with self.assertRaises(ValueError):
331 class Wrong(Enum):
332 _any_name_ = 9
333
Ethan Furman6db1fd52015-09-17 21:49:12 -0700334 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800335 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700336 class Logic(Enum):
337 true = True
338 false = False
339 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800340 self.assertTrue(Logic.false)
341 # unless overridden
342 class RealLogic(Enum):
343 true = True
344 false = False
345 def __bool__(self):
346 return bool(self._value_)
347 self.assertTrue(RealLogic.true)
348 self.assertFalse(RealLogic.false)
349 # mixed Enums depend on mixed-in type
350 class IntLogic(int, Enum):
351 true = 1
352 false = 0
353 self.assertTrue(IntLogic.true)
354 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700355
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700356 def test_contains(self):
357 Season = self.Season
358 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530359 with self.assertRaises(TypeError):
360 3 in Season
361 with self.assertRaises(TypeError):
362 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700363
364 val = Season(3)
365 self.assertIn(val, Season)
366
367 class OtherEnum(Enum):
368 one = 1; two = 2
369 self.assertNotIn(OtherEnum.two, Season)
370
371 def test_comparisons(self):
372 Season = self.Season
373 with self.assertRaises(TypeError):
374 Season.SPRING < Season.WINTER
375 with self.assertRaises(TypeError):
376 Season.SPRING > 4
377
378 self.assertNotEqual(Season.SPRING, 1)
379
380 class Part(Enum):
381 SPRING = 1
382 CLIP = 2
383 BARREL = 3
384
385 self.assertNotEqual(Season.SPRING, Part.SPRING)
386 with self.assertRaises(TypeError):
387 Season.SPRING < Part.CLIP
388
389 def test_enum_duplicates(self):
390 class Season(Enum):
391 SPRING = 1
392 SUMMER = 2
393 AUTUMN = FALL = 3
394 WINTER = 4
395 ANOTHER_SPRING = 1
396 lst = list(Season)
397 self.assertEqual(
398 lst,
399 [Season.SPRING, Season.SUMMER,
400 Season.AUTUMN, Season.WINTER,
401 ])
402 self.assertIs(Season.FALL, Season.AUTUMN)
403 self.assertEqual(Season.FALL.value, 3)
404 self.assertEqual(Season.AUTUMN.value, 3)
405 self.assertIs(Season(3), Season.AUTUMN)
406 self.assertIs(Season(1), Season.SPRING)
407 self.assertEqual(Season.FALL.name, 'AUTUMN')
408 self.assertEqual(
409 [k for k,v in Season.__members__.items() if v.name != k],
410 ['FALL', 'ANOTHER_SPRING'],
411 )
412
Ethan Furman101e0742013-09-15 12:34:36 -0700413 def test_duplicate_name(self):
414 with self.assertRaises(TypeError):
415 class Color(Enum):
416 red = 1
417 green = 2
418 blue = 3
419 red = 4
420
421 with self.assertRaises(TypeError):
422 class Color(Enum):
423 red = 1
424 green = 2
425 blue = 3
426 def red(self):
427 return 'red'
428
429 with self.assertRaises(TypeError):
430 class Color(Enum):
431 @property
432 def red(self):
433 return 'redder'
434 red = 1
435 green = 2
436 blue = 3
437
Zackery Spytz2ec67522020-09-13 14:27:51 -0600438 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700439 with self.assertRaisesRegex(
440 ValueError,
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800441 "_sunder_ names, such as '_bad_', are reserved",
Ethan Furman5a565b32020-09-15 12:27:06 -0700442 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600443 class Bad(Enum):
444 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700445
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700446 def test_enum_with_value_name(self):
447 class Huh(Enum):
448 name = 1
449 value = 2
450 self.assertEqual(
451 list(Huh),
452 [Huh.name, Huh.value],
453 )
454 self.assertIs(type(Huh.name), Huh)
455 self.assertEqual(Huh.name.name, 'name')
456 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700457
458 def test_format_enum(self):
459 Season = self.Season
460 self.assertEqual('{}'.format(Season.SPRING),
461 '{}'.format(str(Season.SPRING)))
462 self.assertEqual( '{:}'.format(Season.SPRING),
463 '{:}'.format(str(Season.SPRING)))
464 self.assertEqual('{:20}'.format(Season.SPRING),
465 '{:20}'.format(str(Season.SPRING)))
466 self.assertEqual('{:^20}'.format(Season.SPRING),
467 '{:^20}'.format(str(Season.SPRING)))
468 self.assertEqual('{:>20}'.format(Season.SPRING),
469 '{:>20}'.format(str(Season.SPRING)))
470 self.assertEqual('{:<20}'.format(Season.SPRING),
471 '{:<20}'.format(str(Season.SPRING)))
472
thatneat2f19e822019-07-04 11:28:37 -0700473 def test_str_override_enum(self):
474 class EnumWithStrOverrides(Enum):
475 one = auto()
476 two = auto()
477
478 def __str__(self):
479 return 'Str!'
480 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
481 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
482
483 def test_format_override_enum(self):
484 class EnumWithFormatOverride(Enum):
485 one = 1.0
486 two = 2.0
487 def __format__(self, spec):
488 return 'Format!!'
489 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
490 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
491
492 def test_str_and_format_override_enum(self):
493 class EnumWithStrFormatOverrides(Enum):
494 one = auto()
495 two = auto()
496 def __str__(self):
497 return 'Str!'
498 def __format__(self, spec):
499 return 'Format!'
500 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
501 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
502
503 def test_str_override_mixin(self):
504 class MixinEnumWithStrOverride(float, Enum):
505 one = 1.0
506 two = 2.0
507 def __str__(self):
508 return 'Overridden!'
509 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
510 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
511
512 def test_str_and_format_override_mixin(self):
513 class MixinWithStrFormatOverrides(float, Enum):
514 one = 1.0
515 two = 2.0
516 def __str__(self):
517 return 'Str!'
518 def __format__(self, spec):
519 return 'Format!'
520 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
521 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
522
523 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700524 class TestFloat(float, Enum):
525 one = 1.0
526 two = 2.0
527 def __format__(self, spec):
528 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700529 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700530 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
531
532 def assertFormatIsValue(self, spec, member):
533 self.assertEqual(spec.format(member), spec.format(member.value))
534
535 def test_format_enum_date(self):
536 Holiday = self.Holiday
537 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
538 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
539 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
540 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
541 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
542 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
543 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
544 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
545
546 def test_format_enum_float(self):
547 Konstants = self.Konstants
548 self.assertFormatIsValue('{}', Konstants.TAU)
549 self.assertFormatIsValue('{:}', Konstants.TAU)
550 self.assertFormatIsValue('{:20}', Konstants.TAU)
551 self.assertFormatIsValue('{:^20}', Konstants.TAU)
552 self.assertFormatIsValue('{:>20}', Konstants.TAU)
553 self.assertFormatIsValue('{:<20}', Konstants.TAU)
554 self.assertFormatIsValue('{:n}', Konstants.TAU)
555 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
556 self.assertFormatIsValue('{:f}', Konstants.TAU)
557
558 def test_format_enum_int(self):
559 Grades = self.Grades
560 self.assertFormatIsValue('{}', Grades.C)
561 self.assertFormatIsValue('{:}', Grades.C)
562 self.assertFormatIsValue('{:20}', Grades.C)
563 self.assertFormatIsValue('{:^20}', Grades.C)
564 self.assertFormatIsValue('{:>20}', Grades.C)
565 self.assertFormatIsValue('{:<20}', Grades.C)
566 self.assertFormatIsValue('{:+}', Grades.C)
567 self.assertFormatIsValue('{:08X}', Grades.C)
568 self.assertFormatIsValue('{:b}', Grades.C)
569
570 def test_format_enum_str(self):
571 Directional = self.Directional
572 self.assertFormatIsValue('{}', Directional.WEST)
573 self.assertFormatIsValue('{:}', Directional.WEST)
574 self.assertFormatIsValue('{:20}', Directional.WEST)
575 self.assertFormatIsValue('{:^20}', Directional.WEST)
576 self.assertFormatIsValue('{:>20}', Directional.WEST)
577 self.assertFormatIsValue('{:<20}', Directional.WEST)
578
Ethan Furman22415ad2020-09-15 16:28:25 -0700579 def test_object_str_override(self):
580 class Colors(Enum):
581 RED, GREEN, BLUE = 1, 2, 3
582 def __repr__(self):
583 return "test.%s" % (self._name_, )
584 __str__ = object.__str__
585 self.assertEqual(str(Colors.RED), 'test.RED')
586
Ethan Furmanbff01f32020-09-15 15:56:26 -0700587 def test_enum_str_override(self):
588 class MyStrEnum(Enum):
589 def __str__(self):
590 return 'MyStr'
591 class MyMethodEnum(Enum):
592 def hello(self):
593 return 'Hello! My name is %s' % self.name
594 class Test1Enum(MyMethodEnum, int, MyStrEnum):
595 One = 1
596 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800597 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700598 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800599 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700600 #
601 class Test2Enum(MyStrEnum, MyMethodEnum):
602 One = 1
603 Two = 2
604 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800605 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700606
607 def test_inherited_data_type(self):
608 class HexInt(int):
609 def __repr__(self):
610 return hex(self)
611 class MyEnum(HexInt, enum.Enum):
612 A = 1
613 B = 2
614 C = 3
615 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
616
617 def test_too_many_data_types(self):
618 with self.assertRaisesRegex(TypeError, 'too many data types'):
619 class Huh(str, int, Enum):
620 One = 1
621
622 class MyStr(str):
623 def hello(self):
624 return 'hello, %s' % self
625 class MyInt(int):
626 def repr(self):
627 return hex(self)
628 with self.assertRaisesRegex(TypeError, 'too many data types'):
629 class Huh(MyStr, MyInt, Enum):
630 One = 1
631
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700632 def test_hash(self):
633 Season = self.Season
634 dates = {}
635 dates[Season.WINTER] = '1225'
636 dates[Season.SPRING] = '0315'
637 dates[Season.SUMMER] = '0704'
638 dates[Season.AUTUMN] = '1031'
639 self.assertEqual(dates[Season.AUTUMN], '1031')
640
641 def test_intenum_from_scratch(self):
642 class phy(int, Enum):
643 pi = 3
644 tau = 2 * pi
645 self.assertTrue(phy.pi < phy.tau)
646
647 def test_intenum_inherited(self):
648 class IntEnum(int, Enum):
649 pass
650 class phy(IntEnum):
651 pi = 3
652 tau = 2 * pi
653 self.assertTrue(phy.pi < phy.tau)
654
655 def test_floatenum_from_scratch(self):
656 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700657 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700658 tau = 2 * pi
659 self.assertTrue(phy.pi < phy.tau)
660
661 def test_floatenum_inherited(self):
662 class FloatEnum(float, Enum):
663 pass
664 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700665 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700666 tau = 2 * pi
667 self.assertTrue(phy.pi < phy.tau)
668
669 def test_strenum_from_scratch(self):
670 class phy(str, Enum):
671 pi = 'Pi'
672 tau = 'Tau'
673 self.assertTrue(phy.pi < phy.tau)
674
Ethan Furman0063ff42020-09-21 17:23:13 -0700675 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700676 class phy(StrEnum):
677 pi = 'Pi'
678 tau = 'Tau'
679 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700680 self.assertEqual(phy.pi.upper(), 'PI')
681 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700682
683 def test_intenum(self):
684 class WeekDay(IntEnum):
685 SUNDAY = 1
686 MONDAY = 2
687 TUESDAY = 3
688 WEDNESDAY = 4
689 THURSDAY = 5
690 FRIDAY = 6
691 SATURDAY = 7
692
693 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
694 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
695
696 lst = list(WeekDay)
697 self.assertEqual(len(lst), len(WeekDay))
698 self.assertEqual(len(WeekDay), 7)
699 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
700 target = target.split()
701 for i, weekday in enumerate(target, 1):
702 e = WeekDay(i)
703 self.assertEqual(e, i)
704 self.assertEqual(int(e), i)
705 self.assertEqual(e.name, weekday)
706 self.assertIn(e, WeekDay)
707 self.assertEqual(lst.index(e)+1, i)
708 self.assertTrue(0 < e < 8)
709 self.assertIs(type(e), WeekDay)
710 self.assertIsInstance(e, int)
711 self.assertIsInstance(e, Enum)
712
713 def test_intenum_duplicates(self):
714 class WeekDay(IntEnum):
715 SUNDAY = 1
716 MONDAY = 2
717 TUESDAY = TEUSDAY = 3
718 WEDNESDAY = 4
719 THURSDAY = 5
720 FRIDAY = 6
721 SATURDAY = 7
722 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
723 self.assertEqual(WeekDay(3).name, 'TUESDAY')
724 self.assertEqual([k for k,v in WeekDay.__members__.items()
725 if v.name != k], ['TEUSDAY', ])
726
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300727 def test_intenum_from_bytes(self):
728 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
729 with self.assertRaises(ValueError):
730 IntStooges.from_bytes(b'\x00\x05', 'big')
731
732 def test_floatenum_fromhex(self):
733 h = float.hex(FloatStooges.MOE.value)
734 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
735 h = float.hex(FloatStooges.MOE.value + 0.01)
736 with self.assertRaises(ValueError):
737 FloatStooges.fromhex(h)
738
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700739 def test_pickle_enum(self):
740 if isinstance(Stooges, Exception):
741 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800742 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
743 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700744
745 def test_pickle_int(self):
746 if isinstance(IntStooges, Exception):
747 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800748 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
749 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750
751 def test_pickle_float(self):
752 if isinstance(FloatStooges, Exception):
753 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800754 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
755 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700756
757 def test_pickle_enum_function(self):
758 if isinstance(Answer, Exception):
759 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800760 test_pickle_dump_load(self.assertIs, Answer.him)
761 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700762
763 def test_pickle_enum_function_with_module(self):
764 if isinstance(Question, Exception):
765 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800766 test_pickle_dump_load(self.assertIs, Question.who)
767 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700768
Ethan Furmanca1b7942014-02-08 11:36:27 -0800769 def test_enum_function_with_qualname(self):
770 if isinstance(Theory, Exception):
771 raise Theory
772 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
773
774 def test_class_nested_enum_and_pickle_protocol_four(self):
775 # would normally just have this directly in the class namespace
776 class NestedEnum(Enum):
777 twigs = 'common'
778 shiny = 'rare'
779
780 self.__class__.NestedEnum = NestedEnum
781 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300782 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800783
Ethan Furman24e837f2015-03-18 17:27:57 -0700784 def test_pickle_by_name(self):
785 class ReplaceGlobalInt(IntEnum):
786 ONE = 1
787 TWO = 2
788 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
789 for proto in range(HIGHEST_PROTOCOL):
790 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
791
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700792 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800793 BadPickle = Enum(
794 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700795 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800796 # now break BadPickle to test exception raising
797 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800798 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
799 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700800
801 def test_string_enum(self):
802 class SkillLevel(str, Enum):
803 master = 'what is the sound of one hand clapping?'
804 journeyman = 'why did the chicken cross the road?'
805 apprentice = 'knock, knock!'
806 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
807
808 def test_getattr_getitem(self):
809 class Period(Enum):
810 morning = 1
811 noon = 2
812 evening = 3
813 night = 4
814 self.assertIs(Period(2), Period.noon)
815 self.assertIs(getattr(Period, 'night'), Period.night)
816 self.assertIs(Period['morning'], Period.morning)
817
818 def test_getattr_dunder(self):
819 Season = self.Season
820 self.assertTrue(getattr(Season, '__eq__'))
821
822 def test_iteration_order(self):
823 class Season(Enum):
824 SUMMER = 2
825 WINTER = 4
826 AUTUMN = 3
827 SPRING = 1
828 self.assertEqual(
829 list(Season),
830 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
831 )
832
Ethan Furman2131a4a2013-09-14 18:11:24 -0700833 def test_reversed_iteration_order(self):
834 self.assertEqual(
835 list(reversed(self.Season)),
836 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
837 self.Season.SPRING]
838 )
839
Martin Pantereb995702016-07-28 01:11:04 +0000840 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700841 SummerMonth = Enum('SummerMonth', 'june july august')
842 lst = list(SummerMonth)
843 self.assertEqual(len(lst), len(SummerMonth))
844 self.assertEqual(len(SummerMonth), 3, SummerMonth)
845 self.assertEqual(
846 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
847 lst,
848 )
849 for i, month in enumerate('june july august'.split(), 1):
850 e = SummerMonth(i)
851 self.assertEqual(int(e.value), i)
852 self.assertNotEqual(e, i)
853 self.assertEqual(e.name, month)
854 self.assertIn(e, SummerMonth)
855 self.assertIs(type(e), SummerMonth)
856
Martin Pantereb995702016-07-28 01:11:04 +0000857 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700858 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
859 lst = list(SummerMonth)
860 self.assertEqual(len(lst), len(SummerMonth))
861 self.assertEqual(len(SummerMonth), 3, SummerMonth)
862 self.assertEqual(
863 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
864 lst,
865 )
866 for i, month in enumerate('june july august'.split(), 10):
867 e = SummerMonth(i)
868 self.assertEqual(int(e.value), i)
869 self.assertNotEqual(e, i)
870 self.assertEqual(e.name, month)
871 self.assertIn(e, SummerMonth)
872 self.assertIs(type(e), SummerMonth)
873
Martin Pantereb995702016-07-28 01:11:04 +0000874 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700875 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
876 lst = list(SummerMonth)
877 self.assertEqual(len(lst), len(SummerMonth))
878 self.assertEqual(len(SummerMonth), 3, SummerMonth)
879 self.assertEqual(
880 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
881 lst,
882 )
883 for i, month in enumerate('june july august'.split(), 1):
884 e = SummerMonth(i)
885 self.assertEqual(int(e.value), i)
886 self.assertNotEqual(e, i)
887 self.assertEqual(e.name, month)
888 self.assertIn(e, SummerMonth)
889 self.assertIs(type(e), SummerMonth)
890
Martin Pantereb995702016-07-28 01:11:04 +0000891 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700892 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
893 lst = list(SummerMonth)
894 self.assertEqual(len(lst), len(SummerMonth))
895 self.assertEqual(len(SummerMonth), 3, SummerMonth)
896 self.assertEqual(
897 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
898 lst,
899 )
900 for i, month in enumerate('june july august'.split(), 20):
901 e = SummerMonth(i)
902 self.assertEqual(int(e.value), i)
903 self.assertNotEqual(e, i)
904 self.assertEqual(e.name, month)
905 self.assertIn(e, SummerMonth)
906 self.assertIs(type(e), SummerMonth)
907
Martin Pantereb995702016-07-28 01:11:04 +0000908 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700909 SummerMonth = Enum(
910 'SummerMonth',
911 (('june', 1), ('july', 2), ('august', 3))
912 )
913 lst = list(SummerMonth)
914 self.assertEqual(len(lst), len(SummerMonth))
915 self.assertEqual(len(SummerMonth), 3, SummerMonth)
916 self.assertEqual(
917 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
918 lst,
919 )
920 for i, month in enumerate('june july august'.split(), 1):
921 e = SummerMonth(i)
922 self.assertEqual(int(e.value), i)
923 self.assertNotEqual(e, i)
924 self.assertEqual(e.name, month)
925 self.assertIn(e, SummerMonth)
926 self.assertIs(type(e), SummerMonth)
927
Martin Pantereb995702016-07-28 01:11:04 +0000928 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700929 SummerMonth = Enum(
930 'SummerMonth',
931 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
932 )
933 lst = list(SummerMonth)
934 self.assertEqual(len(lst), len(SummerMonth))
935 self.assertEqual(len(SummerMonth), 3, SummerMonth)
936 self.assertEqual(
937 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
938 lst,
939 )
940 for i, month in enumerate('june july august'.split(), 1):
941 e = SummerMonth(i)
942 self.assertEqual(int(e.value), i)
943 self.assertNotEqual(e, i)
944 self.assertEqual(e.name, month)
945 self.assertIn(e, SummerMonth)
946 self.assertIs(type(e), SummerMonth)
947
Martin Pantereb995702016-07-28 01:11:04 +0000948 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700949 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
950 lst = list(SummerMonth)
951 self.assertEqual(len(lst), len(SummerMonth))
952 self.assertEqual(len(SummerMonth), 3, SummerMonth)
953 self.assertEqual(
954 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
955 lst,
956 )
957 for i, month in enumerate('june july august'.split(), 1):
958 e = SummerMonth(i)
959 self.assertEqual(e, i)
960 self.assertEqual(e.name, month)
961 self.assertIn(e, SummerMonth)
962 self.assertIs(type(e), SummerMonth)
963
Martin Pantereb995702016-07-28 01:11:04 +0000964 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700965 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
966 lst = list(SummerMonth)
967 self.assertEqual(len(lst), len(SummerMonth))
968 self.assertEqual(len(SummerMonth), 3, SummerMonth)
969 self.assertEqual(
970 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
971 lst,
972 )
973 for i, month in enumerate('june july august'.split(), 30):
974 e = SummerMonth(i)
975 self.assertEqual(e, i)
976 self.assertEqual(e.name, month)
977 self.assertIn(e, SummerMonth)
978 self.assertIs(type(e), SummerMonth)
979
Martin Pantereb995702016-07-28 01:11:04 +0000980 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700981 SummerMonth = IntEnum('SummerMonth', 'june july august')
982 lst = list(SummerMonth)
983 self.assertEqual(len(lst), len(SummerMonth))
984 self.assertEqual(len(SummerMonth), 3, SummerMonth)
985 self.assertEqual(
986 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
987 lst,
988 )
989 for i, month in enumerate('june july august'.split(), 1):
990 e = SummerMonth(i)
991 self.assertEqual(e, i)
992 self.assertEqual(e.name, month)
993 self.assertIn(e, SummerMonth)
994 self.assertIs(type(e), SummerMonth)
995
Martin Pantereb995702016-07-28 01:11:04 +0000996 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700997 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
998 lst = list(SummerMonth)
999 self.assertEqual(len(lst), len(SummerMonth))
1000 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1001 self.assertEqual(
1002 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1003 lst,
1004 )
1005 for i, month in enumerate('june july august'.split(), 40):
1006 e = SummerMonth(i)
1007 self.assertEqual(e, i)
1008 self.assertEqual(e.name, month)
1009 self.assertIn(e, SummerMonth)
1010 self.assertIs(type(e), SummerMonth)
1011
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001012 def test_subclassing(self):
1013 if isinstance(Name, Exception):
1014 raise Name
1015 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1016 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1017 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001018 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001019
1020 def test_extending(self):
1021 class Color(Enum):
1022 red = 1
1023 green = 2
1024 blue = 3
1025 with self.assertRaises(TypeError):
1026 class MoreColor(Color):
1027 cyan = 4
1028 magenta = 5
1029 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001030 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1031 class EvenMoreColor(Color, IntEnum):
1032 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001033
1034 def test_exclude_methods(self):
1035 class whatever(Enum):
1036 this = 'that'
1037 these = 'those'
1038 def really(self):
1039 return 'no, not %s' % self.value
1040 self.assertIsNot(type(whatever.really), whatever)
1041 self.assertEqual(whatever.this.really(), 'no, not that')
1042
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001043 def test_wrong_inheritance_order(self):
1044 with self.assertRaises(TypeError):
1045 class Wrong(Enum, str):
1046 NotHere = 'error before this point'
1047
1048 def test_intenum_transitivity(self):
1049 class number(IntEnum):
1050 one = 1
1051 two = 2
1052 three = 3
1053 class numero(IntEnum):
1054 uno = 1
1055 dos = 2
1056 tres = 3
1057 self.assertEqual(number.one, numero.uno)
1058 self.assertEqual(number.two, numero.dos)
1059 self.assertEqual(number.three, numero.tres)
1060
1061 def test_wrong_enum_in_call(self):
1062 class Monochrome(Enum):
1063 black = 0
1064 white = 1
1065 class Gender(Enum):
1066 male = 0
1067 female = 1
1068 self.assertRaises(ValueError, Monochrome, Gender.male)
1069
1070 def test_wrong_enum_in_mixed_call(self):
1071 class Monochrome(IntEnum):
1072 black = 0
1073 white = 1
1074 class Gender(Enum):
1075 male = 0
1076 female = 1
1077 self.assertRaises(ValueError, Monochrome, Gender.male)
1078
1079 def test_mixed_enum_in_call_1(self):
1080 class Monochrome(IntEnum):
1081 black = 0
1082 white = 1
1083 class Gender(IntEnum):
1084 male = 0
1085 female = 1
1086 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1087
1088 def test_mixed_enum_in_call_2(self):
1089 class Monochrome(Enum):
1090 black = 0
1091 white = 1
1092 class Gender(IntEnum):
1093 male = 0
1094 female = 1
1095 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1096
1097 def test_flufl_enum(self):
1098 class Fluflnum(Enum):
1099 def __int__(self):
1100 return int(self.value)
1101 class MailManOptions(Fluflnum):
1102 option1 = 1
1103 option2 = 2
1104 option3 = 3
1105 self.assertEqual(int(MailManOptions.option1), 1)
1106
Ethan Furman5e5a8232013-08-04 08:42:23 -07001107 def test_introspection(self):
1108 class Number(IntEnum):
1109 one = 100
1110 two = 200
1111 self.assertIs(Number.one._member_type_, int)
1112 self.assertIs(Number._member_type_, int)
1113 class String(str, Enum):
1114 yarn = 'soft'
1115 rope = 'rough'
1116 wire = 'hard'
1117 self.assertIs(String.yarn._member_type_, str)
1118 self.assertIs(String._member_type_, str)
1119 class Plain(Enum):
1120 vanilla = 'white'
1121 one = 1
1122 self.assertIs(Plain.vanilla._member_type_, object)
1123 self.assertIs(Plain._member_type_, object)
1124
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001125 def test_no_such_enum_member(self):
1126 class Color(Enum):
1127 red = 1
1128 green = 2
1129 blue = 3
1130 with self.assertRaises(ValueError):
1131 Color(4)
1132 with self.assertRaises(KeyError):
1133 Color['chartreuse']
1134
1135 def test_new_repr(self):
1136 class Color(Enum):
1137 red = 1
1138 green = 2
1139 blue = 3
1140 def __repr__(self):
1141 return "don't you just love shades of %s?" % self.name
1142 self.assertEqual(
1143 repr(Color.blue),
1144 "don't you just love shades of blue?",
1145 )
1146
1147 def test_inherited_repr(self):
1148 class MyEnum(Enum):
1149 def __repr__(self):
1150 return "My name is %s." % self.name
1151 class MyIntEnum(int, MyEnum):
1152 this = 1
1153 that = 2
1154 theother = 3
1155 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1156
1157 def test_multiple_mixin_mro(self):
1158 class auto_enum(type(Enum)):
1159 def __new__(metacls, cls, bases, classdict):
1160 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001161 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001162 names = set(classdict._member_names)
1163 i = 0
1164 for k in classdict._member_names:
1165 v = classdict[k]
1166 if v is Ellipsis:
1167 v = i
1168 else:
1169 i = v
1170 i += 1
1171 temp[k] = v
1172 for k, v in classdict.items():
1173 if k not in names:
1174 temp[k] = v
1175 return super(auto_enum, metacls).__new__(
1176 metacls, cls, bases, temp)
1177
1178 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1179 pass
1180
1181 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1182 pass
1183
1184 class TestAutoNumber(AutoNumberedEnum):
1185 a = ...
1186 b = 3
1187 c = ...
1188
1189 class TestAutoInt(AutoIntEnum):
1190 a = ...
1191 b = 3
1192 c = ...
1193
1194 def test_subclasses_with_getnewargs(self):
1195 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001196 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001197 def __new__(cls, *args):
1198 _args = args
1199 name, *args = args
1200 if len(args) == 0:
1201 raise TypeError("name and value must be specified")
1202 self = int.__new__(cls, *args)
1203 self._intname = name
1204 self._args = _args
1205 return self
1206 def __getnewargs__(self):
1207 return self._args
1208 @property
1209 def __name__(self):
1210 return self._intname
1211 def __repr__(self):
1212 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001213 return "{}({!r}, {})".format(
1214 type(self).__name__,
1215 self.__name__,
1216 int.__repr__(self),
1217 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001218 def __str__(self):
1219 # str() is unchanged, even if it relies on the repr() fallback
1220 base = int
1221 base_str = base.__str__
1222 if base_str.__objclass__ is object:
1223 return base.__repr__(self)
1224 return base_str(self)
1225 # for simplicity, we only define one operator that
1226 # propagates expressions
1227 def __add__(self, other):
1228 temp = int(self) + int( other)
1229 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1230 return NamedInt(
1231 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001232 temp,
1233 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001234 else:
1235 return temp
1236
1237 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001238 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001239 x = ('the-x', 1)
1240 y = ('the-y', 2)
1241
Ethan Furman2aa27322013-07-19 19:35:56 -07001242
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243 self.assertIs(NEI.__new__, Enum.__new__)
1244 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1245 globals()['NamedInt'] = NamedInt
1246 globals()['NEI'] = NEI
1247 NI5 = NamedInt('test', 5)
1248 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001249 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001250 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001251 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001252 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001253
Ethan Furmanca1b7942014-02-08 11:36:27 -08001254 def test_subclasses_with_getnewargs_ex(self):
1255 class NamedInt(int):
1256 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1257 def __new__(cls, *args):
1258 _args = args
1259 name, *args = args
1260 if len(args) == 0:
1261 raise TypeError("name and value must be specified")
1262 self = int.__new__(cls, *args)
1263 self._intname = name
1264 self._args = _args
1265 return self
1266 def __getnewargs_ex__(self):
1267 return self._args, {}
1268 @property
1269 def __name__(self):
1270 return self._intname
1271 def __repr__(self):
1272 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001273 return "{}({!r}, {})".format(
1274 type(self).__name__,
1275 self.__name__,
1276 int.__repr__(self),
1277 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001278 def __str__(self):
1279 # str() is unchanged, even if it relies on the repr() fallback
1280 base = int
1281 base_str = base.__str__
1282 if base_str.__objclass__ is object:
1283 return base.__repr__(self)
1284 return base_str(self)
1285 # for simplicity, we only define one operator that
1286 # propagates expressions
1287 def __add__(self, other):
1288 temp = int(self) + int( other)
1289 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1290 return NamedInt(
1291 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001292 temp,
1293 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001294 else:
1295 return temp
1296
1297 class NEI(NamedInt, Enum):
1298 __qualname__ = 'NEI' # needed for pickle protocol 4
1299 x = ('the-x', 1)
1300 y = ('the-y', 2)
1301
1302
1303 self.assertIs(NEI.__new__, Enum.__new__)
1304 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1305 globals()['NamedInt'] = NamedInt
1306 globals()['NEI'] = NEI
1307 NI5 = NamedInt('test', 5)
1308 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001309 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001310 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001311 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001312 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001313
1314 def test_subclasses_with_reduce(self):
1315 class NamedInt(int):
1316 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1317 def __new__(cls, *args):
1318 _args = args
1319 name, *args = args
1320 if len(args) == 0:
1321 raise TypeError("name and value must be specified")
1322 self = int.__new__(cls, *args)
1323 self._intname = name
1324 self._args = _args
1325 return self
1326 def __reduce__(self):
1327 return self.__class__, self._args
1328 @property
1329 def __name__(self):
1330 return self._intname
1331 def __repr__(self):
1332 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001333 return "{}({!r}, {})".format(
1334 type(self).__name__,
1335 self.__name__,
1336 int.__repr__(self),
1337 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001338 def __str__(self):
1339 # str() is unchanged, even if it relies on the repr() fallback
1340 base = int
1341 base_str = base.__str__
1342 if base_str.__objclass__ is object:
1343 return base.__repr__(self)
1344 return base_str(self)
1345 # for simplicity, we only define one operator that
1346 # propagates expressions
1347 def __add__(self, other):
1348 temp = int(self) + int( other)
1349 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1350 return NamedInt(
1351 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001352 temp,
1353 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354 else:
1355 return temp
1356
1357 class NEI(NamedInt, Enum):
1358 __qualname__ = 'NEI' # needed for pickle protocol 4
1359 x = ('the-x', 1)
1360 y = ('the-y', 2)
1361
1362
1363 self.assertIs(NEI.__new__, Enum.__new__)
1364 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1365 globals()['NamedInt'] = NamedInt
1366 globals()['NEI'] = NEI
1367 NI5 = NamedInt('test', 5)
1368 self.assertEqual(NI5, 5)
1369 test_pickle_dump_load(self.assertEqual, NI5, 5)
1370 self.assertEqual(NEI.y.value, 2)
1371 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001372 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001373
1374 def test_subclasses_with_reduce_ex(self):
1375 class NamedInt(int):
1376 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1377 def __new__(cls, *args):
1378 _args = args
1379 name, *args = args
1380 if len(args) == 0:
1381 raise TypeError("name and value must be specified")
1382 self = int.__new__(cls, *args)
1383 self._intname = name
1384 self._args = _args
1385 return self
1386 def __reduce_ex__(self, proto):
1387 return self.__class__, self._args
1388 @property
1389 def __name__(self):
1390 return self._intname
1391 def __repr__(self):
1392 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001393 return "{}({!r}, {})".format(
1394 type(self).__name__,
1395 self.__name__,
1396 int.__repr__(self),
1397 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001398 def __str__(self):
1399 # str() is unchanged, even if it relies on the repr() fallback
1400 base = int
1401 base_str = base.__str__
1402 if base_str.__objclass__ is object:
1403 return base.__repr__(self)
1404 return base_str(self)
1405 # for simplicity, we only define one operator that
1406 # propagates expressions
1407 def __add__(self, other):
1408 temp = int(self) + int( other)
1409 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1410 return NamedInt(
1411 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001412 temp,
1413 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001414 else:
1415 return temp
1416
1417 class NEI(NamedInt, Enum):
1418 __qualname__ = 'NEI' # needed for pickle protocol 4
1419 x = ('the-x', 1)
1420 y = ('the-y', 2)
1421
Ethan Furmanca1b7942014-02-08 11:36:27 -08001422 self.assertIs(NEI.__new__, Enum.__new__)
1423 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1424 globals()['NamedInt'] = NamedInt
1425 globals()['NEI'] = NEI
1426 NI5 = NamedInt('test', 5)
1427 self.assertEqual(NI5, 5)
1428 test_pickle_dump_load(self.assertEqual, NI5, 5)
1429 self.assertEqual(NEI.y.value, 2)
1430 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001431 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001432
Ethan Furmandc870522014-02-18 12:37:12 -08001433 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001434 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001435 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 def __new__(cls, *args):
1437 _args = args
1438 name, *args = args
1439 if len(args) == 0:
1440 raise TypeError("name and value must be specified")
1441 self = int.__new__(cls, *args)
1442 self._intname = name
1443 self._args = _args
1444 return self
1445 @property
1446 def __name__(self):
1447 return self._intname
1448 def __repr__(self):
1449 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001450 return "{}({!r}, {})".format(
1451 type(self).__name__,
1452 self.__name__,
1453 int.__repr__(self),
1454 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001455 def __str__(self):
1456 # str() is unchanged, even if it relies on the repr() fallback
1457 base = int
1458 base_str = base.__str__
1459 if base_str.__objclass__ is object:
1460 return base.__repr__(self)
1461 return base_str(self)
1462 # for simplicity, we only define one operator that
1463 # propagates expressions
1464 def __add__(self, other):
1465 temp = int(self) + int( other)
1466 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1467 return NamedInt(
1468 '({0} + {1})'.format(self.__name__, other.__name__),
1469 temp )
1470 else:
1471 return temp
1472
1473 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001474 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001475 x = ('the-x', 1)
1476 y = ('the-y', 2)
1477
1478 self.assertIs(NEI.__new__, Enum.__new__)
1479 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1480 globals()['NamedInt'] = NamedInt
1481 globals()['NEI'] = NEI
1482 NI5 = NamedInt('test', 5)
1483 self.assertEqual(NI5, 5)
1484 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001485 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1486 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001487
Ethan Furmandc870522014-02-18 12:37:12 -08001488 def test_subclasses_without_direct_pickle_support_using_name(self):
1489 class NamedInt(int):
1490 __qualname__ = 'NamedInt'
1491 def __new__(cls, *args):
1492 _args = args
1493 name, *args = args
1494 if len(args) == 0:
1495 raise TypeError("name and value must be specified")
1496 self = int.__new__(cls, *args)
1497 self._intname = name
1498 self._args = _args
1499 return self
1500 @property
1501 def __name__(self):
1502 return self._intname
1503 def __repr__(self):
1504 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001505 return "{}({!r}, {})".format(
1506 type(self).__name__,
1507 self.__name__,
1508 int.__repr__(self),
1509 )
Ethan Furmandc870522014-02-18 12:37:12 -08001510 def __str__(self):
1511 # str() is unchanged, even if it relies on the repr() fallback
1512 base = int
1513 base_str = base.__str__
1514 if base_str.__objclass__ is object:
1515 return base.__repr__(self)
1516 return base_str(self)
1517 # for simplicity, we only define one operator that
1518 # propagates expressions
1519 def __add__(self, other):
1520 temp = int(self) + int( other)
1521 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1522 return NamedInt(
1523 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001524 temp,
1525 )
Ethan Furmandc870522014-02-18 12:37:12 -08001526 else:
1527 return temp
1528
1529 class NEI(NamedInt, Enum):
1530 __qualname__ = 'NEI'
1531 x = ('the-x', 1)
1532 y = ('the-y', 2)
1533 def __reduce_ex__(self, proto):
1534 return getattr, (self.__class__, self._name_)
1535
1536 self.assertIs(NEI.__new__, Enum.__new__)
1537 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1538 globals()['NamedInt'] = NamedInt
1539 globals()['NEI'] = NEI
1540 NI5 = NamedInt('test', 5)
1541 self.assertEqual(NI5, 5)
1542 self.assertEqual(NEI.y.value, 2)
1543 test_pickle_dump_load(self.assertIs, NEI.y)
1544 test_pickle_dump_load(self.assertIs, NEI)
1545
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001546 def test_tuple_subclass(self):
1547 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001548 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001549 first = (1, 'for the money')
1550 second = (2, 'for the show')
1551 third = (3, 'for the music')
1552 self.assertIs(type(SomeTuple.first), SomeTuple)
1553 self.assertIsInstance(SomeTuple.second, tuple)
1554 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1555 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001556 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557
1558 def test_duplicate_values_give_unique_enum_items(self):
1559 class AutoNumber(Enum):
1560 first = ()
1561 second = ()
1562 third = ()
1563 def __new__(cls):
1564 value = len(cls.__members__) + 1
1565 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001566 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001567 return obj
1568 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001569 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001570 self.assertEqual(
1571 list(AutoNumber),
1572 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1573 )
1574 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001575 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001576 self.assertIs(AutoNumber(1), AutoNumber.first)
1577
1578 def test_inherited_new_from_enhanced_enum(self):
1579 class AutoNumber(Enum):
1580 def __new__(cls):
1581 value = len(cls.__members__) + 1
1582 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001583 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001584 return obj
1585 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001586 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001587 class Color(AutoNumber):
1588 red = ()
1589 green = ()
1590 blue = ()
1591 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1592 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1593
1594 def test_inherited_new_from_mixed_enum(self):
1595 class AutoNumber(IntEnum):
1596 def __new__(cls):
1597 value = len(cls.__members__) + 1
1598 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001599 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001600 return obj
1601 class Color(AutoNumber):
1602 red = ()
1603 green = ()
1604 blue = ()
1605 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1606 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1607
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001608 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001609 class OrdinaryEnum(Enum):
1610 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001611 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1612 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001613
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 def test_ordered_mixin(self):
1615 class OrderedEnum(Enum):
1616 def __ge__(self, other):
1617 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001618 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001619 return NotImplemented
1620 def __gt__(self, other):
1621 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001622 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001623 return NotImplemented
1624 def __le__(self, other):
1625 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001626 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001627 return NotImplemented
1628 def __lt__(self, other):
1629 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001630 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001631 return NotImplemented
1632 class Grade(OrderedEnum):
1633 A = 5
1634 B = 4
1635 C = 3
1636 D = 2
1637 F = 1
1638 self.assertGreater(Grade.A, Grade.B)
1639 self.assertLessEqual(Grade.F, Grade.C)
1640 self.assertLess(Grade.D, Grade.A)
1641 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001642 self.assertEqual(Grade.B, Grade.B)
1643 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001644
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001645 def test_extending2(self):
1646 class Shade(Enum):
1647 def shade(self):
1648 print(self.name)
1649 class Color(Shade):
1650 red = 1
1651 green = 2
1652 blue = 3
1653 with self.assertRaises(TypeError):
1654 class MoreColor(Color):
1655 cyan = 4
1656 magenta = 5
1657 yellow = 6
1658
1659 def test_extending3(self):
1660 class Shade(Enum):
1661 def shade(self):
1662 return self.name
1663 class Color(Shade):
1664 def hex(self):
1665 return '%s hexlified!' % self.value
1666 class MoreColor(Color):
1667 cyan = 4
1668 magenta = 5
1669 yellow = 6
1670 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1671
orlnub1230fb9fad2018-09-12 20:28:53 +03001672 def test_subclass_duplicate_name(self):
1673 class Base(Enum):
1674 def test(self):
1675 pass
1676 class Test(Base):
1677 test = 1
1678 self.assertIs(type(Test.test), Test)
1679
1680 def test_subclass_duplicate_name_dynamic(self):
1681 from types import DynamicClassAttribute
1682 class Base(Enum):
1683 @DynamicClassAttribute
1684 def test(self):
1685 return 'dynamic'
1686 class Test(Base):
1687 test = 1
1688 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001689 class Base2(Enum):
1690 @enum.property
1691 def flash(self):
1692 return 'flashy dynamic'
1693 class Test(Base2):
1694 flash = 1
1695 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001696
1697 def test_no_duplicates(self):
1698 class UniqueEnum(Enum):
1699 def __init__(self, *args):
1700 cls = self.__class__
1701 if any(self.value == e.value for e in cls):
1702 a = self.name
1703 e = cls(self.value).name
1704 raise ValueError(
1705 "aliases not allowed in UniqueEnum: %r --> %r"
1706 % (a, e)
1707 )
1708 class Color(UniqueEnum):
1709 red = 1
1710 green = 2
1711 blue = 3
1712 with self.assertRaises(ValueError):
1713 class Color(UniqueEnum):
1714 red = 1
1715 green = 2
1716 blue = 3
1717 grene = 2
1718
1719 def test_init(self):
1720 class Planet(Enum):
1721 MERCURY = (3.303e+23, 2.4397e6)
1722 VENUS = (4.869e+24, 6.0518e6)
1723 EARTH = (5.976e+24, 6.37814e6)
1724 MARS = (6.421e+23, 3.3972e6)
1725 JUPITER = (1.9e+27, 7.1492e7)
1726 SATURN = (5.688e+26, 6.0268e7)
1727 URANUS = (8.686e+25, 2.5559e7)
1728 NEPTUNE = (1.024e+26, 2.4746e7)
1729 def __init__(self, mass, radius):
1730 self.mass = mass # in kilograms
1731 self.radius = radius # in meters
1732 @property
1733 def surface_gravity(self):
1734 # universal gravitational constant (m3 kg-1 s-2)
1735 G = 6.67300E-11
1736 return G * self.mass / (self.radius * self.radius)
1737 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1738 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1739
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001740 def test_ignore(self):
1741 class Period(timedelta, Enum):
1742 '''
1743 different lengths of time
1744 '''
1745 def __new__(cls, value, period):
1746 obj = timedelta.__new__(cls, value)
1747 obj._value_ = value
1748 obj.period = period
1749 return obj
1750 _ignore_ = 'Period i'
1751 Period = vars()
1752 for i in range(13):
1753 Period['month_%d' % i] = i*30, 'month'
1754 for i in range(53):
1755 Period['week_%d' % i] = i*7, 'week'
1756 for i in range(32):
1757 Period['day_%d' % i] = i, 'day'
1758 OneDay = day_1
1759 OneWeek = week_1
1760 OneMonth = month_1
1761 self.assertFalse(hasattr(Period, '_ignore_'))
1762 self.assertFalse(hasattr(Period, 'Period'))
1763 self.assertFalse(hasattr(Period, 'i'))
1764 self.assertTrue(isinstance(Period.day_1, timedelta))
1765 self.assertTrue(Period.month_1 is Period.day_30)
1766 self.assertTrue(Period.week_4 is Period.day_28)
1767
Ethan Furman2aa27322013-07-19 19:35:56 -07001768 def test_nonhash_value(self):
1769 class AutoNumberInAList(Enum):
1770 def __new__(cls):
1771 value = [len(cls.__members__) + 1]
1772 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001773 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001774 return obj
1775 class ColorInAList(AutoNumberInAList):
1776 red = ()
1777 green = ()
1778 blue = ()
1779 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001780 for enum, value in zip(ColorInAList, range(3)):
1781 value += 1
1782 self.assertEqual(enum.value, [value])
1783 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001784
Ethan Furmanb41803e2013-07-25 13:50:45 -07001785 def test_conflicting_types_resolved_in_new(self):
1786 class LabelledIntEnum(int, Enum):
1787 def __new__(cls, *args):
1788 value, label = args
1789 obj = int.__new__(cls, value)
1790 obj.label = label
1791 obj._value_ = value
1792 return obj
1793
1794 class LabelledList(LabelledIntEnum):
1795 unprocessed = (1, "Unprocessed")
1796 payment_complete = (2, "Payment Complete")
1797
1798 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1799 self.assertEqual(LabelledList.unprocessed, 1)
1800 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001801
Ethan Furmanc16595e2016-09-10 23:36:59 -07001802 def test_auto_number(self):
1803 class Color(Enum):
1804 red = auto()
1805 blue = auto()
1806 green = auto()
1807
1808 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1809 self.assertEqual(Color.red.value, 1)
1810 self.assertEqual(Color.blue.value, 2)
1811 self.assertEqual(Color.green.value, 3)
1812
1813 def test_auto_name(self):
1814 class Color(Enum):
1815 def _generate_next_value_(name, start, count, last):
1816 return name
1817 red = auto()
1818 blue = auto()
1819 green = auto()
1820
1821 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1822 self.assertEqual(Color.red.value, 'red')
1823 self.assertEqual(Color.blue.value, 'blue')
1824 self.assertEqual(Color.green.value, 'green')
1825
1826 def test_auto_name_inherit(self):
1827 class AutoNameEnum(Enum):
1828 def _generate_next_value_(name, start, count, last):
1829 return name
1830 class Color(AutoNameEnum):
1831 red = auto()
1832 blue = auto()
1833 green = auto()
1834
1835 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1836 self.assertEqual(Color.red.value, 'red')
1837 self.assertEqual(Color.blue.value, 'blue')
1838 self.assertEqual(Color.green.value, 'green')
1839
1840 def test_auto_garbage(self):
1841 class Color(Enum):
1842 red = 'red'
1843 blue = auto()
1844 self.assertEqual(Color.blue.value, 1)
1845
1846 def test_auto_garbage_corrected(self):
1847 class Color(Enum):
1848 red = 'red'
1849 blue = 2
1850 green = auto()
1851
1852 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1853 self.assertEqual(Color.red.value, 'red')
1854 self.assertEqual(Color.blue.value, 2)
1855 self.assertEqual(Color.green.value, 3)
1856
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001857 def test_auto_order(self):
1858 with self.assertRaises(TypeError):
1859 class Color(Enum):
1860 red = auto()
1861 green = auto()
1862 blue = auto()
1863 def _generate_next_value_(name, start, count, last):
1864 return name
1865
Ethan Furmanfc23a942020-09-16 12:37:54 -07001866 def test_auto_order_wierd(self):
1867 weird_auto = auto()
1868 weird_auto.value = 'pathological case'
1869 class Color(Enum):
1870 red = weird_auto
1871 def _generate_next_value_(name, start, count, last):
1872 return name
1873 blue = auto()
1874 self.assertEqual(list(Color), [Color.red, Color.blue])
1875 self.assertEqual(Color.red.value, 'pathological case')
1876 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001877
Ethan Furman3515dcc2016-09-18 13:15:41 -07001878 def test_duplicate_auto(self):
1879 class Dupes(Enum):
1880 first = primero = auto()
1881 second = auto()
1882 third = auto()
1883 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1884
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001885 def test_default_missing(self):
1886 class Color(Enum):
1887 RED = 1
1888 GREEN = 2
1889 BLUE = 3
1890 try:
1891 Color(7)
1892 except ValueError as exc:
1893 self.assertTrue(exc.__context__ is None)
1894 else:
1895 raise Exception('Exception not raised.')
1896
Ethan Furman019f0a02018-09-12 11:43:34 -07001897 def test_missing(self):
1898 class Color(Enum):
1899 red = 1
1900 green = 2
1901 blue = 3
1902 @classmethod
1903 def _missing_(cls, item):
1904 if item == 'three':
1905 return cls.blue
1906 elif item == 'bad return':
1907 # trigger internal error
1908 return 5
1909 elif item == 'error out':
1910 raise ZeroDivisionError
1911 else:
1912 # trigger not found
1913 return None
1914 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001915 try:
1916 Color(7)
1917 except ValueError as exc:
1918 self.assertTrue(exc.__context__ is None)
1919 else:
1920 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001921 try:
1922 Color('bad return')
1923 except TypeError as exc:
1924 self.assertTrue(isinstance(exc.__context__, ValueError))
1925 else:
1926 raise Exception('Exception not raised.')
1927 try:
1928 Color('error out')
1929 except ZeroDivisionError as exc:
1930 self.assertTrue(isinstance(exc.__context__, ValueError))
1931 else:
1932 raise Exception('Exception not raised.')
1933
Ethan Furman5bdab642018-09-21 19:03:09 -07001934 def test_multiple_mixin(self):
1935 class MaxMixin:
1936 @classproperty
1937 def MAX(cls):
1938 max = len(cls)
1939 cls.MAX = max
1940 return max
1941 class StrMixin:
1942 def __str__(self):
1943 return self._name_.lower()
1944 class SomeEnum(Enum):
1945 def behavior(self):
1946 return 'booyah'
1947 class AnotherEnum(Enum):
1948 def behavior(self):
1949 return 'nuhuh!'
1950 def social(self):
1951 return "what's up?"
1952 class Color(MaxMixin, Enum):
1953 RED = auto()
1954 GREEN = auto()
1955 BLUE = auto()
1956 self.assertEqual(Color.RED.value, 1)
1957 self.assertEqual(Color.GREEN.value, 2)
1958 self.assertEqual(Color.BLUE.value, 3)
1959 self.assertEqual(Color.MAX, 3)
1960 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1961 class Color(MaxMixin, StrMixin, Enum):
1962 RED = auto()
1963 GREEN = auto()
1964 BLUE = auto()
1965 self.assertEqual(Color.RED.value, 1)
1966 self.assertEqual(Color.GREEN.value, 2)
1967 self.assertEqual(Color.BLUE.value, 3)
1968 self.assertEqual(Color.MAX, 3)
1969 self.assertEqual(str(Color.BLUE), 'blue')
1970 class Color(StrMixin, MaxMixin, Enum):
1971 RED = auto()
1972 GREEN = auto()
1973 BLUE = auto()
1974 self.assertEqual(Color.RED.value, 1)
1975 self.assertEqual(Color.GREEN.value, 2)
1976 self.assertEqual(Color.BLUE.value, 3)
1977 self.assertEqual(Color.MAX, 3)
1978 self.assertEqual(str(Color.BLUE), 'blue')
1979 class CoolColor(StrMixin, SomeEnum, Enum):
1980 RED = auto()
1981 GREEN = auto()
1982 BLUE = auto()
1983 self.assertEqual(CoolColor.RED.value, 1)
1984 self.assertEqual(CoolColor.GREEN.value, 2)
1985 self.assertEqual(CoolColor.BLUE.value, 3)
1986 self.assertEqual(str(CoolColor.BLUE), 'blue')
1987 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1988 class CoolerColor(StrMixin, AnotherEnum, Enum):
1989 RED = auto()
1990 GREEN = auto()
1991 BLUE = auto()
1992 self.assertEqual(CoolerColor.RED.value, 1)
1993 self.assertEqual(CoolerColor.GREEN.value, 2)
1994 self.assertEqual(CoolerColor.BLUE.value, 3)
1995 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1996 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1997 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1998 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1999 RED = auto()
2000 GREEN = auto()
2001 BLUE = auto()
2002 self.assertEqual(CoolestColor.RED.value, 1)
2003 self.assertEqual(CoolestColor.GREEN.value, 2)
2004 self.assertEqual(CoolestColor.BLUE.value, 3)
2005 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2006 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2007 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2008 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2009 RED = auto()
2010 GREEN = auto()
2011 BLUE = auto()
2012 self.assertEqual(ConfusedColor.RED.value, 1)
2013 self.assertEqual(ConfusedColor.GREEN.value, 2)
2014 self.assertEqual(ConfusedColor.BLUE.value, 3)
2015 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2016 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2017 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2018 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2019 RED = auto()
2020 GREEN = auto()
2021 BLUE = auto()
2022 self.assertEqual(ReformedColor.RED.value, 1)
2023 self.assertEqual(ReformedColor.GREEN.value, 2)
2024 self.assertEqual(ReformedColor.BLUE.value, 3)
2025 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2026 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2027 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2028 self.assertTrue(issubclass(ReformedColor, int))
2029
Ethan Furmancd453852018-10-05 23:29:36 -07002030 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002031 @unique
2032 class Decision1(StrEnum):
2033 REVERT = "REVERT"
2034 REVERT_ALL = "REVERT_ALL"
2035 RETRY = "RETRY"
2036 class MyEnum(StrEnum):
2037 pass
2038 @unique
2039 class Decision2(MyEnum):
2040 REVERT = "REVERT"
2041 REVERT_ALL = "REVERT_ALL"
2042 RETRY = "RETRY"
2043
Ethan Furmanc2667362020-12-07 00:17:31 -08002044 def test_multiple_mixin_inherited(self):
2045 class MyInt(int):
2046 def __new__(cls, value):
2047 return super().__new__(cls, value)
2048
2049 class HexMixin:
2050 def __repr__(self):
2051 return hex(self)
2052
2053 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2054 pass
2055
2056 class Foo(MyIntEnum):
2057 TEST = 1
2058 self.assertTrue(isinstance(Foo.TEST, MyInt))
2059 self.assertEqual(repr(Foo.TEST), "0x1")
2060
2061 class Fee(MyIntEnum):
2062 TEST = 1
2063 def __new__(cls, value):
2064 value += 1
2065 member = int.__new__(cls, value)
2066 member._value_ = value
2067 return member
2068 self.assertEqual(Fee.TEST, 2)
2069
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002070 def test_empty_globals(self):
2071 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2072 # when using compile and exec because f_globals is empty
2073 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2074 code = compile(code, "<string>", "exec")
2075 global_ns = {}
2076 local_ls = {}
2077 exec(code, global_ns, local_ls)
2078
Ethan Furman0063ff42020-09-21 17:23:13 -07002079 def test_strenum(self):
2080 class GoodStrEnum(StrEnum):
2081 one = '1'
2082 two = '2'
2083 three = b'3', 'ascii'
2084 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002085 self.assertEqual(GoodStrEnum.one, '1')
2086 self.assertEqual(str(GoodStrEnum.one), '1')
2087 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2088 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2089 #
2090 class DumbMixin:
2091 def __str__(self):
2092 return "don't do this"
2093 class DumbStrEnum(DumbMixin, StrEnum):
2094 five = '5'
2095 six = '6'
2096 seven = '7'
2097 self.assertEqual(DumbStrEnum.seven, '7')
2098 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2099 #
2100 class EnumMixin(Enum):
2101 def hello(self):
2102 print('hello from %s' % (self, ))
2103 class HelloEnum(EnumMixin, StrEnum):
2104 eight = '8'
2105 self.assertEqual(HelloEnum.eight, '8')
2106 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2107 #
2108 class GoodbyeMixin:
2109 def goodbye(self):
2110 print('%s wishes you a fond farewell')
2111 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2112 nine = '9'
2113 self.assertEqual(GoodbyeEnum.nine, '9')
2114 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2115 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002116 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2117 class FirstFailedStrEnum(StrEnum):
2118 one = 1
2119 two = '2'
2120 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2121 class SecondFailedStrEnum(StrEnum):
2122 one = '1'
2123 two = 2,
2124 three = '3'
2125 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2126 class ThirdFailedStrEnum(StrEnum):
2127 one = '1'
2128 two = 2
2129 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2130 class ThirdFailedStrEnum(StrEnum):
2131 one = '1'
2132 two = b'2', sys.getdefaultencoding
2133 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2134 class ThirdFailedStrEnum(StrEnum):
2135 one = '1'
2136 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002137
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002138 def test_missing_value_error(self):
2139 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2140 class Combined(str, Enum):
2141 #
2142 def __new__(cls, value, sequence):
2143 enum = str.__new__(cls, value)
2144 if '(' in value:
2145 fis_name, segment = value.split('(', 1)
2146 segment = segment.strip(' )')
2147 else:
2148 fis_name = value
2149 segment = None
2150 enum.fis_name = fis_name
2151 enum.segment = segment
2152 enum.sequence = sequence
2153 return enum
2154 #
2155 def __repr__(self):
2156 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2157 #
2158 key_type = 'An$(1,2)', 0
2159 company_id = 'An$(3,2)', 1
2160 code = 'An$(5,1)', 2
2161 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002162
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002163 @unittest.skipUnless(
2164 sys.version_info[:2] == (3, 9),
2165 'private variables are now normal attributes',
2166 )
2167 def test_warning_for_private_variables(self):
2168 with self.assertWarns(DeprecationWarning):
2169 class Private(Enum):
2170 __corporal = 'Radar'
2171 self.assertEqual(Private._Private__corporal.value, 'Radar')
2172 try:
2173 with self.assertWarns(DeprecationWarning):
2174 class Private(Enum):
2175 __major_ = 'Hoolihan'
2176 except ValueError:
2177 pass
2178
2179 def test_private_variable_is_normal_attribute(self):
2180 class Private(Enum):
2181 __corporal = 'Radar'
2182 __major_ = 'Hoolihan'
2183 self.assertEqual(Private._Private__corporal, 'Radar')
2184 self.assertEqual(Private._Private__major_, 'Hoolihan')
2185
Ethan Furmanefb13be2020-12-10 12:20:06 -08002186 def test_strenum_auto(self):
2187 class Strings(StrEnum):
2188 ONE = auto()
2189 TWO = auto()
2190 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2191
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002192
Ethan Furmana6582872020-12-10 13:07:00 -08002193 def test_dynamic_members_with_static_methods(self):
2194 #
2195 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2196 class Foo(Enum):
2197 vars().update({
2198 k: v
2199 for k, v in foo_defines.items()
2200 if k.startswith('FOO_')
2201 })
2202 def upper(self):
2203 return self.value.upper()
2204 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2205 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2206 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2207 #
2208 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2209 class FooBar(Enum):
2210 vars().update({
2211 k: v
2212 for k, v in foo_defines.items()
2213 if k.startswith('FOO_')
2214 },
2215 **{'FOO_CAT': 'small'},
2216 )
2217 def upper(self):
2218 return self.value.upper()
2219
2220
Ethan Furmane8e61272016-08-20 07:19:31 -07002221class TestOrder(unittest.TestCase):
2222
2223 def test_same_members(self):
2224 class Color(Enum):
2225 _order_ = 'red green blue'
2226 red = 1
2227 green = 2
2228 blue = 3
2229
2230 def test_same_members_with_aliases(self):
2231 class Color(Enum):
2232 _order_ = 'red green blue'
2233 red = 1
2234 green = 2
2235 blue = 3
2236 verde = green
2237
2238 def test_same_members_wrong_order(self):
2239 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2240 class Color(Enum):
2241 _order_ = 'red green blue'
2242 red = 1
2243 blue = 3
2244 green = 2
2245
2246 def test_order_has_extra_members(self):
2247 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2248 class Color(Enum):
2249 _order_ = 'red green blue purple'
2250 red = 1
2251 green = 2
2252 blue = 3
2253
2254 def test_order_has_extra_members_with_aliases(self):
2255 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2256 class Color(Enum):
2257 _order_ = 'red green blue purple'
2258 red = 1
2259 green = 2
2260 blue = 3
2261 verde = green
2262
2263 def test_enum_has_extra_members(self):
2264 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2265 class Color(Enum):
2266 _order_ = 'red green blue'
2267 red = 1
2268 green = 2
2269 blue = 3
2270 purple = 4
2271
2272 def test_enum_has_extra_members_with_aliases(self):
2273 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2274 class Color(Enum):
2275 _order_ = 'red green blue'
2276 red = 1
2277 green = 2
2278 blue = 3
2279 purple = 4
2280 verde = green
2281
2282
Ethan Furman65a5a472016-09-01 23:55:19 -07002283class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002284 """Tests of the Flags."""
2285
Ethan Furman65a5a472016-09-01 23:55:19 -07002286 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002287 R, W, X = 4, 2, 1
2288
Ethan Furman65a5a472016-09-01 23:55:19 -07002289 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002290 RO = 0
2291 WO = 1
2292 RW = 2
2293 AC = 3
2294 CE = 1<<19
2295
Rahul Jha94306522018-09-10 23:51:04 +05302296 class Color(Flag):
2297 BLACK = 0
2298 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002299 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302300 GREEN = 2
2301 BLUE = 4
2302 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002303 WHITE = RED|GREEN|BLUE
2304 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302305
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002306 def test_str(self):
2307 Perm = self.Perm
2308 self.assertEqual(str(Perm.R), 'Perm.R')
2309 self.assertEqual(str(Perm.W), 'Perm.W')
2310 self.assertEqual(str(Perm.X), 'Perm.X')
2311 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2312 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002313 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002314 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2315 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2316 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2317 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002318 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002319 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2320
2321 Open = self.Open
2322 self.assertEqual(str(Open.RO), 'Open.RO')
2323 self.assertEqual(str(Open.WO), 'Open.WO')
2324 self.assertEqual(str(Open.AC), 'Open.AC')
2325 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002326 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2327 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2328 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002329 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002330 self.assertEqual(str(~Open.CE), 'Open.AC')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002331 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2332 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2333
2334 def test_repr(self):
2335 Perm = self.Perm
2336 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2337 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2338 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2339 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2340 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002341 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002342 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2343 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2344 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2345 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002346 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002347 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2348
2349 Open = self.Open
2350 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2351 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2352 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2353 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002354 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2355 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2356 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002357 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002358 self.assertEqual(repr(~Open.CE), '<Open.AC: 3>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002359 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2360 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2361
Ethan Furman37440ee2020-12-08 11:14:10 -08002362 def test_format(self):
2363 Perm = self.Perm
2364 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2365 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2366
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002367 def test_or(self):
2368 Perm = self.Perm
2369 for i in Perm:
2370 for j in Perm:
2371 self.assertEqual((i | j), Perm(i.value | j.value))
2372 self.assertEqual((i | j).value, i.value | j.value)
2373 self.assertIs(type(i | j), Perm)
2374 for i in Perm:
2375 self.assertIs(i | i, i)
2376 Open = self.Open
2377 self.assertIs(Open.RO | Open.CE, Open.CE)
2378
2379 def test_and(self):
2380 Perm = self.Perm
2381 RW = Perm.R | Perm.W
2382 RX = Perm.R | Perm.X
2383 WX = Perm.W | Perm.X
2384 RWX = Perm.R | Perm.W | Perm.X
2385 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2386 for i in values:
2387 for j in values:
2388 self.assertEqual((i & j).value, i.value & j.value)
2389 self.assertIs(type(i & j), Perm)
2390 for i in Perm:
2391 self.assertIs(i & i, i)
2392 self.assertIs(i & RWX, i)
2393 self.assertIs(RWX & i, i)
2394 Open = self.Open
2395 self.assertIs(Open.RO & Open.CE, Open.RO)
2396
2397 def test_xor(self):
2398 Perm = self.Perm
2399 for i in Perm:
2400 for j in Perm:
2401 self.assertEqual((i ^ j).value, i.value ^ j.value)
2402 self.assertIs(type(i ^ j), Perm)
2403 for i in Perm:
2404 self.assertIs(i ^ Perm(0), i)
2405 self.assertIs(Perm(0) ^ i, i)
2406 Open = self.Open
2407 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2408 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2409
2410 def test_invert(self):
2411 Perm = self.Perm
2412 RW = Perm.R | Perm.W
2413 RX = Perm.R | Perm.X
2414 WX = Perm.W | Perm.X
2415 RWX = Perm.R | Perm.W | Perm.X
2416 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2417 for i in values:
2418 self.assertIs(type(~i), Perm)
2419 self.assertEqual(~~i, i)
2420 for i in Perm:
2421 self.assertIs(~~i, i)
2422 Open = self.Open
2423 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2424 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2425
Ethan Furman25d94bb2016-09-02 16:32:32 -07002426 def test_bool(self):
2427 Perm = self.Perm
2428 for f in Perm:
2429 self.assertTrue(f)
2430 Open = self.Open
2431 for f in Open:
2432 self.assertEqual(bool(f.value), bool(f))
2433
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002434 def test_boundary(self):
2435 self.assertIs(enum.Flag._boundary_, STRICT)
2436 class Iron(Flag, boundary=STRICT):
2437 ONE = 1
2438 TWO = 2
2439 EIGHT = 8
2440 self.assertIs(Iron._boundary_, STRICT)
2441 #
2442 class Water(Flag, boundary=CONFORM):
2443 ONE = 1
2444 TWO = 2
2445 EIGHT = 8
2446 self.assertIs(Water._boundary_, CONFORM)
2447 #
2448 class Space(Flag, boundary=EJECT):
2449 ONE = 1
2450 TWO = 2
2451 EIGHT = 8
2452 self.assertIs(Space._boundary_, EJECT)
2453 #
2454 class Bizarre(Flag, boundary=KEEP):
2455 b = 3
2456 c = 4
2457 d = 6
2458 #
2459 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
2460 self.assertIs(Water(7), Water.ONE|Water.TWO)
2461 self.assertIs(Water(~9), Water.TWO)
2462 self.assertEqual(Space(7), 7)
2463 self.assertTrue(type(Space(7)) is int)
2464 self.assertEqual(list(Bizarre), [Bizarre.c])
2465 self.assertIs(Bizarre(3), Bizarre.b)
2466 self.assertIs(Bizarre(6), Bizarre.d)
2467
2468 def test_iter(self):
2469 Color = self.Color
2470 Open = self.Open
2471 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2472 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2473
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002474 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002475 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002476 lst = list(Perm)
2477 self.assertEqual(len(lst), len(Perm))
2478 self.assertEqual(len(Perm), 3, Perm)
2479 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2480 for i, n in enumerate('R W X'.split()):
2481 v = 1<<i
2482 e = Perm(v)
2483 self.assertEqual(e.value, v)
2484 self.assertEqual(type(e.value), int)
2485 self.assertEqual(e.name, n)
2486 self.assertIn(e, Perm)
2487 self.assertIs(type(e), Perm)
2488
2489 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002490 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002491 lst = list(Perm)
2492 self.assertEqual(len(lst), len(Perm))
2493 self.assertEqual(len(Perm), 3, Perm)
2494 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2495 for i, n in enumerate('R W X'.split()):
2496 v = 8<<i
2497 e = Perm(v)
2498 self.assertEqual(e.value, v)
2499 self.assertEqual(type(e.value), int)
2500 self.assertEqual(e.name, n)
2501 self.assertIn(e, Perm)
2502 self.assertIs(type(e), Perm)
2503
2504 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002505 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002506 lst = list(Perm)
2507 self.assertEqual(len(lst), len(Perm))
2508 self.assertEqual(len(Perm), 3, Perm)
2509 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2510 for i, n in enumerate('R W X'.split()):
2511 v = 1<<i
2512 e = Perm(v)
2513 self.assertEqual(e.value, v)
2514 self.assertEqual(type(e.value), int)
2515 self.assertEqual(e.name, n)
2516 self.assertIn(e, Perm)
2517 self.assertIs(type(e), Perm)
2518
2519 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002520 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002521 lst = list(Perm)
2522 self.assertEqual(len(lst), len(Perm))
2523 self.assertEqual(len(Perm), 3, Perm)
2524 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2525 for i, n in enumerate('R W X'.split()):
2526 v = 1<<(2*i+1)
2527 e = Perm(v)
2528 self.assertEqual(e.value, v)
2529 self.assertEqual(type(e.value), int)
2530 self.assertEqual(e.name, n)
2531 self.assertIn(e, Perm)
2532 self.assertIs(type(e), Perm)
2533
2534 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002535 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002536 lst = list(Perm)
2537 self.assertEqual(len(lst), len(Perm))
2538 self.assertEqual(len(Perm), 3, Perm)
2539 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2540 for i, n in enumerate('R W X'.split()):
2541 v = 1<<(2*i+1)
2542 e = Perm(v)
2543 self.assertEqual(e.value, v)
2544 self.assertEqual(type(e.value), int)
2545 self.assertEqual(e.name, n)
2546 self.assertIn(e, Perm)
2547 self.assertIs(type(e), Perm)
2548
Ethan Furman65a5a472016-09-01 23:55:19 -07002549 def test_pickle(self):
2550 if isinstance(FlagStooges, Exception):
2551 raise FlagStooges
2552 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2553 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002554
Rahul Jha94306522018-09-10 23:51:04 +05302555 def test_contains(self):
2556 Open = self.Open
2557 Color = self.Color
2558 self.assertFalse(Color.BLACK in Open)
2559 self.assertFalse(Open.RO in Color)
2560 with self.assertRaises(TypeError):
2561 'BLACK' in Color
2562 with self.assertRaises(TypeError):
2563 'RO' in Open
2564 with self.assertRaises(TypeError):
2565 1 in Color
2566 with self.assertRaises(TypeError):
2567 1 in Open
2568
2569 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002570 Perm = self.Perm
2571 R, W, X = Perm
2572 RW = R | W
2573 RX = R | X
2574 WX = W | X
2575 RWX = R | W | X
2576 self.assertTrue(R in RW)
2577 self.assertTrue(R in RX)
2578 self.assertTrue(R in RWX)
2579 self.assertTrue(W in RW)
2580 self.assertTrue(W in WX)
2581 self.assertTrue(W in RWX)
2582 self.assertTrue(X in RX)
2583 self.assertTrue(X in WX)
2584 self.assertTrue(X in RWX)
2585 self.assertFalse(R in WX)
2586 self.assertFalse(W in RX)
2587 self.assertFalse(X in RW)
2588
Ethan Furman7219e272020-09-16 13:01:00 -07002589 def test_member_iter(self):
2590 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002591 self.assertEqual(list(Color.BLACK), [])
2592 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002593 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2594 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002595 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2596 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2597
2598 def test_member_length(self):
2599 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2600 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2601 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2602 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2603
2604 def test_number_reset_and_order_cleanup(self):
2605 class Confused(Flag):
2606 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2607 ONE = auto()
2608 TWO = auto()
2609 FOUR = auto()
2610 DOS = 2
2611 EIGHT = auto()
2612 SIXTEEN = auto()
2613 self.assertEqual(
2614 list(Confused),
2615 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2616 self.assertIs(Confused.TWO, Confused.DOS)
2617 self.assertEqual(Confused.DOS._value_, 2)
2618 self.assertEqual(Confused.EIGHT._value_, 8)
2619 self.assertEqual(Confused.SIXTEEN._value_, 16)
2620
2621 def test_aliases(self):
2622 Color = self.Color
2623 self.assertEqual(Color(1).name, 'RED')
2624 self.assertEqual(Color['ROJO'].name, 'RED')
2625 self.assertEqual(Color(7).name, 'WHITE')
2626 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2627 self.assertIs(Color.BLANCO, Color.WHITE)
2628 Open = self.Open
2629 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002630
Ethan Furmanc16595e2016-09-10 23:36:59 -07002631 def test_auto_number(self):
2632 class Color(Flag):
2633 red = auto()
2634 blue = auto()
2635 green = auto()
2636
2637 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2638 self.assertEqual(Color.red.value, 1)
2639 self.assertEqual(Color.blue.value, 2)
2640 self.assertEqual(Color.green.value, 4)
2641
2642 def test_auto_number_garbage(self):
2643 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2644 class Color(Flag):
2645 red = 'not an int'
2646 blue = auto()
2647
Ethan Furman3515dcc2016-09-18 13:15:41 -07002648 def test_duplicate_auto(self):
2649 class Dupes(Enum):
2650 first = primero = auto()
2651 second = auto()
2652 third = auto()
2653 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2654
2655 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002656 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2657 class Bizarre(Flag):
2658 b = 3
2659 c = 4
2660 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002661
Ethan Furman5bdab642018-09-21 19:03:09 -07002662 def test_multiple_mixin(self):
2663 class AllMixin:
2664 @classproperty
2665 def ALL(cls):
2666 members = list(cls)
2667 all_value = None
2668 if members:
2669 all_value = members[0]
2670 for member in members[1:]:
2671 all_value |= member
2672 cls.ALL = all_value
2673 return all_value
2674 class StrMixin:
2675 def __str__(self):
2676 return self._name_.lower()
2677 class Color(AllMixin, Flag):
2678 RED = auto()
2679 GREEN = auto()
2680 BLUE = auto()
2681 self.assertEqual(Color.RED.value, 1)
2682 self.assertEqual(Color.GREEN.value, 2)
2683 self.assertEqual(Color.BLUE.value, 4)
2684 self.assertEqual(Color.ALL.value, 7)
2685 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2686 class Color(AllMixin, StrMixin, Flag):
2687 RED = auto()
2688 GREEN = auto()
2689 BLUE = auto()
2690 self.assertEqual(Color.RED.value, 1)
2691 self.assertEqual(Color.GREEN.value, 2)
2692 self.assertEqual(Color.BLUE.value, 4)
2693 self.assertEqual(Color.ALL.value, 7)
2694 self.assertEqual(str(Color.BLUE), 'blue')
2695 class Color(StrMixin, AllMixin, Flag):
2696 RED = auto()
2697 GREEN = auto()
2698 BLUE = auto()
2699 self.assertEqual(Color.RED.value, 1)
2700 self.assertEqual(Color.GREEN.value, 2)
2701 self.assertEqual(Color.BLUE.value, 4)
2702 self.assertEqual(Color.ALL.value, 7)
2703 self.assertEqual(str(Color.BLUE), 'blue')
2704
Hai Shie80697d2020-05-28 06:10:27 +08002705 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002706 def test_unique_composite(self):
2707 # override __eq__ to be identity only
2708 class TestFlag(Flag):
2709 one = auto()
2710 two = auto()
2711 three = auto()
2712 four = auto()
2713 five = auto()
2714 six = auto()
2715 seven = auto()
2716 eight = auto()
2717 def __eq__(self, other):
2718 return self is other
2719 def __hash__(self):
2720 return hash(self._value_)
2721 # have multiple threads competing to complete the composite members
2722 seen = set()
2723 failed = False
2724 def cycle_enum():
2725 nonlocal failed
2726 try:
2727 for i in range(256):
2728 seen.add(TestFlag(i))
2729 except Exception:
2730 failed = True
2731 threads = [
2732 threading.Thread(target=cycle_enum)
2733 for _ in range(8)
2734 ]
Hai Shie80697d2020-05-28 06:10:27 +08002735 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002736 pass
2737 # check that only 248 members were created
2738 self.assertFalse(
2739 failed,
2740 'at least one thread failed while creating composite members')
2741 self.assertEqual(256, len(seen), 'too many composite members created')
2742
Ethan Furman6bd94de2020-12-09 16:41:22 -08002743 def test_init_subclass(self):
2744 class MyEnum(Flag):
2745 def __init_subclass__(cls, **kwds):
2746 super().__init_subclass__(**kwds)
2747 self.assertFalse(cls.__dict__.get('_test', False))
2748 cls._test1 = 'MyEnum'
2749 #
2750 class TheirEnum(MyEnum):
2751 def __init_subclass__(cls, **kwds):
2752 super(TheirEnum, cls).__init_subclass__(**kwds)
2753 cls._test2 = 'TheirEnum'
2754 class WhoseEnum(TheirEnum):
2755 def __init_subclass__(cls, **kwds):
2756 pass
2757 class NoEnum(WhoseEnum):
2758 ONE = 1
2759 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2760 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2761 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2762 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2763 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2764 #
2765 class OurEnum(MyEnum):
2766 def __init_subclass__(cls, **kwds):
2767 cls._test2 = 'OurEnum'
2768 class WhereEnum(OurEnum):
2769 def __init_subclass__(cls, **kwds):
2770 pass
2771 class NeverEnum(WhereEnum):
2772 ONE = 1
2773 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2774 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2775 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2776 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2777 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2778
Ethan Furmanc16595e2016-09-10 23:36:59 -07002779
Ethan Furman65a5a472016-09-01 23:55:19 -07002780class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002781 """Tests of the IntFlags."""
2782
Ethan Furman65a5a472016-09-01 23:55:19 -07002783 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002784 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002785 W = 1 << 1
2786 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002787
Ethan Furman65a5a472016-09-01 23:55:19 -07002788 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002789 RO = 0
2790 WO = 1
2791 RW = 2
2792 AC = 3
2793 CE = 1<<19
2794
Rahul Jha94306522018-09-10 23:51:04 +05302795 class Color(IntFlag):
2796 BLACK = 0
2797 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002798 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302799 GREEN = 2
2800 BLUE = 4
2801 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002802 WHITE = RED|GREEN|BLUE
2803 BLANCO = RED|GREEN|BLUE
2804
2805 class Skip(IntFlag):
2806 FIRST = 1
2807 SECOND = 2
2808 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302809
Ethan Furman3515dcc2016-09-18 13:15:41 -07002810 def test_type(self):
2811 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002812 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002813 Open = self.Open
2814 for f in Perm:
2815 self.assertTrue(isinstance(f, Perm))
2816 self.assertEqual(f, f.value)
2817 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2818 self.assertEqual(Perm.W | Perm.X, 3)
2819 for f in Open:
2820 self.assertTrue(isinstance(f, Open))
2821 self.assertEqual(f, f.value)
2822 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2823 self.assertEqual(Open.WO | Open.RW, 3)
2824
2825
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002826 def test_str(self):
2827 Perm = self.Perm
2828 self.assertEqual(str(Perm.R), 'Perm.R')
2829 self.assertEqual(str(Perm.W), 'Perm.W')
2830 self.assertEqual(str(Perm.X), 'Perm.X')
2831 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2832 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002833 self.assertEqual(str(Perm.R | 8), '12')
2834 self.assertEqual(str(Perm(0)), 'Perm(0)')
2835 self.assertEqual(str(Perm(8)), '8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002836 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2837 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2838 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2839 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002840 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2841 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002842 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002843 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002844
2845 Open = self.Open
2846 self.assertEqual(str(Open.RO), 'Open.RO')
2847 self.assertEqual(str(Open.WO), 'Open.WO')
2848 self.assertEqual(str(Open.AC), 'Open.AC')
2849 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002850 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2851 self.assertEqual(str(Open(4)), '4')
2852 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2853 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002854 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002855 self.assertEqual(str(~Open.CE), 'Open.AC')
2856 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002857 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002858 self.assertEqual(str(Open(~4)), '-5')
2859
2860 Skip = self.Skip
2861 self.assertEqual(str(Skip(~4)), 'Skip.FIRST|SECOND|EIGHTH')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002862
2863 def test_repr(self):
2864 Perm = self.Perm
2865 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2866 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2867 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2868 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2869 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002870 self.assertEqual(repr(Perm.R | 8), '12')
2871 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
2872 self.assertEqual(repr(Perm(8)), '8')
2873 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2874 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2875 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2876 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2877 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
2878 self.assertEqual(repr(~(Perm.R | 8)), '-13')
2879 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2880 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002881
2882 Open = self.Open
2883 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2884 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2885 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2886 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002887 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2888 self.assertEqual(repr(Open(4)), '4')
2889 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2890 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
2891 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2892 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2893 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2894 self.assertEqual(repr(Open(~4)), '-5')
2895
2896 Skip = self.Skip
2897 self.assertEqual(repr(Skip(~4)), '<Skip.FIRST|SECOND|EIGHTH: 11>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002898
Ethan Furman37440ee2020-12-08 11:14:10 -08002899 def test_format(self):
2900 Perm = self.Perm
2901 self.assertEqual(format(Perm.R, ''), '4')
2902 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2903
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002904 def test_or(self):
2905 Perm = self.Perm
2906 for i in Perm:
2907 for j in Perm:
2908 self.assertEqual(i | j, i.value | j.value)
2909 self.assertEqual((i | j).value, i.value | j.value)
2910 self.assertIs(type(i | j), Perm)
2911 for j in range(8):
2912 self.assertEqual(i | j, i.value | j)
2913 self.assertEqual((i | j).value, i.value | j)
2914 self.assertIs(type(i | j), Perm)
2915 self.assertEqual(j | i, j | i.value)
2916 self.assertEqual((j | i).value, j | i.value)
2917 self.assertIs(type(j | i), Perm)
2918 for i in Perm:
2919 self.assertIs(i | i, i)
2920 self.assertIs(i | 0, i)
2921 self.assertIs(0 | i, i)
2922 Open = self.Open
2923 self.assertIs(Open.RO | Open.CE, Open.CE)
2924
2925 def test_and(self):
2926 Perm = self.Perm
2927 RW = Perm.R | Perm.W
2928 RX = Perm.R | Perm.X
2929 WX = Perm.W | Perm.X
2930 RWX = Perm.R | Perm.W | Perm.X
2931 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2932 for i in values:
2933 for j in values:
2934 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2935 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2936 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2937 for j in range(8):
2938 self.assertEqual(i & j, i.value & j)
2939 self.assertEqual((i & j).value, i.value & j)
2940 self.assertIs(type(i & j), Perm)
2941 self.assertEqual(j & i, j & i.value)
2942 self.assertEqual((j & i).value, j & i.value)
2943 self.assertIs(type(j & i), Perm)
2944 for i in Perm:
2945 self.assertIs(i & i, i)
2946 self.assertIs(i & 7, i)
2947 self.assertIs(7 & i, i)
2948 Open = self.Open
2949 self.assertIs(Open.RO & Open.CE, Open.RO)
2950
2951 def test_xor(self):
2952 Perm = self.Perm
2953 for i in Perm:
2954 for j in Perm:
2955 self.assertEqual(i ^ j, i.value ^ j.value)
2956 self.assertEqual((i ^ j).value, i.value ^ j.value)
2957 self.assertIs(type(i ^ j), Perm)
2958 for j in range(8):
2959 self.assertEqual(i ^ j, i.value ^ j)
2960 self.assertEqual((i ^ j).value, i.value ^ j)
2961 self.assertIs(type(i ^ j), Perm)
2962 self.assertEqual(j ^ i, j ^ i.value)
2963 self.assertEqual((j ^ i).value, j ^ i.value)
2964 self.assertIs(type(j ^ i), Perm)
2965 for i in Perm:
2966 self.assertIs(i ^ 0, i)
2967 self.assertIs(0 ^ i, i)
2968 Open = self.Open
2969 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2970 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2971
2972 def test_invert(self):
2973 Perm = self.Perm
2974 RW = Perm.R | Perm.W
2975 RX = Perm.R | Perm.X
2976 WX = Perm.W | Perm.X
2977 RWX = Perm.R | Perm.W | Perm.X
2978 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2979 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002980 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002981 self.assertIs(type(~i), Perm)
2982 self.assertEqual(~~i, i)
2983 for i in Perm:
2984 self.assertIs(~~i, i)
2985 Open = self.Open
2986 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2987 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2988
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002989 def test_boundary(self):
2990 self.assertIs(enum.IntFlag._boundary_, EJECT)
2991 class Iron(IntFlag, boundary=STRICT):
2992 ONE = 1
2993 TWO = 2
2994 EIGHT = 8
2995 self.assertIs(Iron._boundary_, STRICT)
2996 #
2997 class Water(IntFlag, boundary=CONFORM):
2998 ONE = 1
2999 TWO = 2
3000 EIGHT = 8
3001 self.assertIs(Water._boundary_, CONFORM)
3002 #
3003 class Space(IntFlag, boundary=EJECT):
3004 ONE = 1
3005 TWO = 2
3006 EIGHT = 8
3007 self.assertIs(Space._boundary_, EJECT)
3008 #
3009 class Bizarre(IntFlag, boundary=KEEP):
3010 b = 3
3011 c = 4
3012 d = 6
3013 #
3014 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
3015 self.assertIs(Water(7), Water.ONE|Water.TWO)
3016 self.assertIs(Water(~9), Water.TWO)
3017 self.assertEqual(Space(7), 7)
3018 self.assertTrue(type(Space(7)) is int)
3019 self.assertEqual(list(Bizarre), [Bizarre.c])
3020 self.assertIs(Bizarre(3), Bizarre.b)
3021 self.assertIs(Bizarre(6), Bizarre.d)
3022
3023 def test_iter(self):
3024 Color = self.Color
3025 Open = self.Open
3026 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3027 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3028
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003029 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003030 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003031 lst = list(Perm)
3032 self.assertEqual(len(lst), len(Perm))
3033 self.assertEqual(len(Perm), 3, Perm)
3034 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3035 for i, n in enumerate('R W X'.split()):
3036 v = 1<<i
3037 e = Perm(v)
3038 self.assertEqual(e.value, v)
3039 self.assertEqual(type(e.value), int)
3040 self.assertEqual(e, v)
3041 self.assertEqual(e.name, n)
3042 self.assertIn(e, Perm)
3043 self.assertIs(type(e), Perm)
3044
3045 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003046 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003047 lst = list(Perm)
3048 self.assertEqual(len(lst), len(Perm))
3049 self.assertEqual(len(Perm), 3, Perm)
3050 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3051 for i, n in enumerate('R W X'.split()):
3052 v = 8<<i
3053 e = Perm(v)
3054 self.assertEqual(e.value, v)
3055 self.assertEqual(type(e.value), int)
3056 self.assertEqual(e, v)
3057 self.assertEqual(e.name, n)
3058 self.assertIn(e, Perm)
3059 self.assertIs(type(e), Perm)
3060
3061 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003062 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003063 lst = list(Perm)
3064 self.assertEqual(len(lst), len(Perm))
3065 self.assertEqual(len(Perm), 3, Perm)
3066 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3067 for i, n in enumerate('R W X'.split()):
3068 v = 1<<i
3069 e = Perm(v)
3070 self.assertEqual(e.value, v)
3071 self.assertEqual(type(e.value), int)
3072 self.assertEqual(e, v)
3073 self.assertEqual(e.name, n)
3074 self.assertIn(e, Perm)
3075 self.assertIs(type(e), Perm)
3076
3077 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003078 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003079 lst = list(Perm)
3080 self.assertEqual(len(lst), len(Perm))
3081 self.assertEqual(len(Perm), 3, Perm)
3082 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3083 for i, n in enumerate('R W X'.split()):
3084 v = 1<<(2*i+1)
3085 e = Perm(v)
3086 self.assertEqual(e.value, v)
3087 self.assertEqual(type(e.value), int)
3088 self.assertEqual(e, v)
3089 self.assertEqual(e.name, n)
3090 self.assertIn(e, Perm)
3091 self.assertIs(type(e), Perm)
3092
3093 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003094 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003095 lst = list(Perm)
3096 self.assertEqual(len(lst), len(Perm))
3097 self.assertEqual(len(Perm), 3, Perm)
3098 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3099 for i, n in enumerate('R W X'.split()):
3100 v = 1<<(2*i+1)
3101 e = Perm(v)
3102 self.assertEqual(e.value, v)
3103 self.assertEqual(type(e.value), int)
3104 self.assertEqual(e, v)
3105 self.assertEqual(e.name, n)
3106 self.assertIn(e, Perm)
3107 self.assertIs(type(e), Perm)
3108
3109
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003110 def test_programatic_function_from_empty_list(self):
3111 Perm = enum.IntFlag('Perm', [])
3112 lst = list(Perm)
3113 self.assertEqual(len(lst), len(Perm))
3114 self.assertEqual(len(Perm), 0, Perm)
3115 Thing = enum.Enum('Thing', [])
3116 lst = list(Thing)
3117 self.assertEqual(len(lst), len(Thing))
3118 self.assertEqual(len(Thing), 0, Thing)
3119
3120
3121 def test_programatic_function_from_empty_tuple(self):
3122 Perm = enum.IntFlag('Perm', ())
3123 lst = list(Perm)
3124 self.assertEqual(len(lst), len(Perm))
3125 self.assertEqual(len(Perm), 0, Perm)
3126 Thing = enum.Enum('Thing', ())
3127 self.assertEqual(len(lst), len(Thing))
3128 self.assertEqual(len(Thing), 0, Thing)
3129
Rahul Jha94306522018-09-10 23:51:04 +05303130 def test_contains(self):
3131 Open = self.Open
3132 Color = self.Color
3133 self.assertTrue(Color.GREEN in Color)
3134 self.assertTrue(Open.RW in Open)
3135 self.assertFalse(Color.GREEN in Open)
3136 self.assertFalse(Open.RW in Color)
3137 with self.assertRaises(TypeError):
3138 'GREEN' in Color
3139 with self.assertRaises(TypeError):
3140 'RW' in Open
3141 with self.assertRaises(TypeError):
3142 2 in Color
3143 with self.assertRaises(TypeError):
3144 2 in Open
3145
3146 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003147 Perm = self.Perm
3148 R, W, X = Perm
3149 RW = R | W
3150 RX = R | X
3151 WX = W | X
3152 RWX = R | W | X
3153 self.assertTrue(R in RW)
3154 self.assertTrue(R in RX)
3155 self.assertTrue(R in RWX)
3156 self.assertTrue(W in RW)
3157 self.assertTrue(W in WX)
3158 self.assertTrue(W in RWX)
3159 self.assertTrue(X in RX)
3160 self.assertTrue(X in WX)
3161 self.assertTrue(X in RWX)
3162 self.assertFalse(R in WX)
3163 self.assertFalse(W in RX)
3164 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303165 with self.assertRaises(TypeError):
3166 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003167
Ethan Furman7219e272020-09-16 13:01:00 -07003168 def test_member_iter(self):
3169 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003170 self.assertEqual(list(Color.BLACK), [])
3171 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003172 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3173 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003174 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3175
3176 def test_member_length(self):
3177 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3178 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3179 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3180 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3181
3182 def test_aliases(self):
3183 Color = self.Color
3184 self.assertEqual(Color(1).name, 'RED')
3185 self.assertEqual(Color['ROJO'].name, 'RED')
3186 self.assertEqual(Color(7).name, 'WHITE')
3187 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3188 self.assertIs(Color.BLANCO, Color.WHITE)
3189 Open = self.Open
3190 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003191
Ethan Furman25d94bb2016-09-02 16:32:32 -07003192 def test_bool(self):
3193 Perm = self.Perm
3194 for f in Perm:
3195 self.assertTrue(f)
3196 Open = self.Open
3197 for f in Open:
3198 self.assertEqual(bool(f.value), bool(f))
3199
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003200 def test_bizarre(self):
3201 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3202 class Bizarre(IntFlag):
3203 b = 3
3204 c = 4
3205 d = 6
3206
Ethan Furman5bdab642018-09-21 19:03:09 -07003207 def test_multiple_mixin(self):
3208 class AllMixin:
3209 @classproperty
3210 def ALL(cls):
3211 members = list(cls)
3212 all_value = None
3213 if members:
3214 all_value = members[0]
3215 for member in members[1:]:
3216 all_value |= member
3217 cls.ALL = all_value
3218 return all_value
3219 class StrMixin:
3220 def __str__(self):
3221 return self._name_.lower()
3222 class Color(AllMixin, IntFlag):
3223 RED = auto()
3224 GREEN = auto()
3225 BLUE = auto()
3226 self.assertEqual(Color.RED.value, 1)
3227 self.assertEqual(Color.GREEN.value, 2)
3228 self.assertEqual(Color.BLUE.value, 4)
3229 self.assertEqual(Color.ALL.value, 7)
3230 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3231 class Color(AllMixin, StrMixin, IntFlag):
3232 RED = auto()
3233 GREEN = auto()
3234 BLUE = auto()
3235 self.assertEqual(Color.RED.value, 1)
3236 self.assertEqual(Color.GREEN.value, 2)
3237 self.assertEqual(Color.BLUE.value, 4)
3238 self.assertEqual(Color.ALL.value, 7)
3239 self.assertEqual(str(Color.BLUE), 'blue')
3240 class Color(StrMixin, AllMixin, IntFlag):
3241 RED = auto()
3242 GREEN = auto()
3243 BLUE = auto()
3244 self.assertEqual(Color.RED.value, 1)
3245 self.assertEqual(Color.GREEN.value, 2)
3246 self.assertEqual(Color.BLUE.value, 4)
3247 self.assertEqual(Color.ALL.value, 7)
3248 self.assertEqual(str(Color.BLUE), 'blue')
3249
Hai Shie80697d2020-05-28 06:10:27 +08003250 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003251 def test_unique_composite(self):
3252 # override __eq__ to be identity only
3253 class TestFlag(IntFlag):
3254 one = auto()
3255 two = auto()
3256 three = auto()
3257 four = auto()
3258 five = auto()
3259 six = auto()
3260 seven = auto()
3261 eight = auto()
3262 def __eq__(self, other):
3263 return self is other
3264 def __hash__(self):
3265 return hash(self._value_)
3266 # have multiple threads competing to complete the composite members
3267 seen = set()
3268 failed = False
3269 def cycle_enum():
3270 nonlocal failed
3271 try:
3272 for i in range(256):
3273 seen.add(TestFlag(i))
3274 except Exception:
3275 failed = True
3276 threads = [
3277 threading.Thread(target=cycle_enum)
3278 for _ in range(8)
3279 ]
Hai Shie80697d2020-05-28 06:10:27 +08003280 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003281 pass
3282 # check that only 248 members were created
3283 self.assertFalse(
3284 failed,
3285 'at least one thread failed while creating composite members')
3286 self.assertEqual(256, len(seen), 'too many composite members created')
3287
3288
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003289class TestEmptyAndNonLatinStrings(unittest.TestCase):
3290
3291 def test_empty_string(self):
3292 with self.assertRaises(ValueError):
3293 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3294
3295 def test_non_latin_character_string(self):
3296 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3297 item = getattr(greek_abc, '\u03B1')
3298 self.assertEqual(item.value, 1)
3299
3300 def test_non_latin_number_string(self):
3301 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3302 item = getattr(hebrew_123, '\u05D0')
3303 self.assertEqual(item.value, 1)
3304
3305
Ethan Furmanf24bb352013-07-18 17:05:39 -07003306class TestUnique(unittest.TestCase):
3307
3308 def test_unique_clean(self):
3309 @unique
3310 class Clean(Enum):
3311 one = 1
3312 two = 'dos'
3313 tres = 4.0
3314 @unique
3315 class Cleaner(IntEnum):
3316 single = 1
3317 double = 2
3318 triple = 3
3319
3320 def test_unique_dirty(self):
3321 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3322 @unique
3323 class Dirty(Enum):
3324 one = 1
3325 two = 'dos'
3326 tres = 1
3327 with self.assertRaisesRegex(
3328 ValueError,
3329 'double.*single.*turkey.*triple',
3330 ):
3331 @unique
3332 class Dirtier(IntEnum):
3333 single = 1
3334 double = 1
3335 triple = 3
3336 turkey = 3
3337
Ethan Furman3803ad42016-05-01 10:03:53 -07003338 def test_unique_with_name(self):
3339 @unique
3340 class Silly(Enum):
3341 one = 1
3342 two = 'dos'
3343 name = 3
3344 @unique
3345 class Sillier(IntEnum):
3346 single = 1
3347 name = 2
3348 triple = 3
3349 value = 4
3350
Ethan Furmanf24bb352013-07-18 17:05:39 -07003351
Ethan Furman5bdab642018-09-21 19:03:09 -07003352
Ethan Furman3323da92015-04-11 09:39:59 -07003353expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003354Help on class Color in module %s:
3355
3356class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003357 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003358 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003359 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003360 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003361 | Method resolution order:
3362 | Color
3363 | enum.Enum
3364 | builtins.object
3365 |\x20\x20
3366 | Data and other attributes defined here:
3367 |\x20\x20
3368 | blue = <Color.blue: 3>
3369 |\x20\x20
3370 | green = <Color.green: 2>
3371 |\x20\x20
3372 | red = <Color.red: 1>
3373 |\x20\x20
3374 | ----------------------------------------------------------------------
3375 | Data descriptors inherited from enum.Enum:
3376 |\x20\x20
3377 | name
3378 | The name of the Enum member.
3379 |\x20\x20
3380 | value
3381 | The value of the Enum member.
3382 |\x20\x20
3383 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003384 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003385 |\x20\x20
3386 | __members__
3387 | Returns a mapping of member name->value.
3388 |\x20\x20\x20\x20\x20\x20
3389 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003390 | is a read-only view of the internal mapping."""
3391
3392expected_help_output_without_docs = """\
3393Help on class Color in module %s:
3394
3395class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003396 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3397 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003398 | Method resolution order:
3399 | Color
3400 | enum.Enum
3401 | builtins.object
3402 |\x20\x20
3403 | Data and other attributes defined here:
3404 |\x20\x20
3405 | blue = <Color.blue: 3>
3406 |\x20\x20
3407 | green = <Color.green: 2>
3408 |\x20\x20
3409 | red = <Color.red: 1>
3410 |\x20\x20
3411 | ----------------------------------------------------------------------
3412 | Data descriptors inherited from enum.Enum:
3413 |\x20\x20
3414 | name
3415 |\x20\x20
3416 | value
3417 |\x20\x20
3418 | ----------------------------------------------------------------------
3419 | Data descriptors inherited from enum.EnumMeta:
3420 |\x20\x20
3421 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003422
3423class TestStdLib(unittest.TestCase):
3424
Ethan Furman48a724f2015-04-11 23:23:06 -07003425 maxDiff = None
3426
Ethan Furman5875d742013-10-21 20:45:55 -07003427 class Color(Enum):
3428 red = 1
3429 green = 2
3430 blue = 3
3431
3432 def test_pydoc(self):
3433 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003434 if StrEnum.__doc__ is None:
3435 expected_text = expected_help_output_without_docs % __name__
3436 else:
3437 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003438 output = StringIO()
3439 helper = pydoc.Helper(output=output)
3440 helper(self.Color)
3441 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003442 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003443
3444 def test_inspect_getmembers(self):
3445 values = dict((
3446 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003447 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003448 ('__members__', self.Color.__members__),
3449 ('__module__', __name__),
3450 ('blue', self.Color.blue),
3451 ('green', self.Color.green),
3452 ('name', Enum.__dict__['name']),
3453 ('red', self.Color.red),
3454 ('value', Enum.__dict__['value']),
3455 ))
3456 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003457 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003458 failed = False
3459 for k in values.keys():
3460 if result[k] != values[k]:
3461 print()
3462 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3463 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3464 failed = True
3465 if failed:
3466 self.fail("result does not equal expected, see print above")
3467
3468 def test_inspect_classify_class_attrs(self):
3469 # indirectly test __objclass__
3470 from inspect import Attribute
3471 values = [
3472 Attribute(name='__class__', kind='data',
3473 defining_class=object, object=EnumMeta),
3474 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003475 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003476 Attribute(name='__members__', kind='property',
3477 defining_class=EnumMeta, object=EnumMeta.__members__),
3478 Attribute(name='__module__', kind='data',
3479 defining_class=self.Color, object=__name__),
3480 Attribute(name='blue', kind='data',
3481 defining_class=self.Color, object=self.Color.blue),
3482 Attribute(name='green', kind='data',
3483 defining_class=self.Color, object=self.Color.green),
3484 Attribute(name='red', kind='data',
3485 defining_class=self.Color, object=self.Color.red),
3486 Attribute(name='name', kind='data',
3487 defining_class=Enum, object=Enum.__dict__['name']),
3488 Attribute(name='value', kind='data',
3489 defining_class=Enum, object=Enum.__dict__['value']),
3490 ]
3491 values.sort(key=lambda item: item.name)
3492 result = list(inspect.classify_class_attrs(self.Color))
3493 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003494 self.assertEqual(
3495 len(values), len(result),
3496 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3497 )
Ethan Furman5875d742013-10-21 20:45:55 -07003498 failed = False
3499 for v, r in zip(values, result):
3500 if r != v:
3501 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3502 failed = True
3503 if failed:
3504 self.fail("result does not equal expected, see print above")
3505
Martin Panter19e69c52015-11-14 12:46:42 +00003506
3507class MiscTestCase(unittest.TestCase):
3508 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003509 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003510
3511
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003512# These are unordered here on purpose to ensure that declaration order
3513# makes no difference.
3514CONVERT_TEST_NAME_D = 5
3515CONVERT_TEST_NAME_C = 5
3516CONVERT_TEST_NAME_B = 5
3517CONVERT_TEST_NAME_A = 5 # This one should sort first.
3518CONVERT_TEST_NAME_E = 5
3519CONVERT_TEST_NAME_F = 5
3520
3521class TestIntEnumConvert(unittest.TestCase):
3522 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003523 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003524 'UnittestConvert',
3525 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003526 filter=lambda x: x.startswith('CONVERT_TEST_'))
3527 # We don't want the reverse lookup value to vary when there are
3528 # multiple possible names for a given value. It should always
3529 # report the first lexigraphical name in that case.
3530 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3531
3532 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003533 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003534 'UnittestConvert',
3535 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003536 filter=lambda x: x.startswith('CONVERT_TEST_'))
3537 # Ensure that test_type has all of the desired names and values.
3538 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3539 test_type.CONVERT_TEST_NAME_A)
3540 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3541 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3542 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3543 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3544 # Ensure that test_type only picked up names matching the filter.
3545 self.assertEqual([name for name in dir(test_type)
3546 if name[0:2] not in ('CO', '__')],
3547 [], msg='Names other than CONVERT_TEST_* found.')
3548
orlnub1230fb9fad2018-09-12 20:28:53 +03003549 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3550 '_convert was deprecated in 3.8')
3551 def test_convert_warn(self):
3552 with self.assertWarns(DeprecationWarning):
3553 enum.IntEnum._convert(
3554 'UnittestConvert',
3555 ('test.test_enum', '__main__')[__name__=='__main__'],
3556 filter=lambda x: x.startswith('CONVERT_TEST_'))
3557
3558 @unittest.skipUnless(sys.version_info >= (3, 9),
3559 '_convert was removed in 3.9')
3560 def test_convert_raise(self):
3561 with self.assertRaises(AttributeError):
3562 enum.IntEnum._convert(
3563 'UnittestConvert',
3564 ('test.test_enum', '__main__')[__name__=='__main__'],
3565 filter=lambda x: x.startswith('CONVERT_TEST_'))
3566
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003567
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003568if __name__ == '__main__':
3569 unittest.main()