blob: 96de878faf72d4127d971786592754f338f19c1a [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 Furman01faf452021-01-26 12:52:52 -080021 if os.path.exists('../../Doc/library/enum.rst'):
22 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 Furmanefb13be2020-12-10 12:20:06 -08002188 def test_strenum_auto(self):
2189 class Strings(StrEnum):
2190 ONE = auto()
2191 TWO = auto()
2192 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2193
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002194
Ethan Furmana6582872020-12-10 13:07:00 -08002195 def test_dynamic_members_with_static_methods(self):
2196 #
2197 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2198 class Foo(Enum):
2199 vars().update({
2200 k: v
2201 for k, v in foo_defines.items()
2202 if k.startswith('FOO_')
2203 })
2204 def upper(self):
2205 return self.value.upper()
2206 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2207 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2208 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2209 #
2210 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2211 class FooBar(Enum):
2212 vars().update({
2213 k: v
2214 for k, v in foo_defines.items()
2215 if k.startswith('FOO_')
2216 },
2217 **{'FOO_CAT': 'small'},
2218 )
2219 def upper(self):
2220 return self.value.upper()
2221
2222
Ethan Furmane8e61272016-08-20 07:19:31 -07002223class TestOrder(unittest.TestCase):
2224
2225 def test_same_members(self):
2226 class Color(Enum):
2227 _order_ = 'red green blue'
2228 red = 1
2229 green = 2
2230 blue = 3
2231
2232 def test_same_members_with_aliases(self):
2233 class Color(Enum):
2234 _order_ = 'red green blue'
2235 red = 1
2236 green = 2
2237 blue = 3
2238 verde = green
2239
2240 def test_same_members_wrong_order(self):
2241 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2242 class Color(Enum):
2243 _order_ = 'red green blue'
2244 red = 1
2245 blue = 3
2246 green = 2
2247
2248 def test_order_has_extra_members(self):
2249 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2250 class Color(Enum):
2251 _order_ = 'red green blue purple'
2252 red = 1
2253 green = 2
2254 blue = 3
2255
2256 def test_order_has_extra_members_with_aliases(self):
2257 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2258 class Color(Enum):
2259 _order_ = 'red green blue purple'
2260 red = 1
2261 green = 2
2262 blue = 3
2263 verde = green
2264
2265 def test_enum_has_extra_members(self):
2266 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2267 class Color(Enum):
2268 _order_ = 'red green blue'
2269 red = 1
2270 green = 2
2271 blue = 3
2272 purple = 4
2273
2274 def test_enum_has_extra_members_with_aliases(self):
2275 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2276 class Color(Enum):
2277 _order_ = 'red green blue'
2278 red = 1
2279 green = 2
2280 blue = 3
2281 purple = 4
2282 verde = green
2283
2284
Ethan Furman65a5a472016-09-01 23:55:19 -07002285class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002286 """Tests of the Flags."""
2287
Ethan Furman65a5a472016-09-01 23:55:19 -07002288 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002289 R, W, X = 4, 2, 1
2290
Ethan Furman65a5a472016-09-01 23:55:19 -07002291 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002292 RO = 0
2293 WO = 1
2294 RW = 2
2295 AC = 3
2296 CE = 1<<19
2297
Rahul Jha94306522018-09-10 23:51:04 +05302298 class Color(Flag):
2299 BLACK = 0
2300 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002301 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302302 GREEN = 2
2303 BLUE = 4
2304 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002305 WHITE = RED|GREEN|BLUE
2306 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302307
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002308 def test_str(self):
2309 Perm = self.Perm
2310 self.assertEqual(str(Perm.R), 'Perm.R')
2311 self.assertEqual(str(Perm.W), 'Perm.W')
2312 self.assertEqual(str(Perm.X), 'Perm.X')
2313 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2314 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002315 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002316 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2317 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2318 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2319 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002320 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002321 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2322
2323 Open = self.Open
2324 self.assertEqual(str(Open.RO), 'Open.RO')
2325 self.assertEqual(str(Open.WO), 'Open.WO')
2326 self.assertEqual(str(Open.AC), 'Open.AC')
2327 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002328 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2329 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2330 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002331 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002332 self.assertEqual(str(~Open.CE), 'Open.AC')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002333 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2334 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2335
2336 def test_repr(self):
2337 Perm = self.Perm
2338 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2339 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2340 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2341 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2342 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002343 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002344 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2345 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2346 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2347 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002348 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002349 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2350
2351 Open = self.Open
2352 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2353 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2354 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2355 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002356 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2357 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2358 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002359 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002360 self.assertEqual(repr(~Open.CE), '<Open.AC: 3>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002361 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2362 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2363
Ethan Furman37440ee2020-12-08 11:14:10 -08002364 def test_format(self):
2365 Perm = self.Perm
2366 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2367 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2368
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002369 def test_or(self):
2370 Perm = self.Perm
2371 for i in Perm:
2372 for j in Perm:
2373 self.assertEqual((i | j), Perm(i.value | j.value))
2374 self.assertEqual((i | j).value, i.value | j.value)
2375 self.assertIs(type(i | j), Perm)
2376 for i in Perm:
2377 self.assertIs(i | i, i)
2378 Open = self.Open
2379 self.assertIs(Open.RO | Open.CE, Open.CE)
2380
2381 def test_and(self):
2382 Perm = self.Perm
2383 RW = Perm.R | Perm.W
2384 RX = Perm.R | Perm.X
2385 WX = Perm.W | Perm.X
2386 RWX = Perm.R | Perm.W | Perm.X
2387 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2388 for i in values:
2389 for j in values:
2390 self.assertEqual((i & j).value, i.value & j.value)
2391 self.assertIs(type(i & j), Perm)
2392 for i in Perm:
2393 self.assertIs(i & i, i)
2394 self.assertIs(i & RWX, i)
2395 self.assertIs(RWX & i, i)
2396 Open = self.Open
2397 self.assertIs(Open.RO & Open.CE, Open.RO)
2398
2399 def test_xor(self):
2400 Perm = self.Perm
2401 for i in Perm:
2402 for j in Perm:
2403 self.assertEqual((i ^ j).value, i.value ^ j.value)
2404 self.assertIs(type(i ^ j), Perm)
2405 for i in Perm:
2406 self.assertIs(i ^ Perm(0), i)
2407 self.assertIs(Perm(0) ^ i, i)
2408 Open = self.Open
2409 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2410 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2411
2412 def test_invert(self):
2413 Perm = self.Perm
2414 RW = Perm.R | Perm.W
2415 RX = Perm.R | Perm.X
2416 WX = Perm.W | Perm.X
2417 RWX = Perm.R | Perm.W | Perm.X
2418 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2419 for i in values:
2420 self.assertIs(type(~i), Perm)
2421 self.assertEqual(~~i, i)
2422 for i in Perm:
2423 self.assertIs(~~i, i)
2424 Open = self.Open
2425 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2426 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2427
Ethan Furman25d94bb2016-09-02 16:32:32 -07002428 def test_bool(self):
2429 Perm = self.Perm
2430 for f in Perm:
2431 self.assertTrue(f)
2432 Open = self.Open
2433 for f in Open:
2434 self.assertEqual(bool(f.value), bool(f))
2435
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002436 def test_boundary(self):
2437 self.assertIs(enum.Flag._boundary_, STRICT)
2438 class Iron(Flag, boundary=STRICT):
2439 ONE = 1
2440 TWO = 2
2441 EIGHT = 8
2442 self.assertIs(Iron._boundary_, STRICT)
2443 #
2444 class Water(Flag, boundary=CONFORM):
2445 ONE = 1
2446 TWO = 2
2447 EIGHT = 8
2448 self.assertIs(Water._boundary_, CONFORM)
2449 #
2450 class Space(Flag, boundary=EJECT):
2451 ONE = 1
2452 TWO = 2
2453 EIGHT = 8
2454 self.assertIs(Space._boundary_, EJECT)
2455 #
2456 class Bizarre(Flag, boundary=KEEP):
2457 b = 3
2458 c = 4
2459 d = 6
2460 #
2461 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
2462 self.assertIs(Water(7), Water.ONE|Water.TWO)
2463 self.assertIs(Water(~9), Water.TWO)
2464 self.assertEqual(Space(7), 7)
2465 self.assertTrue(type(Space(7)) is int)
2466 self.assertEqual(list(Bizarre), [Bizarre.c])
2467 self.assertIs(Bizarre(3), Bizarre.b)
2468 self.assertIs(Bizarre(6), Bizarre.d)
2469
2470 def test_iter(self):
2471 Color = self.Color
2472 Open = self.Open
2473 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2474 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2475
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002476 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002477 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002478 lst = list(Perm)
2479 self.assertEqual(len(lst), len(Perm))
2480 self.assertEqual(len(Perm), 3, Perm)
2481 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2482 for i, n in enumerate('R W X'.split()):
2483 v = 1<<i
2484 e = Perm(v)
2485 self.assertEqual(e.value, v)
2486 self.assertEqual(type(e.value), int)
2487 self.assertEqual(e.name, n)
2488 self.assertIn(e, Perm)
2489 self.assertIs(type(e), Perm)
2490
2491 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002492 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002493 lst = list(Perm)
2494 self.assertEqual(len(lst), len(Perm))
2495 self.assertEqual(len(Perm), 3, Perm)
2496 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2497 for i, n in enumerate('R W X'.split()):
2498 v = 8<<i
2499 e = Perm(v)
2500 self.assertEqual(e.value, v)
2501 self.assertEqual(type(e.value), int)
2502 self.assertEqual(e.name, n)
2503 self.assertIn(e, Perm)
2504 self.assertIs(type(e), Perm)
2505
2506 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002507 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002508 lst = list(Perm)
2509 self.assertEqual(len(lst), len(Perm))
2510 self.assertEqual(len(Perm), 3, Perm)
2511 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2512 for i, n in enumerate('R W X'.split()):
2513 v = 1<<i
2514 e = Perm(v)
2515 self.assertEqual(e.value, v)
2516 self.assertEqual(type(e.value), int)
2517 self.assertEqual(e.name, n)
2518 self.assertIn(e, Perm)
2519 self.assertIs(type(e), Perm)
2520
2521 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002522 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002523 lst = list(Perm)
2524 self.assertEqual(len(lst), len(Perm))
2525 self.assertEqual(len(Perm), 3, Perm)
2526 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2527 for i, n in enumerate('R W X'.split()):
2528 v = 1<<(2*i+1)
2529 e = Perm(v)
2530 self.assertEqual(e.value, v)
2531 self.assertEqual(type(e.value), int)
2532 self.assertEqual(e.name, n)
2533 self.assertIn(e, Perm)
2534 self.assertIs(type(e), Perm)
2535
2536 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002537 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002538 lst = list(Perm)
2539 self.assertEqual(len(lst), len(Perm))
2540 self.assertEqual(len(Perm), 3, Perm)
2541 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2542 for i, n in enumerate('R W X'.split()):
2543 v = 1<<(2*i+1)
2544 e = Perm(v)
2545 self.assertEqual(e.value, v)
2546 self.assertEqual(type(e.value), int)
2547 self.assertEqual(e.name, n)
2548 self.assertIn(e, Perm)
2549 self.assertIs(type(e), Perm)
2550
Ethan Furman65a5a472016-09-01 23:55:19 -07002551 def test_pickle(self):
2552 if isinstance(FlagStooges, Exception):
2553 raise FlagStooges
2554 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2555 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002556
Rahul Jha94306522018-09-10 23:51:04 +05302557 def test_contains(self):
2558 Open = self.Open
2559 Color = self.Color
2560 self.assertFalse(Color.BLACK in Open)
2561 self.assertFalse(Open.RO in Color)
2562 with self.assertRaises(TypeError):
2563 'BLACK' in Color
2564 with self.assertRaises(TypeError):
2565 'RO' in Open
2566 with self.assertRaises(TypeError):
2567 1 in Color
2568 with self.assertRaises(TypeError):
2569 1 in Open
2570
2571 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002572 Perm = self.Perm
2573 R, W, X = Perm
2574 RW = R | W
2575 RX = R | X
2576 WX = W | X
2577 RWX = R | W | X
2578 self.assertTrue(R in RW)
2579 self.assertTrue(R in RX)
2580 self.assertTrue(R in RWX)
2581 self.assertTrue(W in RW)
2582 self.assertTrue(W in WX)
2583 self.assertTrue(W in RWX)
2584 self.assertTrue(X in RX)
2585 self.assertTrue(X in WX)
2586 self.assertTrue(X in RWX)
2587 self.assertFalse(R in WX)
2588 self.assertFalse(W in RX)
2589 self.assertFalse(X in RW)
2590
Ethan Furman7219e272020-09-16 13:01:00 -07002591 def test_member_iter(self):
2592 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002593 self.assertEqual(list(Color.BLACK), [])
2594 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002595 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2596 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002597 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2598 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2599
2600 def test_member_length(self):
2601 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2602 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2603 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2604 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2605
2606 def test_number_reset_and_order_cleanup(self):
2607 class Confused(Flag):
2608 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2609 ONE = auto()
2610 TWO = auto()
2611 FOUR = auto()
2612 DOS = 2
2613 EIGHT = auto()
2614 SIXTEEN = auto()
2615 self.assertEqual(
2616 list(Confused),
2617 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2618 self.assertIs(Confused.TWO, Confused.DOS)
2619 self.assertEqual(Confused.DOS._value_, 2)
2620 self.assertEqual(Confused.EIGHT._value_, 8)
2621 self.assertEqual(Confused.SIXTEEN._value_, 16)
2622
2623 def test_aliases(self):
2624 Color = self.Color
2625 self.assertEqual(Color(1).name, 'RED')
2626 self.assertEqual(Color['ROJO'].name, 'RED')
2627 self.assertEqual(Color(7).name, 'WHITE')
2628 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2629 self.assertIs(Color.BLANCO, Color.WHITE)
2630 Open = self.Open
2631 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002632
Ethan Furmanc16595e2016-09-10 23:36:59 -07002633 def test_auto_number(self):
2634 class Color(Flag):
2635 red = auto()
2636 blue = auto()
2637 green = auto()
2638
2639 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2640 self.assertEqual(Color.red.value, 1)
2641 self.assertEqual(Color.blue.value, 2)
2642 self.assertEqual(Color.green.value, 4)
2643
2644 def test_auto_number_garbage(self):
2645 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2646 class Color(Flag):
2647 red = 'not an int'
2648 blue = auto()
2649
Ethan Furman3515dcc2016-09-18 13:15:41 -07002650 def test_duplicate_auto(self):
2651 class Dupes(Enum):
2652 first = primero = auto()
2653 second = auto()
2654 third = auto()
2655 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2656
2657 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002658 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2659 class Bizarre(Flag):
2660 b = 3
2661 c = 4
2662 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002663
Ethan Furman5bdab642018-09-21 19:03:09 -07002664 def test_multiple_mixin(self):
2665 class AllMixin:
2666 @classproperty
2667 def ALL(cls):
2668 members = list(cls)
2669 all_value = None
2670 if members:
2671 all_value = members[0]
2672 for member in members[1:]:
2673 all_value |= member
2674 cls.ALL = all_value
2675 return all_value
2676 class StrMixin:
2677 def __str__(self):
2678 return self._name_.lower()
2679 class Color(AllMixin, Flag):
2680 RED = auto()
2681 GREEN = auto()
2682 BLUE = auto()
2683 self.assertEqual(Color.RED.value, 1)
2684 self.assertEqual(Color.GREEN.value, 2)
2685 self.assertEqual(Color.BLUE.value, 4)
2686 self.assertEqual(Color.ALL.value, 7)
2687 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2688 class Color(AllMixin, StrMixin, Flag):
2689 RED = auto()
2690 GREEN = auto()
2691 BLUE = auto()
2692 self.assertEqual(Color.RED.value, 1)
2693 self.assertEqual(Color.GREEN.value, 2)
2694 self.assertEqual(Color.BLUE.value, 4)
2695 self.assertEqual(Color.ALL.value, 7)
2696 self.assertEqual(str(Color.BLUE), 'blue')
2697 class Color(StrMixin, AllMixin, Flag):
2698 RED = auto()
2699 GREEN = auto()
2700 BLUE = auto()
2701 self.assertEqual(Color.RED.value, 1)
2702 self.assertEqual(Color.GREEN.value, 2)
2703 self.assertEqual(Color.BLUE.value, 4)
2704 self.assertEqual(Color.ALL.value, 7)
2705 self.assertEqual(str(Color.BLUE), 'blue')
2706
Hai Shie80697d2020-05-28 06:10:27 +08002707 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002708 def test_unique_composite(self):
2709 # override __eq__ to be identity only
2710 class TestFlag(Flag):
2711 one = auto()
2712 two = auto()
2713 three = auto()
2714 four = auto()
2715 five = auto()
2716 six = auto()
2717 seven = auto()
2718 eight = auto()
2719 def __eq__(self, other):
2720 return self is other
2721 def __hash__(self):
2722 return hash(self._value_)
2723 # have multiple threads competing to complete the composite members
2724 seen = set()
2725 failed = False
2726 def cycle_enum():
2727 nonlocal failed
2728 try:
2729 for i in range(256):
2730 seen.add(TestFlag(i))
2731 except Exception:
2732 failed = True
2733 threads = [
2734 threading.Thread(target=cycle_enum)
2735 for _ in range(8)
2736 ]
Hai Shie80697d2020-05-28 06:10:27 +08002737 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002738 pass
2739 # check that only 248 members were created
2740 self.assertFalse(
2741 failed,
2742 'at least one thread failed while creating composite members')
2743 self.assertEqual(256, len(seen), 'too many composite members created')
2744
Ethan Furman6bd94de2020-12-09 16:41:22 -08002745 def test_init_subclass(self):
2746 class MyEnum(Flag):
2747 def __init_subclass__(cls, **kwds):
2748 super().__init_subclass__(**kwds)
2749 self.assertFalse(cls.__dict__.get('_test', False))
2750 cls._test1 = 'MyEnum'
2751 #
2752 class TheirEnum(MyEnum):
2753 def __init_subclass__(cls, **kwds):
2754 super(TheirEnum, cls).__init_subclass__(**kwds)
2755 cls._test2 = 'TheirEnum'
2756 class WhoseEnum(TheirEnum):
2757 def __init_subclass__(cls, **kwds):
2758 pass
2759 class NoEnum(WhoseEnum):
2760 ONE = 1
2761 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2762 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2763 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2764 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2765 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2766 #
2767 class OurEnum(MyEnum):
2768 def __init_subclass__(cls, **kwds):
2769 cls._test2 = 'OurEnum'
2770 class WhereEnum(OurEnum):
2771 def __init_subclass__(cls, **kwds):
2772 pass
2773 class NeverEnum(WhereEnum):
2774 ONE = 1
2775 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2776 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2777 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2778 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2779 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2780
Ethan Furmanc16595e2016-09-10 23:36:59 -07002781
Ethan Furman65a5a472016-09-01 23:55:19 -07002782class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002783 """Tests of the IntFlags."""
2784
Ethan Furman65a5a472016-09-01 23:55:19 -07002785 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002786 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002787 W = 1 << 1
2788 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002789
Ethan Furman65a5a472016-09-01 23:55:19 -07002790 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002791 RO = 0
2792 WO = 1
2793 RW = 2
2794 AC = 3
2795 CE = 1<<19
2796
Rahul Jha94306522018-09-10 23:51:04 +05302797 class Color(IntFlag):
2798 BLACK = 0
2799 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002800 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302801 GREEN = 2
2802 BLUE = 4
2803 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002804 WHITE = RED|GREEN|BLUE
2805 BLANCO = RED|GREEN|BLUE
2806
2807 class Skip(IntFlag):
2808 FIRST = 1
2809 SECOND = 2
2810 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302811
Ethan Furman3515dcc2016-09-18 13:15:41 -07002812 def test_type(self):
2813 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002814 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002815 Open = self.Open
2816 for f in Perm:
2817 self.assertTrue(isinstance(f, Perm))
2818 self.assertEqual(f, f.value)
2819 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2820 self.assertEqual(Perm.W | Perm.X, 3)
2821 for f in Open:
2822 self.assertTrue(isinstance(f, Open))
2823 self.assertEqual(f, f.value)
2824 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2825 self.assertEqual(Open.WO | Open.RW, 3)
2826
2827
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002828 def test_str(self):
2829 Perm = self.Perm
2830 self.assertEqual(str(Perm.R), 'Perm.R')
2831 self.assertEqual(str(Perm.W), 'Perm.W')
2832 self.assertEqual(str(Perm.X), 'Perm.X')
2833 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2834 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002835 self.assertEqual(str(Perm.R | 8), '12')
2836 self.assertEqual(str(Perm(0)), 'Perm(0)')
2837 self.assertEqual(str(Perm(8)), '8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002838 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2839 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2840 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2841 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002842 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2843 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002844 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002845 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002846
2847 Open = self.Open
2848 self.assertEqual(str(Open.RO), 'Open.RO')
2849 self.assertEqual(str(Open.WO), 'Open.WO')
2850 self.assertEqual(str(Open.AC), 'Open.AC')
2851 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002852 self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
2853 self.assertEqual(str(Open(4)), '4')
2854 self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
2855 self.assertEqual(str(~Open.WO), 'Open.RW|CE')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002856 self.assertEqual(str(~Open.AC), 'Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002857 self.assertEqual(str(~Open.CE), 'Open.AC')
2858 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002859 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002860 self.assertEqual(str(Open(~4)), '-5')
2861
2862 Skip = self.Skip
2863 self.assertEqual(str(Skip(~4)), 'Skip.FIRST|SECOND|EIGHTH')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002864
2865 def test_repr(self):
2866 Perm = self.Perm
2867 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2868 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2869 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2870 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2871 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002872 self.assertEqual(repr(Perm.R | 8), '12')
2873 self.assertEqual(repr(Perm(0)), '<Perm: 0>')
2874 self.assertEqual(repr(Perm(8)), '8')
2875 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2876 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2877 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2878 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2879 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
2880 self.assertEqual(repr(~(Perm.R | 8)), '-13')
2881 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2882 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002883
2884 Open = self.Open
2885 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2886 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2887 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2888 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002889 self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
2890 self.assertEqual(repr(Open(4)), '4')
2891 self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
2892 self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
2893 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2894 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2895 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2896 self.assertEqual(repr(Open(~4)), '-5')
2897
2898 Skip = self.Skip
2899 self.assertEqual(repr(Skip(~4)), '<Skip.FIRST|SECOND|EIGHTH: 11>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002900
Ethan Furman37440ee2020-12-08 11:14:10 -08002901 def test_format(self):
2902 Perm = self.Perm
2903 self.assertEqual(format(Perm.R, ''), '4')
2904 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2905
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002906 def test_or(self):
2907 Perm = self.Perm
2908 for i in Perm:
2909 for j in Perm:
2910 self.assertEqual(i | j, i.value | j.value)
2911 self.assertEqual((i | j).value, i.value | j.value)
2912 self.assertIs(type(i | j), Perm)
2913 for j in range(8):
2914 self.assertEqual(i | j, i.value | j)
2915 self.assertEqual((i | j).value, i.value | j)
2916 self.assertIs(type(i | j), Perm)
2917 self.assertEqual(j | i, j | i.value)
2918 self.assertEqual((j | i).value, j | i.value)
2919 self.assertIs(type(j | i), Perm)
2920 for i in Perm:
2921 self.assertIs(i | i, i)
2922 self.assertIs(i | 0, i)
2923 self.assertIs(0 | i, i)
2924 Open = self.Open
2925 self.assertIs(Open.RO | Open.CE, Open.CE)
2926
2927 def test_and(self):
2928 Perm = self.Perm
2929 RW = Perm.R | Perm.W
2930 RX = Perm.R | Perm.X
2931 WX = Perm.W | Perm.X
2932 RWX = Perm.R | Perm.W | Perm.X
2933 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2934 for i in values:
2935 for j in values:
2936 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2937 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2938 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2939 for j in range(8):
2940 self.assertEqual(i & j, i.value & j)
2941 self.assertEqual((i & j).value, i.value & j)
2942 self.assertIs(type(i & j), Perm)
2943 self.assertEqual(j & i, j & i.value)
2944 self.assertEqual((j & i).value, j & i.value)
2945 self.assertIs(type(j & i), Perm)
2946 for i in Perm:
2947 self.assertIs(i & i, i)
2948 self.assertIs(i & 7, i)
2949 self.assertIs(7 & i, i)
2950 Open = self.Open
2951 self.assertIs(Open.RO & Open.CE, Open.RO)
2952
2953 def test_xor(self):
2954 Perm = self.Perm
2955 for i in Perm:
2956 for j in Perm:
2957 self.assertEqual(i ^ j, i.value ^ j.value)
2958 self.assertEqual((i ^ j).value, i.value ^ j.value)
2959 self.assertIs(type(i ^ j), Perm)
2960 for j in range(8):
2961 self.assertEqual(i ^ j, i.value ^ j)
2962 self.assertEqual((i ^ j).value, i.value ^ j)
2963 self.assertIs(type(i ^ j), Perm)
2964 self.assertEqual(j ^ i, j ^ i.value)
2965 self.assertEqual((j ^ i).value, j ^ i.value)
2966 self.assertIs(type(j ^ i), Perm)
2967 for i in Perm:
2968 self.assertIs(i ^ 0, i)
2969 self.assertIs(0 ^ i, i)
2970 Open = self.Open
2971 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2972 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2973
2974 def test_invert(self):
2975 Perm = self.Perm
2976 RW = Perm.R | Perm.W
2977 RX = Perm.R | Perm.X
2978 WX = Perm.W | Perm.X
2979 RWX = Perm.R | Perm.W | Perm.X
2980 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2981 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002982 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002983 self.assertIs(type(~i), Perm)
2984 self.assertEqual(~~i, i)
2985 for i in Perm:
2986 self.assertIs(~~i, i)
2987 Open = self.Open
2988 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2989 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2990
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002991 def test_boundary(self):
2992 self.assertIs(enum.IntFlag._boundary_, EJECT)
2993 class Iron(IntFlag, boundary=STRICT):
2994 ONE = 1
2995 TWO = 2
2996 EIGHT = 8
2997 self.assertIs(Iron._boundary_, STRICT)
2998 #
2999 class Water(IntFlag, boundary=CONFORM):
3000 ONE = 1
3001 TWO = 2
3002 EIGHT = 8
3003 self.assertIs(Water._boundary_, CONFORM)
3004 #
3005 class Space(IntFlag, boundary=EJECT):
3006 ONE = 1
3007 TWO = 2
3008 EIGHT = 8
3009 self.assertIs(Space._boundary_, EJECT)
3010 #
3011 class Bizarre(IntFlag, boundary=KEEP):
3012 b = 3
3013 c = 4
3014 d = 6
3015 #
3016 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
3017 self.assertIs(Water(7), Water.ONE|Water.TWO)
3018 self.assertIs(Water(~9), Water.TWO)
3019 self.assertEqual(Space(7), 7)
3020 self.assertTrue(type(Space(7)) is int)
3021 self.assertEqual(list(Bizarre), [Bizarre.c])
3022 self.assertIs(Bizarre(3), Bizarre.b)
3023 self.assertIs(Bizarre(6), Bizarre.d)
3024
3025 def test_iter(self):
3026 Color = self.Color
3027 Open = self.Open
3028 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3029 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3030
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003031 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003032 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003033 lst = list(Perm)
3034 self.assertEqual(len(lst), len(Perm))
3035 self.assertEqual(len(Perm), 3, Perm)
3036 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3037 for i, n in enumerate('R W X'.split()):
3038 v = 1<<i
3039 e = Perm(v)
3040 self.assertEqual(e.value, v)
3041 self.assertEqual(type(e.value), int)
3042 self.assertEqual(e, v)
3043 self.assertEqual(e.name, n)
3044 self.assertIn(e, Perm)
3045 self.assertIs(type(e), Perm)
3046
3047 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003048 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003049 lst = list(Perm)
3050 self.assertEqual(len(lst), len(Perm))
3051 self.assertEqual(len(Perm), 3, Perm)
3052 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3053 for i, n in enumerate('R W X'.split()):
3054 v = 8<<i
3055 e = Perm(v)
3056 self.assertEqual(e.value, v)
3057 self.assertEqual(type(e.value), int)
3058 self.assertEqual(e, v)
3059 self.assertEqual(e.name, n)
3060 self.assertIn(e, Perm)
3061 self.assertIs(type(e), Perm)
3062
3063 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003064 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003065 lst = list(Perm)
3066 self.assertEqual(len(lst), len(Perm))
3067 self.assertEqual(len(Perm), 3, Perm)
3068 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3069 for i, n in enumerate('R W X'.split()):
3070 v = 1<<i
3071 e = Perm(v)
3072 self.assertEqual(e.value, v)
3073 self.assertEqual(type(e.value), int)
3074 self.assertEqual(e, v)
3075 self.assertEqual(e.name, n)
3076 self.assertIn(e, Perm)
3077 self.assertIs(type(e), Perm)
3078
3079 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003080 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003081 lst = list(Perm)
3082 self.assertEqual(len(lst), len(Perm))
3083 self.assertEqual(len(Perm), 3, Perm)
3084 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3085 for i, n in enumerate('R W X'.split()):
3086 v = 1<<(2*i+1)
3087 e = Perm(v)
3088 self.assertEqual(e.value, v)
3089 self.assertEqual(type(e.value), int)
3090 self.assertEqual(e, v)
3091 self.assertEqual(e.name, n)
3092 self.assertIn(e, Perm)
3093 self.assertIs(type(e), Perm)
3094
3095 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003096 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003097 lst = list(Perm)
3098 self.assertEqual(len(lst), len(Perm))
3099 self.assertEqual(len(Perm), 3, Perm)
3100 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3101 for i, n in enumerate('R W X'.split()):
3102 v = 1<<(2*i+1)
3103 e = Perm(v)
3104 self.assertEqual(e.value, v)
3105 self.assertEqual(type(e.value), int)
3106 self.assertEqual(e, v)
3107 self.assertEqual(e.name, n)
3108 self.assertIn(e, Perm)
3109 self.assertIs(type(e), Perm)
3110
3111
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003112 def test_programatic_function_from_empty_list(self):
3113 Perm = enum.IntFlag('Perm', [])
3114 lst = list(Perm)
3115 self.assertEqual(len(lst), len(Perm))
3116 self.assertEqual(len(Perm), 0, Perm)
3117 Thing = enum.Enum('Thing', [])
3118 lst = list(Thing)
3119 self.assertEqual(len(lst), len(Thing))
3120 self.assertEqual(len(Thing), 0, Thing)
3121
3122
3123 def test_programatic_function_from_empty_tuple(self):
3124 Perm = enum.IntFlag('Perm', ())
3125 lst = list(Perm)
3126 self.assertEqual(len(lst), len(Perm))
3127 self.assertEqual(len(Perm), 0, Perm)
3128 Thing = enum.Enum('Thing', ())
3129 self.assertEqual(len(lst), len(Thing))
3130 self.assertEqual(len(Thing), 0, Thing)
3131
Rahul Jha94306522018-09-10 23:51:04 +05303132 def test_contains(self):
3133 Open = self.Open
3134 Color = self.Color
3135 self.assertTrue(Color.GREEN in Color)
3136 self.assertTrue(Open.RW in Open)
3137 self.assertFalse(Color.GREEN in Open)
3138 self.assertFalse(Open.RW in Color)
3139 with self.assertRaises(TypeError):
3140 'GREEN' in Color
3141 with self.assertRaises(TypeError):
3142 'RW' in Open
3143 with self.assertRaises(TypeError):
3144 2 in Color
3145 with self.assertRaises(TypeError):
3146 2 in Open
3147
3148 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003149 Perm = self.Perm
3150 R, W, X = Perm
3151 RW = R | W
3152 RX = R | X
3153 WX = W | X
3154 RWX = R | W | X
3155 self.assertTrue(R in RW)
3156 self.assertTrue(R in RX)
3157 self.assertTrue(R in RWX)
3158 self.assertTrue(W in RW)
3159 self.assertTrue(W in WX)
3160 self.assertTrue(W in RWX)
3161 self.assertTrue(X in RX)
3162 self.assertTrue(X in WX)
3163 self.assertTrue(X in RWX)
3164 self.assertFalse(R in WX)
3165 self.assertFalse(W in RX)
3166 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303167 with self.assertRaises(TypeError):
3168 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003169
Ethan Furman7219e272020-09-16 13:01:00 -07003170 def test_member_iter(self):
3171 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003172 self.assertEqual(list(Color.BLACK), [])
3173 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003174 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3175 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003176 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3177
3178 def test_member_length(self):
3179 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3180 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3181 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3182 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3183
3184 def test_aliases(self):
3185 Color = self.Color
3186 self.assertEqual(Color(1).name, 'RED')
3187 self.assertEqual(Color['ROJO'].name, 'RED')
3188 self.assertEqual(Color(7).name, 'WHITE')
3189 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3190 self.assertIs(Color.BLANCO, Color.WHITE)
3191 Open = self.Open
3192 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003193
Ethan Furman25d94bb2016-09-02 16:32:32 -07003194 def test_bool(self):
3195 Perm = self.Perm
3196 for f in Perm:
3197 self.assertTrue(f)
3198 Open = self.Open
3199 for f in Open:
3200 self.assertEqual(bool(f.value), bool(f))
3201
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003202 def test_bizarre(self):
3203 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3204 class Bizarre(IntFlag):
3205 b = 3
3206 c = 4
3207 d = 6
3208
Ethan Furman5bdab642018-09-21 19:03:09 -07003209 def test_multiple_mixin(self):
3210 class AllMixin:
3211 @classproperty
3212 def ALL(cls):
3213 members = list(cls)
3214 all_value = None
3215 if members:
3216 all_value = members[0]
3217 for member in members[1:]:
3218 all_value |= member
3219 cls.ALL = all_value
3220 return all_value
3221 class StrMixin:
3222 def __str__(self):
3223 return self._name_.lower()
3224 class Color(AllMixin, IntFlag):
3225 RED = auto()
3226 GREEN = auto()
3227 BLUE = auto()
3228 self.assertEqual(Color.RED.value, 1)
3229 self.assertEqual(Color.GREEN.value, 2)
3230 self.assertEqual(Color.BLUE.value, 4)
3231 self.assertEqual(Color.ALL.value, 7)
3232 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3233 class Color(AllMixin, StrMixin, IntFlag):
3234 RED = auto()
3235 GREEN = auto()
3236 BLUE = auto()
3237 self.assertEqual(Color.RED.value, 1)
3238 self.assertEqual(Color.GREEN.value, 2)
3239 self.assertEqual(Color.BLUE.value, 4)
3240 self.assertEqual(Color.ALL.value, 7)
3241 self.assertEqual(str(Color.BLUE), 'blue')
3242 class Color(StrMixin, AllMixin, IntFlag):
3243 RED = auto()
3244 GREEN = auto()
3245 BLUE = auto()
3246 self.assertEqual(Color.RED.value, 1)
3247 self.assertEqual(Color.GREEN.value, 2)
3248 self.assertEqual(Color.BLUE.value, 4)
3249 self.assertEqual(Color.ALL.value, 7)
3250 self.assertEqual(str(Color.BLUE), 'blue')
3251
Hai Shie80697d2020-05-28 06:10:27 +08003252 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003253 def test_unique_composite(self):
3254 # override __eq__ to be identity only
3255 class TestFlag(IntFlag):
3256 one = auto()
3257 two = auto()
3258 three = auto()
3259 four = auto()
3260 five = auto()
3261 six = auto()
3262 seven = auto()
3263 eight = auto()
3264 def __eq__(self, other):
3265 return self is other
3266 def __hash__(self):
3267 return hash(self._value_)
3268 # have multiple threads competing to complete the composite members
3269 seen = set()
3270 failed = False
3271 def cycle_enum():
3272 nonlocal failed
3273 try:
3274 for i in range(256):
3275 seen.add(TestFlag(i))
3276 except Exception:
3277 failed = True
3278 threads = [
3279 threading.Thread(target=cycle_enum)
3280 for _ in range(8)
3281 ]
Hai Shie80697d2020-05-28 06:10:27 +08003282 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003283 pass
3284 # check that only 248 members were created
3285 self.assertFalse(
3286 failed,
3287 'at least one thread failed while creating composite members')
3288 self.assertEqual(256, len(seen), 'too many composite members created')
3289
3290
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003291class TestEmptyAndNonLatinStrings(unittest.TestCase):
3292
3293 def test_empty_string(self):
3294 with self.assertRaises(ValueError):
3295 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3296
3297 def test_non_latin_character_string(self):
3298 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3299 item = getattr(greek_abc, '\u03B1')
3300 self.assertEqual(item.value, 1)
3301
3302 def test_non_latin_number_string(self):
3303 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3304 item = getattr(hebrew_123, '\u05D0')
3305 self.assertEqual(item.value, 1)
3306
3307
Ethan Furmanf24bb352013-07-18 17:05:39 -07003308class TestUnique(unittest.TestCase):
3309
3310 def test_unique_clean(self):
3311 @unique
3312 class Clean(Enum):
3313 one = 1
3314 two = 'dos'
3315 tres = 4.0
3316 @unique
3317 class Cleaner(IntEnum):
3318 single = 1
3319 double = 2
3320 triple = 3
3321
3322 def test_unique_dirty(self):
3323 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3324 @unique
3325 class Dirty(Enum):
3326 one = 1
3327 two = 'dos'
3328 tres = 1
3329 with self.assertRaisesRegex(
3330 ValueError,
3331 'double.*single.*turkey.*triple',
3332 ):
3333 @unique
3334 class Dirtier(IntEnum):
3335 single = 1
3336 double = 1
3337 triple = 3
3338 turkey = 3
3339
Ethan Furman3803ad42016-05-01 10:03:53 -07003340 def test_unique_with_name(self):
3341 @unique
3342 class Silly(Enum):
3343 one = 1
3344 two = 'dos'
3345 name = 3
3346 @unique
3347 class Sillier(IntEnum):
3348 single = 1
3349 name = 2
3350 triple = 3
3351 value = 4
3352
Ethan Furmanf24bb352013-07-18 17:05:39 -07003353
Ethan Furman5bdab642018-09-21 19:03:09 -07003354
Ethan Furman3323da92015-04-11 09:39:59 -07003355expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003356Help on class Color in module %s:
3357
3358class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003359 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003360 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003361 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003362 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003363 | Method resolution order:
3364 | Color
3365 | enum.Enum
3366 | builtins.object
3367 |\x20\x20
3368 | Data and other attributes defined here:
3369 |\x20\x20
3370 | blue = <Color.blue: 3>
3371 |\x20\x20
3372 | green = <Color.green: 2>
3373 |\x20\x20
3374 | red = <Color.red: 1>
3375 |\x20\x20
3376 | ----------------------------------------------------------------------
3377 | Data descriptors inherited from enum.Enum:
3378 |\x20\x20
3379 | name
3380 | The name of the Enum member.
3381 |\x20\x20
3382 | value
3383 | The value of the Enum member.
3384 |\x20\x20
3385 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003386 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003387 |\x20\x20
3388 | __members__
3389 | Returns a mapping of member name->value.
3390 |\x20\x20\x20\x20\x20\x20
3391 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003392 | is a read-only view of the internal mapping."""
3393
3394expected_help_output_without_docs = """\
3395Help on class Color in module %s:
3396
3397class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003398 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3399 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003400 | Method resolution order:
3401 | Color
3402 | enum.Enum
3403 | builtins.object
3404 |\x20\x20
3405 | Data and other attributes defined here:
3406 |\x20\x20
3407 | blue = <Color.blue: 3>
3408 |\x20\x20
3409 | green = <Color.green: 2>
3410 |\x20\x20
3411 | red = <Color.red: 1>
3412 |\x20\x20
3413 | ----------------------------------------------------------------------
3414 | Data descriptors inherited from enum.Enum:
3415 |\x20\x20
3416 | name
3417 |\x20\x20
3418 | value
3419 |\x20\x20
3420 | ----------------------------------------------------------------------
3421 | Data descriptors inherited from enum.EnumMeta:
3422 |\x20\x20
3423 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003424
3425class TestStdLib(unittest.TestCase):
3426
Ethan Furman48a724f2015-04-11 23:23:06 -07003427 maxDiff = None
3428
Ethan Furman5875d742013-10-21 20:45:55 -07003429 class Color(Enum):
3430 red = 1
3431 green = 2
3432 blue = 3
3433
3434 def test_pydoc(self):
3435 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003436 if StrEnum.__doc__ is None:
3437 expected_text = expected_help_output_without_docs % __name__
3438 else:
3439 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003440 output = StringIO()
3441 helper = pydoc.Helper(output=output)
3442 helper(self.Color)
3443 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003444 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003445
3446 def test_inspect_getmembers(self):
3447 values = dict((
3448 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003449 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003450 ('__members__', self.Color.__members__),
3451 ('__module__', __name__),
3452 ('blue', self.Color.blue),
3453 ('green', self.Color.green),
3454 ('name', Enum.__dict__['name']),
3455 ('red', self.Color.red),
3456 ('value', Enum.__dict__['value']),
3457 ))
3458 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003459 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003460 failed = False
3461 for k in values.keys():
3462 if result[k] != values[k]:
3463 print()
3464 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3465 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3466 failed = True
3467 if failed:
3468 self.fail("result does not equal expected, see print above")
3469
3470 def test_inspect_classify_class_attrs(self):
3471 # indirectly test __objclass__
3472 from inspect import Attribute
3473 values = [
3474 Attribute(name='__class__', kind='data',
3475 defining_class=object, object=EnumMeta),
3476 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003477 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003478 Attribute(name='__members__', kind='property',
3479 defining_class=EnumMeta, object=EnumMeta.__members__),
3480 Attribute(name='__module__', kind='data',
3481 defining_class=self.Color, object=__name__),
3482 Attribute(name='blue', kind='data',
3483 defining_class=self.Color, object=self.Color.blue),
3484 Attribute(name='green', kind='data',
3485 defining_class=self.Color, object=self.Color.green),
3486 Attribute(name='red', kind='data',
3487 defining_class=self.Color, object=self.Color.red),
3488 Attribute(name='name', kind='data',
3489 defining_class=Enum, object=Enum.__dict__['name']),
3490 Attribute(name='value', kind='data',
3491 defining_class=Enum, object=Enum.__dict__['value']),
3492 ]
3493 values.sort(key=lambda item: item.name)
3494 result = list(inspect.classify_class_attrs(self.Color))
3495 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003496 self.assertEqual(
3497 len(values), len(result),
3498 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3499 )
Ethan Furman5875d742013-10-21 20:45:55 -07003500 failed = False
3501 for v, r in zip(values, result):
3502 if r != v:
3503 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3504 failed = True
3505 if failed:
3506 self.fail("result does not equal expected, see print above")
3507
Martin Panter19e69c52015-11-14 12:46:42 +00003508
3509class MiscTestCase(unittest.TestCase):
3510 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003511 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003512
3513
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003514# These are unordered here on purpose to ensure that declaration order
3515# makes no difference.
3516CONVERT_TEST_NAME_D = 5
3517CONVERT_TEST_NAME_C = 5
3518CONVERT_TEST_NAME_B = 5
3519CONVERT_TEST_NAME_A = 5 # This one should sort first.
3520CONVERT_TEST_NAME_E = 5
3521CONVERT_TEST_NAME_F = 5
3522
3523class TestIntEnumConvert(unittest.TestCase):
3524 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003525 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003526 'UnittestConvert',
3527 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003528 filter=lambda x: x.startswith('CONVERT_TEST_'))
3529 # We don't want the reverse lookup value to vary when there are
3530 # multiple possible names for a given value. It should always
3531 # report the first lexigraphical name in that case.
3532 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3533
3534 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003535 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003536 'UnittestConvert',
3537 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003538 filter=lambda x: x.startswith('CONVERT_TEST_'))
3539 # Ensure that test_type has all of the desired names and values.
3540 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3541 test_type.CONVERT_TEST_NAME_A)
3542 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3543 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3544 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3545 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3546 # Ensure that test_type only picked up names matching the filter.
3547 self.assertEqual([name for name in dir(test_type)
3548 if name[0:2] not in ('CO', '__')],
3549 [], msg='Names other than CONVERT_TEST_* found.')
3550
orlnub1230fb9fad2018-09-12 20:28:53 +03003551 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3552 '_convert was deprecated in 3.8')
3553 def test_convert_warn(self):
3554 with self.assertWarns(DeprecationWarning):
3555 enum.IntEnum._convert(
3556 'UnittestConvert',
3557 ('test.test_enum', '__main__')[__name__=='__main__'],
3558 filter=lambda x: x.startswith('CONVERT_TEST_'))
3559
3560 @unittest.skipUnless(sys.version_info >= (3, 9),
3561 '_convert was removed in 3.9')
3562 def test_convert_raise(self):
3563 with self.assertRaises(AttributeError):
3564 enum.IntEnum._convert(
3565 'UnittestConvert',
3566 ('test.test_enum', '__main__')[__name__=='__main__'],
3567 filter=lambda x: x.startswith('CONVERT_TEST_'))
3568
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003569
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003570if __name__ == '__main__':
3571 unittest.main()