blob: 6002cd85622cfeb4b5c81e70698b16fd589a6cc2 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002import doctest
Ethan Furman5875d742013-10-21 20:45:55 -07003import inspect
Ethan Furman01faf452021-01-26 12:52:52 -08004import os
Ethan Furman5875d742013-10-21 20:45:55 -07005import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03006import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02008import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07009from collections import OrderedDict
Ethan Furmanb7751062021-03-30 21:17:26 -070010from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080011from enum import STRICT, CONFORM, EJECT, KEEP
Ethan Furman5875d742013-10-21 20:45:55 -070012from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080013from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000014from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030015from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080016from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080017from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080018
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080019def load_tests(loader, tests, ignore):
20 tests.addTests(doctest.DocTestSuite(enum))
Ethan Furman44e580f2021-03-03 09:54:30 -080021 if os.path.exists('Doc/library/enum.rst'):
Ethan Furman01faf452021-01-26 12:52:52 -080022 tests.addTests(doctest.DocFileSuite(
23 '../../Doc/library/enum.rst',
24 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
25 ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080026 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070027
28# for pickle tests
29try:
30 class Stooges(Enum):
31 LARRY = 1
32 CURLY = 2
33 MOE = 3
34except Exception as exc:
35 Stooges = exc
36
37try:
38 class IntStooges(int, Enum):
39 LARRY = 1
40 CURLY = 2
41 MOE = 3
42except Exception as exc:
43 IntStooges = exc
44
45try:
46 class FloatStooges(float, Enum):
47 LARRY = 1.39
48 CURLY = 2.72
49 MOE = 3.142596
50except Exception as exc:
51 FloatStooges = exc
52
Ethan Furman65a5a472016-09-01 23:55:19 -070053try:
54 class FlagStooges(Flag):
55 LARRY = 1
56 CURLY = 2
57 MOE = 3
58except Exception as exc:
59 FlagStooges = exc
60
Ethan Furman6b3d64a2013-06-14 16:55:46 -070061# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070062class Name(StrEnum):
63 BDFL = 'Guido van Rossum'
64 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070065
66try:
67 Question = Enum('Question', 'who what when where why', module=__name__)
68except Exception as exc:
69 Question = exc
70
71try:
72 Answer = Enum('Answer', 'him this then there because')
73except Exception as exc:
74 Answer = exc
75
Ethan Furmanca1b7942014-02-08 11:36:27 -080076try:
77 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
78except Exception as exc:
79 Theory = exc
80
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081# for doctests
82try:
83 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080084 TOMATO = 1
85 BANANA = 2
86 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070087except Exception:
88 pass
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 if target is None:
92 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030093 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080094 assertion(loads(dumps(source, protocol=protocol)), target)
95
Serhiy Storchakae50e7802015-03-31 16:56:49 +030096def test_pickle_exception(assertion, exception, obj):
97 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080098 with assertion(exception):
99 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -0700100
101class TestHelpers(unittest.TestCase):
102 # _is_descriptor, _is_sunder, _is_dunder
103
104 def test_is_descriptor(self):
105 class foo:
106 pass
107 for attr in ('__get__','__set__','__delete__'):
108 obj = foo()
109 self.assertFalse(enum._is_descriptor(obj))
110 setattr(obj, attr, 1)
111 self.assertTrue(enum._is_descriptor(obj))
112
113 def test_is_sunder(self):
114 for s in ('_a_', '_aa_'):
115 self.assertTrue(enum._is_sunder(s))
116
117 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_sunder(s))
120
121 def test_is_dunder(self):
122 for s in ('__a__', '__aa__'):
123 self.assertTrue(enum._is_dunder(s))
124 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
125 '__', '___', '____', '_____',):
126 self.assertFalse(enum._is_dunder(s))
127
Ethan Furman5bdab642018-09-21 19:03:09 -0700128# for subclassing tests
129
130class classproperty:
131
132 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
133 self.fget = fget
134 self.fset = fset
135 self.fdel = fdel
136 if doc is None and fget is not None:
137 doc = fget.__doc__
138 self.__doc__ = doc
139
140 def __get__(self, instance, ownerclass):
141 return self.fget(ownerclass)
142
143
Ethan Furmanc16595e2016-09-10 23:36:59 -0700144# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700145
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700146class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800147
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700148 def setUp(self):
149 class Season(Enum):
150 SPRING = 1
151 SUMMER = 2
152 AUTUMN = 3
153 WINTER = 4
154 self.Season = Season
155
Ethan Furmanec15a822013-08-31 19:17:41 -0700156 class Konstants(float, Enum):
157 E = 2.7182818
158 PI = 3.1415926
159 TAU = 2 * PI
160 self.Konstants = Konstants
161
162 class Grades(IntEnum):
163 A = 5
164 B = 4
165 C = 3
166 D = 2
167 F = 0
168 self.Grades = Grades
169
170 class Directional(str, Enum):
171 EAST = 'east'
172 WEST = 'west'
173 NORTH = 'north'
174 SOUTH = 'south'
175 self.Directional = Directional
176
177 from datetime import date
178 class Holiday(date, Enum):
179 NEW_YEAR = 2013, 1, 1
180 IDES_OF_MARCH = 2013, 3, 15
181 self.Holiday = Holiday
182
Ethan Furman388a3922013-08-12 06:51:41 -0700183 def test_dir_on_class(self):
184 Season = self.Season
185 self.assertEqual(
186 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700188 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
189 )
190
191 def test_dir_on_item(self):
192 Season = self.Season
193 self.assertEqual(
194 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700195 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700196 )
197
Ethan Furmanc850f342013-09-15 16:59:35 -0700198 def test_dir_with_added_behavior(self):
199 class Test(Enum):
200 this = 'that'
201 these = 'those'
202 def wowser(self):
203 return ("Wowser! I'm %s!" % self.name)
204 self.assertEqual(
205 set(dir(Test)),
206 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
207 )
208 self.assertEqual(
209 set(dir(Test.this)),
210 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
211 )
212
Ethan Furman0ae550b2014-10-14 08:58:32 -0700213 def test_dir_on_sub_with_behavior_on_super(self):
214 # see issue22506
215 class SuperEnum(Enum):
216 def invisible(self):
217 return "did you see me?"
218 class SubEnum(SuperEnum):
219 sample = 5
220 self.assertEqual(
221 set(dir(SubEnum.sample)),
222 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
223 )
224
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200225 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
226 # see issue40084
227 class SuperEnum(IntEnum):
228 def __new__(cls, value, description=""):
229 obj = int.__new__(cls, value)
230 obj._value_ = value
231 obj.description = description
232 return obj
233 class SubEnum(SuperEnum):
234 sample = 5
235 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum_in_enum_out(self):
238 Season = self.Season
239 self.assertIs(Season(Season.WINTER), Season.WINTER)
240
241 def test_enum_value(self):
242 Season = self.Season
243 self.assertEqual(Season.SPRING.value, 1)
244
245 def test_intenum_value(self):
246 self.assertEqual(IntStooges.CURLY.value, 2)
247
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700248 def test_enum(self):
249 Season = self.Season
250 lst = list(Season)
251 self.assertEqual(len(lst), len(Season))
252 self.assertEqual(len(Season), 4, Season)
253 self.assertEqual(
254 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
255
256 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
257 e = Season(i)
258 self.assertEqual(e, getattr(Season, season))
259 self.assertEqual(e.value, i)
260 self.assertNotEqual(e, i)
261 self.assertEqual(e.name, season)
262 self.assertIn(e, Season)
263 self.assertIs(type(e), Season)
264 self.assertIsInstance(e, Season)
Ethan Furmanb7751062021-03-30 21:17:26 -0700265 self.assertEqual(str(e), season)
266 self.assertEqual(repr(e), 'Season.{0}'.format(season))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700267
268 def test_value_name(self):
269 Season = self.Season
270 self.assertEqual(Season.SPRING.name, 'SPRING')
271 self.assertEqual(Season.SPRING.value, 1)
272 with self.assertRaises(AttributeError):
273 Season.SPRING.name = 'invierno'
274 with self.assertRaises(AttributeError):
275 Season.SPRING.value = 2
276
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700277 def test_changing_member(self):
278 Season = self.Season
279 with self.assertRaises(AttributeError):
280 Season.WINTER = 'really cold'
281
Ethan Furman64a99722013-09-22 16:18:19 -0700282 def test_attribute_deletion(self):
283 class Season(Enum):
284 SPRING = 1
285 SUMMER = 2
286 AUTUMN = 3
287 WINTER = 4
288
289 def spam(cls):
290 pass
291
292 self.assertTrue(hasattr(Season, 'spam'))
293 del Season.spam
294 self.assertFalse(hasattr(Season, 'spam'))
295
296 with self.assertRaises(AttributeError):
297 del Season.SPRING
298 with self.assertRaises(AttributeError):
299 del Season.DRY
300 with self.assertRaises(AttributeError):
301 del Season.SPRING.name
302
Ethan Furman5de67b12016-04-13 23:52:09 -0700303 def test_bool_of_class(self):
304 class Empty(Enum):
305 pass
306 self.assertTrue(bool(Empty))
307
308 def test_bool_of_member(self):
309 class Count(Enum):
310 zero = 0
311 one = 1
312 two = 2
313 for member in Count:
314 self.assertTrue(bool(member))
315
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700316 def test_invalid_names(self):
317 with self.assertRaises(ValueError):
318 class Wrong(Enum):
319 mro = 9
320 with self.assertRaises(ValueError):
321 class Wrong(Enum):
322 _create_= 11
323 with self.assertRaises(ValueError):
324 class Wrong(Enum):
325 _get_mixins_ = 9
326 with self.assertRaises(ValueError):
327 class Wrong(Enum):
328 _find_new_ = 1
329 with self.assertRaises(ValueError):
330 class Wrong(Enum):
331 _any_name_ = 9
332
Ethan Furman6db1fd52015-09-17 21:49:12 -0700333 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800334 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700335 class Logic(Enum):
336 true = True
337 false = False
338 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800339 self.assertTrue(Logic.false)
340 # unless overridden
341 class RealLogic(Enum):
342 true = True
343 false = False
344 def __bool__(self):
345 return bool(self._value_)
346 self.assertTrue(RealLogic.true)
347 self.assertFalse(RealLogic.false)
348 # mixed Enums depend on mixed-in type
349 class IntLogic(int, Enum):
350 true = 1
351 false = 0
352 self.assertTrue(IntLogic.true)
353 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700354
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700355 def test_contains(self):
356 Season = self.Season
357 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530358 with self.assertRaises(TypeError):
359 3 in Season
360 with self.assertRaises(TypeError):
361 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700362
363 val = Season(3)
364 self.assertIn(val, Season)
365
366 class OtherEnum(Enum):
367 one = 1; two = 2
368 self.assertNotIn(OtherEnum.two, Season)
369
370 def test_comparisons(self):
371 Season = self.Season
372 with self.assertRaises(TypeError):
373 Season.SPRING < Season.WINTER
374 with self.assertRaises(TypeError):
375 Season.SPRING > 4
376
377 self.assertNotEqual(Season.SPRING, 1)
378
379 class Part(Enum):
380 SPRING = 1
381 CLIP = 2
382 BARREL = 3
383
384 self.assertNotEqual(Season.SPRING, Part.SPRING)
385 with self.assertRaises(TypeError):
386 Season.SPRING < Part.CLIP
387
388 def test_enum_duplicates(self):
389 class Season(Enum):
390 SPRING = 1
391 SUMMER = 2
392 AUTUMN = FALL = 3
393 WINTER = 4
394 ANOTHER_SPRING = 1
395 lst = list(Season)
396 self.assertEqual(
397 lst,
398 [Season.SPRING, Season.SUMMER,
399 Season.AUTUMN, Season.WINTER,
400 ])
401 self.assertIs(Season.FALL, Season.AUTUMN)
402 self.assertEqual(Season.FALL.value, 3)
403 self.assertEqual(Season.AUTUMN.value, 3)
404 self.assertIs(Season(3), Season.AUTUMN)
405 self.assertIs(Season(1), Season.SPRING)
406 self.assertEqual(Season.FALL.name, 'AUTUMN')
407 self.assertEqual(
408 [k for k,v in Season.__members__.items() if v.name != k],
409 ['FALL', 'ANOTHER_SPRING'],
410 )
411
Ethan Furman101e0742013-09-15 12:34:36 -0700412 def test_duplicate_name(self):
413 with self.assertRaises(TypeError):
414 class Color(Enum):
415 red = 1
416 green = 2
417 blue = 3
418 red = 4
419
420 with self.assertRaises(TypeError):
421 class Color(Enum):
422 red = 1
423 green = 2
424 blue = 3
425 def red(self):
426 return 'red'
427
428 with self.assertRaises(TypeError):
429 class Color(Enum):
430 @property
431 def red(self):
432 return 'redder'
433 red = 1
434 green = 2
435 blue = 3
436
Zackery Spytz2ec67522020-09-13 14:27:51 -0600437 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700438 with self.assertRaisesRegex(
439 ValueError,
Ethan Furmanb7751062021-03-30 21:17:26 -0700440 '_sunder_ names, such as ._bad_., are reserved',
Ethan Furman5a565b32020-09-15 12:27:06 -0700441 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600442 class Bad(Enum):
443 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700444
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700445 def test_enum_with_value_name(self):
446 class Huh(Enum):
447 name = 1
448 value = 2
449 self.assertEqual(
450 list(Huh),
451 [Huh.name, Huh.value],
452 )
453 self.assertIs(type(Huh.name), Huh)
454 self.assertEqual(Huh.name.name, 'name')
455 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700456
457 def test_format_enum(self):
458 Season = self.Season
459 self.assertEqual('{}'.format(Season.SPRING),
460 '{}'.format(str(Season.SPRING)))
461 self.assertEqual( '{:}'.format(Season.SPRING),
462 '{:}'.format(str(Season.SPRING)))
463 self.assertEqual('{:20}'.format(Season.SPRING),
464 '{:20}'.format(str(Season.SPRING)))
465 self.assertEqual('{:^20}'.format(Season.SPRING),
466 '{:^20}'.format(str(Season.SPRING)))
467 self.assertEqual('{:>20}'.format(Season.SPRING),
468 '{:>20}'.format(str(Season.SPRING)))
469 self.assertEqual('{:<20}'.format(Season.SPRING),
470 '{:<20}'.format(str(Season.SPRING)))
471
thatneat2f19e822019-07-04 11:28:37 -0700472 def test_str_override_enum(self):
473 class EnumWithStrOverrides(Enum):
474 one = auto()
475 two = auto()
476
477 def __str__(self):
478 return 'Str!'
479 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
480 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
481
482 def test_format_override_enum(self):
483 class EnumWithFormatOverride(Enum):
484 one = 1.0
485 two = 2.0
486 def __format__(self, spec):
487 return 'Format!!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700488 self.assertEqual(str(EnumWithFormatOverride.one), 'one')
thatneat2f19e822019-07-04 11:28:37 -0700489 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
490
491 def test_str_and_format_override_enum(self):
492 class EnumWithStrFormatOverrides(Enum):
493 one = auto()
494 two = auto()
495 def __str__(self):
496 return 'Str!'
497 def __format__(self, spec):
498 return 'Format!'
499 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
500 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
501
502 def test_str_override_mixin(self):
503 class MixinEnumWithStrOverride(float, Enum):
504 one = 1.0
505 two = 2.0
506 def __str__(self):
507 return 'Overridden!'
508 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
509 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
510
511 def test_str_and_format_override_mixin(self):
512 class MixinWithStrFormatOverrides(float, Enum):
513 one = 1.0
514 two = 2.0
515 def __str__(self):
516 return 'Str!'
517 def __format__(self, spec):
518 return 'Format!'
519 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
520 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
521
522 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700523 class TestFloat(float, Enum):
524 one = 1.0
525 two = 2.0
526 def __format__(self, spec):
527 return 'TestFloat success!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700528 self.assertEqual(str(TestFloat.one), 'one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700529 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
530
531 def assertFormatIsValue(self, spec, member):
532 self.assertEqual(spec.format(member), spec.format(member.value))
533
534 def test_format_enum_date(self):
535 Holiday = self.Holiday
536 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
537 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
538 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
539 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
540 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
541 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
542 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
543 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
544
545 def test_format_enum_float(self):
546 Konstants = self.Konstants
547 self.assertFormatIsValue('{}', Konstants.TAU)
548 self.assertFormatIsValue('{:}', Konstants.TAU)
549 self.assertFormatIsValue('{:20}', Konstants.TAU)
550 self.assertFormatIsValue('{:^20}', Konstants.TAU)
551 self.assertFormatIsValue('{:>20}', Konstants.TAU)
552 self.assertFormatIsValue('{:<20}', Konstants.TAU)
553 self.assertFormatIsValue('{:n}', Konstants.TAU)
554 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
555 self.assertFormatIsValue('{:f}', Konstants.TAU)
556
557 def test_format_enum_int(self):
558 Grades = self.Grades
559 self.assertFormatIsValue('{}', Grades.C)
560 self.assertFormatIsValue('{:}', Grades.C)
561 self.assertFormatIsValue('{:20}', Grades.C)
562 self.assertFormatIsValue('{:^20}', Grades.C)
563 self.assertFormatIsValue('{:>20}', Grades.C)
564 self.assertFormatIsValue('{:<20}', Grades.C)
565 self.assertFormatIsValue('{:+}', Grades.C)
566 self.assertFormatIsValue('{:08X}', Grades.C)
567 self.assertFormatIsValue('{:b}', Grades.C)
568
569 def test_format_enum_str(self):
570 Directional = self.Directional
571 self.assertFormatIsValue('{}', Directional.WEST)
572 self.assertFormatIsValue('{:}', Directional.WEST)
573 self.assertFormatIsValue('{:20}', Directional.WEST)
574 self.assertFormatIsValue('{:^20}', Directional.WEST)
575 self.assertFormatIsValue('{:>20}', Directional.WEST)
576 self.assertFormatIsValue('{:<20}', Directional.WEST)
577
Ethan Furman22415ad2020-09-15 16:28:25 -0700578 def test_object_str_override(self):
579 class Colors(Enum):
580 RED, GREEN, BLUE = 1, 2, 3
581 def __repr__(self):
582 return "test.%s" % (self._name_, )
583 __str__ = object.__str__
584 self.assertEqual(str(Colors.RED), 'test.RED')
585
Ethan Furmanbff01f32020-09-15 15:56:26 -0700586 def test_enum_str_override(self):
587 class MyStrEnum(Enum):
588 def __str__(self):
589 return 'MyStr'
590 class MyMethodEnum(Enum):
591 def hello(self):
592 return 'Hello! My name is %s' % self.name
593 class Test1Enum(MyMethodEnum, int, MyStrEnum):
594 One = 1
595 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800596 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800598 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700599 #
600 class Test2Enum(MyStrEnum, MyMethodEnum):
601 One = 1
602 Two = 2
603 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800604 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700605
606 def test_inherited_data_type(self):
607 class HexInt(int):
608 def __repr__(self):
609 return hex(self)
610 class MyEnum(HexInt, enum.Enum):
611 A = 1
612 B = 2
613 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700614 def __repr__(self):
615 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700616 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
617
618 def test_too_many_data_types(self):
619 with self.assertRaisesRegex(TypeError, 'too many data types'):
620 class Huh(str, int, Enum):
621 One = 1
622
623 class MyStr(str):
624 def hello(self):
625 return 'hello, %s' % self
626 class MyInt(int):
627 def repr(self):
628 return hex(self)
629 with self.assertRaisesRegex(TypeError, 'too many data types'):
630 class Huh(MyStr, MyInt, Enum):
631 One = 1
632
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700633 def test_hash(self):
634 Season = self.Season
635 dates = {}
636 dates[Season.WINTER] = '1225'
637 dates[Season.SPRING] = '0315'
638 dates[Season.SUMMER] = '0704'
639 dates[Season.AUTUMN] = '1031'
640 self.assertEqual(dates[Season.AUTUMN], '1031')
641
642 def test_intenum_from_scratch(self):
643 class phy(int, Enum):
644 pi = 3
645 tau = 2 * pi
646 self.assertTrue(phy.pi < phy.tau)
647
648 def test_intenum_inherited(self):
649 class IntEnum(int, Enum):
650 pass
651 class phy(IntEnum):
652 pi = 3
653 tau = 2 * pi
654 self.assertTrue(phy.pi < phy.tau)
655
656 def test_floatenum_from_scratch(self):
657 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700658 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700659 tau = 2 * pi
660 self.assertTrue(phy.pi < phy.tau)
661
662 def test_floatenum_inherited(self):
663 class FloatEnum(float, Enum):
664 pass
665 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700666 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 tau = 2 * pi
668 self.assertTrue(phy.pi < phy.tau)
669
670 def test_strenum_from_scratch(self):
671 class phy(str, Enum):
672 pi = 'Pi'
673 tau = 'Tau'
674 self.assertTrue(phy.pi < phy.tau)
675
Ethan Furman0063ff42020-09-21 17:23:13 -0700676 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700677 class phy(StrEnum):
678 pi = 'Pi'
679 tau = 'Tau'
680 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700681 self.assertEqual(phy.pi.upper(), 'PI')
682 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700683
684 def test_intenum(self):
685 class WeekDay(IntEnum):
686 SUNDAY = 1
687 MONDAY = 2
688 TUESDAY = 3
689 WEDNESDAY = 4
690 THURSDAY = 5
691 FRIDAY = 6
692 SATURDAY = 7
693
694 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
695 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
696
697 lst = list(WeekDay)
698 self.assertEqual(len(lst), len(WeekDay))
699 self.assertEqual(len(WeekDay), 7)
700 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
701 target = target.split()
702 for i, weekday in enumerate(target, 1):
703 e = WeekDay(i)
704 self.assertEqual(e, i)
705 self.assertEqual(int(e), i)
706 self.assertEqual(e.name, weekday)
707 self.assertIn(e, WeekDay)
708 self.assertEqual(lst.index(e)+1, i)
709 self.assertTrue(0 < e < 8)
710 self.assertIs(type(e), WeekDay)
711 self.assertIsInstance(e, int)
712 self.assertIsInstance(e, Enum)
713
714 def test_intenum_duplicates(self):
715 class WeekDay(IntEnum):
716 SUNDAY = 1
717 MONDAY = 2
718 TUESDAY = TEUSDAY = 3
719 WEDNESDAY = 4
720 THURSDAY = 5
721 FRIDAY = 6
722 SATURDAY = 7
723 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
724 self.assertEqual(WeekDay(3).name, 'TUESDAY')
725 self.assertEqual([k for k,v in WeekDay.__members__.items()
726 if v.name != k], ['TEUSDAY', ])
727
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300728 def test_intenum_from_bytes(self):
729 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
730 with self.assertRaises(ValueError):
731 IntStooges.from_bytes(b'\x00\x05', 'big')
732
733 def test_floatenum_fromhex(self):
734 h = float.hex(FloatStooges.MOE.value)
735 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
736 h = float.hex(FloatStooges.MOE.value + 0.01)
737 with self.assertRaises(ValueError):
738 FloatStooges.fromhex(h)
739
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700740 def test_pickle_enum(self):
741 if isinstance(Stooges, Exception):
742 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800743 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
744 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700745
746 def test_pickle_int(self):
747 if isinstance(IntStooges, Exception):
748 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800749 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
750 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700751
752 def test_pickle_float(self):
753 if isinstance(FloatStooges, Exception):
754 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800755 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
756 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700757
758 def test_pickle_enum_function(self):
759 if isinstance(Answer, Exception):
760 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800761 test_pickle_dump_load(self.assertIs, Answer.him)
762 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700763
764 def test_pickle_enum_function_with_module(self):
765 if isinstance(Question, Exception):
766 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800767 test_pickle_dump_load(self.assertIs, Question.who)
768 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700769
Ethan Furmanca1b7942014-02-08 11:36:27 -0800770 def test_enum_function_with_qualname(self):
771 if isinstance(Theory, Exception):
772 raise Theory
773 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
774
775 def test_class_nested_enum_and_pickle_protocol_four(self):
776 # would normally just have this directly in the class namespace
777 class NestedEnum(Enum):
778 twigs = 'common'
779 shiny = 'rare'
780
781 self.__class__.NestedEnum = NestedEnum
782 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300783 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784
Ethan Furman24e837f2015-03-18 17:27:57 -0700785 def test_pickle_by_name(self):
786 class ReplaceGlobalInt(IntEnum):
787 ONE = 1
788 TWO = 2
789 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
790 for proto in range(HIGHEST_PROTOCOL):
791 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
792
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700793 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800794 BadPickle = Enum(
795 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700796 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800797 # now break BadPickle to test exception raising
798 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800799 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
800 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700801
802 def test_string_enum(self):
803 class SkillLevel(str, Enum):
804 master = 'what is the sound of one hand clapping?'
805 journeyman = 'why did the chicken cross the road?'
806 apprentice = 'knock, knock!'
807 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
808
809 def test_getattr_getitem(self):
810 class Period(Enum):
811 morning = 1
812 noon = 2
813 evening = 3
814 night = 4
815 self.assertIs(Period(2), Period.noon)
816 self.assertIs(getattr(Period, 'night'), Period.night)
817 self.assertIs(Period['morning'], Period.morning)
818
819 def test_getattr_dunder(self):
820 Season = self.Season
821 self.assertTrue(getattr(Season, '__eq__'))
822
823 def test_iteration_order(self):
824 class Season(Enum):
825 SUMMER = 2
826 WINTER = 4
827 AUTUMN = 3
828 SPRING = 1
829 self.assertEqual(
830 list(Season),
831 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
832 )
833
Ethan Furman2131a4a2013-09-14 18:11:24 -0700834 def test_reversed_iteration_order(self):
835 self.assertEqual(
836 list(reversed(self.Season)),
837 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
838 self.Season.SPRING]
839 )
840
Martin Pantereb995702016-07-28 01:11:04 +0000841 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700842 SummerMonth = Enum('SummerMonth', 'june july august')
843 lst = list(SummerMonth)
844 self.assertEqual(len(lst), len(SummerMonth))
845 self.assertEqual(len(SummerMonth), 3, SummerMonth)
846 self.assertEqual(
847 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
848 lst,
849 )
850 for i, month in enumerate('june july august'.split(), 1):
851 e = SummerMonth(i)
852 self.assertEqual(int(e.value), i)
853 self.assertNotEqual(e, i)
854 self.assertEqual(e.name, month)
855 self.assertIn(e, SummerMonth)
856 self.assertIs(type(e), SummerMonth)
857
Martin Pantereb995702016-07-28 01:11:04 +0000858 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700859 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
860 lst = list(SummerMonth)
861 self.assertEqual(len(lst), len(SummerMonth))
862 self.assertEqual(len(SummerMonth), 3, SummerMonth)
863 self.assertEqual(
864 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
865 lst,
866 )
867 for i, month in enumerate('june july august'.split(), 10):
868 e = SummerMonth(i)
869 self.assertEqual(int(e.value), i)
870 self.assertNotEqual(e, i)
871 self.assertEqual(e.name, month)
872 self.assertIn(e, SummerMonth)
873 self.assertIs(type(e), SummerMonth)
874
Martin Pantereb995702016-07-28 01:11:04 +0000875 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700876 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
877 lst = list(SummerMonth)
878 self.assertEqual(len(lst), len(SummerMonth))
879 self.assertEqual(len(SummerMonth), 3, SummerMonth)
880 self.assertEqual(
881 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
882 lst,
883 )
884 for i, month in enumerate('june july august'.split(), 1):
885 e = SummerMonth(i)
886 self.assertEqual(int(e.value), i)
887 self.assertNotEqual(e, i)
888 self.assertEqual(e.name, month)
889 self.assertIn(e, SummerMonth)
890 self.assertIs(type(e), SummerMonth)
891
Martin Pantereb995702016-07-28 01:11:04 +0000892 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700893 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
894 lst = list(SummerMonth)
895 self.assertEqual(len(lst), len(SummerMonth))
896 self.assertEqual(len(SummerMonth), 3, SummerMonth)
897 self.assertEqual(
898 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
899 lst,
900 )
901 for i, month in enumerate('june july august'.split(), 20):
902 e = SummerMonth(i)
903 self.assertEqual(int(e.value), i)
904 self.assertNotEqual(e, i)
905 self.assertEqual(e.name, month)
906 self.assertIn(e, SummerMonth)
907 self.assertIs(type(e), SummerMonth)
908
Martin Pantereb995702016-07-28 01:11:04 +0000909 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700910 SummerMonth = Enum(
911 'SummerMonth',
912 (('june', 1), ('july', 2), ('august', 3))
913 )
914 lst = list(SummerMonth)
915 self.assertEqual(len(lst), len(SummerMonth))
916 self.assertEqual(len(SummerMonth), 3, SummerMonth)
917 self.assertEqual(
918 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
919 lst,
920 )
921 for i, month in enumerate('june july august'.split(), 1):
922 e = SummerMonth(i)
923 self.assertEqual(int(e.value), i)
924 self.assertNotEqual(e, i)
925 self.assertEqual(e.name, month)
926 self.assertIn(e, SummerMonth)
927 self.assertIs(type(e), SummerMonth)
928
Martin Pantereb995702016-07-28 01:11:04 +0000929 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700930 SummerMonth = Enum(
931 'SummerMonth',
932 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
933 )
934 lst = list(SummerMonth)
935 self.assertEqual(len(lst), len(SummerMonth))
936 self.assertEqual(len(SummerMonth), 3, SummerMonth)
937 self.assertEqual(
938 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
939 lst,
940 )
941 for i, month in enumerate('june july august'.split(), 1):
942 e = SummerMonth(i)
943 self.assertEqual(int(e.value), i)
944 self.assertNotEqual(e, i)
945 self.assertEqual(e.name, month)
946 self.assertIn(e, SummerMonth)
947 self.assertIs(type(e), SummerMonth)
948
Martin Pantereb995702016-07-28 01:11:04 +0000949 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700950 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
951 lst = list(SummerMonth)
952 self.assertEqual(len(lst), len(SummerMonth))
953 self.assertEqual(len(SummerMonth), 3, SummerMonth)
954 self.assertEqual(
955 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
956 lst,
957 )
958 for i, month in enumerate('june july august'.split(), 1):
959 e = SummerMonth(i)
960 self.assertEqual(e, i)
961 self.assertEqual(e.name, month)
962 self.assertIn(e, SummerMonth)
963 self.assertIs(type(e), SummerMonth)
964
Martin Pantereb995702016-07-28 01:11:04 +0000965 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700966 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
967 lst = list(SummerMonth)
968 self.assertEqual(len(lst), len(SummerMonth))
969 self.assertEqual(len(SummerMonth), 3, SummerMonth)
970 self.assertEqual(
971 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
972 lst,
973 )
974 for i, month in enumerate('june july august'.split(), 30):
975 e = SummerMonth(i)
976 self.assertEqual(e, i)
977 self.assertEqual(e.name, month)
978 self.assertIn(e, SummerMonth)
979 self.assertIs(type(e), SummerMonth)
980
Martin Pantereb995702016-07-28 01:11:04 +0000981 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700982 SummerMonth = IntEnum('SummerMonth', 'june july august')
983 lst = list(SummerMonth)
984 self.assertEqual(len(lst), len(SummerMonth))
985 self.assertEqual(len(SummerMonth), 3, SummerMonth)
986 self.assertEqual(
987 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
988 lst,
989 )
990 for i, month in enumerate('june july august'.split(), 1):
991 e = SummerMonth(i)
992 self.assertEqual(e, i)
993 self.assertEqual(e.name, month)
994 self.assertIn(e, SummerMonth)
995 self.assertIs(type(e), SummerMonth)
996
Martin Pantereb995702016-07-28 01:11:04 +0000997 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700998 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
999 lst = list(SummerMonth)
1000 self.assertEqual(len(lst), len(SummerMonth))
1001 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1002 self.assertEqual(
1003 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1004 lst,
1005 )
1006 for i, month in enumerate('june july august'.split(), 40):
1007 e = SummerMonth(i)
1008 self.assertEqual(e, i)
1009 self.assertEqual(e.name, month)
1010 self.assertIn(e, SummerMonth)
1011 self.assertIs(type(e), SummerMonth)
1012
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001013 def test_subclassing(self):
1014 if isinstance(Name, Exception):
1015 raise Name
1016 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1017 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1018 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001019 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001020
1021 def test_extending(self):
1022 class Color(Enum):
1023 red = 1
1024 green = 2
1025 blue = 3
1026 with self.assertRaises(TypeError):
1027 class MoreColor(Color):
1028 cyan = 4
1029 magenta = 5
1030 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001031 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1032 class EvenMoreColor(Color, IntEnum):
1033 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034
1035 def test_exclude_methods(self):
1036 class whatever(Enum):
1037 this = 'that'
1038 these = 'those'
1039 def really(self):
1040 return 'no, not %s' % self.value
1041 self.assertIsNot(type(whatever.really), whatever)
1042 self.assertEqual(whatever.this.really(), 'no, not that')
1043
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001044 def test_wrong_inheritance_order(self):
1045 with self.assertRaises(TypeError):
1046 class Wrong(Enum, str):
1047 NotHere = 'error before this point'
1048
1049 def test_intenum_transitivity(self):
1050 class number(IntEnum):
1051 one = 1
1052 two = 2
1053 three = 3
1054 class numero(IntEnum):
1055 uno = 1
1056 dos = 2
1057 tres = 3
1058 self.assertEqual(number.one, numero.uno)
1059 self.assertEqual(number.two, numero.dos)
1060 self.assertEqual(number.three, numero.tres)
1061
1062 def test_wrong_enum_in_call(self):
1063 class Monochrome(Enum):
1064 black = 0
1065 white = 1
1066 class Gender(Enum):
1067 male = 0
1068 female = 1
1069 self.assertRaises(ValueError, Monochrome, Gender.male)
1070
1071 def test_wrong_enum_in_mixed_call(self):
1072 class Monochrome(IntEnum):
1073 black = 0
1074 white = 1
1075 class Gender(Enum):
1076 male = 0
1077 female = 1
1078 self.assertRaises(ValueError, Monochrome, Gender.male)
1079
1080 def test_mixed_enum_in_call_1(self):
1081 class Monochrome(IntEnum):
1082 black = 0
1083 white = 1
1084 class Gender(IntEnum):
1085 male = 0
1086 female = 1
1087 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1088
1089 def test_mixed_enum_in_call_2(self):
1090 class Monochrome(Enum):
1091 black = 0
1092 white = 1
1093 class Gender(IntEnum):
1094 male = 0
1095 female = 1
1096 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1097
1098 def test_flufl_enum(self):
1099 class Fluflnum(Enum):
1100 def __int__(self):
1101 return int(self.value)
1102 class MailManOptions(Fluflnum):
1103 option1 = 1
1104 option2 = 2
1105 option3 = 3
1106 self.assertEqual(int(MailManOptions.option1), 1)
1107
Ethan Furman5e5a8232013-08-04 08:42:23 -07001108 def test_introspection(self):
1109 class Number(IntEnum):
1110 one = 100
1111 two = 200
1112 self.assertIs(Number.one._member_type_, int)
1113 self.assertIs(Number._member_type_, int)
1114 class String(str, Enum):
1115 yarn = 'soft'
1116 rope = 'rough'
1117 wire = 'hard'
1118 self.assertIs(String.yarn._member_type_, str)
1119 self.assertIs(String._member_type_, str)
1120 class Plain(Enum):
1121 vanilla = 'white'
1122 one = 1
1123 self.assertIs(Plain.vanilla._member_type_, object)
1124 self.assertIs(Plain._member_type_, object)
1125
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001126 def test_no_such_enum_member(self):
1127 class Color(Enum):
1128 red = 1
1129 green = 2
1130 blue = 3
1131 with self.assertRaises(ValueError):
1132 Color(4)
1133 with self.assertRaises(KeyError):
1134 Color['chartreuse']
1135
1136 def test_new_repr(self):
1137 class Color(Enum):
1138 red = 1
1139 green = 2
1140 blue = 3
1141 def __repr__(self):
1142 return "don't you just love shades of %s?" % self.name
1143 self.assertEqual(
1144 repr(Color.blue),
1145 "don't you just love shades of blue?",
1146 )
1147
1148 def test_inherited_repr(self):
1149 class MyEnum(Enum):
1150 def __repr__(self):
1151 return "My name is %s." % self.name
1152 class MyIntEnum(int, MyEnum):
1153 this = 1
1154 that = 2
1155 theother = 3
1156 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1157
1158 def test_multiple_mixin_mro(self):
1159 class auto_enum(type(Enum)):
1160 def __new__(metacls, cls, bases, classdict):
1161 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001162 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001163 names = set(classdict._member_names)
1164 i = 0
1165 for k in classdict._member_names:
1166 v = classdict[k]
1167 if v is Ellipsis:
1168 v = i
1169 else:
1170 i = v
1171 i += 1
1172 temp[k] = v
1173 for k, v in classdict.items():
1174 if k not in names:
1175 temp[k] = v
1176 return super(auto_enum, metacls).__new__(
1177 metacls, cls, bases, temp)
1178
1179 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1180 pass
1181
1182 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1183 pass
1184
1185 class TestAutoNumber(AutoNumberedEnum):
1186 a = ...
1187 b = 3
1188 c = ...
1189
1190 class TestAutoInt(AutoIntEnum):
1191 a = ...
1192 b = 3
1193 c = ...
1194
1195 def test_subclasses_with_getnewargs(self):
1196 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001197 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001198 def __new__(cls, *args):
1199 _args = args
1200 name, *args = args
1201 if len(args) == 0:
1202 raise TypeError("name and value must be specified")
1203 self = int.__new__(cls, *args)
1204 self._intname = name
1205 self._args = _args
1206 return self
1207 def __getnewargs__(self):
1208 return self._args
1209 @property
1210 def __name__(self):
1211 return self._intname
1212 def __repr__(self):
1213 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001214 return "{}({!r}, {})".format(
1215 type(self).__name__,
1216 self.__name__,
1217 int.__repr__(self),
1218 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001219 def __str__(self):
1220 # str() is unchanged, even if it relies on the repr() fallback
1221 base = int
1222 base_str = base.__str__
1223 if base_str.__objclass__ is object:
1224 return base.__repr__(self)
1225 return base_str(self)
1226 # for simplicity, we only define one operator that
1227 # propagates expressions
1228 def __add__(self, other):
1229 temp = int(self) + int( other)
1230 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1231 return NamedInt(
1232 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001233 temp,
1234 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001235 else:
1236 return temp
1237
1238 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001239 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240 x = ('the-x', 1)
1241 y = ('the-y', 2)
1242
Ethan Furman2aa27322013-07-19 19:35:56 -07001243
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001244 self.assertIs(NEI.__new__, Enum.__new__)
1245 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1246 globals()['NamedInt'] = NamedInt
1247 globals()['NEI'] = NEI
1248 NI5 = NamedInt('test', 5)
1249 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001250 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001251 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001252 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001253 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001254
Ethan Furmanca1b7942014-02-08 11:36:27 -08001255 def test_subclasses_with_getnewargs_ex(self):
1256 class NamedInt(int):
1257 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1258 def __new__(cls, *args):
1259 _args = args
1260 name, *args = args
1261 if len(args) == 0:
1262 raise TypeError("name and value must be specified")
1263 self = int.__new__(cls, *args)
1264 self._intname = name
1265 self._args = _args
1266 return self
1267 def __getnewargs_ex__(self):
1268 return self._args, {}
1269 @property
1270 def __name__(self):
1271 return self._intname
1272 def __repr__(self):
1273 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001274 return "{}({!r}, {})".format(
1275 type(self).__name__,
1276 self.__name__,
1277 int.__repr__(self),
1278 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001279 def __str__(self):
1280 # str() is unchanged, even if it relies on the repr() fallback
1281 base = int
1282 base_str = base.__str__
1283 if base_str.__objclass__ is object:
1284 return base.__repr__(self)
1285 return base_str(self)
1286 # for simplicity, we only define one operator that
1287 # propagates expressions
1288 def __add__(self, other):
1289 temp = int(self) + int( other)
1290 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1291 return NamedInt(
1292 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001293 temp,
1294 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001295 else:
1296 return temp
1297
1298 class NEI(NamedInt, Enum):
1299 __qualname__ = 'NEI' # needed for pickle protocol 4
1300 x = ('the-x', 1)
1301 y = ('the-y', 2)
1302
1303
1304 self.assertIs(NEI.__new__, Enum.__new__)
1305 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1306 globals()['NamedInt'] = NamedInt
1307 globals()['NEI'] = NEI
1308 NI5 = NamedInt('test', 5)
1309 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001310 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001311 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001312 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001313 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001314
1315 def test_subclasses_with_reduce(self):
1316 class NamedInt(int):
1317 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1318 def __new__(cls, *args):
1319 _args = args
1320 name, *args = args
1321 if len(args) == 0:
1322 raise TypeError("name and value must be specified")
1323 self = int.__new__(cls, *args)
1324 self._intname = name
1325 self._args = _args
1326 return self
1327 def __reduce__(self):
1328 return self.__class__, self._args
1329 @property
1330 def __name__(self):
1331 return self._intname
1332 def __repr__(self):
1333 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001334 return "{}({!r}, {})".format(
1335 type(self).__name__,
1336 self.__name__,
1337 int.__repr__(self),
1338 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001339 def __str__(self):
1340 # str() is unchanged, even if it relies on the repr() fallback
1341 base = int
1342 base_str = base.__str__
1343 if base_str.__objclass__ is object:
1344 return base.__repr__(self)
1345 return base_str(self)
1346 # for simplicity, we only define one operator that
1347 # propagates expressions
1348 def __add__(self, other):
1349 temp = int(self) + int( other)
1350 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1351 return NamedInt(
1352 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001353 temp,
1354 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001355 else:
1356 return temp
1357
1358 class NEI(NamedInt, Enum):
1359 __qualname__ = 'NEI' # needed for pickle protocol 4
1360 x = ('the-x', 1)
1361 y = ('the-y', 2)
1362
1363
1364 self.assertIs(NEI.__new__, Enum.__new__)
1365 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1366 globals()['NamedInt'] = NamedInt
1367 globals()['NEI'] = NEI
1368 NI5 = NamedInt('test', 5)
1369 self.assertEqual(NI5, 5)
1370 test_pickle_dump_load(self.assertEqual, NI5, 5)
1371 self.assertEqual(NEI.y.value, 2)
1372 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001373 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001374
1375 def test_subclasses_with_reduce_ex(self):
1376 class NamedInt(int):
1377 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1378 def __new__(cls, *args):
1379 _args = args
1380 name, *args = args
1381 if len(args) == 0:
1382 raise TypeError("name and value must be specified")
1383 self = int.__new__(cls, *args)
1384 self._intname = name
1385 self._args = _args
1386 return self
1387 def __reduce_ex__(self, proto):
1388 return self.__class__, self._args
1389 @property
1390 def __name__(self):
1391 return self._intname
1392 def __repr__(self):
1393 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001394 return "{}({!r}, {})".format(
1395 type(self).__name__,
1396 self.__name__,
1397 int.__repr__(self),
1398 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001399 def __str__(self):
1400 # str() is unchanged, even if it relies on the repr() fallback
1401 base = int
1402 base_str = base.__str__
1403 if base_str.__objclass__ is object:
1404 return base.__repr__(self)
1405 return base_str(self)
1406 # for simplicity, we only define one operator that
1407 # propagates expressions
1408 def __add__(self, other):
1409 temp = int(self) + int( other)
1410 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1411 return NamedInt(
1412 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001413 temp,
1414 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001415 else:
1416 return temp
1417
1418 class NEI(NamedInt, Enum):
1419 __qualname__ = 'NEI' # needed for pickle protocol 4
1420 x = ('the-x', 1)
1421 y = ('the-y', 2)
1422
Ethan Furmanca1b7942014-02-08 11:36:27 -08001423 self.assertIs(NEI.__new__, Enum.__new__)
1424 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1425 globals()['NamedInt'] = NamedInt
1426 globals()['NEI'] = NEI
1427 NI5 = NamedInt('test', 5)
1428 self.assertEqual(NI5, 5)
1429 test_pickle_dump_load(self.assertEqual, NI5, 5)
1430 self.assertEqual(NEI.y.value, 2)
1431 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001432 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001433
Ethan Furmandc870522014-02-18 12:37:12 -08001434 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001435 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001436 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001437 def __new__(cls, *args):
1438 _args = args
1439 name, *args = args
1440 if len(args) == 0:
1441 raise TypeError("name and value must be specified")
1442 self = int.__new__(cls, *args)
1443 self._intname = name
1444 self._args = _args
1445 return self
1446 @property
1447 def __name__(self):
1448 return self._intname
1449 def __repr__(self):
1450 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001451 return "{}({!r}, {})".format(
1452 type(self).__name__,
1453 self.__name__,
1454 int.__repr__(self),
1455 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 def __str__(self):
1457 # str() is unchanged, even if it relies on the repr() fallback
1458 base = int
1459 base_str = base.__str__
1460 if base_str.__objclass__ is object:
1461 return base.__repr__(self)
1462 return base_str(self)
1463 # for simplicity, we only define one operator that
1464 # propagates expressions
1465 def __add__(self, other):
1466 temp = int(self) + int( other)
1467 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1468 return NamedInt(
1469 '({0} + {1})'.format(self.__name__, other.__name__),
1470 temp )
1471 else:
1472 return temp
1473
1474 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001475 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001476 x = ('the-x', 1)
1477 y = ('the-y', 2)
1478
1479 self.assertIs(NEI.__new__, Enum.__new__)
1480 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1481 globals()['NamedInt'] = NamedInt
1482 globals()['NEI'] = NEI
1483 NI5 = NamedInt('test', 5)
1484 self.assertEqual(NI5, 5)
1485 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001486 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1487 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001488
Ethan Furmandc870522014-02-18 12:37:12 -08001489 def test_subclasses_without_direct_pickle_support_using_name(self):
1490 class NamedInt(int):
1491 __qualname__ = 'NamedInt'
1492 def __new__(cls, *args):
1493 _args = args
1494 name, *args = args
1495 if len(args) == 0:
1496 raise TypeError("name and value must be specified")
1497 self = int.__new__(cls, *args)
1498 self._intname = name
1499 self._args = _args
1500 return self
1501 @property
1502 def __name__(self):
1503 return self._intname
1504 def __repr__(self):
1505 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001506 return "{}({!r}, {})".format(
1507 type(self).__name__,
1508 self.__name__,
1509 int.__repr__(self),
1510 )
Ethan Furmandc870522014-02-18 12:37:12 -08001511 def __str__(self):
1512 # str() is unchanged, even if it relies on the repr() fallback
1513 base = int
1514 base_str = base.__str__
1515 if base_str.__objclass__ is object:
1516 return base.__repr__(self)
1517 return base_str(self)
1518 # for simplicity, we only define one operator that
1519 # propagates expressions
1520 def __add__(self, other):
1521 temp = int(self) + int( other)
1522 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1523 return NamedInt(
1524 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001525 temp,
1526 )
Ethan Furmandc870522014-02-18 12:37:12 -08001527 else:
1528 return temp
1529
1530 class NEI(NamedInt, Enum):
1531 __qualname__ = 'NEI'
1532 x = ('the-x', 1)
1533 y = ('the-y', 2)
1534 def __reduce_ex__(self, proto):
1535 return getattr, (self.__class__, self._name_)
1536
1537 self.assertIs(NEI.__new__, Enum.__new__)
1538 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1539 globals()['NamedInt'] = NamedInt
1540 globals()['NEI'] = NEI
1541 NI5 = NamedInt('test', 5)
1542 self.assertEqual(NI5, 5)
1543 self.assertEqual(NEI.y.value, 2)
1544 test_pickle_dump_load(self.assertIs, NEI.y)
1545 test_pickle_dump_load(self.assertIs, NEI)
1546
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 def test_tuple_subclass(self):
1548 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001549 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001550 first = (1, 'for the money')
1551 second = (2, 'for the show')
1552 third = (3, 'for the music')
1553 self.assertIs(type(SomeTuple.first), SomeTuple)
1554 self.assertIsInstance(SomeTuple.second, tuple)
1555 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1556 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001557 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558
1559 def test_duplicate_values_give_unique_enum_items(self):
1560 class AutoNumber(Enum):
1561 first = ()
1562 second = ()
1563 third = ()
1564 def __new__(cls):
1565 value = len(cls.__members__) + 1
1566 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001567 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001568 return obj
1569 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001570 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001571 self.assertEqual(
1572 list(AutoNumber),
1573 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1574 )
1575 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001576 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 self.assertIs(AutoNumber(1), AutoNumber.first)
1578
1579 def test_inherited_new_from_enhanced_enum(self):
1580 class AutoNumber(Enum):
1581 def __new__(cls):
1582 value = len(cls.__members__) + 1
1583 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001584 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001585 return obj
1586 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001587 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001588 class Color(AutoNumber):
1589 red = ()
1590 green = ()
1591 blue = ()
1592 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1593 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1594
1595 def test_inherited_new_from_mixed_enum(self):
1596 class AutoNumber(IntEnum):
1597 def __new__(cls):
1598 value = len(cls.__members__) + 1
1599 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001600 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001601 return obj
1602 class Color(AutoNumber):
1603 red = ()
1604 green = ()
1605 blue = ()
1606 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1607 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1608
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001609 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001610 class OrdinaryEnum(Enum):
1611 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001612 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1613 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001614
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001615 def test_ordered_mixin(self):
1616 class OrderedEnum(Enum):
1617 def __ge__(self, other):
1618 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001619 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001620 return NotImplemented
1621 def __gt__(self, other):
1622 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001623 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001624 return NotImplemented
1625 def __le__(self, other):
1626 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001627 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001628 return NotImplemented
1629 def __lt__(self, other):
1630 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001631 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001632 return NotImplemented
1633 class Grade(OrderedEnum):
1634 A = 5
1635 B = 4
1636 C = 3
1637 D = 2
1638 F = 1
1639 self.assertGreater(Grade.A, Grade.B)
1640 self.assertLessEqual(Grade.F, Grade.C)
1641 self.assertLess(Grade.D, Grade.A)
1642 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001643 self.assertEqual(Grade.B, Grade.B)
1644 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001645
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001646 def test_extending2(self):
1647 class Shade(Enum):
1648 def shade(self):
1649 print(self.name)
1650 class Color(Shade):
1651 red = 1
1652 green = 2
1653 blue = 3
1654 with self.assertRaises(TypeError):
1655 class MoreColor(Color):
1656 cyan = 4
1657 magenta = 5
1658 yellow = 6
1659
1660 def test_extending3(self):
1661 class Shade(Enum):
1662 def shade(self):
1663 return self.name
1664 class Color(Shade):
1665 def hex(self):
1666 return '%s hexlified!' % self.value
1667 class MoreColor(Color):
1668 cyan = 4
1669 magenta = 5
1670 yellow = 6
1671 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1672
orlnub1230fb9fad2018-09-12 20:28:53 +03001673 def test_subclass_duplicate_name(self):
1674 class Base(Enum):
1675 def test(self):
1676 pass
1677 class Test(Base):
1678 test = 1
1679 self.assertIs(type(Test.test), Test)
1680
1681 def test_subclass_duplicate_name_dynamic(self):
1682 from types import DynamicClassAttribute
1683 class Base(Enum):
1684 @DynamicClassAttribute
1685 def test(self):
1686 return 'dynamic'
1687 class Test(Base):
1688 test = 1
1689 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001690 class Base2(Enum):
1691 @enum.property
1692 def flash(self):
1693 return 'flashy dynamic'
1694 class Test(Base2):
1695 flash = 1
1696 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001697
1698 def test_no_duplicates(self):
1699 class UniqueEnum(Enum):
1700 def __init__(self, *args):
1701 cls = self.__class__
1702 if any(self.value == e.value for e in cls):
1703 a = self.name
1704 e = cls(self.value).name
1705 raise ValueError(
1706 "aliases not allowed in UniqueEnum: %r --> %r"
1707 % (a, e)
1708 )
1709 class Color(UniqueEnum):
1710 red = 1
1711 green = 2
1712 blue = 3
1713 with self.assertRaises(ValueError):
1714 class Color(UniqueEnum):
1715 red = 1
1716 green = 2
1717 blue = 3
1718 grene = 2
1719
1720 def test_init(self):
1721 class Planet(Enum):
1722 MERCURY = (3.303e+23, 2.4397e6)
1723 VENUS = (4.869e+24, 6.0518e6)
1724 EARTH = (5.976e+24, 6.37814e6)
1725 MARS = (6.421e+23, 3.3972e6)
1726 JUPITER = (1.9e+27, 7.1492e7)
1727 SATURN = (5.688e+26, 6.0268e7)
1728 URANUS = (8.686e+25, 2.5559e7)
1729 NEPTUNE = (1.024e+26, 2.4746e7)
1730 def __init__(self, mass, radius):
1731 self.mass = mass # in kilograms
1732 self.radius = radius # in meters
1733 @property
1734 def surface_gravity(self):
1735 # universal gravitational constant (m3 kg-1 s-2)
1736 G = 6.67300E-11
1737 return G * self.mass / (self.radius * self.radius)
1738 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1739 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1740
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001741 def test_ignore(self):
1742 class Period(timedelta, Enum):
1743 '''
1744 different lengths of time
1745 '''
1746 def __new__(cls, value, period):
1747 obj = timedelta.__new__(cls, value)
1748 obj._value_ = value
1749 obj.period = period
1750 return obj
1751 _ignore_ = 'Period i'
1752 Period = vars()
1753 for i in range(13):
1754 Period['month_%d' % i] = i*30, 'month'
1755 for i in range(53):
1756 Period['week_%d' % i] = i*7, 'week'
1757 for i in range(32):
1758 Period['day_%d' % i] = i, 'day'
1759 OneDay = day_1
1760 OneWeek = week_1
1761 OneMonth = month_1
1762 self.assertFalse(hasattr(Period, '_ignore_'))
1763 self.assertFalse(hasattr(Period, 'Period'))
1764 self.assertFalse(hasattr(Period, 'i'))
1765 self.assertTrue(isinstance(Period.day_1, timedelta))
1766 self.assertTrue(Period.month_1 is Period.day_30)
1767 self.assertTrue(Period.week_4 is Period.day_28)
1768
Ethan Furman2aa27322013-07-19 19:35:56 -07001769 def test_nonhash_value(self):
1770 class AutoNumberInAList(Enum):
1771 def __new__(cls):
1772 value = [len(cls.__members__) + 1]
1773 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001774 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001775 return obj
1776 class ColorInAList(AutoNumberInAList):
1777 red = ()
1778 green = ()
1779 blue = ()
1780 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001781 for enum, value in zip(ColorInAList, range(3)):
1782 value += 1
1783 self.assertEqual(enum.value, [value])
1784 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001785
Ethan Furmanb41803e2013-07-25 13:50:45 -07001786 def test_conflicting_types_resolved_in_new(self):
1787 class LabelledIntEnum(int, Enum):
1788 def __new__(cls, *args):
1789 value, label = args
1790 obj = int.__new__(cls, value)
1791 obj.label = label
1792 obj._value_ = value
1793 return obj
1794
1795 class LabelledList(LabelledIntEnum):
1796 unprocessed = (1, "Unprocessed")
1797 payment_complete = (2, "Payment Complete")
1798
1799 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1800 self.assertEqual(LabelledList.unprocessed, 1)
1801 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001802
Ethan Furmanc16595e2016-09-10 23:36:59 -07001803 def test_auto_number(self):
1804 class Color(Enum):
1805 red = auto()
1806 blue = auto()
1807 green = auto()
1808
1809 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1810 self.assertEqual(Color.red.value, 1)
1811 self.assertEqual(Color.blue.value, 2)
1812 self.assertEqual(Color.green.value, 3)
1813
1814 def test_auto_name(self):
1815 class Color(Enum):
1816 def _generate_next_value_(name, start, count, last):
1817 return name
1818 red = auto()
1819 blue = auto()
1820 green = auto()
1821
1822 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1823 self.assertEqual(Color.red.value, 'red')
1824 self.assertEqual(Color.blue.value, 'blue')
1825 self.assertEqual(Color.green.value, 'green')
1826
1827 def test_auto_name_inherit(self):
1828 class AutoNameEnum(Enum):
1829 def _generate_next_value_(name, start, count, last):
1830 return name
1831 class Color(AutoNameEnum):
1832 red = auto()
1833 blue = auto()
1834 green = auto()
1835
1836 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1837 self.assertEqual(Color.red.value, 'red')
1838 self.assertEqual(Color.blue.value, 'blue')
1839 self.assertEqual(Color.green.value, 'green')
1840
1841 def test_auto_garbage(self):
1842 class Color(Enum):
1843 red = 'red'
1844 blue = auto()
1845 self.assertEqual(Color.blue.value, 1)
1846
1847 def test_auto_garbage_corrected(self):
1848 class Color(Enum):
1849 red = 'red'
1850 blue = 2
1851 green = auto()
1852
1853 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1854 self.assertEqual(Color.red.value, 'red')
1855 self.assertEqual(Color.blue.value, 2)
1856 self.assertEqual(Color.green.value, 3)
1857
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001858 def test_auto_order(self):
1859 with self.assertRaises(TypeError):
1860 class Color(Enum):
1861 red = auto()
1862 green = auto()
1863 blue = auto()
1864 def _generate_next_value_(name, start, count, last):
1865 return name
1866
Ethan Furmanfc23a942020-09-16 12:37:54 -07001867 def test_auto_order_wierd(self):
1868 weird_auto = auto()
1869 weird_auto.value = 'pathological case'
1870 class Color(Enum):
1871 red = weird_auto
1872 def _generate_next_value_(name, start, count, last):
1873 return name
1874 blue = auto()
1875 self.assertEqual(list(Color), [Color.red, Color.blue])
1876 self.assertEqual(Color.red.value, 'pathological case')
1877 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001878
Ethan Furman3515dcc2016-09-18 13:15:41 -07001879 def test_duplicate_auto(self):
1880 class Dupes(Enum):
1881 first = primero = auto()
1882 second = auto()
1883 third = auto()
1884 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1885
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001886 def test_default_missing(self):
1887 class Color(Enum):
1888 RED = 1
1889 GREEN = 2
1890 BLUE = 3
1891 try:
1892 Color(7)
1893 except ValueError as exc:
1894 self.assertTrue(exc.__context__ is None)
1895 else:
1896 raise Exception('Exception not raised.')
1897
Ethan Furman019f0a02018-09-12 11:43:34 -07001898 def test_missing(self):
1899 class Color(Enum):
1900 red = 1
1901 green = 2
1902 blue = 3
1903 @classmethod
1904 def _missing_(cls, item):
1905 if item == 'three':
1906 return cls.blue
1907 elif item == 'bad return':
1908 # trigger internal error
1909 return 5
1910 elif item == 'error out':
1911 raise ZeroDivisionError
1912 else:
1913 # trigger not found
1914 return None
1915 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001916 try:
1917 Color(7)
1918 except ValueError as exc:
1919 self.assertTrue(exc.__context__ is None)
1920 else:
1921 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001922 try:
1923 Color('bad return')
1924 except TypeError as exc:
1925 self.assertTrue(isinstance(exc.__context__, ValueError))
1926 else:
1927 raise Exception('Exception not raised.')
1928 try:
1929 Color('error out')
1930 except ZeroDivisionError as exc:
1931 self.assertTrue(isinstance(exc.__context__, ValueError))
1932 else:
1933 raise Exception('Exception not raised.')
1934
Ethan Furman5bdab642018-09-21 19:03:09 -07001935 def test_multiple_mixin(self):
1936 class MaxMixin:
1937 @classproperty
1938 def MAX(cls):
1939 max = len(cls)
1940 cls.MAX = max
1941 return max
1942 class StrMixin:
1943 def __str__(self):
1944 return self._name_.lower()
1945 class SomeEnum(Enum):
1946 def behavior(self):
1947 return 'booyah'
1948 class AnotherEnum(Enum):
1949 def behavior(self):
1950 return 'nuhuh!'
1951 def social(self):
1952 return "what's up?"
1953 class Color(MaxMixin, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(Color.RED.value, 1)
1958 self.assertEqual(Color.GREEN.value, 2)
1959 self.assertEqual(Color.BLUE.value, 3)
1960 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07001961 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07001962 class Color(MaxMixin, StrMixin, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(Color.RED.value, 1)
1967 self.assertEqual(Color.GREEN.value, 2)
1968 self.assertEqual(Color.BLUE.value, 3)
1969 self.assertEqual(Color.MAX, 3)
1970 self.assertEqual(str(Color.BLUE), 'blue')
1971 class Color(StrMixin, MaxMixin, Enum):
1972 RED = auto()
1973 GREEN = auto()
1974 BLUE = auto()
1975 self.assertEqual(Color.RED.value, 1)
1976 self.assertEqual(Color.GREEN.value, 2)
1977 self.assertEqual(Color.BLUE.value, 3)
1978 self.assertEqual(Color.MAX, 3)
1979 self.assertEqual(str(Color.BLUE), 'blue')
1980 class CoolColor(StrMixin, SomeEnum, Enum):
1981 RED = auto()
1982 GREEN = auto()
1983 BLUE = auto()
1984 self.assertEqual(CoolColor.RED.value, 1)
1985 self.assertEqual(CoolColor.GREEN.value, 2)
1986 self.assertEqual(CoolColor.BLUE.value, 3)
1987 self.assertEqual(str(CoolColor.BLUE), 'blue')
1988 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1989 class CoolerColor(StrMixin, AnotherEnum, Enum):
1990 RED = auto()
1991 GREEN = auto()
1992 BLUE = auto()
1993 self.assertEqual(CoolerColor.RED.value, 1)
1994 self.assertEqual(CoolerColor.GREEN.value, 2)
1995 self.assertEqual(CoolerColor.BLUE.value, 3)
1996 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1997 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1998 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1999 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2000 RED = auto()
2001 GREEN = auto()
2002 BLUE = auto()
2003 self.assertEqual(CoolestColor.RED.value, 1)
2004 self.assertEqual(CoolestColor.GREEN.value, 2)
2005 self.assertEqual(CoolestColor.BLUE.value, 3)
2006 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2007 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2008 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2009 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2010 RED = auto()
2011 GREEN = auto()
2012 BLUE = auto()
2013 self.assertEqual(ConfusedColor.RED.value, 1)
2014 self.assertEqual(ConfusedColor.GREEN.value, 2)
2015 self.assertEqual(ConfusedColor.BLUE.value, 3)
2016 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2017 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2018 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2019 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2020 RED = auto()
2021 GREEN = auto()
2022 BLUE = auto()
2023 self.assertEqual(ReformedColor.RED.value, 1)
2024 self.assertEqual(ReformedColor.GREEN.value, 2)
2025 self.assertEqual(ReformedColor.BLUE.value, 3)
2026 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2027 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2028 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2029 self.assertTrue(issubclass(ReformedColor, int))
2030
Ethan Furmancd453852018-10-05 23:29:36 -07002031 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002032 @unique
2033 class Decision1(StrEnum):
2034 REVERT = "REVERT"
2035 REVERT_ALL = "REVERT_ALL"
2036 RETRY = "RETRY"
2037 class MyEnum(StrEnum):
2038 pass
2039 @unique
2040 class Decision2(MyEnum):
2041 REVERT = "REVERT"
2042 REVERT_ALL = "REVERT_ALL"
2043 RETRY = "RETRY"
2044
Ethan Furmanc2667362020-12-07 00:17:31 -08002045 def test_multiple_mixin_inherited(self):
2046 class MyInt(int):
2047 def __new__(cls, value):
2048 return super().__new__(cls, value)
2049
2050 class HexMixin:
2051 def __repr__(self):
2052 return hex(self)
2053
2054 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2055 pass
2056
2057 class Foo(MyIntEnum):
2058 TEST = 1
2059 self.assertTrue(isinstance(Foo.TEST, MyInt))
2060 self.assertEqual(repr(Foo.TEST), "0x1")
2061
2062 class Fee(MyIntEnum):
2063 TEST = 1
2064 def __new__(cls, value):
2065 value += 1
2066 member = int.__new__(cls, value)
2067 member._value_ = value
2068 return member
2069 self.assertEqual(Fee.TEST, 2)
2070
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002071 def test_empty_globals(self):
2072 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2073 # when using compile and exec because f_globals is empty
2074 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2075 code = compile(code, "<string>", "exec")
2076 global_ns = {}
2077 local_ls = {}
2078 exec(code, global_ns, local_ls)
2079
Ethan Furman0063ff42020-09-21 17:23:13 -07002080 def test_strenum(self):
2081 class GoodStrEnum(StrEnum):
2082 one = '1'
2083 two = '2'
2084 three = b'3', 'ascii'
2085 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002086 self.assertEqual(GoodStrEnum.one, '1')
2087 self.assertEqual(str(GoodStrEnum.one), '1')
2088 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2089 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2090 #
2091 class DumbMixin:
2092 def __str__(self):
2093 return "don't do this"
2094 class DumbStrEnum(DumbMixin, StrEnum):
2095 five = '5'
2096 six = '6'
2097 seven = '7'
2098 self.assertEqual(DumbStrEnum.seven, '7')
2099 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2100 #
2101 class EnumMixin(Enum):
2102 def hello(self):
2103 print('hello from %s' % (self, ))
2104 class HelloEnum(EnumMixin, StrEnum):
2105 eight = '8'
2106 self.assertEqual(HelloEnum.eight, '8')
2107 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2108 #
2109 class GoodbyeMixin:
2110 def goodbye(self):
2111 print('%s wishes you a fond farewell')
2112 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2113 nine = '9'
2114 self.assertEqual(GoodbyeEnum.nine, '9')
2115 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2116 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002117 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2118 class FirstFailedStrEnum(StrEnum):
2119 one = 1
2120 two = '2'
2121 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2122 class SecondFailedStrEnum(StrEnum):
2123 one = '1'
2124 two = 2,
2125 three = '3'
2126 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2127 class ThirdFailedStrEnum(StrEnum):
2128 one = '1'
2129 two = 2
2130 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2131 class ThirdFailedStrEnum(StrEnum):
2132 one = '1'
2133 two = b'2', sys.getdefaultencoding
2134 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2135 class ThirdFailedStrEnum(StrEnum):
2136 one = '1'
2137 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002138
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002139 def test_missing_value_error(self):
2140 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2141 class Combined(str, Enum):
2142 #
2143 def __new__(cls, value, sequence):
2144 enum = str.__new__(cls, value)
2145 if '(' in value:
2146 fis_name, segment = value.split('(', 1)
2147 segment = segment.strip(' )')
2148 else:
2149 fis_name = value
2150 segment = None
2151 enum.fis_name = fis_name
2152 enum.segment = segment
2153 enum.sequence = sequence
2154 return enum
2155 #
2156 def __repr__(self):
2157 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2158 #
2159 key_type = 'An$(1,2)', 0
2160 company_id = 'An$(3,2)', 1
2161 code = 'An$(5,1)', 2
2162 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002163
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002164 @unittest.skipUnless(
2165 sys.version_info[:2] == (3, 9),
2166 'private variables are now normal attributes',
2167 )
2168 def test_warning_for_private_variables(self):
2169 with self.assertWarns(DeprecationWarning):
2170 class Private(Enum):
2171 __corporal = 'Radar'
2172 self.assertEqual(Private._Private__corporal.value, 'Radar')
2173 try:
2174 with self.assertWarns(DeprecationWarning):
2175 class Private(Enum):
2176 __major_ = 'Hoolihan'
2177 except ValueError:
2178 pass
2179
2180 def test_private_variable_is_normal_attribute(self):
2181 class Private(Enum):
2182 __corporal = 'Radar'
2183 __major_ = 'Hoolihan'
2184 self.assertEqual(Private._Private__corporal, 'Radar')
2185 self.assertEqual(Private._Private__major_, 'Hoolihan')
2186
Ethan Furmand65b9032021-02-08 17:32:38 -08002187 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002188 sys.version_info[:2] < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002189 'member-member access now raises an exception',
2190 )
2191 def test_warning_for_member_from_member_access(self):
2192 with self.assertWarns(DeprecationWarning):
2193 class Di(Enum):
2194 YES = 1
2195 NO = 0
2196 nope = Di.YES.NO
2197 self.assertIs(Di.NO, nope)
2198
2199 @unittest.skipUnless(
Ethan Furman44e580f2021-03-03 09:54:30 -08002200 sys.version_info[:2] >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002201 'member-member access currently issues a warning',
2202 )
2203 def test_exception_for_member_from_member_access(self):
2204 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2205 class Di(Enum):
2206 YES = 1
2207 NO = 0
2208 nope = Di.YES.NO
2209
Ethan Furmanefb13be2020-12-10 12:20:06 -08002210 def test_strenum_auto(self):
2211 class Strings(StrEnum):
2212 ONE = auto()
2213 TWO = auto()
2214 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2215
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002216
Ethan Furmana6582872020-12-10 13:07:00 -08002217 def test_dynamic_members_with_static_methods(self):
2218 #
2219 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2220 class Foo(Enum):
2221 vars().update({
2222 k: v
2223 for k, v in foo_defines.items()
2224 if k.startswith('FOO_')
2225 })
2226 def upper(self):
2227 return self.value.upper()
2228 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2229 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2230 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2231 #
2232 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2233 class FooBar(Enum):
2234 vars().update({
2235 k: v
2236 for k, v in foo_defines.items()
2237 if k.startswith('FOO_')
2238 },
2239 **{'FOO_CAT': 'small'},
2240 )
2241 def upper(self):
2242 return self.value.upper()
2243
2244
Ethan Furmane8e61272016-08-20 07:19:31 -07002245class TestOrder(unittest.TestCase):
2246
2247 def test_same_members(self):
2248 class Color(Enum):
2249 _order_ = 'red green blue'
2250 red = 1
2251 green = 2
2252 blue = 3
2253
2254 def test_same_members_with_aliases(self):
2255 class Color(Enum):
2256 _order_ = 'red green blue'
2257 red = 1
2258 green = 2
2259 blue = 3
2260 verde = green
2261
2262 def test_same_members_wrong_order(self):
2263 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2264 class Color(Enum):
2265 _order_ = 'red green blue'
2266 red = 1
2267 blue = 3
2268 green = 2
2269
2270 def test_order_has_extra_members(self):
2271 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2272 class Color(Enum):
2273 _order_ = 'red green blue purple'
2274 red = 1
2275 green = 2
2276 blue = 3
2277
2278 def test_order_has_extra_members_with_aliases(self):
2279 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2280 class Color(Enum):
2281 _order_ = 'red green blue purple'
2282 red = 1
2283 green = 2
2284 blue = 3
2285 verde = green
2286
2287 def test_enum_has_extra_members(self):
2288 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2289 class Color(Enum):
2290 _order_ = 'red green blue'
2291 red = 1
2292 green = 2
2293 blue = 3
2294 purple = 4
2295
2296 def test_enum_has_extra_members_with_aliases(self):
2297 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2298 class Color(Enum):
2299 _order_ = 'red green blue'
2300 red = 1
2301 green = 2
2302 blue = 3
2303 purple = 4
2304 verde = green
2305
2306
Ethan Furman65a5a472016-09-01 23:55:19 -07002307class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002308 """Tests of the Flags."""
2309
Ethan Furman65a5a472016-09-01 23:55:19 -07002310 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002311 R, W, X = 4, 2, 1
2312
Ethan Furman65a5a472016-09-01 23:55:19 -07002313 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002314 RO = 0
2315 WO = 1
2316 RW = 2
2317 AC = 3
2318 CE = 1<<19
2319
Rahul Jha94306522018-09-10 23:51:04 +05302320 class Color(Flag):
2321 BLACK = 0
2322 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002323 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302324 GREEN = 2
2325 BLUE = 4
2326 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002327 WHITE = RED|GREEN|BLUE
2328 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302329
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002330 def test_str(self):
2331 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002332 self.assertEqual(str(Perm.R), 'R')
2333 self.assertEqual(str(Perm.W), 'W')
2334 self.assertEqual(str(Perm.X), 'X')
2335 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2336 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002337 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002338 self.assertEqual(str(~Perm.R), 'W|X')
2339 self.assertEqual(str(~Perm.W), 'R|X')
2340 self.assertEqual(str(~Perm.X), 'R|W')
2341 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002342 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002343 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002344
2345 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002346 self.assertEqual(str(Open.RO), 'RO')
2347 self.assertEqual(str(Open.WO), 'WO')
2348 self.assertEqual(str(Open.AC), 'AC')
2349 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2350 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2351 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2352 self.assertEqual(str(~Open.WO), 'RW|CE')
2353 self.assertEqual(str(~Open.AC), 'CE')
2354 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2355 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002356
2357 def test_repr(self):
2358 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002359 self.assertEqual(repr(Perm.R), 'Perm.R')
2360 self.assertEqual(repr(Perm.W), 'Perm.W')
2361 self.assertEqual(repr(Perm.X), 'Perm.X')
2362 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2363 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2364 self.assertEqual(repr(Perm(0)), '0x0')
2365 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2366 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2367 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2368 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2369 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2370 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002371
2372 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002373 self.assertEqual(repr(Open.RO), 'Open.RO')
2374 self.assertEqual(repr(Open.WO), 'Open.WO')
2375 self.assertEqual(repr(Open.AC), 'Open.AC')
2376 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2377 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2378 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2379 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2380 self.assertEqual(repr(~Open.AC), 'Open.CE')
2381 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2382 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383
Ethan Furman37440ee2020-12-08 11:14:10 -08002384 def test_format(self):
2385 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002386 self.assertEqual(format(Perm.R, ''), 'R')
2387 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002388
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002389 def test_or(self):
2390 Perm = self.Perm
2391 for i in Perm:
2392 for j in Perm:
2393 self.assertEqual((i | j), Perm(i.value | j.value))
2394 self.assertEqual((i | j).value, i.value | j.value)
2395 self.assertIs(type(i | j), Perm)
2396 for i in Perm:
2397 self.assertIs(i | i, i)
2398 Open = self.Open
2399 self.assertIs(Open.RO | Open.CE, Open.CE)
2400
2401 def test_and(self):
2402 Perm = self.Perm
2403 RW = Perm.R | Perm.W
2404 RX = Perm.R | Perm.X
2405 WX = Perm.W | Perm.X
2406 RWX = Perm.R | Perm.W | Perm.X
2407 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2408 for i in values:
2409 for j in values:
2410 self.assertEqual((i & j).value, i.value & j.value)
2411 self.assertIs(type(i & j), Perm)
2412 for i in Perm:
2413 self.assertIs(i & i, i)
2414 self.assertIs(i & RWX, i)
2415 self.assertIs(RWX & i, i)
2416 Open = self.Open
2417 self.assertIs(Open.RO & Open.CE, Open.RO)
2418
2419 def test_xor(self):
2420 Perm = self.Perm
2421 for i in Perm:
2422 for j in Perm:
2423 self.assertEqual((i ^ j).value, i.value ^ j.value)
2424 self.assertIs(type(i ^ j), Perm)
2425 for i in Perm:
2426 self.assertIs(i ^ Perm(0), i)
2427 self.assertIs(Perm(0) ^ i, i)
2428 Open = self.Open
2429 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2430 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2431
2432 def test_invert(self):
2433 Perm = self.Perm
2434 RW = Perm.R | Perm.W
2435 RX = Perm.R | Perm.X
2436 WX = Perm.W | Perm.X
2437 RWX = Perm.R | Perm.W | Perm.X
2438 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2439 for i in values:
2440 self.assertIs(type(~i), Perm)
2441 self.assertEqual(~~i, i)
2442 for i in Perm:
2443 self.assertIs(~~i, i)
2444 Open = self.Open
2445 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2446 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2447
Ethan Furman25d94bb2016-09-02 16:32:32 -07002448 def test_bool(self):
2449 Perm = self.Perm
2450 for f in Perm:
2451 self.assertTrue(f)
2452 Open = self.Open
2453 for f in Open:
2454 self.assertEqual(bool(f.value), bool(f))
2455
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002456 def test_boundary(self):
2457 self.assertIs(enum.Flag._boundary_, STRICT)
2458 class Iron(Flag, boundary=STRICT):
2459 ONE = 1
2460 TWO = 2
2461 EIGHT = 8
2462 self.assertIs(Iron._boundary_, STRICT)
2463 #
2464 class Water(Flag, boundary=CONFORM):
2465 ONE = 1
2466 TWO = 2
2467 EIGHT = 8
2468 self.assertIs(Water._boundary_, CONFORM)
2469 #
2470 class Space(Flag, boundary=EJECT):
2471 ONE = 1
2472 TWO = 2
2473 EIGHT = 8
2474 self.assertIs(Space._boundary_, EJECT)
2475 #
2476 class Bizarre(Flag, boundary=KEEP):
2477 b = 3
2478 c = 4
2479 d = 6
2480 #
2481 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
2482 self.assertIs(Water(7), Water.ONE|Water.TWO)
2483 self.assertIs(Water(~9), Water.TWO)
2484 self.assertEqual(Space(7), 7)
2485 self.assertTrue(type(Space(7)) is int)
2486 self.assertEqual(list(Bizarre), [Bizarre.c])
2487 self.assertIs(Bizarre(3), Bizarre.b)
2488 self.assertIs(Bizarre(6), Bizarre.d)
2489
2490 def test_iter(self):
2491 Color = self.Color
2492 Open = self.Open
2493 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2494 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2495
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002496 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002497 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002498 lst = list(Perm)
2499 self.assertEqual(len(lst), len(Perm))
2500 self.assertEqual(len(Perm), 3, Perm)
2501 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2502 for i, n in enumerate('R W X'.split()):
2503 v = 1<<i
2504 e = Perm(v)
2505 self.assertEqual(e.value, v)
2506 self.assertEqual(type(e.value), int)
2507 self.assertEqual(e.name, n)
2508 self.assertIn(e, Perm)
2509 self.assertIs(type(e), Perm)
2510
2511 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002512 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002513 lst = list(Perm)
2514 self.assertEqual(len(lst), len(Perm))
2515 self.assertEqual(len(Perm), 3, Perm)
2516 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2517 for i, n in enumerate('R W X'.split()):
2518 v = 8<<i
2519 e = Perm(v)
2520 self.assertEqual(e.value, v)
2521 self.assertEqual(type(e.value), int)
2522 self.assertEqual(e.name, n)
2523 self.assertIn(e, Perm)
2524 self.assertIs(type(e), Perm)
2525
2526 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002527 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002528 lst = list(Perm)
2529 self.assertEqual(len(lst), len(Perm))
2530 self.assertEqual(len(Perm), 3, Perm)
2531 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2532 for i, n in enumerate('R W X'.split()):
2533 v = 1<<i
2534 e = Perm(v)
2535 self.assertEqual(e.value, v)
2536 self.assertEqual(type(e.value), int)
2537 self.assertEqual(e.name, n)
2538 self.assertIn(e, Perm)
2539 self.assertIs(type(e), Perm)
2540
2541 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002542 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002543 lst = list(Perm)
2544 self.assertEqual(len(lst), len(Perm))
2545 self.assertEqual(len(Perm), 3, Perm)
2546 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2547 for i, n in enumerate('R W X'.split()):
2548 v = 1<<(2*i+1)
2549 e = Perm(v)
2550 self.assertEqual(e.value, v)
2551 self.assertEqual(type(e.value), int)
2552 self.assertEqual(e.name, n)
2553 self.assertIn(e, Perm)
2554 self.assertIs(type(e), Perm)
2555
2556 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002557 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002558 lst = list(Perm)
2559 self.assertEqual(len(lst), len(Perm))
2560 self.assertEqual(len(Perm), 3, Perm)
2561 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2562 for i, n in enumerate('R W X'.split()):
2563 v = 1<<(2*i+1)
2564 e = Perm(v)
2565 self.assertEqual(e.value, v)
2566 self.assertEqual(type(e.value), int)
2567 self.assertEqual(e.name, n)
2568 self.assertIn(e, Perm)
2569 self.assertIs(type(e), Perm)
2570
Ethan Furman65a5a472016-09-01 23:55:19 -07002571 def test_pickle(self):
2572 if isinstance(FlagStooges, Exception):
2573 raise FlagStooges
2574 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2575 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002576
Rahul Jha94306522018-09-10 23:51:04 +05302577 def test_contains(self):
2578 Open = self.Open
2579 Color = self.Color
2580 self.assertFalse(Color.BLACK in Open)
2581 self.assertFalse(Open.RO in Color)
2582 with self.assertRaises(TypeError):
2583 'BLACK' in Color
2584 with self.assertRaises(TypeError):
2585 'RO' in Open
2586 with self.assertRaises(TypeError):
2587 1 in Color
2588 with self.assertRaises(TypeError):
2589 1 in Open
2590
2591 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002592 Perm = self.Perm
2593 R, W, X = Perm
2594 RW = R | W
2595 RX = R | X
2596 WX = W | X
2597 RWX = R | W | X
2598 self.assertTrue(R in RW)
2599 self.assertTrue(R in RX)
2600 self.assertTrue(R in RWX)
2601 self.assertTrue(W in RW)
2602 self.assertTrue(W in WX)
2603 self.assertTrue(W in RWX)
2604 self.assertTrue(X in RX)
2605 self.assertTrue(X in WX)
2606 self.assertTrue(X in RWX)
2607 self.assertFalse(R in WX)
2608 self.assertFalse(W in RX)
2609 self.assertFalse(X in RW)
2610
Ethan Furman7219e272020-09-16 13:01:00 -07002611 def test_member_iter(self):
2612 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002613 self.assertEqual(list(Color.BLACK), [])
2614 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002615 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2616 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002617 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2618 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2619
2620 def test_member_length(self):
2621 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2622 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2623 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2624 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2625
2626 def test_number_reset_and_order_cleanup(self):
2627 class Confused(Flag):
2628 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2629 ONE = auto()
2630 TWO = auto()
2631 FOUR = auto()
2632 DOS = 2
2633 EIGHT = auto()
2634 SIXTEEN = auto()
2635 self.assertEqual(
2636 list(Confused),
2637 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2638 self.assertIs(Confused.TWO, Confused.DOS)
2639 self.assertEqual(Confused.DOS._value_, 2)
2640 self.assertEqual(Confused.EIGHT._value_, 8)
2641 self.assertEqual(Confused.SIXTEEN._value_, 16)
2642
2643 def test_aliases(self):
2644 Color = self.Color
2645 self.assertEqual(Color(1).name, 'RED')
2646 self.assertEqual(Color['ROJO'].name, 'RED')
2647 self.assertEqual(Color(7).name, 'WHITE')
2648 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2649 self.assertIs(Color.BLANCO, Color.WHITE)
2650 Open = self.Open
2651 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002652
Ethan Furmanc16595e2016-09-10 23:36:59 -07002653 def test_auto_number(self):
2654 class Color(Flag):
2655 red = auto()
2656 blue = auto()
2657 green = auto()
2658
2659 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2660 self.assertEqual(Color.red.value, 1)
2661 self.assertEqual(Color.blue.value, 2)
2662 self.assertEqual(Color.green.value, 4)
2663
2664 def test_auto_number_garbage(self):
2665 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2666 class Color(Flag):
2667 red = 'not an int'
2668 blue = auto()
2669
Ethan Furman3515dcc2016-09-18 13:15:41 -07002670 def test_duplicate_auto(self):
2671 class Dupes(Enum):
2672 first = primero = auto()
2673 second = auto()
2674 third = auto()
2675 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2676
2677 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002678 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2679 class Bizarre(Flag):
2680 b = 3
2681 c = 4
2682 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002683
Ethan Furman5bdab642018-09-21 19:03:09 -07002684 def test_multiple_mixin(self):
2685 class AllMixin:
2686 @classproperty
2687 def ALL(cls):
2688 members = list(cls)
2689 all_value = None
2690 if members:
2691 all_value = members[0]
2692 for member in members[1:]:
2693 all_value |= member
2694 cls.ALL = all_value
2695 return all_value
2696 class StrMixin:
2697 def __str__(self):
2698 return self._name_.lower()
2699 class Color(AllMixin, Flag):
2700 RED = auto()
2701 GREEN = auto()
2702 BLUE = auto()
2703 self.assertEqual(Color.RED.value, 1)
2704 self.assertEqual(Color.GREEN.value, 2)
2705 self.assertEqual(Color.BLUE.value, 4)
2706 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002707 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002708 class Color(AllMixin, StrMixin, Flag):
2709 RED = auto()
2710 GREEN = auto()
2711 BLUE = auto()
2712 self.assertEqual(Color.RED.value, 1)
2713 self.assertEqual(Color.GREEN.value, 2)
2714 self.assertEqual(Color.BLUE.value, 4)
2715 self.assertEqual(Color.ALL.value, 7)
2716 self.assertEqual(str(Color.BLUE), 'blue')
2717 class Color(StrMixin, AllMixin, Flag):
2718 RED = auto()
2719 GREEN = auto()
2720 BLUE = auto()
2721 self.assertEqual(Color.RED.value, 1)
2722 self.assertEqual(Color.GREEN.value, 2)
2723 self.assertEqual(Color.BLUE.value, 4)
2724 self.assertEqual(Color.ALL.value, 7)
2725 self.assertEqual(str(Color.BLUE), 'blue')
2726
Hai Shie80697d2020-05-28 06:10:27 +08002727 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002728 def test_unique_composite(self):
2729 # override __eq__ to be identity only
2730 class TestFlag(Flag):
2731 one = auto()
2732 two = auto()
2733 three = auto()
2734 four = auto()
2735 five = auto()
2736 six = auto()
2737 seven = auto()
2738 eight = auto()
2739 def __eq__(self, other):
2740 return self is other
2741 def __hash__(self):
2742 return hash(self._value_)
2743 # have multiple threads competing to complete the composite members
2744 seen = set()
2745 failed = False
2746 def cycle_enum():
2747 nonlocal failed
2748 try:
2749 for i in range(256):
2750 seen.add(TestFlag(i))
2751 except Exception:
2752 failed = True
2753 threads = [
2754 threading.Thread(target=cycle_enum)
2755 for _ in range(8)
2756 ]
Hai Shie80697d2020-05-28 06:10:27 +08002757 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002758 pass
2759 # check that only 248 members were created
2760 self.assertFalse(
2761 failed,
2762 'at least one thread failed while creating composite members')
2763 self.assertEqual(256, len(seen), 'too many composite members created')
2764
Ethan Furman6bd94de2020-12-09 16:41:22 -08002765 def test_init_subclass(self):
2766 class MyEnum(Flag):
2767 def __init_subclass__(cls, **kwds):
2768 super().__init_subclass__(**kwds)
2769 self.assertFalse(cls.__dict__.get('_test', False))
2770 cls._test1 = 'MyEnum'
2771 #
2772 class TheirEnum(MyEnum):
2773 def __init_subclass__(cls, **kwds):
2774 super(TheirEnum, cls).__init_subclass__(**kwds)
2775 cls._test2 = 'TheirEnum'
2776 class WhoseEnum(TheirEnum):
2777 def __init_subclass__(cls, **kwds):
2778 pass
2779 class NoEnum(WhoseEnum):
2780 ONE = 1
2781 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2782 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2783 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2784 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2785 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2786 #
2787 class OurEnum(MyEnum):
2788 def __init_subclass__(cls, **kwds):
2789 cls._test2 = 'OurEnum'
2790 class WhereEnum(OurEnum):
2791 def __init_subclass__(cls, **kwds):
2792 pass
2793 class NeverEnum(WhereEnum):
2794 ONE = 1
2795 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2796 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2797 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2798 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2799 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2800
Ethan Furmanc16595e2016-09-10 23:36:59 -07002801
Ethan Furman65a5a472016-09-01 23:55:19 -07002802class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002803 """Tests of the IntFlags."""
2804
Ethan Furman65a5a472016-09-01 23:55:19 -07002805 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002806 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002807 W = 1 << 1
2808 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002809
Ethan Furman65a5a472016-09-01 23:55:19 -07002810 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002811 RO = 0
2812 WO = 1
2813 RW = 2
2814 AC = 3
2815 CE = 1<<19
2816
Rahul Jha94306522018-09-10 23:51:04 +05302817 class Color(IntFlag):
2818 BLACK = 0
2819 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002820 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302821 GREEN = 2
2822 BLUE = 4
2823 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002824 WHITE = RED|GREEN|BLUE
2825 BLANCO = RED|GREEN|BLUE
2826
2827 class Skip(IntFlag):
2828 FIRST = 1
2829 SECOND = 2
2830 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302831
Ethan Furman3515dcc2016-09-18 13:15:41 -07002832 def test_type(self):
2833 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002834 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002835 Open = self.Open
2836 for f in Perm:
2837 self.assertTrue(isinstance(f, Perm))
2838 self.assertEqual(f, f.value)
2839 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2840 self.assertEqual(Perm.W | Perm.X, 3)
2841 for f in Open:
2842 self.assertTrue(isinstance(f, Open))
2843 self.assertEqual(f, f.value)
2844 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2845 self.assertEqual(Open.WO | Open.RW, 3)
2846
2847
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002848 def test_str(self):
2849 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002850 self.assertEqual(str(Perm.R), 'R')
2851 self.assertEqual(str(Perm.W), 'W')
2852 self.assertEqual(str(Perm.X), 'X')
2853 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2854 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002855 self.assertEqual(str(Perm.R | 8), '12')
2856 self.assertEqual(str(Perm(0)), 'Perm(0)')
2857 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002858 self.assertEqual(str(~Perm.R), 'W|X')
2859 self.assertEqual(str(~Perm.W), 'R|X')
2860 self.assertEqual(str(~Perm.X), 'R|W')
2861 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002862 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2863 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002864 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002865 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002866
2867 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002868 self.assertEqual(str(Open.RO), 'RO')
2869 self.assertEqual(str(Open.WO), 'WO')
2870 self.assertEqual(str(Open.AC), 'AC')
2871 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2872 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002873 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002874 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2875 self.assertEqual(str(~Open.WO), 'RW|CE')
2876 self.assertEqual(str(~Open.AC), 'CE')
2877 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2878 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002879 self.assertEqual(str(Open(~4)), '-5')
2880
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002881 def test_repr(self):
2882 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002883 self.assertEqual(repr(Perm.R), 'Perm.R')
2884 self.assertEqual(repr(Perm.W), 'Perm.W')
2885 self.assertEqual(repr(Perm.X), 'Perm.X')
2886 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2887 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002888 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07002889 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002890 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002891 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2892 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2893 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2894 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2895 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002896 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002897 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002898 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002899
2900 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002901 self.assertEqual(repr(Open.RO), 'Open.RO')
2902 self.assertEqual(repr(Open.WO), 'Open.WO')
2903 self.assertEqual(repr(Open.AC), 'Open.AC')
2904 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2905 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002906 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002907 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2908 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2909 self.assertEqual(repr(~Open.AC), 'Open.CE')
2910 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2911 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002912 self.assertEqual(repr(Open(~4)), '-5')
2913
Ethan Furman37440ee2020-12-08 11:14:10 -08002914 def test_format(self):
2915 Perm = self.Perm
2916 self.assertEqual(format(Perm.R, ''), '4')
2917 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2918
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002919 def test_or(self):
2920 Perm = self.Perm
2921 for i in Perm:
2922 for j in Perm:
2923 self.assertEqual(i | j, i.value | j.value)
2924 self.assertEqual((i | j).value, i.value | j.value)
2925 self.assertIs(type(i | j), Perm)
2926 for j in range(8):
2927 self.assertEqual(i | j, i.value | j)
2928 self.assertEqual((i | j).value, i.value | j)
2929 self.assertIs(type(i | j), Perm)
2930 self.assertEqual(j | i, j | i.value)
2931 self.assertEqual((j | i).value, j | i.value)
2932 self.assertIs(type(j | i), Perm)
2933 for i in Perm:
2934 self.assertIs(i | i, i)
2935 self.assertIs(i | 0, i)
2936 self.assertIs(0 | i, i)
2937 Open = self.Open
2938 self.assertIs(Open.RO | Open.CE, Open.CE)
2939
2940 def test_and(self):
2941 Perm = self.Perm
2942 RW = Perm.R | Perm.W
2943 RX = Perm.R | Perm.X
2944 WX = Perm.W | Perm.X
2945 RWX = Perm.R | Perm.W | Perm.X
2946 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2947 for i in values:
2948 for j in values:
2949 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2950 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2951 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2952 for j in range(8):
2953 self.assertEqual(i & j, i.value & j)
2954 self.assertEqual((i & j).value, i.value & j)
2955 self.assertIs(type(i & j), Perm)
2956 self.assertEqual(j & i, j & i.value)
2957 self.assertEqual((j & i).value, j & i.value)
2958 self.assertIs(type(j & i), Perm)
2959 for i in Perm:
2960 self.assertIs(i & i, i)
2961 self.assertIs(i & 7, i)
2962 self.assertIs(7 & i, i)
2963 Open = self.Open
2964 self.assertIs(Open.RO & Open.CE, Open.RO)
2965
2966 def test_xor(self):
2967 Perm = self.Perm
2968 for i in Perm:
2969 for j in Perm:
2970 self.assertEqual(i ^ j, i.value ^ j.value)
2971 self.assertEqual((i ^ j).value, i.value ^ j.value)
2972 self.assertIs(type(i ^ j), Perm)
2973 for j in range(8):
2974 self.assertEqual(i ^ j, i.value ^ j)
2975 self.assertEqual((i ^ j).value, i.value ^ j)
2976 self.assertIs(type(i ^ j), Perm)
2977 self.assertEqual(j ^ i, j ^ i.value)
2978 self.assertEqual((j ^ i).value, j ^ i.value)
2979 self.assertIs(type(j ^ i), Perm)
2980 for i in Perm:
2981 self.assertIs(i ^ 0, i)
2982 self.assertIs(0 ^ i, i)
2983 Open = self.Open
2984 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2985 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2986
2987 def test_invert(self):
2988 Perm = self.Perm
2989 RW = Perm.R | Perm.W
2990 RX = Perm.R | Perm.X
2991 WX = Perm.W | Perm.X
2992 RWX = Perm.R | Perm.W | Perm.X
2993 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2994 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002995 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002996 self.assertIs(type(~i), Perm)
2997 self.assertEqual(~~i, i)
2998 for i in Perm:
2999 self.assertIs(~~i, i)
3000 Open = self.Open
3001 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3002 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3003
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003004 def test_boundary(self):
3005 self.assertIs(enum.IntFlag._boundary_, EJECT)
3006 class Iron(IntFlag, boundary=STRICT):
3007 ONE = 1
3008 TWO = 2
3009 EIGHT = 8
3010 self.assertIs(Iron._boundary_, STRICT)
3011 #
3012 class Water(IntFlag, boundary=CONFORM):
3013 ONE = 1
3014 TWO = 2
3015 EIGHT = 8
3016 self.assertIs(Water._boundary_, CONFORM)
3017 #
3018 class Space(IntFlag, boundary=EJECT):
3019 ONE = 1
3020 TWO = 2
3021 EIGHT = 8
3022 self.assertIs(Space._boundary_, EJECT)
3023 #
3024 class Bizarre(IntFlag, boundary=KEEP):
3025 b = 3
3026 c = 4
3027 d = 6
3028 #
3029 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
3030 self.assertIs(Water(7), Water.ONE|Water.TWO)
3031 self.assertIs(Water(~9), Water.TWO)
3032 self.assertEqual(Space(7), 7)
3033 self.assertTrue(type(Space(7)) is int)
3034 self.assertEqual(list(Bizarre), [Bizarre.c])
3035 self.assertIs(Bizarre(3), Bizarre.b)
3036 self.assertIs(Bizarre(6), Bizarre.d)
3037
3038 def test_iter(self):
3039 Color = self.Color
3040 Open = self.Open
3041 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3042 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3043
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003044 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003045 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003046 lst = list(Perm)
3047 self.assertEqual(len(lst), len(Perm))
3048 self.assertEqual(len(Perm), 3, Perm)
3049 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3050 for i, n in enumerate('R W X'.split()):
3051 v = 1<<i
3052 e = Perm(v)
3053 self.assertEqual(e.value, v)
3054 self.assertEqual(type(e.value), int)
3055 self.assertEqual(e, v)
3056 self.assertEqual(e.name, n)
3057 self.assertIn(e, Perm)
3058 self.assertIs(type(e), Perm)
3059
3060 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003061 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003062 lst = list(Perm)
3063 self.assertEqual(len(lst), len(Perm))
3064 self.assertEqual(len(Perm), 3, Perm)
3065 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3066 for i, n in enumerate('R W X'.split()):
3067 v = 8<<i
3068 e = Perm(v)
3069 self.assertEqual(e.value, v)
3070 self.assertEqual(type(e.value), int)
3071 self.assertEqual(e, v)
3072 self.assertEqual(e.name, n)
3073 self.assertIn(e, Perm)
3074 self.assertIs(type(e), Perm)
3075
3076 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003077 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003078 lst = list(Perm)
3079 self.assertEqual(len(lst), len(Perm))
3080 self.assertEqual(len(Perm), 3, Perm)
3081 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3082 for i, n in enumerate('R W X'.split()):
3083 v = 1<<i
3084 e = Perm(v)
3085 self.assertEqual(e.value, v)
3086 self.assertEqual(type(e.value), int)
3087 self.assertEqual(e, v)
3088 self.assertEqual(e.name, n)
3089 self.assertIn(e, Perm)
3090 self.assertIs(type(e), Perm)
3091
3092 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003093 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003094 lst = list(Perm)
3095 self.assertEqual(len(lst), len(Perm))
3096 self.assertEqual(len(Perm), 3, Perm)
3097 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3098 for i, n in enumerate('R W X'.split()):
3099 v = 1<<(2*i+1)
3100 e = Perm(v)
3101 self.assertEqual(e.value, v)
3102 self.assertEqual(type(e.value), int)
3103 self.assertEqual(e, v)
3104 self.assertEqual(e.name, n)
3105 self.assertIn(e, Perm)
3106 self.assertIs(type(e), Perm)
3107
3108 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003109 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003110 lst = list(Perm)
3111 self.assertEqual(len(lst), len(Perm))
3112 self.assertEqual(len(Perm), 3, Perm)
3113 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3114 for i, n in enumerate('R W X'.split()):
3115 v = 1<<(2*i+1)
3116 e = Perm(v)
3117 self.assertEqual(e.value, v)
3118 self.assertEqual(type(e.value), int)
3119 self.assertEqual(e, v)
3120 self.assertEqual(e.name, n)
3121 self.assertIn(e, Perm)
3122 self.assertIs(type(e), Perm)
3123
3124
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003125 def test_programatic_function_from_empty_list(self):
3126 Perm = enum.IntFlag('Perm', [])
3127 lst = list(Perm)
3128 self.assertEqual(len(lst), len(Perm))
3129 self.assertEqual(len(Perm), 0, Perm)
3130 Thing = enum.Enum('Thing', [])
3131 lst = list(Thing)
3132 self.assertEqual(len(lst), len(Thing))
3133 self.assertEqual(len(Thing), 0, Thing)
3134
3135
3136 def test_programatic_function_from_empty_tuple(self):
3137 Perm = enum.IntFlag('Perm', ())
3138 lst = list(Perm)
3139 self.assertEqual(len(lst), len(Perm))
3140 self.assertEqual(len(Perm), 0, Perm)
3141 Thing = enum.Enum('Thing', ())
3142 self.assertEqual(len(lst), len(Thing))
3143 self.assertEqual(len(Thing), 0, Thing)
3144
Rahul Jha94306522018-09-10 23:51:04 +05303145 def test_contains(self):
3146 Open = self.Open
3147 Color = self.Color
3148 self.assertTrue(Color.GREEN in Color)
3149 self.assertTrue(Open.RW in Open)
3150 self.assertFalse(Color.GREEN in Open)
3151 self.assertFalse(Open.RW in Color)
3152 with self.assertRaises(TypeError):
3153 'GREEN' in Color
3154 with self.assertRaises(TypeError):
3155 'RW' in Open
3156 with self.assertRaises(TypeError):
3157 2 in Color
3158 with self.assertRaises(TypeError):
3159 2 in Open
3160
3161 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003162 Perm = self.Perm
3163 R, W, X = Perm
3164 RW = R | W
3165 RX = R | X
3166 WX = W | X
3167 RWX = R | W | X
3168 self.assertTrue(R in RW)
3169 self.assertTrue(R in RX)
3170 self.assertTrue(R in RWX)
3171 self.assertTrue(W in RW)
3172 self.assertTrue(W in WX)
3173 self.assertTrue(W in RWX)
3174 self.assertTrue(X in RX)
3175 self.assertTrue(X in WX)
3176 self.assertTrue(X in RWX)
3177 self.assertFalse(R in WX)
3178 self.assertFalse(W in RX)
3179 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303180 with self.assertRaises(TypeError):
3181 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003182
Ethan Furman7219e272020-09-16 13:01:00 -07003183 def test_member_iter(self):
3184 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003185 self.assertEqual(list(Color.BLACK), [])
3186 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003187 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3188 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003189 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3190
3191 def test_member_length(self):
3192 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3193 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3194 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3195 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3196
3197 def test_aliases(self):
3198 Color = self.Color
3199 self.assertEqual(Color(1).name, 'RED')
3200 self.assertEqual(Color['ROJO'].name, 'RED')
3201 self.assertEqual(Color(7).name, 'WHITE')
3202 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3203 self.assertIs(Color.BLANCO, Color.WHITE)
3204 Open = self.Open
3205 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003206
Ethan Furman25d94bb2016-09-02 16:32:32 -07003207 def test_bool(self):
3208 Perm = self.Perm
3209 for f in Perm:
3210 self.assertTrue(f)
3211 Open = self.Open
3212 for f in Open:
3213 self.assertEqual(bool(f.value), bool(f))
3214
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003215 def test_bizarre(self):
3216 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3217 class Bizarre(IntFlag):
3218 b = 3
3219 c = 4
3220 d = 6
3221
Ethan Furman5bdab642018-09-21 19:03:09 -07003222 def test_multiple_mixin(self):
3223 class AllMixin:
3224 @classproperty
3225 def ALL(cls):
3226 members = list(cls)
3227 all_value = None
3228 if members:
3229 all_value = members[0]
3230 for member in members[1:]:
3231 all_value |= member
3232 cls.ALL = all_value
3233 return all_value
3234 class StrMixin:
3235 def __str__(self):
3236 return self._name_.lower()
3237 class Color(AllMixin, IntFlag):
3238 RED = auto()
3239 GREEN = auto()
3240 BLUE = auto()
3241 self.assertEqual(Color.RED.value, 1)
3242 self.assertEqual(Color.GREEN.value, 2)
3243 self.assertEqual(Color.BLUE.value, 4)
3244 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003245 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003246 class Color(AllMixin, StrMixin, IntFlag):
3247 RED = auto()
3248 GREEN = auto()
3249 BLUE = auto()
3250 self.assertEqual(Color.RED.value, 1)
3251 self.assertEqual(Color.GREEN.value, 2)
3252 self.assertEqual(Color.BLUE.value, 4)
3253 self.assertEqual(Color.ALL.value, 7)
3254 self.assertEqual(str(Color.BLUE), 'blue')
3255 class Color(StrMixin, AllMixin, IntFlag):
3256 RED = auto()
3257 GREEN = auto()
3258 BLUE = auto()
3259 self.assertEqual(Color.RED.value, 1)
3260 self.assertEqual(Color.GREEN.value, 2)
3261 self.assertEqual(Color.BLUE.value, 4)
3262 self.assertEqual(Color.ALL.value, 7)
3263 self.assertEqual(str(Color.BLUE), 'blue')
3264
Hai Shie80697d2020-05-28 06:10:27 +08003265 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003266 def test_unique_composite(self):
3267 # override __eq__ to be identity only
3268 class TestFlag(IntFlag):
3269 one = auto()
3270 two = auto()
3271 three = auto()
3272 four = auto()
3273 five = auto()
3274 six = auto()
3275 seven = auto()
3276 eight = auto()
3277 def __eq__(self, other):
3278 return self is other
3279 def __hash__(self):
3280 return hash(self._value_)
3281 # have multiple threads competing to complete the composite members
3282 seen = set()
3283 failed = False
3284 def cycle_enum():
3285 nonlocal failed
3286 try:
3287 for i in range(256):
3288 seen.add(TestFlag(i))
3289 except Exception:
3290 failed = True
3291 threads = [
3292 threading.Thread(target=cycle_enum)
3293 for _ in range(8)
3294 ]
Hai Shie80697d2020-05-28 06:10:27 +08003295 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003296 pass
3297 # check that only 248 members were created
3298 self.assertFalse(
3299 failed,
3300 'at least one thread failed while creating composite members')
3301 self.assertEqual(256, len(seen), 'too many composite members created')
3302
3303
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003304class TestEmptyAndNonLatinStrings(unittest.TestCase):
3305
3306 def test_empty_string(self):
3307 with self.assertRaises(ValueError):
3308 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3309
3310 def test_non_latin_character_string(self):
3311 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3312 item = getattr(greek_abc, '\u03B1')
3313 self.assertEqual(item.value, 1)
3314
3315 def test_non_latin_number_string(self):
3316 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3317 item = getattr(hebrew_123, '\u05D0')
3318 self.assertEqual(item.value, 1)
3319
3320
Ethan Furmanf24bb352013-07-18 17:05:39 -07003321class TestUnique(unittest.TestCase):
3322
3323 def test_unique_clean(self):
3324 @unique
3325 class Clean(Enum):
3326 one = 1
3327 two = 'dos'
3328 tres = 4.0
3329 @unique
3330 class Cleaner(IntEnum):
3331 single = 1
3332 double = 2
3333 triple = 3
3334
3335 def test_unique_dirty(self):
3336 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3337 @unique
3338 class Dirty(Enum):
3339 one = 1
3340 two = 'dos'
3341 tres = 1
3342 with self.assertRaisesRegex(
3343 ValueError,
3344 'double.*single.*turkey.*triple',
3345 ):
3346 @unique
3347 class Dirtier(IntEnum):
3348 single = 1
3349 double = 1
3350 triple = 3
3351 turkey = 3
3352
Ethan Furman3803ad42016-05-01 10:03:53 -07003353 def test_unique_with_name(self):
3354 @unique
3355 class Silly(Enum):
3356 one = 1
3357 two = 'dos'
3358 name = 3
3359 @unique
3360 class Sillier(IntEnum):
3361 single = 1
3362 name = 2
3363 triple = 3
3364 value = 4
3365
Ethan Furmanf24bb352013-07-18 17:05:39 -07003366
Ethan Furmanb7751062021-03-30 21:17:26 -07003367class TestEnumTypeSubclassing(unittest.TestCase):
3368 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003369
Ethan Furman3323da92015-04-11 09:39:59 -07003370expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003371Help on class Color in module %s:
3372
3373class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003374 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003375 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003376 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003377 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003378 | Method resolution order:
3379 | Color
3380 | enum.Enum
3381 | builtins.object
3382 |\x20\x20
3383 | Data and other attributes defined here:
3384 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003385 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003386 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003387 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003388 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003389 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003390 |\x20\x20
3391 | ----------------------------------------------------------------------
3392 | Data descriptors inherited from enum.Enum:
3393 |\x20\x20
3394 | name
3395 | The name of the Enum member.
3396 |\x20\x20
3397 | value
3398 | The value of the Enum member.
3399 |\x20\x20
3400 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003401 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003402 |\x20\x20
3403 | __members__
3404 | Returns a mapping of member name->value.
3405 |\x20\x20\x20\x20\x20\x20
3406 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003407 | is a read-only view of the internal mapping."""
3408
3409expected_help_output_without_docs = """\
3410Help on class Color in module %s:
3411
3412class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003413 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3414 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003415 | Method resolution order:
3416 | Color
3417 | enum.Enum
3418 | builtins.object
3419 |\x20\x20
3420 | Data and other attributes defined here:
3421 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003422 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003423 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003424 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003425 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003426 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003427 |\x20\x20
3428 | ----------------------------------------------------------------------
3429 | Data descriptors inherited from enum.Enum:
3430 |\x20\x20
3431 | name
3432 |\x20\x20
3433 | value
3434 |\x20\x20
3435 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003436 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003437 |\x20\x20
3438 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003439
3440class TestStdLib(unittest.TestCase):
3441
Ethan Furman48a724f2015-04-11 23:23:06 -07003442 maxDiff = None
3443
Ethan Furman5875d742013-10-21 20:45:55 -07003444 class Color(Enum):
3445 red = 1
3446 green = 2
3447 blue = 3
3448
3449 def test_pydoc(self):
3450 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003451 if StrEnum.__doc__ is None:
3452 expected_text = expected_help_output_without_docs % __name__
3453 else:
3454 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003455 output = StringIO()
3456 helper = pydoc.Helper(output=output)
3457 helper(self.Color)
3458 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003459 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003460
3461 def test_inspect_getmembers(self):
3462 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003463 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003464 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003465 ('__members__', self.Color.__members__),
3466 ('__module__', __name__),
3467 ('blue', self.Color.blue),
3468 ('green', self.Color.green),
3469 ('name', Enum.__dict__['name']),
3470 ('red', self.Color.red),
3471 ('value', Enum.__dict__['value']),
3472 ))
3473 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003474 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003475 failed = False
3476 for k in values.keys():
3477 if result[k] != values[k]:
3478 print()
3479 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3480 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3481 failed = True
3482 if failed:
3483 self.fail("result does not equal expected, see print above")
3484
3485 def test_inspect_classify_class_attrs(self):
3486 # indirectly test __objclass__
3487 from inspect import Attribute
3488 values = [
3489 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003490 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003491 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003492 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003493 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003494 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003495 Attribute(name='__module__', kind='data',
3496 defining_class=self.Color, object=__name__),
3497 Attribute(name='blue', kind='data',
3498 defining_class=self.Color, object=self.Color.blue),
3499 Attribute(name='green', kind='data',
3500 defining_class=self.Color, object=self.Color.green),
3501 Attribute(name='red', kind='data',
3502 defining_class=self.Color, object=self.Color.red),
3503 Attribute(name='name', kind='data',
3504 defining_class=Enum, object=Enum.__dict__['name']),
3505 Attribute(name='value', kind='data',
3506 defining_class=Enum, object=Enum.__dict__['value']),
3507 ]
3508 values.sort(key=lambda item: item.name)
3509 result = list(inspect.classify_class_attrs(self.Color))
3510 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003511 self.assertEqual(
3512 len(values), len(result),
3513 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3514 )
Ethan Furman5875d742013-10-21 20:45:55 -07003515 failed = False
3516 for v, r in zip(values, result):
3517 if r != v:
3518 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3519 failed = True
3520 if failed:
3521 self.fail("result does not equal expected, see print above")
3522
Martin Panter19e69c52015-11-14 12:46:42 +00003523
3524class MiscTestCase(unittest.TestCase):
3525 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003526 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003527
3528
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003529# These are unordered here on purpose to ensure that declaration order
3530# makes no difference.
3531CONVERT_TEST_NAME_D = 5
3532CONVERT_TEST_NAME_C = 5
3533CONVERT_TEST_NAME_B = 5
3534CONVERT_TEST_NAME_A = 5 # This one should sort first.
3535CONVERT_TEST_NAME_E = 5
3536CONVERT_TEST_NAME_F = 5
3537
3538class TestIntEnumConvert(unittest.TestCase):
3539 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003540 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003541 'UnittestConvert',
3542 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003543 filter=lambda x: x.startswith('CONVERT_TEST_'))
3544 # We don't want the reverse lookup value to vary when there are
3545 # multiple possible names for a given value. It should always
3546 # report the first lexigraphical name in that case.
3547 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3548
3549 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003550 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003551 'UnittestConvert',
3552 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003553 filter=lambda x: x.startswith('CONVERT_TEST_'))
3554 # Ensure that test_type has all of the desired names and values.
3555 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3556 test_type.CONVERT_TEST_NAME_A)
3557 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3558 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3559 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3560 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3561 # Ensure that test_type only picked up names matching the filter.
3562 self.assertEqual([name for name in dir(test_type)
3563 if name[0:2] not in ('CO', '__')],
3564 [], msg='Names other than CONVERT_TEST_* found.')
3565
orlnub1230fb9fad2018-09-12 20:28:53 +03003566 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3567 '_convert was deprecated in 3.8')
3568 def test_convert_warn(self):
3569 with self.assertWarns(DeprecationWarning):
3570 enum.IntEnum._convert(
3571 'UnittestConvert',
3572 ('test.test_enum', '__main__')[__name__=='__main__'],
3573 filter=lambda x: x.startswith('CONVERT_TEST_'))
3574
3575 @unittest.skipUnless(sys.version_info >= (3, 9),
3576 '_convert was removed in 3.9')
3577 def test_convert_raise(self):
3578 with self.assertRaises(AttributeError):
3579 enum.IntEnum._convert(
3580 'UnittestConvert',
3581 ('test.test_enum', '__main__')[__name__=='__main__'],
3582 filter=lambda x: x.startswith('CONVERT_TEST_'))
3583
Ethan Furmanb7751062021-03-30 21:17:26 -07003584 def test_convert_repr_and_str(self):
3585 module = ('test.test_enum', '__main__')[__name__=='__main__']
3586 test_type = enum.IntEnum._convert_(
3587 'UnittestConvert',
3588 module,
3589 filter=lambda x: x.startswith('CONVERT_TEST_'))
3590 self.assertEqual(repr(test_type.CONVERT_TEST_NAME_A), '%s.CONVERT_TEST_NAME_A' % module)
3591 self.assertEqual(str(test_type.CONVERT_TEST_NAME_A), 'CONVERT_TEST_NAME_A')
3592 self.assertEqual(format(test_type.CONVERT_TEST_NAME_A), '5')
3593
3594# global names for StrEnum._convert_ test
3595CONVERT_STR_TEST_2 = 'goodbye'
3596CONVERT_STR_TEST_1 = 'hello'
3597
3598class TestStrEnumConvert(unittest.TestCase):
3599
3600 def test_convert(self):
3601 test_type = enum.StrEnum._convert_(
3602 'UnittestConvert',
3603 ('test.test_enum', '__main__')[__name__=='__main__'],
3604 filter=lambda x: x.startswith('CONVERT_STR_'))
3605 # Ensure that test_type has all of the desired names and values.
3606 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3607 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3608 # Ensure that test_type only picked up names matching the filter.
3609 self.assertEqual([name for name in dir(test_type)
3610 if name[0:2] not in ('CO', '__')],
3611 [], msg='Names other than CONVERT_STR_* found.')
3612
3613 def test_convert_repr_and_str(self):
3614 module = ('test.test_enum', '__main__')[__name__=='__main__']
3615 test_type = enum.StrEnum._convert_(
3616 'UnittestConvert',
3617 module,
3618 filter=lambda x: x.startswith('CONVERT_STR_'))
3619 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3620 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
3621 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
3622
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003623
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003624if __name__ == '__main__':
3625 unittest.main()