blob: 69392e01faacd5d802835df74763a8eedf77fce8 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002import doctest
Ethan Furman5875d742013-10-21 20:45:55 -07003import inspect
Ethan Furman01faf452021-01-26 12:52:52 -08004import os
Ethan Furman5875d742013-10-21 20:45:55 -07005import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03006import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02008import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07009from collections import OrderedDict
Ethan Furman0063ff42020-09-21 17:23:13 -070010from enum import Enum, IntEnum, StrEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080011from enum import STRICT, CONFORM, EJECT, KEEP
Ethan Furman5875d742013-10-21 20:45:55 -070012from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080013from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000014from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030015from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080016from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080017from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080018
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080019def load_tests(loader, tests, ignore):
20 tests.addTests(doctest.DocTestSuite(enum))
Ethan Furman44e580f2021-03-03 09:54:30 -080021 if os.path.exists('Doc/library/enum.rst'):
Ethan Furman01faf452021-01-26 12:52:52 -080022 tests.addTests(doctest.DocFileSuite(
23 '../../Doc/library/enum.rst',
24 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
25 ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080026 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070027
28# for pickle tests
29try:
30 class Stooges(Enum):
31 LARRY = 1
32 CURLY = 2
33 MOE = 3
34except Exception as exc:
35 Stooges = exc
36
37try:
38 class IntStooges(int, Enum):
39 LARRY = 1
40 CURLY = 2
41 MOE = 3
42except Exception as exc:
43 IntStooges = exc
44
45try:
46 class FloatStooges(float, Enum):
47 LARRY = 1.39
48 CURLY = 2.72
49 MOE = 3.142596
50except Exception as exc:
51 FloatStooges = exc
52
Ethan Furman65a5a472016-09-01 23:55:19 -070053try:
54 class FlagStooges(Flag):
55 LARRY = 1
56 CURLY = 2
57 MOE = 3
58except Exception as exc:
59 FlagStooges = exc
60
Ethan Furman6b3d64a2013-06-14 16:55:46 -070061# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070062class Name(StrEnum):
63 BDFL = 'Guido van Rossum'
64 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070065
66try:
67 Question = Enum('Question', 'who what when where why', module=__name__)
68except Exception as exc:
69 Question = exc
70
71try:
72 Answer = Enum('Answer', 'him this then there because')
73except Exception as exc:
74 Answer = exc
75
Ethan Furmanca1b7942014-02-08 11:36:27 -080076try:
77 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
78except Exception as exc:
79 Theory = exc
80
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081# for doctests
82try:
83 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080084 TOMATO = 1
85 BANANA = 2
86 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070087except Exception:
88 pass
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 if target is None:
92 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030093 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080094 assertion(loads(dumps(source, protocol=protocol)), target)
95
Serhiy Storchakae50e7802015-03-31 16:56:49 +030096def test_pickle_exception(assertion, exception, obj):
97 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080098 with assertion(exception):
99 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -0700100
101class TestHelpers(unittest.TestCase):
102 # _is_descriptor, _is_sunder, _is_dunder
103
104 def test_is_descriptor(self):
105 class foo:
106 pass
107 for attr in ('__get__','__set__','__delete__'):
108 obj = foo()
109 self.assertFalse(enum._is_descriptor(obj))
110 setattr(obj, attr, 1)
111 self.assertTrue(enum._is_descriptor(obj))
112
113 def test_is_sunder(self):
114 for s in ('_a_', '_aa_'):
115 self.assertTrue(enum._is_sunder(s))
116
117 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_sunder(s))
120
121 def test_is_dunder(self):
122 for s in ('__a__', '__aa__'):
123 self.assertTrue(enum._is_dunder(s))
124 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
125 '__', '___', '____', '_____',):
126 self.assertFalse(enum._is_dunder(s))
127
Ethan Furman5bdab642018-09-21 19:03:09 -0700128# for subclassing tests
129
130class classproperty:
131
132 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
133 self.fget = fget
134 self.fset = fset
135 self.fdel = fdel
136 if doc is None and fget is not None:
137 doc = fget.__doc__
138 self.__doc__ = doc
139
140 def __get__(self, instance, ownerclass):
141 return self.fget(ownerclass)
142
143
Ethan Furmanc16595e2016-09-10 23:36:59 -0700144# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700145
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700146class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800147
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700148 def setUp(self):
149 class Season(Enum):
150 SPRING = 1
151 SUMMER = 2
152 AUTUMN = 3
153 WINTER = 4
154 self.Season = Season
155
Ethan Furmanec15a822013-08-31 19:17:41 -0700156 class Konstants(float, Enum):
157 E = 2.7182818
158 PI = 3.1415926
159 TAU = 2 * PI
160 self.Konstants = Konstants
161
162 class Grades(IntEnum):
163 A = 5
164 B = 4
165 C = 3
166 D = 2
167 F = 0
168 self.Grades = Grades
169
170 class Directional(str, Enum):
171 EAST = 'east'
172 WEST = 'west'
173 NORTH = 'north'
174 SOUTH = 'south'
175 self.Directional = Directional
176
177 from datetime import date
178 class Holiday(date, Enum):
179 NEW_YEAR = 2013, 1, 1
180 IDES_OF_MARCH = 2013, 3, 15
181 self.Holiday = Holiday
182
Ethan Furman388a3922013-08-12 06:51:41 -0700183 def test_dir_on_class(self):
184 Season = self.Season
185 self.assertEqual(
186 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700188 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
189 )
190
191 def test_dir_on_item(self):
192 Season = self.Season
193 self.assertEqual(
194 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700195 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700196 )
197
Ethan Furmanc850f342013-09-15 16:59:35 -0700198 def test_dir_with_added_behavior(self):
199 class Test(Enum):
200 this = 'that'
201 these = 'those'
202 def wowser(self):
203 return ("Wowser! I'm %s!" % self.name)
204 self.assertEqual(
205 set(dir(Test)),
206 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
207 )
208 self.assertEqual(
209 set(dir(Test.this)),
210 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
211 )
212
Ethan Furman0ae550b2014-10-14 08:58:32 -0700213 def test_dir_on_sub_with_behavior_on_super(self):
214 # see issue22506
215 class SuperEnum(Enum):
216 def invisible(self):
217 return "did you see me?"
218 class SubEnum(SuperEnum):
219 sample = 5
220 self.assertEqual(
221 set(dir(SubEnum.sample)),
222 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
223 )
224
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200225 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
226 # see issue40084
227 class SuperEnum(IntEnum):
228 def __new__(cls, value, description=""):
229 obj = int.__new__(cls, value)
230 obj._value_ = value
231 obj.description = description
232 return obj
233 class SubEnum(SuperEnum):
234 sample = 5
235 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum_in_enum_out(self):
238 Season = self.Season
239 self.assertIs(Season(Season.WINTER), Season.WINTER)
240
241 def test_enum_value(self):
242 Season = self.Season
243 self.assertEqual(Season.SPRING.value, 1)
244
245 def test_intenum_value(self):
246 self.assertEqual(IntStooges.CURLY.value, 2)
247
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700248 def test_enum(self):
249 Season = self.Season
250 lst = list(Season)
251 self.assertEqual(len(lst), len(Season))
252 self.assertEqual(len(Season), 4, Season)
253 self.assertEqual(
254 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
255
256 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
257 e = Season(i)
258 self.assertEqual(e, getattr(Season, season))
259 self.assertEqual(e.value, i)
260 self.assertNotEqual(e, i)
261 self.assertEqual(e.name, season)
262 self.assertIn(e, Season)
263 self.assertIs(type(e), Season)
264 self.assertIsInstance(e, Season)
265 self.assertEqual(str(e), 'Season.' + season)
266 self.assertEqual(
267 repr(e),
268 '<Season.{0}: {1}>'.format(season, i),
269 )
270
271 def test_value_name(self):
272 Season = self.Season
273 self.assertEqual(Season.SPRING.name, 'SPRING')
274 self.assertEqual(Season.SPRING.value, 1)
275 with self.assertRaises(AttributeError):
276 Season.SPRING.name = 'invierno'
277 with self.assertRaises(AttributeError):
278 Season.SPRING.value = 2
279
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700280 def test_changing_member(self):
281 Season = self.Season
282 with self.assertRaises(AttributeError):
283 Season.WINTER = 'really cold'
284
Ethan Furman64a99722013-09-22 16:18:19 -0700285 def test_attribute_deletion(self):
286 class Season(Enum):
287 SPRING = 1
288 SUMMER = 2
289 AUTUMN = 3
290 WINTER = 4
291
292 def spam(cls):
293 pass
294
295 self.assertTrue(hasattr(Season, 'spam'))
296 del Season.spam
297 self.assertFalse(hasattr(Season, 'spam'))
298
299 with self.assertRaises(AttributeError):
300 del Season.SPRING
301 with self.assertRaises(AttributeError):
302 del Season.DRY
303 with self.assertRaises(AttributeError):
304 del Season.SPRING.name
305
Ethan Furman5de67b12016-04-13 23:52:09 -0700306 def test_bool_of_class(self):
307 class Empty(Enum):
308 pass
309 self.assertTrue(bool(Empty))
310
311 def test_bool_of_member(self):
312 class Count(Enum):
313 zero = 0
314 one = 1
315 two = 2
316 for member in Count:
317 self.assertTrue(bool(member))
318
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700319 def test_invalid_names(self):
320 with self.assertRaises(ValueError):
321 class Wrong(Enum):
322 mro = 9
323 with self.assertRaises(ValueError):
324 class Wrong(Enum):
325 _create_= 11
326 with self.assertRaises(ValueError):
327 class Wrong(Enum):
328 _get_mixins_ = 9
329 with self.assertRaises(ValueError):
330 class Wrong(Enum):
331 _find_new_ = 1
332 with self.assertRaises(ValueError):
333 class Wrong(Enum):
334 _any_name_ = 9
335
Ethan Furman6db1fd52015-09-17 21:49:12 -0700336 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800337 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700338 class Logic(Enum):
339 true = True
340 false = False
341 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800342 self.assertTrue(Logic.false)
343 # unless overridden
344 class RealLogic(Enum):
345 true = True
346 false = False
347 def __bool__(self):
348 return bool(self._value_)
349 self.assertTrue(RealLogic.true)
350 self.assertFalse(RealLogic.false)
351 # mixed Enums depend on mixed-in type
352 class IntLogic(int, Enum):
353 true = 1
354 false = 0
355 self.assertTrue(IntLogic.true)
356 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700357
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700358 def test_contains(self):
359 Season = self.Season
360 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530361 with self.assertRaises(TypeError):
362 3 in Season
363 with self.assertRaises(TypeError):
364 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700365
366 val = Season(3)
367 self.assertIn(val, Season)
368
369 class OtherEnum(Enum):
370 one = 1; two = 2
371 self.assertNotIn(OtherEnum.two, Season)
372
373 def test_comparisons(self):
374 Season = self.Season
375 with self.assertRaises(TypeError):
376 Season.SPRING < Season.WINTER
377 with self.assertRaises(TypeError):
378 Season.SPRING > 4
379
380 self.assertNotEqual(Season.SPRING, 1)
381
382 class Part(Enum):
383 SPRING = 1
384 CLIP = 2
385 BARREL = 3
386
387 self.assertNotEqual(Season.SPRING, Part.SPRING)
388 with self.assertRaises(TypeError):
389 Season.SPRING < Part.CLIP
390
391 def test_enum_duplicates(self):
392 class Season(Enum):
393 SPRING = 1
394 SUMMER = 2
395 AUTUMN = FALL = 3
396 WINTER = 4
397 ANOTHER_SPRING = 1
398 lst = list(Season)
399 self.assertEqual(
400 lst,
401 [Season.SPRING, Season.SUMMER,
402 Season.AUTUMN, Season.WINTER,
403 ])
404 self.assertIs(Season.FALL, Season.AUTUMN)
405 self.assertEqual(Season.FALL.value, 3)
406 self.assertEqual(Season.AUTUMN.value, 3)
407 self.assertIs(Season(3), Season.AUTUMN)
408 self.assertIs(Season(1), Season.SPRING)
409 self.assertEqual(Season.FALL.name, 'AUTUMN')
410 self.assertEqual(
411 [k for k,v in Season.__members__.items() if v.name != k],
412 ['FALL', 'ANOTHER_SPRING'],
413 )
414
Ethan Furman101e0742013-09-15 12:34:36 -0700415 def test_duplicate_name(self):
416 with self.assertRaises(TypeError):
417 class Color(Enum):
418 red = 1
419 green = 2
420 blue = 3
421 red = 4
422
423 with self.assertRaises(TypeError):
424 class Color(Enum):
425 red = 1
426 green = 2
427 blue = 3
428 def red(self):
429 return 'red'
430
431 with self.assertRaises(TypeError):
432 class Color(Enum):
433 @property
434 def red(self):
435 return 'redder'
436 red = 1
437 green = 2
438 blue = 3
439
Zackery Spytz2ec67522020-09-13 14:27:51 -0600440 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700441 with self.assertRaisesRegex(
442 ValueError,
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800443 "_sunder_ names, such as '_bad_', are reserved",
Ethan Furman5a565b32020-09-15 12:27:06 -0700444 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600445 class Bad(Enum):
446 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700447
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700448 def test_enum_with_value_name(self):
449 class Huh(Enum):
450 name = 1
451 value = 2
452 self.assertEqual(
453 list(Huh),
454 [Huh.name, Huh.value],
455 )
456 self.assertIs(type(Huh.name), Huh)
457 self.assertEqual(Huh.name.name, 'name')
458 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700459
460 def test_format_enum(self):
461 Season = self.Season
462 self.assertEqual('{}'.format(Season.SPRING),
463 '{}'.format(str(Season.SPRING)))
464 self.assertEqual( '{:}'.format(Season.SPRING),
465 '{:}'.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 self.assertEqual('{:<20}'.format(Season.SPRING),
473 '{:<20}'.format(str(Season.SPRING)))
474
thatneat2f19e822019-07-04 11:28:37 -0700475 def test_str_override_enum(self):
476 class EnumWithStrOverrides(Enum):
477 one = auto()
478 two = auto()
479
480 def __str__(self):
481 return 'Str!'
482 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
483 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
484
485 def test_format_override_enum(self):
486 class EnumWithFormatOverride(Enum):
487 one = 1.0
488 two = 2.0
489 def __format__(self, spec):
490 return 'Format!!'
491 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
492 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
493
494 def test_str_and_format_override_enum(self):
495 class EnumWithStrFormatOverrides(Enum):
496 one = auto()
497 two = auto()
498 def __str__(self):
499 return 'Str!'
500 def __format__(self, spec):
501 return 'Format!'
502 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
503 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
504
505 def test_str_override_mixin(self):
506 class MixinEnumWithStrOverride(float, Enum):
507 one = 1.0
508 two = 2.0
509 def __str__(self):
510 return 'Overridden!'
511 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
512 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
513
514 def test_str_and_format_override_mixin(self):
515 class MixinWithStrFormatOverrides(float, Enum):
516 one = 1.0
517 two = 2.0
518 def __str__(self):
519 return 'Str!'
520 def __format__(self, spec):
521 return 'Format!'
522 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
523 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
524
525 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700526 class TestFloat(float, Enum):
527 one = 1.0
528 two = 2.0
529 def __format__(self, spec):
530 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700531 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700532 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
533
534 def assertFormatIsValue(self, spec, member):
535 self.assertEqual(spec.format(member), spec.format(member.value))
536
537 def test_format_enum_date(self):
538 Holiday = self.Holiday
539 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
540 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
541 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
542 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
543 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
544 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
545 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
546 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
547
548 def test_format_enum_float(self):
549 Konstants = self.Konstants
550 self.assertFormatIsValue('{}', Konstants.TAU)
551 self.assertFormatIsValue('{:}', Konstants.TAU)
552 self.assertFormatIsValue('{:20}', Konstants.TAU)
553 self.assertFormatIsValue('{:^20}', Konstants.TAU)
554 self.assertFormatIsValue('{:>20}', Konstants.TAU)
555 self.assertFormatIsValue('{:<20}', Konstants.TAU)
556 self.assertFormatIsValue('{:n}', Konstants.TAU)
557 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
558 self.assertFormatIsValue('{:f}', Konstants.TAU)
559
560 def test_format_enum_int(self):
561 Grades = self.Grades
562 self.assertFormatIsValue('{}', Grades.C)
563 self.assertFormatIsValue('{:}', Grades.C)
564 self.assertFormatIsValue('{:20}', Grades.C)
565 self.assertFormatIsValue('{:^20}', Grades.C)
566 self.assertFormatIsValue('{:>20}', Grades.C)
567 self.assertFormatIsValue('{:<20}', Grades.C)
568 self.assertFormatIsValue('{:+}', Grades.C)
569 self.assertFormatIsValue('{:08X}', Grades.C)
570 self.assertFormatIsValue('{:b}', Grades.C)
571
572 def test_format_enum_str(self):
573 Directional = self.Directional
574 self.assertFormatIsValue('{}', Directional.WEST)
575 self.assertFormatIsValue('{:}', Directional.WEST)
576 self.assertFormatIsValue('{:20}', Directional.WEST)
577 self.assertFormatIsValue('{:^20}', Directional.WEST)
578 self.assertFormatIsValue('{:>20}', Directional.WEST)
579 self.assertFormatIsValue('{:<20}', Directional.WEST)
580
Ethan Furman22415ad2020-09-15 16:28:25 -0700581 def test_object_str_override(self):
582 class Colors(Enum):
583 RED, GREEN, BLUE = 1, 2, 3
584 def __repr__(self):
585 return "test.%s" % (self._name_, )
586 __str__ = object.__str__
587 self.assertEqual(str(Colors.RED), 'test.RED')
588
Ethan Furmanbff01f32020-09-15 15:56:26 -0700589 def test_enum_str_override(self):
590 class MyStrEnum(Enum):
591 def __str__(self):
592 return 'MyStr'
593 class MyMethodEnum(Enum):
594 def hello(self):
595 return 'Hello! My name is %s' % self.name
596 class Test1Enum(MyMethodEnum, int, MyStrEnum):
597 One = 1
598 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800599 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700600 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800601 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700602 #
603 class Test2Enum(MyStrEnum, MyMethodEnum):
604 One = 1
605 Two = 2
606 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800607 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700608
609 def test_inherited_data_type(self):
610 class HexInt(int):
611 def __repr__(self):
612 return hex(self)
613 class MyEnum(HexInt, enum.Enum):
614 A = 1
615 B = 2
616 C = 3
617 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
618
619 def test_too_many_data_types(self):
620 with self.assertRaisesRegex(TypeError, 'too many data types'):
621 class Huh(str, int, Enum):
622 One = 1
623
624 class MyStr(str):
625 def hello(self):
626 return 'hello, %s' % self
627 class MyInt(int):
628 def repr(self):
629 return hex(self)
630 with self.assertRaisesRegex(TypeError, 'too many data types'):
631 class Huh(MyStr, MyInt, Enum):
632 One = 1
633
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700634 def test_hash(self):
635 Season = self.Season
636 dates = {}
637 dates[Season.WINTER] = '1225'
638 dates[Season.SPRING] = '0315'
639 dates[Season.SUMMER] = '0704'
640 dates[Season.AUTUMN] = '1031'
641 self.assertEqual(dates[Season.AUTUMN], '1031')
642
643 def test_intenum_from_scratch(self):
644 class phy(int, Enum):
645 pi = 3
646 tau = 2 * pi
647 self.assertTrue(phy.pi < phy.tau)
648
649 def test_intenum_inherited(self):
650 class IntEnum(int, Enum):
651 pass
652 class phy(IntEnum):
653 pi = 3
654 tau = 2 * pi
655 self.assertTrue(phy.pi < phy.tau)
656
657 def test_floatenum_from_scratch(self):
658 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700659 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700660 tau = 2 * pi
661 self.assertTrue(phy.pi < phy.tau)
662
663 def test_floatenum_inherited(self):
664 class FloatEnum(float, Enum):
665 pass
666 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700667 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700668 tau = 2 * pi
669 self.assertTrue(phy.pi < phy.tau)
670
671 def test_strenum_from_scratch(self):
672 class phy(str, Enum):
673 pi = 'Pi'
674 tau = 'Tau'
675 self.assertTrue(phy.pi < phy.tau)
676
Ethan Furman0063ff42020-09-21 17:23:13 -0700677 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700678 class phy(StrEnum):
679 pi = 'Pi'
680 tau = 'Tau'
681 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700682 self.assertEqual(phy.pi.upper(), 'PI')
683 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700684
685 def test_intenum(self):
686 class WeekDay(IntEnum):
687 SUNDAY = 1
688 MONDAY = 2
689 TUESDAY = 3
690 WEDNESDAY = 4
691 THURSDAY = 5
692 FRIDAY = 6
693 SATURDAY = 7
694
695 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
696 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
697
698 lst = list(WeekDay)
699 self.assertEqual(len(lst), len(WeekDay))
700 self.assertEqual(len(WeekDay), 7)
701 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
702 target = target.split()
703 for i, weekday in enumerate(target, 1):
704 e = WeekDay(i)
705 self.assertEqual(e, i)
706 self.assertEqual(int(e), i)
707 self.assertEqual(e.name, weekday)
708 self.assertIn(e, WeekDay)
709 self.assertEqual(lst.index(e)+1, i)
710 self.assertTrue(0 < e < 8)
711 self.assertIs(type(e), WeekDay)
712 self.assertIsInstance(e, int)
713 self.assertIsInstance(e, Enum)
714
715 def test_intenum_duplicates(self):
716 class WeekDay(IntEnum):
717 SUNDAY = 1
718 MONDAY = 2
719 TUESDAY = TEUSDAY = 3
720 WEDNESDAY = 4
721 THURSDAY = 5
722 FRIDAY = 6
723 SATURDAY = 7
724 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
725 self.assertEqual(WeekDay(3).name, 'TUESDAY')
726 self.assertEqual([k for k,v in WeekDay.__members__.items()
727 if v.name != k], ['TEUSDAY', ])
728
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300729 def test_intenum_from_bytes(self):
730 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
731 with self.assertRaises(ValueError):
732 IntStooges.from_bytes(b'\x00\x05', 'big')
733
734 def test_floatenum_fromhex(self):
735 h = float.hex(FloatStooges.MOE.value)
736 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
737 h = float.hex(FloatStooges.MOE.value + 0.01)
738 with self.assertRaises(ValueError):
739 FloatStooges.fromhex(h)
740
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700741 def test_pickle_enum(self):
742 if isinstance(Stooges, Exception):
743 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800744 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
745 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700746
747 def test_pickle_int(self):
748 if isinstance(IntStooges, Exception):
749 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800750 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
751 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700752
753 def test_pickle_float(self):
754 if isinstance(FloatStooges, Exception):
755 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800756 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
757 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700758
759 def test_pickle_enum_function(self):
760 if isinstance(Answer, Exception):
761 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800762 test_pickle_dump_load(self.assertIs, Answer.him)
763 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700764
765 def test_pickle_enum_function_with_module(self):
766 if isinstance(Question, Exception):
767 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800768 test_pickle_dump_load(self.assertIs, Question.who)
769 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700770
Ethan Furmanca1b7942014-02-08 11:36:27 -0800771 def test_enum_function_with_qualname(self):
772 if isinstance(Theory, Exception):
773 raise Theory
774 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
775
776 def test_class_nested_enum_and_pickle_protocol_four(self):
777 # would normally just have this directly in the class namespace
778 class NestedEnum(Enum):
779 twigs = 'common'
780 shiny = 'rare'
781
782 self.__class__.NestedEnum = NestedEnum
783 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300784 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800785
Ethan Furman24e837f2015-03-18 17:27:57 -0700786 def test_pickle_by_name(self):
787 class ReplaceGlobalInt(IntEnum):
788 ONE = 1
789 TWO = 2
790 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
791 for proto in range(HIGHEST_PROTOCOL):
792 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
793
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700794 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800795 BadPickle = Enum(
796 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700797 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800798 # now break BadPickle to test exception raising
799 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800800 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
801 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700802
803 def test_string_enum(self):
804 class SkillLevel(str, Enum):
805 master = 'what is the sound of one hand clapping?'
806 journeyman = 'why did the chicken cross the road?'
807 apprentice = 'knock, knock!'
808 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
809
810 def test_getattr_getitem(self):
811 class Period(Enum):
812 morning = 1
813 noon = 2
814 evening = 3
815 night = 4
816 self.assertIs(Period(2), Period.noon)
817 self.assertIs(getattr(Period, 'night'), Period.night)
818 self.assertIs(Period['morning'], Period.morning)
819
820 def test_getattr_dunder(self):
821 Season = self.Season
822 self.assertTrue(getattr(Season, '__eq__'))
823
824 def test_iteration_order(self):
825 class Season(Enum):
826 SUMMER = 2
827 WINTER = 4
828 AUTUMN = 3
829 SPRING = 1
830 self.assertEqual(
831 list(Season),
832 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
833 )
834
Ethan Furman2131a4a2013-09-14 18:11:24 -0700835 def test_reversed_iteration_order(self):
836 self.assertEqual(
837 list(reversed(self.Season)),
838 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
839 self.Season.SPRING]
840 )
841
Martin Pantereb995702016-07-28 01:11:04 +0000842 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700843 SummerMonth = Enum('SummerMonth', 'june july august')
844 lst = list(SummerMonth)
845 self.assertEqual(len(lst), len(SummerMonth))
846 self.assertEqual(len(SummerMonth), 3, SummerMonth)
847 self.assertEqual(
848 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
849 lst,
850 )
851 for i, month in enumerate('june july august'.split(), 1):
852 e = SummerMonth(i)
853 self.assertEqual(int(e.value), i)
854 self.assertNotEqual(e, i)
855 self.assertEqual(e.name, month)
856 self.assertIn(e, SummerMonth)
857 self.assertIs(type(e), SummerMonth)
858
Martin Pantereb995702016-07-28 01:11:04 +0000859 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700860 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
861 lst = list(SummerMonth)
862 self.assertEqual(len(lst), len(SummerMonth))
863 self.assertEqual(len(SummerMonth), 3, SummerMonth)
864 self.assertEqual(
865 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
866 lst,
867 )
868 for i, month in enumerate('june july august'.split(), 10):
869 e = SummerMonth(i)
870 self.assertEqual(int(e.value), i)
871 self.assertNotEqual(e, i)
872 self.assertEqual(e.name, month)
873 self.assertIn(e, SummerMonth)
874 self.assertIs(type(e), SummerMonth)
875
Martin Pantereb995702016-07-28 01:11:04 +0000876 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700877 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
878 lst = list(SummerMonth)
879 self.assertEqual(len(lst), len(SummerMonth))
880 self.assertEqual(len(SummerMonth), 3, SummerMonth)
881 self.assertEqual(
882 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
883 lst,
884 )
885 for i, month in enumerate('june july august'.split(), 1):
886 e = SummerMonth(i)
887 self.assertEqual(int(e.value), i)
888 self.assertNotEqual(e, i)
889 self.assertEqual(e.name, month)
890 self.assertIn(e, SummerMonth)
891 self.assertIs(type(e), SummerMonth)
892
Martin Pantereb995702016-07-28 01:11:04 +0000893 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700894 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
895 lst = list(SummerMonth)
896 self.assertEqual(len(lst), len(SummerMonth))
897 self.assertEqual(len(SummerMonth), 3, SummerMonth)
898 self.assertEqual(
899 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
900 lst,
901 )
902 for i, month in enumerate('june july august'.split(), 20):
903 e = SummerMonth(i)
904 self.assertEqual(int(e.value), i)
905 self.assertNotEqual(e, i)
906 self.assertEqual(e.name, month)
907 self.assertIn(e, SummerMonth)
908 self.assertIs(type(e), SummerMonth)
909
Martin Pantereb995702016-07-28 01:11:04 +0000910 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700911 SummerMonth = Enum(
912 'SummerMonth',
913 (('june', 1), ('july', 2), ('august', 3))
914 )
915 lst = list(SummerMonth)
916 self.assertEqual(len(lst), len(SummerMonth))
917 self.assertEqual(len(SummerMonth), 3, SummerMonth)
918 self.assertEqual(
919 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
920 lst,
921 )
922 for i, month in enumerate('june july august'.split(), 1):
923 e = SummerMonth(i)
924 self.assertEqual(int(e.value), i)
925 self.assertNotEqual(e, i)
926 self.assertEqual(e.name, month)
927 self.assertIn(e, SummerMonth)
928 self.assertIs(type(e), SummerMonth)
929
Martin Pantereb995702016-07-28 01:11:04 +0000930 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700931 SummerMonth = Enum(
932 'SummerMonth',
933 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
934 )
935 lst = list(SummerMonth)
936 self.assertEqual(len(lst), len(SummerMonth))
937 self.assertEqual(len(SummerMonth), 3, SummerMonth)
938 self.assertEqual(
939 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
940 lst,
941 )
942 for i, month in enumerate('june july august'.split(), 1):
943 e = SummerMonth(i)
944 self.assertEqual(int(e.value), i)
945 self.assertNotEqual(e, i)
946 self.assertEqual(e.name, month)
947 self.assertIn(e, SummerMonth)
948 self.assertIs(type(e), SummerMonth)
949
Martin Pantereb995702016-07-28 01:11:04 +0000950 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700951 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
952 lst = list(SummerMonth)
953 self.assertEqual(len(lst), len(SummerMonth))
954 self.assertEqual(len(SummerMonth), 3, SummerMonth)
955 self.assertEqual(
956 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
957 lst,
958 )
959 for i, month in enumerate('june july august'.split(), 1):
960 e = SummerMonth(i)
961 self.assertEqual(e, i)
962 self.assertEqual(e.name, month)
963 self.assertIn(e, SummerMonth)
964 self.assertIs(type(e), SummerMonth)
965
Martin Pantereb995702016-07-28 01:11:04 +0000966 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700967 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
968 lst = list(SummerMonth)
969 self.assertEqual(len(lst), len(SummerMonth))
970 self.assertEqual(len(SummerMonth), 3, SummerMonth)
971 self.assertEqual(
972 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
973 lst,
974 )
975 for i, month in enumerate('june july august'.split(), 30):
976 e = SummerMonth(i)
977 self.assertEqual(e, i)
978 self.assertEqual(e.name, month)
979 self.assertIn(e, SummerMonth)
980 self.assertIs(type(e), SummerMonth)
981
Martin Pantereb995702016-07-28 01:11:04 +0000982 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700983 SummerMonth = IntEnum('SummerMonth', 'june july august')
984 lst = list(SummerMonth)
985 self.assertEqual(len(lst), len(SummerMonth))
986 self.assertEqual(len(SummerMonth), 3, SummerMonth)
987 self.assertEqual(
988 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
989 lst,
990 )
991 for i, month in enumerate('june july august'.split(), 1):
992 e = SummerMonth(i)
993 self.assertEqual(e, i)
994 self.assertEqual(e.name, month)
995 self.assertIn(e, SummerMonth)
996 self.assertIs(type(e), SummerMonth)
997
Martin Pantereb995702016-07-28 01:11:04 +0000998 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700999 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1000 lst = list(SummerMonth)
1001 self.assertEqual(len(lst), len(SummerMonth))
1002 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1003 self.assertEqual(
1004 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1005 lst,
1006 )
1007 for i, month in enumerate('june july august'.split(), 40):
1008 e = SummerMonth(i)
1009 self.assertEqual(e, i)
1010 self.assertEqual(e.name, month)
1011 self.assertIn(e, SummerMonth)
1012 self.assertIs(type(e), SummerMonth)
1013
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001014 def test_subclassing(self):
1015 if isinstance(Name, Exception):
1016 raise Name
1017 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1018 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1019 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001020 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001021
1022 def test_extending(self):
1023 class Color(Enum):
1024 red = 1
1025 green = 2
1026 blue = 3
1027 with self.assertRaises(TypeError):
1028 class MoreColor(Color):
1029 cyan = 4
1030 magenta = 5
1031 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001032 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1033 class EvenMoreColor(Color, IntEnum):
1034 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001035
1036 def test_exclude_methods(self):
1037 class whatever(Enum):
1038 this = 'that'
1039 these = 'those'
1040 def really(self):
1041 return 'no, not %s' % self.value
1042 self.assertIsNot(type(whatever.really), whatever)
1043 self.assertEqual(whatever.this.really(), 'no, not that')
1044
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001045 def test_wrong_inheritance_order(self):
1046 with self.assertRaises(TypeError):
1047 class Wrong(Enum, str):
1048 NotHere = 'error before this point'
1049
1050 def test_intenum_transitivity(self):
1051 class number(IntEnum):
1052 one = 1
1053 two = 2
1054 three = 3
1055 class numero(IntEnum):
1056 uno = 1
1057 dos = 2
1058 tres = 3
1059 self.assertEqual(number.one, numero.uno)
1060 self.assertEqual(number.two, numero.dos)
1061 self.assertEqual(number.three, numero.tres)
1062
1063 def test_wrong_enum_in_call(self):
1064 class Monochrome(Enum):
1065 black = 0
1066 white = 1
1067 class Gender(Enum):
1068 male = 0
1069 female = 1
1070 self.assertRaises(ValueError, Monochrome, Gender.male)
1071
1072 def test_wrong_enum_in_mixed_call(self):
1073 class Monochrome(IntEnum):
1074 black = 0
1075 white = 1
1076 class Gender(Enum):
1077 male = 0
1078 female = 1
1079 self.assertRaises(ValueError, Monochrome, Gender.male)
1080
1081 def test_mixed_enum_in_call_1(self):
1082 class Monochrome(IntEnum):
1083 black = 0
1084 white = 1
1085 class Gender(IntEnum):
1086 male = 0
1087 female = 1
1088 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1089
1090 def test_mixed_enum_in_call_2(self):
1091 class Monochrome(Enum):
1092 black = 0
1093 white = 1
1094 class Gender(IntEnum):
1095 male = 0
1096 female = 1
1097 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1098
1099 def test_flufl_enum(self):
1100 class Fluflnum(Enum):
1101 def __int__(self):
1102 return int(self.value)
1103 class MailManOptions(Fluflnum):
1104 option1 = 1
1105 option2 = 2
1106 option3 = 3
1107 self.assertEqual(int(MailManOptions.option1), 1)
1108
Ethan Furman5e5a8232013-08-04 08:42:23 -07001109 def test_introspection(self):
1110 class Number(IntEnum):
1111 one = 100
1112 two = 200
1113 self.assertIs(Number.one._member_type_, int)
1114 self.assertIs(Number._member_type_, int)
1115 class String(str, Enum):
1116 yarn = 'soft'
1117 rope = 'rough'
1118 wire = 'hard'
1119 self.assertIs(String.yarn._member_type_, str)
1120 self.assertIs(String._member_type_, str)
1121 class Plain(Enum):
1122 vanilla = 'white'
1123 one = 1
1124 self.assertIs(Plain.vanilla._member_type_, object)
1125 self.assertIs(Plain._member_type_, object)
1126
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001127 def test_no_such_enum_member(self):
1128 class Color(Enum):
1129 red = 1
1130 green = 2
1131 blue = 3
1132 with self.assertRaises(ValueError):
1133 Color(4)
1134 with self.assertRaises(KeyError):
1135 Color['chartreuse']
1136
1137 def test_new_repr(self):
1138 class Color(Enum):
1139 red = 1
1140 green = 2
1141 blue = 3
1142 def __repr__(self):
1143 return "don't you just love shades of %s?" % self.name
1144 self.assertEqual(
1145 repr(Color.blue),
1146 "don't you just love shades of blue?",
1147 )
1148
1149 def test_inherited_repr(self):
1150 class MyEnum(Enum):
1151 def __repr__(self):
1152 return "My name is %s." % self.name
1153 class MyIntEnum(int, MyEnum):
1154 this = 1
1155 that = 2
1156 theother = 3
1157 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1158
1159 def test_multiple_mixin_mro(self):
1160 class auto_enum(type(Enum)):
1161 def __new__(metacls, cls, bases, classdict):
1162 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001163 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001164 names = set(classdict._member_names)
1165 i = 0
1166 for k in classdict._member_names:
1167 v = classdict[k]
1168 if v is Ellipsis:
1169 v = i
1170 else:
1171 i = v
1172 i += 1
1173 temp[k] = v
1174 for k, v in classdict.items():
1175 if k not in names:
1176 temp[k] = v
1177 return super(auto_enum, metacls).__new__(
1178 metacls, cls, bases, temp)
1179
1180 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1181 pass
1182
1183 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1184 pass
1185
1186 class TestAutoNumber(AutoNumberedEnum):
1187 a = ...
1188 b = 3
1189 c = ...
1190
1191 class TestAutoInt(AutoIntEnum):
1192 a = ...
1193 b = 3
1194 c = ...
1195
1196 def test_subclasses_with_getnewargs(self):
1197 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001198 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001199 def __new__(cls, *args):
1200 _args = args
1201 name, *args = args
1202 if len(args) == 0:
1203 raise TypeError("name and value must be specified")
1204 self = int.__new__(cls, *args)
1205 self._intname = name
1206 self._args = _args
1207 return self
1208 def __getnewargs__(self):
1209 return self._args
1210 @property
1211 def __name__(self):
1212 return self._intname
1213 def __repr__(self):
1214 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001215 return "{}({!r}, {})".format(
1216 type(self).__name__,
1217 self.__name__,
1218 int.__repr__(self),
1219 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001220 def __str__(self):
1221 # str() is unchanged, even if it relies on the repr() fallback
1222 base = int
1223 base_str = base.__str__
1224 if base_str.__objclass__ is object:
1225 return base.__repr__(self)
1226 return base_str(self)
1227 # for simplicity, we only define one operator that
1228 # propagates expressions
1229 def __add__(self, other):
1230 temp = int(self) + int( other)
1231 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1232 return NamedInt(
1233 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001234 temp,
1235 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001236 else:
1237 return temp
1238
1239 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001240 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001241 x = ('the-x', 1)
1242 y = ('the-y', 2)
1243
Ethan Furman2aa27322013-07-19 19:35:56 -07001244
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001245 self.assertIs(NEI.__new__, Enum.__new__)
1246 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1247 globals()['NamedInt'] = NamedInt
1248 globals()['NEI'] = NEI
1249 NI5 = NamedInt('test', 5)
1250 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001251 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001252 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001253 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001254 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001255
Ethan Furmanca1b7942014-02-08 11:36:27 -08001256 def test_subclasses_with_getnewargs_ex(self):
1257 class NamedInt(int):
1258 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1259 def __new__(cls, *args):
1260 _args = args
1261 name, *args = args
1262 if len(args) == 0:
1263 raise TypeError("name and value must be specified")
1264 self = int.__new__(cls, *args)
1265 self._intname = name
1266 self._args = _args
1267 return self
1268 def __getnewargs_ex__(self):
1269 return self._args, {}
1270 @property
1271 def __name__(self):
1272 return self._intname
1273 def __repr__(self):
1274 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001275 return "{}({!r}, {})".format(
1276 type(self).__name__,
1277 self.__name__,
1278 int.__repr__(self),
1279 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001280 def __str__(self):
1281 # str() is unchanged, even if it relies on the repr() fallback
1282 base = int
1283 base_str = base.__str__
1284 if base_str.__objclass__ is object:
1285 return base.__repr__(self)
1286 return base_str(self)
1287 # for simplicity, we only define one operator that
1288 # propagates expressions
1289 def __add__(self, other):
1290 temp = int(self) + int( other)
1291 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1292 return NamedInt(
1293 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001294 temp,
1295 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001296 else:
1297 return temp
1298
1299 class NEI(NamedInt, Enum):
1300 __qualname__ = 'NEI' # needed for pickle protocol 4
1301 x = ('the-x', 1)
1302 y = ('the-y', 2)
1303
1304
1305 self.assertIs(NEI.__new__, Enum.__new__)
1306 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1307 globals()['NamedInt'] = NamedInt
1308 globals()['NEI'] = NEI
1309 NI5 = NamedInt('test', 5)
1310 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001311 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001312 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001313 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001314 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001315
1316 def test_subclasses_with_reduce(self):
1317 class NamedInt(int):
1318 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1319 def __new__(cls, *args):
1320 _args = args
1321 name, *args = args
1322 if len(args) == 0:
1323 raise TypeError("name and value must be specified")
1324 self = int.__new__(cls, *args)
1325 self._intname = name
1326 self._args = _args
1327 return self
1328 def __reduce__(self):
1329 return self.__class__, self._args
1330 @property
1331 def __name__(self):
1332 return self._intname
1333 def __repr__(self):
1334 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001335 return "{}({!r}, {})".format(
1336 type(self).__name__,
1337 self.__name__,
1338 int.__repr__(self),
1339 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001340 def __str__(self):
1341 # str() is unchanged, even if it relies on the repr() fallback
1342 base = int
1343 base_str = base.__str__
1344 if base_str.__objclass__ is object:
1345 return base.__repr__(self)
1346 return base_str(self)
1347 # for simplicity, we only define one operator that
1348 # propagates expressions
1349 def __add__(self, other):
1350 temp = int(self) + int( other)
1351 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1352 return NamedInt(
1353 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001354 temp,
1355 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001356 else:
1357 return temp
1358
1359 class NEI(NamedInt, Enum):
1360 __qualname__ = 'NEI' # needed for pickle protocol 4
1361 x = ('the-x', 1)
1362 y = ('the-y', 2)
1363
1364
1365 self.assertIs(NEI.__new__, Enum.__new__)
1366 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1367 globals()['NamedInt'] = NamedInt
1368 globals()['NEI'] = NEI
1369 NI5 = NamedInt('test', 5)
1370 self.assertEqual(NI5, 5)
1371 test_pickle_dump_load(self.assertEqual, NI5, 5)
1372 self.assertEqual(NEI.y.value, 2)
1373 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001374 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001375
1376 def test_subclasses_with_reduce_ex(self):
1377 class NamedInt(int):
1378 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1379 def __new__(cls, *args):
1380 _args = args
1381 name, *args = args
1382 if len(args) == 0:
1383 raise TypeError("name and value must be specified")
1384 self = int.__new__(cls, *args)
1385 self._intname = name
1386 self._args = _args
1387 return self
1388 def __reduce_ex__(self, proto):
1389 return self.__class__, self._args
1390 @property
1391 def __name__(self):
1392 return self._intname
1393 def __repr__(self):
1394 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001395 return "{}({!r}, {})".format(
1396 type(self).__name__,
1397 self.__name__,
1398 int.__repr__(self),
1399 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001400 def __str__(self):
1401 # str() is unchanged, even if it relies on the repr() fallback
1402 base = int
1403 base_str = base.__str__
1404 if base_str.__objclass__ is object:
1405 return base.__repr__(self)
1406 return base_str(self)
1407 # for simplicity, we only define one operator that
1408 # propagates expressions
1409 def __add__(self, other):
1410 temp = int(self) + int( other)
1411 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1412 return NamedInt(
1413 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001414 temp,
1415 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001416 else:
1417 return temp
1418
1419 class NEI(NamedInt, Enum):
1420 __qualname__ = 'NEI' # needed for pickle protocol 4
1421 x = ('the-x', 1)
1422 y = ('the-y', 2)
1423
Ethan Furmanca1b7942014-02-08 11:36:27 -08001424 self.assertIs(NEI.__new__, Enum.__new__)
1425 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1426 globals()['NamedInt'] = NamedInt
1427 globals()['NEI'] = NEI
1428 NI5 = NamedInt('test', 5)
1429 self.assertEqual(NI5, 5)
1430 test_pickle_dump_load(self.assertEqual, NI5, 5)
1431 self.assertEqual(NEI.y.value, 2)
1432 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001433 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001434
Ethan Furmandc870522014-02-18 12:37:12 -08001435 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001437 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001438 def __new__(cls, *args):
1439 _args = args
1440 name, *args = args
1441 if len(args) == 0:
1442 raise TypeError("name and value must be specified")
1443 self = int.__new__(cls, *args)
1444 self._intname = name
1445 self._args = _args
1446 return self
1447 @property
1448 def __name__(self):
1449 return self._intname
1450 def __repr__(self):
1451 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001452 return "{}({!r}, {})".format(
1453 type(self).__name__,
1454 self.__name__,
1455 int.__repr__(self),
1456 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001457 def __str__(self):
1458 # str() is unchanged, even if it relies on the repr() fallback
1459 base = int
1460 base_str = base.__str__
1461 if base_str.__objclass__ is object:
1462 return base.__repr__(self)
1463 return base_str(self)
1464 # for simplicity, we only define one operator that
1465 # propagates expressions
1466 def __add__(self, other):
1467 temp = int(self) + int( other)
1468 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1469 return NamedInt(
1470 '({0} + {1})'.format(self.__name__, other.__name__),
1471 temp )
1472 else:
1473 return temp
1474
1475 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001476 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477 x = ('the-x', 1)
1478 y = ('the-y', 2)
1479
1480 self.assertIs(NEI.__new__, Enum.__new__)
1481 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1482 globals()['NamedInt'] = NamedInt
1483 globals()['NEI'] = NEI
1484 NI5 = NamedInt('test', 5)
1485 self.assertEqual(NI5, 5)
1486 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001487 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1488 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001489
Ethan Furmandc870522014-02-18 12:37:12 -08001490 def test_subclasses_without_direct_pickle_support_using_name(self):
1491 class NamedInt(int):
1492 __qualname__ = 'NamedInt'
1493 def __new__(cls, *args):
1494 _args = args
1495 name, *args = args
1496 if len(args) == 0:
1497 raise TypeError("name and value must be specified")
1498 self = int.__new__(cls, *args)
1499 self._intname = name
1500 self._args = _args
1501 return self
1502 @property
1503 def __name__(self):
1504 return self._intname
1505 def __repr__(self):
1506 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001507 return "{}({!r}, {})".format(
1508 type(self).__name__,
1509 self.__name__,
1510 int.__repr__(self),
1511 )
Ethan Furmandc870522014-02-18 12:37:12 -08001512 def __str__(self):
1513 # str() is unchanged, even if it relies on the repr() fallback
1514 base = int
1515 base_str = base.__str__
1516 if base_str.__objclass__ is object:
1517 return base.__repr__(self)
1518 return base_str(self)
1519 # for simplicity, we only define one operator that
1520 # propagates expressions
1521 def __add__(self, other):
1522 temp = int(self) + int( other)
1523 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1524 return NamedInt(
1525 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001526 temp,
1527 )
Ethan Furmandc870522014-02-18 12:37:12 -08001528 else:
1529 return temp
1530
1531 class NEI(NamedInt, Enum):
1532 __qualname__ = 'NEI'
1533 x = ('the-x', 1)
1534 y = ('the-y', 2)
1535 def __reduce_ex__(self, proto):
1536 return getattr, (self.__class__, self._name_)
1537
1538 self.assertIs(NEI.__new__, Enum.__new__)
1539 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1540 globals()['NamedInt'] = NamedInt
1541 globals()['NEI'] = NEI
1542 NI5 = NamedInt('test', 5)
1543 self.assertEqual(NI5, 5)
1544 self.assertEqual(NEI.y.value, 2)
1545 test_pickle_dump_load(self.assertIs, NEI.y)
1546 test_pickle_dump_load(self.assertIs, NEI)
1547
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548 def test_tuple_subclass(self):
1549 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001550 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001551 first = (1, 'for the money')
1552 second = (2, 'for the show')
1553 third = (3, 'for the music')
1554 self.assertIs(type(SomeTuple.first), SomeTuple)
1555 self.assertIsInstance(SomeTuple.second, tuple)
1556 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1557 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001558 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001559
1560 def test_duplicate_values_give_unique_enum_items(self):
1561 class AutoNumber(Enum):
1562 first = ()
1563 second = ()
1564 third = ()
1565 def __new__(cls):
1566 value = len(cls.__members__) + 1
1567 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001568 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001569 return obj
1570 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001571 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001572 self.assertEqual(
1573 list(AutoNumber),
1574 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1575 )
1576 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001577 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001578 self.assertIs(AutoNumber(1), AutoNumber.first)
1579
1580 def test_inherited_new_from_enhanced_enum(self):
1581 class AutoNumber(Enum):
1582 def __new__(cls):
1583 value = len(cls.__members__) + 1
1584 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001585 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001586 return obj
1587 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001588 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001589 class Color(AutoNumber):
1590 red = ()
1591 green = ()
1592 blue = ()
1593 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1594 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1595
1596 def test_inherited_new_from_mixed_enum(self):
1597 class AutoNumber(IntEnum):
1598 def __new__(cls):
1599 value = len(cls.__members__) + 1
1600 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001601 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001602 return obj
1603 class Color(AutoNumber):
1604 red = ()
1605 green = ()
1606 blue = ()
1607 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1608 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1609
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001610 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001611 class OrdinaryEnum(Enum):
1612 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001613 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1614 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001615
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001616 def test_ordered_mixin(self):
1617 class OrderedEnum(Enum):
1618 def __ge__(self, other):
1619 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001620 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001621 return NotImplemented
1622 def __gt__(self, other):
1623 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001624 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001625 return NotImplemented
1626 def __le__(self, other):
1627 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001628 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001629 return NotImplemented
1630 def __lt__(self, other):
1631 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001632 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001633 return NotImplemented
1634 class Grade(OrderedEnum):
1635 A = 5
1636 B = 4
1637 C = 3
1638 D = 2
1639 F = 1
1640 self.assertGreater(Grade.A, Grade.B)
1641 self.assertLessEqual(Grade.F, Grade.C)
1642 self.assertLess(Grade.D, Grade.A)
1643 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001644 self.assertEqual(Grade.B, Grade.B)
1645 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001646
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001647 def test_extending2(self):
1648 class Shade(Enum):
1649 def shade(self):
1650 print(self.name)
1651 class Color(Shade):
1652 red = 1
1653 green = 2
1654 blue = 3
1655 with self.assertRaises(TypeError):
1656 class MoreColor(Color):
1657 cyan = 4
1658 magenta = 5
1659 yellow = 6
1660
1661 def test_extending3(self):
1662 class Shade(Enum):
1663 def shade(self):
1664 return self.name
1665 class Color(Shade):
1666 def hex(self):
1667 return '%s hexlified!' % self.value
1668 class MoreColor(Color):
1669 cyan = 4
1670 magenta = 5
1671 yellow = 6
1672 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1673
orlnub1230fb9fad2018-09-12 20:28:53 +03001674 def test_subclass_duplicate_name(self):
1675 class Base(Enum):
1676 def test(self):
1677 pass
1678 class Test(Base):
1679 test = 1
1680 self.assertIs(type(Test.test), Test)
1681
1682 def test_subclass_duplicate_name_dynamic(self):
1683 from types import DynamicClassAttribute
1684 class Base(Enum):
1685 @DynamicClassAttribute
1686 def test(self):
1687 return 'dynamic'
1688 class Test(Base):
1689 test = 1
1690 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001691 class Base2(Enum):
1692 @enum.property
1693 def flash(self):
1694 return 'flashy dynamic'
1695 class Test(Base2):
1696 flash = 1
1697 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001698
1699 def test_no_duplicates(self):
1700 class UniqueEnum(Enum):
1701 def __init__(self, *args):
1702 cls = self.__class__
1703 if any(self.value == e.value for e in cls):
1704 a = self.name
1705 e = cls(self.value).name
1706 raise ValueError(
1707 "aliases not allowed in UniqueEnum: %r --> %r"
1708 % (a, e)
1709 )
1710 class Color(UniqueEnum):
1711 red = 1
1712 green = 2
1713 blue = 3
1714 with self.assertRaises(ValueError):
1715 class Color(UniqueEnum):
1716 red = 1
1717 green = 2
1718 blue = 3
1719 grene = 2
1720
1721 def test_init(self):
1722 class Planet(Enum):
1723 MERCURY = (3.303e+23, 2.4397e6)
1724 VENUS = (4.869e+24, 6.0518e6)
1725 EARTH = (5.976e+24, 6.37814e6)
1726 MARS = (6.421e+23, 3.3972e6)
1727 JUPITER = (1.9e+27, 7.1492e7)
1728 SATURN = (5.688e+26, 6.0268e7)
1729 URANUS = (8.686e+25, 2.5559e7)
1730 NEPTUNE = (1.024e+26, 2.4746e7)
1731 def __init__(self, mass, radius):
1732 self.mass = mass # in kilograms
1733 self.radius = radius # in meters
1734 @property
1735 def surface_gravity(self):
1736 # universal gravitational constant (m3 kg-1 s-2)
1737 G = 6.67300E-11
1738 return G * self.mass / (self.radius * self.radius)
1739 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1740 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1741
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001742 def test_ignore(self):
1743 class Period(timedelta, Enum):
1744 '''
1745 different lengths of time
1746 '''
1747 def __new__(cls, value, period):
1748 obj = timedelta.__new__(cls, value)
1749 obj._value_ = value
1750 obj.period = period
1751 return obj
1752 _ignore_ = 'Period i'
1753 Period = vars()
1754 for i in range(13):
1755 Period['month_%d' % i] = i*30, 'month'
1756 for i in range(53):
1757 Period['week_%d' % i] = i*7, 'week'
1758 for i in range(32):
1759 Period['day_%d' % i] = i, 'day'
1760 OneDay = day_1
1761 OneWeek = week_1
1762 OneMonth = month_1
1763 self.assertFalse(hasattr(Period, '_ignore_'))
1764 self.assertFalse(hasattr(Period, 'Period'))
1765 self.assertFalse(hasattr(Period, 'i'))
1766 self.assertTrue(isinstance(Period.day_1, timedelta))
1767 self.assertTrue(Period.month_1 is Period.day_30)
1768 self.assertTrue(Period.week_4 is Period.day_28)
1769
Ethan Furman2aa27322013-07-19 19:35:56 -07001770 def test_nonhash_value(self):
1771 class AutoNumberInAList(Enum):
1772 def __new__(cls):
1773 value = [len(cls.__members__) + 1]
1774 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001775 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001776 return obj
1777 class ColorInAList(AutoNumberInAList):
1778 red = ()
1779 green = ()
1780 blue = ()
1781 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001782 for enum, value in zip(ColorInAList, range(3)):
1783 value += 1
1784 self.assertEqual(enum.value, [value])
1785 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001786
Ethan Furmanb41803e2013-07-25 13:50:45 -07001787 def test_conflicting_types_resolved_in_new(self):
1788 class LabelledIntEnum(int, Enum):
1789 def __new__(cls, *args):
1790 value, label = args
1791 obj = int.__new__(cls, value)
1792 obj.label = label
1793 obj._value_ = value
1794 return obj
1795
1796 class LabelledList(LabelledIntEnum):
1797 unprocessed = (1, "Unprocessed")
1798 payment_complete = (2, "Payment Complete")
1799
1800 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1801 self.assertEqual(LabelledList.unprocessed, 1)
1802 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001803
Ethan Furmanc16595e2016-09-10 23:36:59 -07001804 def test_auto_number(self):
1805 class Color(Enum):
1806 red = auto()
1807 blue = auto()
1808 green = auto()
1809
1810 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1811 self.assertEqual(Color.red.value, 1)
1812 self.assertEqual(Color.blue.value, 2)
1813 self.assertEqual(Color.green.value, 3)
1814
1815 def test_auto_name(self):
1816 class Color(Enum):
1817 def _generate_next_value_(name, start, count, last):
1818 return name
1819 red = auto()
1820 blue = auto()
1821 green = auto()
1822
1823 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1824 self.assertEqual(Color.red.value, 'red')
1825 self.assertEqual(Color.blue.value, 'blue')
1826 self.assertEqual(Color.green.value, 'green')
1827
1828 def test_auto_name_inherit(self):
1829 class AutoNameEnum(Enum):
1830 def _generate_next_value_(name, start, count, last):
1831 return name
1832 class Color(AutoNameEnum):
1833 red = auto()
1834 blue = auto()
1835 green = auto()
1836
1837 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1838 self.assertEqual(Color.red.value, 'red')
1839 self.assertEqual(Color.blue.value, 'blue')
1840 self.assertEqual(Color.green.value, 'green')
1841
1842 def test_auto_garbage(self):
1843 class Color(Enum):
1844 red = 'red'
1845 blue = auto()
1846 self.assertEqual(Color.blue.value, 1)
1847
1848 def test_auto_garbage_corrected(self):
1849 class Color(Enum):
1850 red = 'red'
1851 blue = 2
1852 green = auto()
1853
1854 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1855 self.assertEqual(Color.red.value, 'red')
1856 self.assertEqual(Color.blue.value, 2)
1857 self.assertEqual(Color.green.value, 3)
1858
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001859 def test_auto_order(self):
1860 with self.assertRaises(TypeError):
1861 class Color(Enum):
1862 red = auto()
1863 green = auto()
1864 blue = auto()
1865 def _generate_next_value_(name, start, count, last):
1866 return name
1867
Ethan Furmanfc23a942020-09-16 12:37:54 -07001868 def test_auto_order_wierd(self):
1869 weird_auto = auto()
1870 weird_auto.value = 'pathological case'
1871 class Color(Enum):
1872 red = weird_auto
1873 def _generate_next_value_(name, start, count, last):
1874 return name
1875 blue = auto()
1876 self.assertEqual(list(Color), [Color.red, Color.blue])
1877 self.assertEqual(Color.red.value, 'pathological case')
1878 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001879
Ethan Furman3515dcc2016-09-18 13:15:41 -07001880 def test_duplicate_auto(self):
1881 class Dupes(Enum):
1882 first = primero = auto()
1883 second = auto()
1884 third = auto()
1885 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1886
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001887 def test_default_missing(self):
1888 class Color(Enum):
1889 RED = 1
1890 GREEN = 2
1891 BLUE = 3
1892 try:
1893 Color(7)
1894 except ValueError as exc:
1895 self.assertTrue(exc.__context__ is None)
1896 else:
1897 raise Exception('Exception not raised.')
1898
Ethan Furman019f0a02018-09-12 11:43:34 -07001899 def test_missing(self):
1900 class Color(Enum):
1901 red = 1
1902 green = 2
1903 blue = 3
1904 @classmethod
1905 def _missing_(cls, item):
1906 if item == 'three':
1907 return cls.blue
1908 elif item == 'bad return':
1909 # trigger internal error
1910 return 5
1911 elif item == 'error out':
1912 raise ZeroDivisionError
1913 else:
1914 # trigger not found
1915 return None
1916 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001917 try:
1918 Color(7)
1919 except ValueError as exc:
1920 self.assertTrue(exc.__context__ is None)
1921 else:
1922 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001923 try:
1924 Color('bad return')
1925 except TypeError as exc:
1926 self.assertTrue(isinstance(exc.__context__, ValueError))
1927 else:
1928 raise Exception('Exception not raised.')
1929 try:
1930 Color('error out')
1931 except ZeroDivisionError as exc:
1932 self.assertTrue(isinstance(exc.__context__, ValueError))
1933 else:
1934 raise Exception('Exception not raised.')
1935
Ethan Furman5bdab642018-09-21 19:03:09 -07001936 def test_multiple_mixin(self):
1937 class MaxMixin:
1938 @classproperty
1939 def MAX(cls):
1940 max = len(cls)
1941 cls.MAX = max
1942 return max
1943 class StrMixin:
1944 def __str__(self):
1945 return self._name_.lower()
1946 class SomeEnum(Enum):
1947 def behavior(self):
1948 return 'booyah'
1949 class AnotherEnum(Enum):
1950 def behavior(self):
1951 return 'nuhuh!'
1952 def social(self):
1953 return "what's up?"
1954 class Color(MaxMixin, Enum):
1955 RED = auto()
1956 GREEN = auto()
1957 BLUE = auto()
1958 self.assertEqual(Color.RED.value, 1)
1959 self.assertEqual(Color.GREEN.value, 2)
1960 self.assertEqual(Color.BLUE.value, 3)
1961 self.assertEqual(Color.MAX, 3)
1962 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1963 class Color(MaxMixin, StrMixin, Enum):
1964 RED = auto()
1965 GREEN = auto()
1966 BLUE = auto()
1967 self.assertEqual(Color.RED.value, 1)
1968 self.assertEqual(Color.GREEN.value, 2)
1969 self.assertEqual(Color.BLUE.value, 3)
1970 self.assertEqual(Color.MAX, 3)
1971 self.assertEqual(str(Color.BLUE), 'blue')
1972 class Color(StrMixin, MaxMixin, Enum):
1973 RED = auto()
1974 GREEN = auto()
1975 BLUE = auto()
1976 self.assertEqual(Color.RED.value, 1)
1977 self.assertEqual(Color.GREEN.value, 2)
1978 self.assertEqual(Color.BLUE.value, 3)
1979 self.assertEqual(Color.MAX, 3)
1980 self.assertEqual(str(Color.BLUE), 'blue')
1981 class CoolColor(StrMixin, SomeEnum, Enum):
1982 RED = auto()
1983 GREEN = auto()
1984 BLUE = auto()
1985 self.assertEqual(CoolColor.RED.value, 1)
1986 self.assertEqual(CoolColor.GREEN.value, 2)
1987 self.assertEqual(CoolColor.BLUE.value, 3)
1988 self.assertEqual(str(CoolColor.BLUE), 'blue')
1989 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1990 class CoolerColor(StrMixin, AnotherEnum, Enum):
1991 RED = auto()
1992 GREEN = auto()
1993 BLUE = auto()
1994 self.assertEqual(CoolerColor.RED.value, 1)
1995 self.assertEqual(CoolerColor.GREEN.value, 2)
1996 self.assertEqual(CoolerColor.BLUE.value, 3)
1997 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1998 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1999 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2000 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2001 RED = auto()
2002 GREEN = auto()
2003 BLUE = auto()
2004 self.assertEqual(CoolestColor.RED.value, 1)
2005 self.assertEqual(CoolestColor.GREEN.value, 2)
2006 self.assertEqual(CoolestColor.BLUE.value, 3)
2007 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2008 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2009 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2010 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2011 RED = auto()
2012 GREEN = auto()
2013 BLUE = auto()
2014 self.assertEqual(ConfusedColor.RED.value, 1)
2015 self.assertEqual(ConfusedColor.GREEN.value, 2)
2016 self.assertEqual(ConfusedColor.BLUE.value, 3)
2017 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2018 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2019 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2020 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2021 RED = auto()
2022 GREEN = auto()
2023 BLUE = auto()
2024 self.assertEqual(ReformedColor.RED.value, 1)
2025 self.assertEqual(ReformedColor.GREEN.value, 2)
2026 self.assertEqual(ReformedColor.BLUE.value, 3)
2027 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2028 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2029 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2030 self.assertTrue(issubclass(ReformedColor, int))
2031
Ethan Furmancd453852018-10-05 23:29:36 -07002032 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002033 @unique
2034 class Decision1(StrEnum):
2035 REVERT = "REVERT"
2036 REVERT_ALL = "REVERT_ALL"
2037 RETRY = "RETRY"
2038 class MyEnum(StrEnum):
2039 pass
2040 @unique
2041 class Decision2(MyEnum):
2042 REVERT = "REVERT"
2043 REVERT_ALL = "REVERT_ALL"
2044 RETRY = "RETRY"
2045
Ethan Furmanc2667362020-12-07 00:17:31 -08002046 def test_multiple_mixin_inherited(self):
2047 class MyInt(int):
2048 def __new__(cls, value):
2049 return super().__new__(cls, value)
2050
2051 class HexMixin:
2052 def __repr__(self):
2053 return hex(self)
2054
2055 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2056 pass
2057
2058 class Foo(MyIntEnum):
2059 TEST = 1
2060 self.assertTrue(isinstance(Foo.TEST, MyInt))
2061 self.assertEqual(repr(Foo.TEST), "0x1")
2062
2063 class Fee(MyIntEnum):
2064 TEST = 1
2065 def __new__(cls, value):
2066 value += 1
2067 member = int.__new__(cls, value)
2068 member._value_ = value
2069 return member
2070 self.assertEqual(Fee.TEST, 2)
2071
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002072 def test_empty_globals(self):
2073 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2074 # when using compile and exec because f_globals is empty
2075 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2076 code = compile(code, "<string>", "exec")
2077 global_ns = {}
2078 local_ls = {}
2079 exec(code, global_ns, local_ls)
2080
Ethan Furman0063ff42020-09-21 17:23:13 -07002081 def test_strenum(self):
2082 class GoodStrEnum(StrEnum):
2083 one = '1'
2084 two = '2'
2085 three = b'3', 'ascii'
2086 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002087 self.assertEqual(GoodStrEnum.one, '1')
2088 self.assertEqual(str(GoodStrEnum.one), '1')
2089 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2090 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2091 #
2092 class DumbMixin:
2093 def __str__(self):
2094 return "don't do this"
2095 class DumbStrEnum(DumbMixin, StrEnum):
2096 five = '5'
2097 six = '6'
2098 seven = '7'
2099 self.assertEqual(DumbStrEnum.seven, '7')
2100 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2101 #
2102 class EnumMixin(Enum):
2103 def hello(self):
2104 print('hello from %s' % (self, ))
2105 class HelloEnum(EnumMixin, StrEnum):
2106 eight = '8'
2107 self.assertEqual(HelloEnum.eight, '8')
2108 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2109 #
2110 class GoodbyeMixin:
2111 def goodbye(self):
2112 print('%s wishes you a fond farewell')
2113 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2114 nine = '9'
2115 self.assertEqual(GoodbyeEnum.nine, '9')
2116 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2117 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002118 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2119 class FirstFailedStrEnum(StrEnum):
2120 one = 1
2121 two = '2'
2122 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2123 class SecondFailedStrEnum(StrEnum):
2124 one = '1'
2125 two = 2,
2126 three = '3'
2127 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2128 class ThirdFailedStrEnum(StrEnum):
2129 one = '1'
2130 two = 2
2131 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2132 class ThirdFailedStrEnum(StrEnum):
2133 one = '1'
2134 two = b'2', sys.getdefaultencoding
2135 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2136 class ThirdFailedStrEnum(StrEnum):
2137 one = '1'
2138 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002139
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002140 def test_missing_value_error(self):
2141 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2142 class Combined(str, Enum):
2143 #
2144 def __new__(cls, value, sequence):
2145 enum = str.__new__(cls, value)
2146 if '(' in value:
2147 fis_name, segment = value.split('(', 1)
2148 segment = segment.strip(' )')
2149 else:
2150 fis_name = value
2151 segment = None
2152 enum.fis_name = fis_name
2153 enum.segment = segment
2154 enum.sequence = sequence
2155 return enum
2156 #
2157 def __repr__(self):
2158 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2159 #
2160 key_type = 'An$(1,2)', 0
2161 company_id = 'An$(3,2)', 1
2162 code = 'An$(5,1)', 2
2163 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002164
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002165 @unittest.skipUnless(
2166 sys.version_info[:2] == (3, 9),
2167 'private variables are now normal attributes',
2168 )
2169 def test_warning_for_private_variables(self):
2170 with self.assertWarns(DeprecationWarning):
2171 class Private(Enum):
2172 __corporal = 'Radar'
2173 self.assertEqual(Private._Private__corporal.value, 'Radar')
2174 try:
2175 with self.assertWarns(DeprecationWarning):
2176 class Private(Enum):
2177 __major_ = 'Hoolihan'
2178 except ValueError:
2179 pass
2180
2181 def test_private_variable_is_normal_attribute(self):
2182 class Private(Enum):
2183 __corporal = 'Radar'
2184 __major_ = 'Hoolihan'
2185 self.assertEqual(Private._Private__corporal, 'Radar')
2186 self.assertEqual(Private._Private__major_, 'Hoolihan')
2187
Ethan Furmand65b9032021-02-08 17:32:38 -08002188 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002189 sys.version_info[:2] < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002190 'member-member access now raises an exception',
2191 )
2192 def test_warning_for_member_from_member_access(self):
2193 with self.assertWarns(DeprecationWarning):
2194 class Di(Enum):
2195 YES = 1
2196 NO = 0
2197 nope = Di.YES.NO
2198 self.assertIs(Di.NO, nope)
2199
2200 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002201 sys.version_info[:2] >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002202 'member-member access currently issues a warning',
2203 )
2204 def test_exception_for_member_from_member_access(self):
2205 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2206 class Di(Enum):
2207 YES = 1
2208 NO = 0
2209 nope = Di.YES.NO
2210
Ethan Furmanefb13be2020-12-10 12:20:06 -08002211 def test_strenum_auto(self):
2212 class Strings(StrEnum):
2213 ONE = auto()
2214 TWO = auto()
2215 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2216
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002217
Ethan Furmana6582872020-12-10 13:07:00 -08002218 def test_dynamic_members_with_static_methods(self):
2219 #
2220 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2221 class Foo(Enum):
2222 vars().update({
2223 k: v
2224 for k, v in foo_defines.items()
2225 if k.startswith('FOO_')
2226 })
2227 def upper(self):
2228 return self.value.upper()
2229 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2230 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2231 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2232 #
2233 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2234 class FooBar(Enum):
2235 vars().update({
2236 k: v
2237 for k, v in foo_defines.items()
2238 if k.startswith('FOO_')
2239 },
2240 **{'FOO_CAT': 'small'},
2241 )
2242 def upper(self):
2243 return self.value.upper()
2244
2245
Ethan Furmane8e61272016-08-20 07:19:31 -07002246class TestOrder(unittest.TestCase):
2247
2248 def test_same_members(self):
2249 class Color(Enum):
2250 _order_ = 'red green blue'
2251 red = 1
2252 green = 2
2253 blue = 3
2254
2255 def test_same_members_with_aliases(self):
2256 class Color(Enum):
2257 _order_ = 'red green blue'
2258 red = 1
2259 green = 2
2260 blue = 3
2261 verde = green
2262
2263 def test_same_members_wrong_order(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 blue = 3
2269 green = 2
2270
2271 def test_order_has_extra_members(self):
2272 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2273 class Color(Enum):
2274 _order_ = 'red green blue purple'
2275 red = 1
2276 green = 2
2277 blue = 3
2278
2279 def test_order_has_extra_members_with_aliases(self):
2280 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2281 class Color(Enum):
2282 _order_ = 'red green blue purple'
2283 red = 1
2284 green = 2
2285 blue = 3
2286 verde = green
2287
2288 def test_enum_has_extra_members(self):
2289 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2290 class Color(Enum):
2291 _order_ = 'red green blue'
2292 red = 1
2293 green = 2
2294 blue = 3
2295 purple = 4
2296
2297 def test_enum_has_extra_members_with_aliases(self):
2298 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2299 class Color(Enum):
2300 _order_ = 'red green blue'
2301 red = 1
2302 green = 2
2303 blue = 3
2304 purple = 4
2305 verde = green
2306
2307
Ethan Furman65a5a472016-09-01 23:55:19 -07002308class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002309 """Tests of the Flags."""
2310
Ethan Furman65a5a472016-09-01 23:55:19 -07002311 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002312 R, W, X = 4, 2, 1
2313
Ethan Furman65a5a472016-09-01 23:55:19 -07002314 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002315 RO = 0
2316 WO = 1
2317 RW = 2
2318 AC = 3
2319 CE = 1<<19
2320
Rahul Jha94306522018-09-10 23:51:04 +05302321 class Color(Flag):
2322 BLACK = 0
2323 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002324 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302325 GREEN = 2
2326 BLUE = 4
2327 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002328 WHITE = RED|GREEN|BLUE
2329 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302330
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002331 def test_str(self):
2332 Perm = self.Perm
2333 self.assertEqual(str(Perm.R), 'Perm.R')
2334 self.assertEqual(str(Perm.W), 'Perm.W')
2335 self.assertEqual(str(Perm.X), 'Perm.X')
2336 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2337 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002338 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002339 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2340 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2341 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2342 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002343 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002344 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2345
2346 Open = self.Open
2347 self.assertEqual(str(Open.RO), 'Open.RO')
2348 self.assertEqual(str(Open.WO), 'Open.WO')
2349 self.assertEqual(str(Open.AC), 'Open.AC')
2350 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002351 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2352 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2353 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002354 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002355 self.assertEqual(str(~Open.CE), 'Open.AC')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002356 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2357 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2358
2359 def test_repr(self):
2360 Perm = self.Perm
2361 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2362 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2363 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2364 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2365 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002366 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002367 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2368 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2369 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2370 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002371 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002372 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2373
2374 Open = self.Open
2375 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2376 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2377 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2378 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002379 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2380 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2381 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002382 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002383 self.assertEqual(repr(~Open.CE), '<Open.AC: 3>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002384 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2385 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2386
Ethan Furman37440ee2020-12-08 11:14:10 -08002387 def test_format(self):
2388 Perm = self.Perm
2389 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2390 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2391
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002392 def test_or(self):
2393 Perm = self.Perm
2394 for i in Perm:
2395 for j in Perm:
2396 self.assertEqual((i | j), Perm(i.value | j.value))
2397 self.assertEqual((i | j).value, i.value | j.value)
2398 self.assertIs(type(i | j), Perm)
2399 for i in Perm:
2400 self.assertIs(i | i, i)
2401 Open = self.Open
2402 self.assertIs(Open.RO | Open.CE, Open.CE)
2403
2404 def test_and(self):
2405 Perm = self.Perm
2406 RW = Perm.R | Perm.W
2407 RX = Perm.R | Perm.X
2408 WX = Perm.W | Perm.X
2409 RWX = Perm.R | Perm.W | Perm.X
2410 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2411 for i in values:
2412 for j in values:
2413 self.assertEqual((i & j).value, i.value & j.value)
2414 self.assertIs(type(i & j), Perm)
2415 for i in Perm:
2416 self.assertIs(i & i, i)
2417 self.assertIs(i & RWX, i)
2418 self.assertIs(RWX & i, i)
2419 Open = self.Open
2420 self.assertIs(Open.RO & Open.CE, Open.RO)
2421
2422 def test_xor(self):
2423 Perm = self.Perm
2424 for i in Perm:
2425 for j in Perm:
2426 self.assertEqual((i ^ j).value, i.value ^ j.value)
2427 self.assertIs(type(i ^ j), Perm)
2428 for i in Perm:
2429 self.assertIs(i ^ Perm(0), i)
2430 self.assertIs(Perm(0) ^ i, i)
2431 Open = self.Open
2432 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2433 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2434
2435 def test_invert(self):
2436 Perm = self.Perm
2437 RW = Perm.R | Perm.W
2438 RX = Perm.R | Perm.X
2439 WX = Perm.W | Perm.X
2440 RWX = Perm.R | Perm.W | Perm.X
2441 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2442 for i in values:
2443 self.assertIs(type(~i), Perm)
2444 self.assertEqual(~~i, i)
2445 for i in Perm:
2446 self.assertIs(~~i, i)
2447 Open = self.Open
2448 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2449 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2450
Ethan Furman25d94bb2016-09-02 16:32:32 -07002451 def test_bool(self):
2452 Perm = self.Perm
2453 for f in Perm:
2454 self.assertTrue(f)
2455 Open = self.Open
2456 for f in Open:
2457 self.assertEqual(bool(f.value), bool(f))
2458
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002459 def test_boundary(self):
2460 self.assertIs(enum.Flag._boundary_, STRICT)
2461 class Iron(Flag, boundary=STRICT):
2462 ONE = 1
2463 TWO = 2
2464 EIGHT = 8
2465 self.assertIs(Iron._boundary_, STRICT)
2466 #
2467 class Water(Flag, boundary=CONFORM):
2468 ONE = 1
2469 TWO = 2
2470 EIGHT = 8
2471 self.assertIs(Water._boundary_, CONFORM)
2472 #
2473 class Space(Flag, boundary=EJECT):
2474 ONE = 1
2475 TWO = 2
2476 EIGHT = 8
2477 self.assertIs(Space._boundary_, EJECT)
2478 #
2479 class Bizarre(Flag, boundary=KEEP):
2480 b = 3
2481 c = 4
2482 d = 6
2483 #
2484 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
2485 self.assertIs(Water(7), Water.ONE|Water.TWO)
2486 self.assertIs(Water(~9), Water.TWO)
2487 self.assertEqual(Space(7), 7)
2488 self.assertTrue(type(Space(7)) is int)
2489 self.assertEqual(list(Bizarre), [Bizarre.c])
2490 self.assertIs(Bizarre(3), Bizarre.b)
2491 self.assertIs(Bizarre(6), Bizarre.d)
2492
2493 def test_iter(self):
2494 Color = self.Color
2495 Open = self.Open
2496 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2497 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2498
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002499 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002500 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002501 lst = list(Perm)
2502 self.assertEqual(len(lst), len(Perm))
2503 self.assertEqual(len(Perm), 3, Perm)
2504 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2505 for i, n in enumerate('R W X'.split()):
2506 v = 1<<i
2507 e = Perm(v)
2508 self.assertEqual(e.value, v)
2509 self.assertEqual(type(e.value), int)
2510 self.assertEqual(e.name, n)
2511 self.assertIn(e, Perm)
2512 self.assertIs(type(e), Perm)
2513
2514 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002515 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002516 lst = list(Perm)
2517 self.assertEqual(len(lst), len(Perm))
2518 self.assertEqual(len(Perm), 3, Perm)
2519 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2520 for i, n in enumerate('R W X'.split()):
2521 v = 8<<i
2522 e = Perm(v)
2523 self.assertEqual(e.value, v)
2524 self.assertEqual(type(e.value), int)
2525 self.assertEqual(e.name, n)
2526 self.assertIn(e, Perm)
2527 self.assertIs(type(e), Perm)
2528
2529 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002530 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002531 lst = list(Perm)
2532 self.assertEqual(len(lst), len(Perm))
2533 self.assertEqual(len(Perm), 3, Perm)
2534 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2535 for i, n in enumerate('R W X'.split()):
2536 v = 1<<i
2537 e = Perm(v)
2538 self.assertEqual(e.value, v)
2539 self.assertEqual(type(e.value), int)
2540 self.assertEqual(e.name, n)
2541 self.assertIn(e, Perm)
2542 self.assertIs(type(e), Perm)
2543
2544 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002545 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002546 lst = list(Perm)
2547 self.assertEqual(len(lst), len(Perm))
2548 self.assertEqual(len(Perm), 3, Perm)
2549 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2550 for i, n in enumerate('R W X'.split()):
2551 v = 1<<(2*i+1)
2552 e = Perm(v)
2553 self.assertEqual(e.value, v)
2554 self.assertEqual(type(e.value), int)
2555 self.assertEqual(e.name, n)
2556 self.assertIn(e, Perm)
2557 self.assertIs(type(e), Perm)
2558
2559 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002560 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002561 lst = list(Perm)
2562 self.assertEqual(len(lst), len(Perm))
2563 self.assertEqual(len(Perm), 3, Perm)
2564 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2565 for i, n in enumerate('R W X'.split()):
2566 v = 1<<(2*i+1)
2567 e = Perm(v)
2568 self.assertEqual(e.value, v)
2569 self.assertEqual(type(e.value), int)
2570 self.assertEqual(e.name, n)
2571 self.assertIn(e, Perm)
2572 self.assertIs(type(e), Perm)
2573
Ethan Furman65a5a472016-09-01 23:55:19 -07002574 def test_pickle(self):
2575 if isinstance(FlagStooges, Exception):
2576 raise FlagStooges
2577 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2578 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002579
Rahul Jha94306522018-09-10 23:51:04 +05302580 def test_contains(self):
2581 Open = self.Open
2582 Color = self.Color
2583 self.assertFalse(Color.BLACK in Open)
2584 self.assertFalse(Open.RO in Color)
2585 with self.assertRaises(TypeError):
2586 'BLACK' in Color
2587 with self.assertRaises(TypeError):
2588 'RO' in Open
2589 with self.assertRaises(TypeError):
2590 1 in Color
2591 with self.assertRaises(TypeError):
2592 1 in Open
2593
2594 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002595 Perm = self.Perm
2596 R, W, X = Perm
2597 RW = R | W
2598 RX = R | X
2599 WX = W | X
2600 RWX = R | W | X
2601 self.assertTrue(R in RW)
2602 self.assertTrue(R in RX)
2603 self.assertTrue(R in RWX)
2604 self.assertTrue(W in RW)
2605 self.assertTrue(W in WX)
2606 self.assertTrue(W in RWX)
2607 self.assertTrue(X in RX)
2608 self.assertTrue(X in WX)
2609 self.assertTrue(X in RWX)
2610 self.assertFalse(R in WX)
2611 self.assertFalse(W in RX)
2612 self.assertFalse(X in RW)
2613
Ethan Furman7219e272020-09-16 13:01:00 -07002614 def test_member_iter(self):
2615 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002616 self.assertEqual(list(Color.BLACK), [])
2617 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002618 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2619 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002620 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2621 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2622
2623 def test_member_length(self):
2624 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2625 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2626 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2627 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2628
2629 def test_number_reset_and_order_cleanup(self):
2630 class Confused(Flag):
2631 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2632 ONE = auto()
2633 TWO = auto()
2634 FOUR = auto()
2635 DOS = 2
2636 EIGHT = auto()
2637 SIXTEEN = auto()
2638 self.assertEqual(
2639 list(Confused),
2640 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2641 self.assertIs(Confused.TWO, Confused.DOS)
2642 self.assertEqual(Confused.DOS._value_, 2)
2643 self.assertEqual(Confused.EIGHT._value_, 8)
2644 self.assertEqual(Confused.SIXTEEN._value_, 16)
2645
2646 def test_aliases(self):
2647 Color = self.Color
2648 self.assertEqual(Color(1).name, 'RED')
2649 self.assertEqual(Color['ROJO'].name, 'RED')
2650 self.assertEqual(Color(7).name, 'WHITE')
2651 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2652 self.assertIs(Color.BLANCO, Color.WHITE)
2653 Open = self.Open
2654 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002655
Ethan Furmanc16595e2016-09-10 23:36:59 -07002656 def test_auto_number(self):
2657 class Color(Flag):
2658 red = auto()
2659 blue = auto()
2660 green = auto()
2661
2662 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2663 self.assertEqual(Color.red.value, 1)
2664 self.assertEqual(Color.blue.value, 2)
2665 self.assertEqual(Color.green.value, 4)
2666
2667 def test_auto_number_garbage(self):
2668 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2669 class Color(Flag):
2670 red = 'not an int'
2671 blue = auto()
2672
Ethan Furman3515dcc2016-09-18 13:15:41 -07002673 def test_duplicate_auto(self):
2674 class Dupes(Enum):
2675 first = primero = auto()
2676 second = auto()
2677 third = auto()
2678 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2679
2680 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002681 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2682 class Bizarre(Flag):
2683 b = 3
2684 c = 4
2685 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002686
Ethan Furman5bdab642018-09-21 19:03:09 -07002687 def test_multiple_mixin(self):
2688 class AllMixin:
2689 @classproperty
2690 def ALL(cls):
2691 members = list(cls)
2692 all_value = None
2693 if members:
2694 all_value = members[0]
2695 for member in members[1:]:
2696 all_value |= member
2697 cls.ALL = all_value
2698 return all_value
2699 class StrMixin:
2700 def __str__(self):
2701 return self._name_.lower()
2702 class Color(AllMixin, Flag):
2703 RED = auto()
2704 GREEN = auto()
2705 BLUE = auto()
2706 self.assertEqual(Color.RED.value, 1)
2707 self.assertEqual(Color.GREEN.value, 2)
2708 self.assertEqual(Color.BLUE.value, 4)
2709 self.assertEqual(Color.ALL.value, 7)
2710 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2711 class Color(AllMixin, StrMixin, Flag):
2712 RED = auto()
2713 GREEN = auto()
2714 BLUE = auto()
2715 self.assertEqual(Color.RED.value, 1)
2716 self.assertEqual(Color.GREEN.value, 2)
2717 self.assertEqual(Color.BLUE.value, 4)
2718 self.assertEqual(Color.ALL.value, 7)
2719 self.assertEqual(str(Color.BLUE), 'blue')
2720 class Color(StrMixin, AllMixin, Flag):
2721 RED = auto()
2722 GREEN = auto()
2723 BLUE = auto()
2724 self.assertEqual(Color.RED.value, 1)
2725 self.assertEqual(Color.GREEN.value, 2)
2726 self.assertEqual(Color.BLUE.value, 4)
2727 self.assertEqual(Color.ALL.value, 7)
2728 self.assertEqual(str(Color.BLUE), 'blue')
2729
Hai Shie80697d2020-05-28 06:10:27 +08002730 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002731 def test_unique_composite(self):
2732 # override __eq__ to be identity only
2733 class TestFlag(Flag):
2734 one = auto()
2735 two = auto()
2736 three = auto()
2737 four = auto()
2738 five = auto()
2739 six = auto()
2740 seven = auto()
2741 eight = auto()
2742 def __eq__(self, other):
2743 return self is other
2744 def __hash__(self):
2745 return hash(self._value_)
2746 # have multiple threads competing to complete the composite members
2747 seen = set()
2748 failed = False
2749 def cycle_enum():
2750 nonlocal failed
2751 try:
2752 for i in range(256):
2753 seen.add(TestFlag(i))
2754 except Exception:
2755 failed = True
2756 threads = [
2757 threading.Thread(target=cycle_enum)
2758 for _ in range(8)
2759 ]
Hai Shie80697d2020-05-28 06:10:27 +08002760 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002761 pass
2762 # check that only 248 members were created
2763 self.assertFalse(
2764 failed,
2765 'at least one thread failed while creating composite members')
2766 self.assertEqual(256, len(seen), 'too many composite members created')
2767
Ethan Furman6bd94de2020-12-09 16:41:22 -08002768 def test_init_subclass(self):
2769 class MyEnum(Flag):
2770 def __init_subclass__(cls, **kwds):
2771 super().__init_subclass__(**kwds)
2772 self.assertFalse(cls.__dict__.get('_test', False))
2773 cls._test1 = 'MyEnum'
2774 #
2775 class TheirEnum(MyEnum):
2776 def __init_subclass__(cls, **kwds):
2777 super(TheirEnum, cls).__init_subclass__(**kwds)
2778 cls._test2 = 'TheirEnum'
2779 class WhoseEnum(TheirEnum):
2780 def __init_subclass__(cls, **kwds):
2781 pass
2782 class NoEnum(WhoseEnum):
2783 ONE = 1
2784 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2785 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2786 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2787 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2788 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2789 #
2790 class OurEnum(MyEnum):
2791 def __init_subclass__(cls, **kwds):
2792 cls._test2 = 'OurEnum'
2793 class WhereEnum(OurEnum):
2794 def __init_subclass__(cls, **kwds):
2795 pass
2796 class NeverEnum(WhereEnum):
2797 ONE = 1
2798 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2799 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2800 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2801 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2802 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2803
Ethan Furmanc16595e2016-09-10 23:36:59 -07002804
Ethan Furman65a5a472016-09-01 23:55:19 -07002805class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002806 """Tests of the IntFlags."""
2807
Ethan Furman65a5a472016-09-01 23:55:19 -07002808 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002809 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002810 W = 1 << 1
2811 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002812
Ethan Furman65a5a472016-09-01 23:55:19 -07002813 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002814 RO = 0
2815 WO = 1
2816 RW = 2
2817 AC = 3
2818 CE = 1<<19
2819
Rahul Jha94306522018-09-10 23:51:04 +05302820 class Color(IntFlag):
2821 BLACK = 0
2822 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002823 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302824 GREEN = 2
2825 BLUE = 4
2826 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002827 WHITE = RED|GREEN|BLUE
2828 BLANCO = RED|GREEN|BLUE
2829
2830 class Skip(IntFlag):
2831 FIRST = 1
2832 SECOND = 2
2833 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302834
Ethan Furman3515dcc2016-09-18 13:15:41 -07002835 def test_type(self):
2836 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002837 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002838 Open = self.Open
2839 for f in Perm:
2840 self.assertTrue(isinstance(f, Perm))
2841 self.assertEqual(f, f.value)
2842 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2843 self.assertEqual(Perm.W | Perm.X, 3)
2844 for f in Open:
2845 self.assertTrue(isinstance(f, Open))
2846 self.assertEqual(f, f.value)
2847 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2848 self.assertEqual(Open.WO | Open.RW, 3)
2849
2850
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002851 def test_str(self):
2852 Perm = self.Perm
2853 self.assertEqual(str(Perm.R), 'Perm.R')
2854 self.assertEqual(str(Perm.W), 'Perm.W')
2855 self.assertEqual(str(Perm.X), 'Perm.X')
2856 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2857 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002858 self.assertEqual(str(Perm.R | 8), '12')
2859 self.assertEqual(str(Perm(0)), 'Perm(0)')
2860 self.assertEqual(str(Perm(8)), '8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002861 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2862 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2863 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2864 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002865 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2866 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002867 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002868 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002869
2870 Open = self.Open
2871 self.assertEqual(str(Open.RO), 'Open.RO')
2872 self.assertEqual(str(Open.WO), 'Open.WO')
2873 self.assertEqual(str(Open.AC), 'Open.AC')
2874 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002875 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2876 self.assertEqual(str(Open(4)), '4')
2877 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2878 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002879 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002880 self.assertEqual(str(~Open.CE), 'Open.AC')
2881 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002882 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002883 self.assertEqual(str(Open(~4)), '-5')
2884
2885 Skip = self.Skip
2886 self.assertEqual(str(Skip(~4)), 'Skip.FIRST|SECOND|EIGHTH')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002887
2888 def test_repr(self):
2889 Perm = self.Perm
2890 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2891 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2892 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2893 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2894 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002895 self.assertEqual(repr(Perm.R | 8), '12')
2896 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
2897 self.assertEqual(repr(Perm(8)), '8')
2898 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2899 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2900 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2901 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2902 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
2903 self.assertEqual(repr(~(Perm.R | 8)), '-13')
2904 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2905 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002906
2907 Open = self.Open
2908 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2909 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2910 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2911 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002912 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2913 self.assertEqual(repr(Open(4)), '4')
2914 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2915 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
2916 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2917 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2918 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2919 self.assertEqual(repr(Open(~4)), '-5')
2920
2921 Skip = self.Skip
2922 self.assertEqual(repr(Skip(~4)), '<Skip.FIRST|SECOND|EIGHTH: 11>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002923
Ethan Furman37440ee2020-12-08 11:14:10 -08002924 def test_format(self):
2925 Perm = self.Perm
2926 self.assertEqual(format(Perm.R, ''), '4')
2927 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2928
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002929 def test_or(self):
2930 Perm = self.Perm
2931 for i in Perm:
2932 for j in Perm:
2933 self.assertEqual(i | j, i.value | j.value)
2934 self.assertEqual((i | j).value, i.value | j.value)
2935 self.assertIs(type(i | j), Perm)
2936 for j in range(8):
2937 self.assertEqual(i | j, i.value | j)
2938 self.assertEqual((i | j).value, i.value | j)
2939 self.assertIs(type(i | j), Perm)
2940 self.assertEqual(j | i, j | i.value)
2941 self.assertEqual((j | i).value, j | i.value)
2942 self.assertIs(type(j | i), Perm)
2943 for i in Perm:
2944 self.assertIs(i | i, i)
2945 self.assertIs(i | 0, i)
2946 self.assertIs(0 | i, i)
2947 Open = self.Open
2948 self.assertIs(Open.RO | Open.CE, Open.CE)
2949
2950 def test_and(self):
2951 Perm = self.Perm
2952 RW = Perm.R | Perm.W
2953 RX = Perm.R | Perm.X
2954 WX = Perm.W | Perm.X
2955 RWX = Perm.R | Perm.W | Perm.X
2956 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2957 for i in values:
2958 for j in values:
2959 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2960 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2961 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2962 for j in range(8):
2963 self.assertEqual(i & j, i.value & j)
2964 self.assertEqual((i & j).value, i.value & j)
2965 self.assertIs(type(i & j), Perm)
2966 self.assertEqual(j & i, j & i.value)
2967 self.assertEqual((j & i).value, j & i.value)
2968 self.assertIs(type(j & i), Perm)
2969 for i in Perm:
2970 self.assertIs(i & i, i)
2971 self.assertIs(i & 7, i)
2972 self.assertIs(7 & i, i)
2973 Open = self.Open
2974 self.assertIs(Open.RO & Open.CE, Open.RO)
2975
2976 def test_xor(self):
2977 Perm = self.Perm
2978 for i in Perm:
2979 for j in Perm:
2980 self.assertEqual(i ^ j, i.value ^ j.value)
2981 self.assertEqual((i ^ j).value, i.value ^ j.value)
2982 self.assertIs(type(i ^ j), Perm)
2983 for j in range(8):
2984 self.assertEqual(i ^ j, i.value ^ j)
2985 self.assertEqual((i ^ j).value, i.value ^ j)
2986 self.assertIs(type(i ^ j), Perm)
2987 self.assertEqual(j ^ i, j ^ i.value)
2988 self.assertEqual((j ^ i).value, j ^ i.value)
2989 self.assertIs(type(j ^ i), Perm)
2990 for i in Perm:
2991 self.assertIs(i ^ 0, i)
2992 self.assertIs(0 ^ i, i)
2993 Open = self.Open
2994 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2995 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2996
2997 def test_invert(self):
2998 Perm = self.Perm
2999 RW = Perm.R | Perm.W
3000 RX = Perm.R | Perm.X
3001 WX = Perm.W | Perm.X
3002 RWX = Perm.R | Perm.W | Perm.X
3003 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3004 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003005 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003006 self.assertIs(type(~i), Perm)
3007 self.assertEqual(~~i, i)
3008 for i in Perm:
3009 self.assertIs(~~i, i)
3010 Open = self.Open
3011 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3012 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3013
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003014 def test_boundary(self):
3015 self.assertIs(enum.IntFlag._boundary_, EJECT)
3016 class Iron(IntFlag, boundary=STRICT):
3017 ONE = 1
3018 TWO = 2
3019 EIGHT = 8
3020 self.assertIs(Iron._boundary_, STRICT)
3021 #
3022 class Water(IntFlag, boundary=CONFORM):
3023 ONE = 1
3024 TWO = 2
3025 EIGHT = 8
3026 self.assertIs(Water._boundary_, CONFORM)
3027 #
3028 class Space(IntFlag, boundary=EJECT):
3029 ONE = 1
3030 TWO = 2
3031 EIGHT = 8
3032 self.assertIs(Space._boundary_, EJECT)
3033 #
3034 class Bizarre(IntFlag, boundary=KEEP):
3035 b = 3
3036 c = 4
3037 d = 6
3038 #
3039 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
3040 self.assertIs(Water(7), Water.ONE|Water.TWO)
3041 self.assertIs(Water(~9), Water.TWO)
3042 self.assertEqual(Space(7), 7)
3043 self.assertTrue(type(Space(7)) is int)
3044 self.assertEqual(list(Bizarre), [Bizarre.c])
3045 self.assertIs(Bizarre(3), Bizarre.b)
3046 self.assertIs(Bizarre(6), Bizarre.d)
3047
3048 def test_iter(self):
3049 Color = self.Color
3050 Open = self.Open
3051 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3052 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3053
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003054 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003055 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003056 lst = list(Perm)
3057 self.assertEqual(len(lst), len(Perm))
3058 self.assertEqual(len(Perm), 3, Perm)
3059 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3060 for i, n in enumerate('R W X'.split()):
3061 v = 1<<i
3062 e = Perm(v)
3063 self.assertEqual(e.value, v)
3064 self.assertEqual(type(e.value), int)
3065 self.assertEqual(e, v)
3066 self.assertEqual(e.name, n)
3067 self.assertIn(e, Perm)
3068 self.assertIs(type(e), Perm)
3069
3070 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003071 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003072 lst = list(Perm)
3073 self.assertEqual(len(lst), len(Perm))
3074 self.assertEqual(len(Perm), 3, Perm)
3075 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3076 for i, n in enumerate('R W X'.split()):
3077 v = 8<<i
3078 e = Perm(v)
3079 self.assertEqual(e.value, v)
3080 self.assertEqual(type(e.value), int)
3081 self.assertEqual(e, v)
3082 self.assertEqual(e.name, n)
3083 self.assertIn(e, Perm)
3084 self.assertIs(type(e), Perm)
3085
3086 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003087 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003088 lst = list(Perm)
3089 self.assertEqual(len(lst), len(Perm))
3090 self.assertEqual(len(Perm), 3, Perm)
3091 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3092 for i, n in enumerate('R W X'.split()):
3093 v = 1<<i
3094 e = Perm(v)
3095 self.assertEqual(e.value, v)
3096 self.assertEqual(type(e.value), int)
3097 self.assertEqual(e, v)
3098 self.assertEqual(e.name, n)
3099 self.assertIn(e, Perm)
3100 self.assertIs(type(e), Perm)
3101
3102 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003103 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003104 lst = list(Perm)
3105 self.assertEqual(len(lst), len(Perm))
3106 self.assertEqual(len(Perm), 3, Perm)
3107 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3108 for i, n in enumerate('R W X'.split()):
3109 v = 1<<(2*i+1)
3110 e = Perm(v)
3111 self.assertEqual(e.value, v)
3112 self.assertEqual(type(e.value), int)
3113 self.assertEqual(e, v)
3114 self.assertEqual(e.name, n)
3115 self.assertIn(e, Perm)
3116 self.assertIs(type(e), Perm)
3117
3118 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003119 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003120 lst = list(Perm)
3121 self.assertEqual(len(lst), len(Perm))
3122 self.assertEqual(len(Perm), 3, Perm)
3123 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3124 for i, n in enumerate('R W X'.split()):
3125 v = 1<<(2*i+1)
3126 e = Perm(v)
3127 self.assertEqual(e.value, v)
3128 self.assertEqual(type(e.value), int)
3129 self.assertEqual(e, v)
3130 self.assertEqual(e.name, n)
3131 self.assertIn(e, Perm)
3132 self.assertIs(type(e), Perm)
3133
3134
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003135 def test_programatic_function_from_empty_list(self):
3136 Perm = enum.IntFlag('Perm', [])
3137 lst = list(Perm)
3138 self.assertEqual(len(lst), len(Perm))
3139 self.assertEqual(len(Perm), 0, Perm)
3140 Thing = enum.Enum('Thing', [])
3141 lst = list(Thing)
3142 self.assertEqual(len(lst), len(Thing))
3143 self.assertEqual(len(Thing), 0, Thing)
3144
3145
3146 def test_programatic_function_from_empty_tuple(self):
3147 Perm = enum.IntFlag('Perm', ())
3148 lst = list(Perm)
3149 self.assertEqual(len(lst), len(Perm))
3150 self.assertEqual(len(Perm), 0, Perm)
3151 Thing = enum.Enum('Thing', ())
3152 self.assertEqual(len(lst), len(Thing))
3153 self.assertEqual(len(Thing), 0, Thing)
3154
Rahul Jha94306522018-09-10 23:51:04 +05303155 def test_contains(self):
3156 Open = self.Open
3157 Color = self.Color
3158 self.assertTrue(Color.GREEN in Color)
3159 self.assertTrue(Open.RW in Open)
3160 self.assertFalse(Color.GREEN in Open)
3161 self.assertFalse(Open.RW in Color)
3162 with self.assertRaises(TypeError):
3163 'GREEN' in Color
3164 with self.assertRaises(TypeError):
3165 'RW' in Open
3166 with self.assertRaises(TypeError):
3167 2 in Color
3168 with self.assertRaises(TypeError):
3169 2 in Open
3170
3171 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003172 Perm = self.Perm
3173 R, W, X = Perm
3174 RW = R | W
3175 RX = R | X
3176 WX = W | X
3177 RWX = R | W | X
3178 self.assertTrue(R in RW)
3179 self.assertTrue(R in RX)
3180 self.assertTrue(R in RWX)
3181 self.assertTrue(W in RW)
3182 self.assertTrue(W in WX)
3183 self.assertTrue(W in RWX)
3184 self.assertTrue(X in RX)
3185 self.assertTrue(X in WX)
3186 self.assertTrue(X in RWX)
3187 self.assertFalse(R in WX)
3188 self.assertFalse(W in RX)
3189 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303190 with self.assertRaises(TypeError):
3191 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003192
Ethan Furman7219e272020-09-16 13:01:00 -07003193 def test_member_iter(self):
3194 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003195 self.assertEqual(list(Color.BLACK), [])
3196 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003197 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3198 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003199 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3200
3201 def test_member_length(self):
3202 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3203 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3204 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3205 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3206
3207 def test_aliases(self):
3208 Color = self.Color
3209 self.assertEqual(Color(1).name, 'RED')
3210 self.assertEqual(Color['ROJO'].name, 'RED')
3211 self.assertEqual(Color(7).name, 'WHITE')
3212 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3213 self.assertIs(Color.BLANCO, Color.WHITE)
3214 Open = self.Open
3215 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003216
Ethan Furman25d94bb2016-09-02 16:32:32 -07003217 def test_bool(self):
3218 Perm = self.Perm
3219 for f in Perm:
3220 self.assertTrue(f)
3221 Open = self.Open
3222 for f in Open:
3223 self.assertEqual(bool(f.value), bool(f))
3224
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003225 def test_bizarre(self):
3226 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3227 class Bizarre(IntFlag):
3228 b = 3
3229 c = 4
3230 d = 6
3231
Ethan Furman5bdab642018-09-21 19:03:09 -07003232 def test_multiple_mixin(self):
3233 class AllMixin:
3234 @classproperty
3235 def ALL(cls):
3236 members = list(cls)
3237 all_value = None
3238 if members:
3239 all_value = members[0]
3240 for member in members[1:]:
3241 all_value |= member
3242 cls.ALL = all_value
3243 return all_value
3244 class StrMixin:
3245 def __str__(self):
3246 return self._name_.lower()
3247 class Color(AllMixin, IntFlag):
3248 RED = auto()
3249 GREEN = auto()
3250 BLUE = auto()
3251 self.assertEqual(Color.RED.value, 1)
3252 self.assertEqual(Color.GREEN.value, 2)
3253 self.assertEqual(Color.BLUE.value, 4)
3254 self.assertEqual(Color.ALL.value, 7)
3255 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3256 class Color(AllMixin, StrMixin, IntFlag):
3257 RED = auto()
3258 GREEN = auto()
3259 BLUE = auto()
3260 self.assertEqual(Color.RED.value, 1)
3261 self.assertEqual(Color.GREEN.value, 2)
3262 self.assertEqual(Color.BLUE.value, 4)
3263 self.assertEqual(Color.ALL.value, 7)
3264 self.assertEqual(str(Color.BLUE), 'blue')
3265 class Color(StrMixin, AllMixin, IntFlag):
3266 RED = auto()
3267 GREEN = auto()
3268 BLUE = auto()
3269 self.assertEqual(Color.RED.value, 1)
3270 self.assertEqual(Color.GREEN.value, 2)
3271 self.assertEqual(Color.BLUE.value, 4)
3272 self.assertEqual(Color.ALL.value, 7)
3273 self.assertEqual(str(Color.BLUE), 'blue')
3274
Hai Shie80697d2020-05-28 06:10:27 +08003275 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003276 def test_unique_composite(self):
3277 # override __eq__ to be identity only
3278 class TestFlag(IntFlag):
3279 one = auto()
3280 two = auto()
3281 three = auto()
3282 four = auto()
3283 five = auto()
3284 six = auto()
3285 seven = auto()
3286 eight = auto()
3287 def __eq__(self, other):
3288 return self is other
3289 def __hash__(self):
3290 return hash(self._value_)
3291 # have multiple threads competing to complete the composite members
3292 seen = set()
3293 failed = False
3294 def cycle_enum():
3295 nonlocal failed
3296 try:
3297 for i in range(256):
3298 seen.add(TestFlag(i))
3299 except Exception:
3300 failed = True
3301 threads = [
3302 threading.Thread(target=cycle_enum)
3303 for _ in range(8)
3304 ]
Hai Shie80697d2020-05-28 06:10:27 +08003305 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003306 pass
3307 # check that only 248 members were created
3308 self.assertFalse(
3309 failed,
3310 'at least one thread failed while creating composite members')
3311 self.assertEqual(256, len(seen), 'too many composite members created')
3312
3313
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003314class TestEmptyAndNonLatinStrings(unittest.TestCase):
3315
3316 def test_empty_string(self):
3317 with self.assertRaises(ValueError):
3318 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3319
3320 def test_non_latin_character_string(self):
3321 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3322 item = getattr(greek_abc, '\u03B1')
3323 self.assertEqual(item.value, 1)
3324
3325 def test_non_latin_number_string(self):
3326 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3327 item = getattr(hebrew_123, '\u05D0')
3328 self.assertEqual(item.value, 1)
3329
3330
Ethan Furmanf24bb352013-07-18 17:05:39 -07003331class TestUnique(unittest.TestCase):
3332
3333 def test_unique_clean(self):
3334 @unique
3335 class Clean(Enum):
3336 one = 1
3337 two = 'dos'
3338 tres = 4.0
3339 @unique
3340 class Cleaner(IntEnum):
3341 single = 1
3342 double = 2
3343 triple = 3
3344
3345 def test_unique_dirty(self):
3346 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3347 @unique
3348 class Dirty(Enum):
3349 one = 1
3350 two = 'dos'
3351 tres = 1
3352 with self.assertRaisesRegex(
3353 ValueError,
3354 'double.*single.*turkey.*triple',
3355 ):
3356 @unique
3357 class Dirtier(IntEnum):
3358 single = 1
3359 double = 1
3360 triple = 3
3361 turkey = 3
3362
Ethan Furman3803ad42016-05-01 10:03:53 -07003363 def test_unique_with_name(self):
3364 @unique
3365 class Silly(Enum):
3366 one = 1
3367 two = 'dos'
3368 name = 3
3369 @unique
3370 class Sillier(IntEnum):
3371 single = 1
3372 name = 2
3373 triple = 3
3374 value = 4
3375
Ethan Furmanf24bb352013-07-18 17:05:39 -07003376
Ethan Furman5bdab642018-09-21 19:03:09 -07003377
Ethan Furman3323da92015-04-11 09:39:59 -07003378expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003379Help on class Color in module %s:
3380
3381class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003382 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003383 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003384 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003385 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003386 | Method resolution order:
3387 | Color
3388 | enum.Enum
3389 | builtins.object
3390 |\x20\x20
3391 | Data and other attributes defined here:
3392 |\x20\x20
3393 | blue = <Color.blue: 3>
3394 |\x20\x20
3395 | green = <Color.green: 2>
3396 |\x20\x20
3397 | red = <Color.red: 1>
3398 |\x20\x20
3399 | ----------------------------------------------------------------------
3400 | Data descriptors inherited from enum.Enum:
3401 |\x20\x20
3402 | name
3403 | The name of the Enum member.
3404 |\x20\x20
3405 | value
3406 | The value of the Enum member.
3407 |\x20\x20
3408 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003409 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003410 |\x20\x20
3411 | __members__
3412 | Returns a mapping of member name->value.
3413 |\x20\x20\x20\x20\x20\x20
3414 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003415 | is a read-only view of the internal mapping."""
3416
3417expected_help_output_without_docs = """\
3418Help on class Color in module %s:
3419
3420class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003421 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3422 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003423 | Method resolution order:
3424 | Color
3425 | enum.Enum
3426 | builtins.object
3427 |\x20\x20
3428 | Data and other attributes defined here:
3429 |\x20\x20
3430 | blue = <Color.blue: 3>
3431 |\x20\x20
3432 | green = <Color.green: 2>
3433 |\x20\x20
3434 | red = <Color.red: 1>
3435 |\x20\x20
3436 | ----------------------------------------------------------------------
3437 | Data descriptors inherited from enum.Enum:
3438 |\x20\x20
3439 | name
3440 |\x20\x20
3441 | value
3442 |\x20\x20
3443 | ----------------------------------------------------------------------
3444 | Data descriptors inherited from enum.EnumMeta:
3445 |\x20\x20
3446 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003447
3448class TestStdLib(unittest.TestCase):
3449
Ethan Furman48a724f2015-04-11 23:23:06 -07003450 maxDiff = None
3451
Ethan Furman5875d742013-10-21 20:45:55 -07003452 class Color(Enum):
3453 red = 1
3454 green = 2
3455 blue = 3
3456
3457 def test_pydoc(self):
3458 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003459 if StrEnum.__doc__ is None:
3460 expected_text = expected_help_output_without_docs % __name__
3461 else:
3462 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003463 output = StringIO()
3464 helper = pydoc.Helper(output=output)
3465 helper(self.Color)
3466 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003467 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003468
3469 def test_inspect_getmembers(self):
3470 values = dict((
3471 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003472 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003473 ('__members__', self.Color.__members__),
3474 ('__module__', __name__),
3475 ('blue', self.Color.blue),
3476 ('green', self.Color.green),
3477 ('name', Enum.__dict__['name']),
3478 ('red', self.Color.red),
3479 ('value', Enum.__dict__['value']),
3480 ))
3481 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003482 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003483 failed = False
3484 for k in values.keys():
3485 if result[k] != values[k]:
3486 print()
3487 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3488 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3489 failed = True
3490 if failed:
3491 self.fail("result does not equal expected, see print above")
3492
3493 def test_inspect_classify_class_attrs(self):
3494 # indirectly test __objclass__
3495 from inspect import Attribute
3496 values = [
3497 Attribute(name='__class__', kind='data',
3498 defining_class=object, object=EnumMeta),
3499 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003500 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003501 Attribute(name='__members__', kind='property',
3502 defining_class=EnumMeta, object=EnumMeta.__members__),
3503 Attribute(name='__module__', kind='data',
3504 defining_class=self.Color, object=__name__),
3505 Attribute(name='blue', kind='data',
3506 defining_class=self.Color, object=self.Color.blue),
3507 Attribute(name='green', kind='data',
3508 defining_class=self.Color, object=self.Color.green),
3509 Attribute(name='red', kind='data',
3510 defining_class=self.Color, object=self.Color.red),
3511 Attribute(name='name', kind='data',
3512 defining_class=Enum, object=Enum.__dict__['name']),
3513 Attribute(name='value', kind='data',
3514 defining_class=Enum, object=Enum.__dict__['value']),
3515 ]
3516 values.sort(key=lambda item: item.name)
3517 result = list(inspect.classify_class_attrs(self.Color))
3518 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003519 self.assertEqual(
3520 len(values), len(result),
3521 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3522 )
Ethan Furman5875d742013-10-21 20:45:55 -07003523 failed = False
3524 for v, r in zip(values, result):
3525 if r != v:
3526 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3527 failed = True
3528 if failed:
3529 self.fail("result does not equal expected, see print above")
3530
Martin Panter19e69c52015-11-14 12:46:42 +00003531
3532class MiscTestCase(unittest.TestCase):
3533 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003534 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003535
3536
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003537# These are unordered here on purpose to ensure that declaration order
3538# makes no difference.
3539CONVERT_TEST_NAME_D = 5
3540CONVERT_TEST_NAME_C = 5
3541CONVERT_TEST_NAME_B = 5
3542CONVERT_TEST_NAME_A = 5 # This one should sort first.
3543CONVERT_TEST_NAME_E = 5
3544CONVERT_TEST_NAME_F = 5
3545
3546class TestIntEnumConvert(unittest.TestCase):
3547 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003548 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003549 'UnittestConvert',
3550 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003551 filter=lambda x: x.startswith('CONVERT_TEST_'))
3552 # We don't want the reverse lookup value to vary when there are
3553 # multiple possible names for a given value. It should always
3554 # report the first lexigraphical name in that case.
3555 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3556
3557 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003558 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003559 'UnittestConvert',
3560 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003561 filter=lambda x: x.startswith('CONVERT_TEST_'))
3562 # Ensure that test_type has all of the desired names and values.
3563 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3564 test_type.CONVERT_TEST_NAME_A)
3565 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3566 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3567 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3568 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3569 # Ensure that test_type only picked up names matching the filter.
3570 self.assertEqual([name for name in dir(test_type)
3571 if name[0:2] not in ('CO', '__')],
3572 [], msg='Names other than CONVERT_TEST_* found.')
3573
orlnub1230fb9fad2018-09-12 20:28:53 +03003574 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3575 '_convert was deprecated in 3.8')
3576 def test_convert_warn(self):
3577 with self.assertWarns(DeprecationWarning):
3578 enum.IntEnum._convert(
3579 'UnittestConvert',
3580 ('test.test_enum', '__main__')[__name__=='__main__'],
3581 filter=lambda x: x.startswith('CONVERT_TEST_'))
3582
3583 @unittest.skipUnless(sys.version_info >= (3, 9),
3584 '_convert was removed in 3.9')
3585 def test_convert_raise(self):
3586 with self.assertRaises(AttributeError):
3587 enum.IntEnum._convert(
3588 'UnittestConvert',
3589 ('test.test_enum', '__main__')[__name__=='__main__'],
3590 filter=lambda x: x.startswith('CONVERT_TEST_'))
3591
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003592
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003593if __name__ == '__main__':
3594 unittest.main()