blob: e918b03cc6c52015eb0a43e3e31a2ad31967694d [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 Furmana02cb472021-04-21 10:20:44 -070011from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
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 Furman6bd92882021-04-27 13:05:08 -070019python_version = sys.version_info[:2]
20
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080021def load_tests(loader, tests, ignore):
22 tests.addTests(doctest.DocTestSuite(enum))
Ethan Furman44e580f2021-03-03 09:54:30 -080023 if os.path.exists('Doc/library/enum.rst'):
Ethan Furman01faf452021-01-26 12:52:52 -080024 tests.addTests(doctest.DocFileSuite(
25 '../../Doc/library/enum.rst',
26 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
27 ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080028 return tests
Ethan Furman6b3d64a2013-06-14 16:55:46 -070029
30# for pickle tests
31try:
32 class Stooges(Enum):
33 LARRY = 1
34 CURLY = 2
35 MOE = 3
36except Exception as exc:
37 Stooges = exc
38
39try:
40 class IntStooges(int, Enum):
41 LARRY = 1
42 CURLY = 2
43 MOE = 3
44except Exception as exc:
45 IntStooges = exc
46
47try:
48 class FloatStooges(float, Enum):
49 LARRY = 1.39
50 CURLY = 2.72
51 MOE = 3.142596
52except Exception as exc:
53 FloatStooges = exc
54
Ethan Furman65a5a472016-09-01 23:55:19 -070055try:
56 class FlagStooges(Flag):
57 LARRY = 1
58 CURLY = 2
59 MOE = 3
60except Exception as exc:
61 FlagStooges = exc
62
Ethan Furman6b3d64a2013-06-14 16:55:46 -070063# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070064class Name(StrEnum):
65 BDFL = 'Guido van Rossum'
66 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070067
68try:
69 Question = Enum('Question', 'who what when where why', module=__name__)
70except Exception as exc:
71 Question = exc
72
73try:
74 Answer = Enum('Answer', 'him this then there because')
75except Exception as exc:
76 Answer = exc
77
Ethan Furmanca1b7942014-02-08 11:36:27 -080078try:
79 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
80except Exception as exc:
81 Theory = exc
82
Ethan Furman6b3d64a2013-06-14 16:55:46 -070083# for doctests
84try:
85 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080086 TOMATO = 1
87 BANANA = 2
88 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070089except Exception:
90 pass
91
Serhiy Storchakae50e7802015-03-31 16:56:49 +030092def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080093 if target is None:
94 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030095 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080096 assertion(loads(dumps(source, protocol=protocol)), target)
97
Serhiy Storchakae50e7802015-03-31 16:56:49 +030098def test_pickle_exception(assertion, exception, obj):
99 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800100 with assertion(exception):
101 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -0700102
103class TestHelpers(unittest.TestCase):
104 # _is_descriptor, _is_sunder, _is_dunder
105
106 def test_is_descriptor(self):
107 class foo:
108 pass
109 for attr in ('__get__','__set__','__delete__'):
110 obj = foo()
111 self.assertFalse(enum._is_descriptor(obj))
112 setattr(obj, attr, 1)
113 self.assertTrue(enum._is_descriptor(obj))
114
115 def test_is_sunder(self):
116 for s in ('_a_', '_aa_'):
117 self.assertTrue(enum._is_sunder(s))
118
119 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
120 '__', '___', '____', '_____',):
121 self.assertFalse(enum._is_sunder(s))
122
123 def test_is_dunder(self):
124 for s in ('__a__', '__aa__'):
125 self.assertTrue(enum._is_dunder(s))
126 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
127 '__', '___', '____', '_____',):
128 self.assertFalse(enum._is_dunder(s))
129
Ethan Furman5bdab642018-09-21 19:03:09 -0700130# for subclassing tests
131
132class classproperty:
133
134 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
135 self.fget = fget
136 self.fset = fset
137 self.fdel = fdel
138 if doc is None and fget is not None:
139 doc = fget.__doc__
140 self.__doc__ = doc
141
142 def __get__(self, instance, ownerclass):
143 return self.fget(ownerclass)
144
145
Ethan Furmanc16595e2016-09-10 23:36:59 -0700146# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700147
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700148class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800149
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700150 def setUp(self):
151 class Season(Enum):
152 SPRING = 1
153 SUMMER = 2
154 AUTUMN = 3
155 WINTER = 4
156 self.Season = Season
157
Ethan Furmanec15a822013-08-31 19:17:41 -0700158 class Konstants(float, Enum):
159 E = 2.7182818
160 PI = 3.1415926
161 TAU = 2 * PI
162 self.Konstants = Konstants
163
164 class Grades(IntEnum):
165 A = 5
166 B = 4
167 C = 3
168 D = 2
169 F = 0
170 self.Grades = Grades
171
172 class Directional(str, Enum):
173 EAST = 'east'
174 WEST = 'west'
175 NORTH = 'north'
176 SOUTH = 'south'
177 self.Directional = Directional
178
179 from datetime import date
180 class Holiday(date, Enum):
181 NEW_YEAR = 2013, 1, 1
182 IDES_OF_MARCH = 2013, 3, 15
183 self.Holiday = Holiday
184
Ethan Furman388a3922013-08-12 06:51:41 -0700185 def test_dir_on_class(self):
186 Season = self.Season
187 self.assertEqual(
188 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700189 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700190 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
191 )
192
193 def test_dir_on_item(self):
194 Season = self.Season
195 self.assertEqual(
196 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700197 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700198 )
199
Ethan Furmanc850f342013-09-15 16:59:35 -0700200 def test_dir_with_added_behavior(self):
201 class Test(Enum):
202 this = 'that'
203 these = 'those'
204 def wowser(self):
205 return ("Wowser! I'm %s!" % self.name)
206 self.assertEqual(
207 set(dir(Test)),
208 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
209 )
210 self.assertEqual(
211 set(dir(Test.this)),
212 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
213 )
214
Ethan Furman0ae550b2014-10-14 08:58:32 -0700215 def test_dir_on_sub_with_behavior_on_super(self):
216 # see issue22506
217 class SuperEnum(Enum):
218 def invisible(self):
219 return "did you see me?"
220 class SubEnum(SuperEnum):
221 sample = 5
222 self.assertEqual(
223 set(dir(SubEnum.sample)),
224 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
225 )
226
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200227 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
228 # see issue40084
229 class SuperEnum(IntEnum):
230 def __new__(cls, value, description=""):
231 obj = int.__new__(cls, value)
232 obj._value_ = value
233 obj.description = description
234 return obj
235 class SubEnum(SuperEnum):
236 sample = 5
237 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
238
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700239 def test_enum_in_enum_out(self):
240 Season = self.Season
241 self.assertIs(Season(Season.WINTER), Season.WINTER)
242
243 def test_enum_value(self):
244 Season = self.Season
245 self.assertEqual(Season.SPRING.value, 1)
246
247 def test_intenum_value(self):
248 self.assertEqual(IntStooges.CURLY.value, 2)
249
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700250 def test_enum(self):
251 Season = self.Season
252 lst = list(Season)
253 self.assertEqual(len(lst), len(Season))
254 self.assertEqual(len(Season), 4, Season)
255 self.assertEqual(
256 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
257
258 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
259 e = Season(i)
260 self.assertEqual(e, getattr(Season, season))
261 self.assertEqual(e.value, i)
262 self.assertNotEqual(e, i)
263 self.assertEqual(e.name, season)
264 self.assertIn(e, Season)
265 self.assertIs(type(e), Season)
266 self.assertIsInstance(e, Season)
Ethan Furmanb7751062021-03-30 21:17:26 -0700267 self.assertEqual(str(e), season)
268 self.assertEqual(repr(e), 'Season.{0}'.format(season))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700269
270 def test_value_name(self):
271 Season = self.Season
272 self.assertEqual(Season.SPRING.name, 'SPRING')
273 self.assertEqual(Season.SPRING.value, 1)
274 with self.assertRaises(AttributeError):
275 Season.SPRING.name = 'invierno'
276 with self.assertRaises(AttributeError):
277 Season.SPRING.value = 2
278
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700279 def test_changing_member(self):
280 Season = self.Season
281 with self.assertRaises(AttributeError):
282 Season.WINTER = 'really cold'
283
Ethan Furman64a99722013-09-22 16:18:19 -0700284 def test_attribute_deletion(self):
285 class Season(Enum):
286 SPRING = 1
287 SUMMER = 2
288 AUTUMN = 3
289 WINTER = 4
290
291 def spam(cls):
292 pass
293
294 self.assertTrue(hasattr(Season, 'spam'))
295 del Season.spam
296 self.assertFalse(hasattr(Season, 'spam'))
297
298 with self.assertRaises(AttributeError):
299 del Season.SPRING
300 with self.assertRaises(AttributeError):
301 del Season.DRY
302 with self.assertRaises(AttributeError):
303 del Season.SPRING.name
304
Ethan Furman5de67b12016-04-13 23:52:09 -0700305 def test_bool_of_class(self):
306 class Empty(Enum):
307 pass
308 self.assertTrue(bool(Empty))
309
310 def test_bool_of_member(self):
311 class Count(Enum):
312 zero = 0
313 one = 1
314 two = 2
315 for member in Count:
316 self.assertTrue(bool(member))
317
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700318 def test_invalid_names(self):
319 with self.assertRaises(ValueError):
320 class Wrong(Enum):
321 mro = 9
322 with self.assertRaises(ValueError):
323 class Wrong(Enum):
324 _create_= 11
325 with self.assertRaises(ValueError):
326 class Wrong(Enum):
327 _get_mixins_ = 9
328 with self.assertRaises(ValueError):
329 class Wrong(Enum):
330 _find_new_ = 1
331 with self.assertRaises(ValueError):
332 class Wrong(Enum):
333 _any_name_ = 9
334
Ethan Furman6db1fd52015-09-17 21:49:12 -0700335 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800336 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700337 class Logic(Enum):
338 true = True
339 false = False
340 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800341 self.assertTrue(Logic.false)
342 # unless overridden
343 class RealLogic(Enum):
344 true = True
345 false = False
346 def __bool__(self):
347 return bool(self._value_)
348 self.assertTrue(RealLogic.true)
349 self.assertFalse(RealLogic.false)
350 # mixed Enums depend on mixed-in type
351 class IntLogic(int, Enum):
352 true = 1
353 false = 0
354 self.assertTrue(IntLogic.true)
355 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700356
Ethan Furman6bd92882021-04-27 13:05:08 -0700357 @unittest.skipIf(
358 python_version >= (3, 12),
359 '__contains__ now returns True/False for all inputs',
360 )
361 def test_contains_er(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700362 Season = self.Season
363 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530364 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -0700365 with self.assertWarns(DeprecationWarning):
366 3 in Season
Rahul Jha94306522018-09-10 23:51:04 +0530367 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -0700368 with self.assertWarns(DeprecationWarning):
369 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700370 val = Season(3)
371 self.assertIn(val, Season)
Ethan Furman6bd92882021-04-27 13:05:08 -0700372 #
373 class OtherEnum(Enum):
374 one = 1; two = 2
375 self.assertNotIn(OtherEnum.two, Season)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700376
Ethan Furman6bd92882021-04-27 13:05:08 -0700377 @unittest.skipIf(
378 python_version < (3, 12),
379 '__contains__ only works with enum memmbers before 3.12',
380 )
381 def test_contains_tf(self):
382 Season = self.Season
383 self.assertIn(Season.AUTUMN, Season)
384 self.assertTrue(3 in Season)
385 self.assertFalse('AUTUMN' in Season)
386 val = Season(3)
387 self.assertIn(val, Season)
388 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700389 class OtherEnum(Enum):
390 one = 1; two = 2
391 self.assertNotIn(OtherEnum.two, Season)
392
393 def test_comparisons(self):
394 Season = self.Season
395 with self.assertRaises(TypeError):
396 Season.SPRING < Season.WINTER
397 with self.assertRaises(TypeError):
398 Season.SPRING > 4
399
400 self.assertNotEqual(Season.SPRING, 1)
401
402 class Part(Enum):
403 SPRING = 1
404 CLIP = 2
405 BARREL = 3
406
407 self.assertNotEqual(Season.SPRING, Part.SPRING)
408 with self.assertRaises(TypeError):
409 Season.SPRING < Part.CLIP
410
411 def test_enum_duplicates(self):
412 class Season(Enum):
413 SPRING = 1
414 SUMMER = 2
415 AUTUMN = FALL = 3
416 WINTER = 4
417 ANOTHER_SPRING = 1
418 lst = list(Season)
419 self.assertEqual(
420 lst,
421 [Season.SPRING, Season.SUMMER,
422 Season.AUTUMN, Season.WINTER,
423 ])
424 self.assertIs(Season.FALL, Season.AUTUMN)
425 self.assertEqual(Season.FALL.value, 3)
426 self.assertEqual(Season.AUTUMN.value, 3)
427 self.assertIs(Season(3), Season.AUTUMN)
428 self.assertIs(Season(1), Season.SPRING)
429 self.assertEqual(Season.FALL.name, 'AUTUMN')
430 self.assertEqual(
431 [k for k,v in Season.__members__.items() if v.name != k],
432 ['FALL', 'ANOTHER_SPRING'],
433 )
434
Ethan Furman101e0742013-09-15 12:34:36 -0700435 def test_duplicate_name(self):
436 with self.assertRaises(TypeError):
437 class Color(Enum):
438 red = 1
439 green = 2
440 blue = 3
441 red = 4
442
443 with self.assertRaises(TypeError):
444 class Color(Enum):
445 red = 1
446 green = 2
447 blue = 3
448 def red(self):
449 return 'red'
450
451 with self.assertRaises(TypeError):
452 class Color(Enum):
453 @property
454 def red(self):
455 return 'redder'
456 red = 1
457 green = 2
458 blue = 3
459
Zackery Spytz2ec67522020-09-13 14:27:51 -0600460 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700461 with self.assertRaisesRegex(
462 ValueError,
Ethan Furmanb7751062021-03-30 21:17:26 -0700463 '_sunder_ names, such as ._bad_., are reserved',
Ethan Furman5a565b32020-09-15 12:27:06 -0700464 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600465 class Bad(Enum):
466 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700467
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700468 def test_enum_with_value_name(self):
469 class Huh(Enum):
470 name = 1
471 value = 2
472 self.assertEqual(
473 list(Huh),
474 [Huh.name, Huh.value],
475 )
476 self.assertIs(type(Huh.name), Huh)
477 self.assertEqual(Huh.name.name, 'name')
478 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700479
480 def test_format_enum(self):
481 Season = self.Season
482 self.assertEqual('{}'.format(Season.SPRING),
483 '{}'.format(str(Season.SPRING)))
484 self.assertEqual( '{:}'.format(Season.SPRING),
485 '{:}'.format(str(Season.SPRING)))
486 self.assertEqual('{:20}'.format(Season.SPRING),
487 '{:20}'.format(str(Season.SPRING)))
488 self.assertEqual('{:^20}'.format(Season.SPRING),
489 '{:^20}'.format(str(Season.SPRING)))
490 self.assertEqual('{:>20}'.format(Season.SPRING),
491 '{:>20}'.format(str(Season.SPRING)))
492 self.assertEqual('{:<20}'.format(Season.SPRING),
493 '{:<20}'.format(str(Season.SPRING)))
494
thatneat2f19e822019-07-04 11:28:37 -0700495 def test_str_override_enum(self):
496 class EnumWithStrOverrides(Enum):
497 one = auto()
498 two = auto()
499
500 def __str__(self):
501 return 'Str!'
502 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
503 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
504
505 def test_format_override_enum(self):
506 class EnumWithFormatOverride(Enum):
507 one = 1.0
508 two = 2.0
509 def __format__(self, spec):
510 return 'Format!!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700511 self.assertEqual(str(EnumWithFormatOverride.one), 'one')
thatneat2f19e822019-07-04 11:28:37 -0700512 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
513
514 def test_str_and_format_override_enum(self):
515 class EnumWithStrFormatOverrides(Enum):
516 one = auto()
517 two = auto()
518 def __str__(self):
519 return 'Str!'
520 def __format__(self, spec):
521 return 'Format!'
522 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
523 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
524
525 def test_str_override_mixin(self):
526 class MixinEnumWithStrOverride(float, Enum):
527 one = 1.0
528 two = 2.0
529 def __str__(self):
530 return 'Overridden!'
531 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
532 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
533
534 def test_str_and_format_override_mixin(self):
535 class MixinWithStrFormatOverrides(float, Enum):
536 one = 1.0
537 two = 2.0
538 def __str__(self):
539 return 'Str!'
540 def __format__(self, spec):
541 return 'Format!'
542 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
543 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
544
545 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700546 class TestFloat(float, Enum):
547 one = 1.0
548 two = 2.0
549 def __format__(self, spec):
550 return 'TestFloat success!'
Ethan Furmanb7751062021-03-30 21:17:26 -0700551 self.assertEqual(str(TestFloat.one), 'one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700552 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
553
Ethan Furman6bd92882021-04-27 13:05:08 -0700554 @unittest.skipIf(
555 python_version < (3, 12),
556 'mixin-format is still using member.value',
557 )
558 def test_mixin_format_warning(self):
559 with self.assertWarns(DeprecationWarning):
560 self.assertEqual(f'{self.Grades.B}', 'Grades.B')
561
562 @unittest.skipIf(
563 python_version >= (3, 12),
Ethan Furman5987b8c2021-04-26 22:42:57 -0700564 'mixin-format now uses member instead of member.value',
565 )
566 def test_mixin_format_warning(self):
567 with self.assertWarns(DeprecationWarning):
568 self.assertEqual(f'{self.Grades.B}', '4')
569
Ethan Furmanec15a822013-08-31 19:17:41 -0700570 def assertFormatIsValue(self, spec, member):
Ethan Furman6bd92882021-04-27 13:05:08 -0700571 if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
572 with self.assertWarns(DeprecationWarning):
573 self.assertEqual(spec.format(member), spec.format(member.value))
574 else:
575 self.assertEqual(spec.format(member), spec.format(member.value))
Ethan Furmanec15a822013-08-31 19:17:41 -0700576
577 def test_format_enum_date(self):
578 Holiday = self.Holiday
579 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
580 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
581 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
582 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
583 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
584 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
585 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
586 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
587
588 def test_format_enum_float(self):
589 Konstants = self.Konstants
590 self.assertFormatIsValue('{}', Konstants.TAU)
591 self.assertFormatIsValue('{:}', Konstants.TAU)
592 self.assertFormatIsValue('{:20}', Konstants.TAU)
593 self.assertFormatIsValue('{:^20}', Konstants.TAU)
594 self.assertFormatIsValue('{:>20}', Konstants.TAU)
595 self.assertFormatIsValue('{:<20}', Konstants.TAU)
596 self.assertFormatIsValue('{:n}', Konstants.TAU)
597 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
598 self.assertFormatIsValue('{:f}', Konstants.TAU)
599
600 def test_format_enum_int(self):
601 Grades = self.Grades
602 self.assertFormatIsValue('{}', Grades.C)
603 self.assertFormatIsValue('{:}', Grades.C)
604 self.assertFormatIsValue('{:20}', Grades.C)
605 self.assertFormatIsValue('{:^20}', Grades.C)
606 self.assertFormatIsValue('{:>20}', Grades.C)
607 self.assertFormatIsValue('{:<20}', Grades.C)
608 self.assertFormatIsValue('{:+}', Grades.C)
609 self.assertFormatIsValue('{:08X}', Grades.C)
610 self.assertFormatIsValue('{:b}', Grades.C)
611
612 def test_format_enum_str(self):
613 Directional = self.Directional
614 self.assertFormatIsValue('{}', Directional.WEST)
615 self.assertFormatIsValue('{:}', Directional.WEST)
616 self.assertFormatIsValue('{:20}', Directional.WEST)
617 self.assertFormatIsValue('{:^20}', Directional.WEST)
618 self.assertFormatIsValue('{:>20}', Directional.WEST)
619 self.assertFormatIsValue('{:<20}', Directional.WEST)
620
Ethan Furman22415ad2020-09-15 16:28:25 -0700621 def test_object_str_override(self):
622 class Colors(Enum):
623 RED, GREEN, BLUE = 1, 2, 3
624 def __repr__(self):
625 return "test.%s" % (self._name_, )
626 __str__ = object.__str__
627 self.assertEqual(str(Colors.RED), 'test.RED')
628
Ethan Furmanbff01f32020-09-15 15:56:26 -0700629 def test_enum_str_override(self):
630 class MyStrEnum(Enum):
631 def __str__(self):
632 return 'MyStr'
633 class MyMethodEnum(Enum):
634 def hello(self):
635 return 'Hello! My name is %s' % self.name
636 class Test1Enum(MyMethodEnum, int, MyStrEnum):
637 One = 1
638 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800639 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700640 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800641 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700642 #
643 class Test2Enum(MyStrEnum, MyMethodEnum):
644 One = 1
645 Two = 2
646 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800647 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700648
649 def test_inherited_data_type(self):
650 class HexInt(int):
651 def __repr__(self):
652 return hex(self)
653 class MyEnum(HexInt, enum.Enum):
654 A = 1
655 B = 2
656 C = 3
Ethan Furmanb7751062021-03-30 21:17:26 -0700657 def __repr__(self):
658 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700659 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
660
661 def test_too_many_data_types(self):
662 with self.assertRaisesRegex(TypeError, 'too many data types'):
663 class Huh(str, int, Enum):
664 One = 1
665
666 class MyStr(str):
667 def hello(self):
668 return 'hello, %s' % self
669 class MyInt(int):
670 def repr(self):
671 return hex(self)
672 with self.assertRaisesRegex(TypeError, 'too many data types'):
673 class Huh(MyStr, MyInt, Enum):
674 One = 1
675
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700676 def test_hash(self):
677 Season = self.Season
678 dates = {}
679 dates[Season.WINTER] = '1225'
680 dates[Season.SPRING] = '0315'
681 dates[Season.SUMMER] = '0704'
682 dates[Season.AUTUMN] = '1031'
683 self.assertEqual(dates[Season.AUTUMN], '1031')
684
685 def test_intenum_from_scratch(self):
686 class phy(int, Enum):
687 pi = 3
688 tau = 2 * pi
689 self.assertTrue(phy.pi < phy.tau)
690
691 def test_intenum_inherited(self):
692 class IntEnum(int, Enum):
693 pass
694 class phy(IntEnum):
695 pi = 3
696 tau = 2 * pi
697 self.assertTrue(phy.pi < phy.tau)
698
699 def test_floatenum_from_scratch(self):
700 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700701 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700702 tau = 2 * pi
703 self.assertTrue(phy.pi < phy.tau)
704
705 def test_floatenum_inherited(self):
706 class FloatEnum(float, Enum):
707 pass
708 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700709 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700710 tau = 2 * pi
711 self.assertTrue(phy.pi < phy.tau)
712
713 def test_strenum_from_scratch(self):
714 class phy(str, Enum):
715 pi = 'Pi'
716 tau = 'Tau'
717 self.assertTrue(phy.pi < phy.tau)
718
Ethan Furman0063ff42020-09-21 17:23:13 -0700719 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700720 class phy(StrEnum):
721 pi = 'Pi'
722 tau = 'Tau'
723 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700724 self.assertEqual(phy.pi.upper(), 'PI')
725 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700726
727 def test_intenum(self):
728 class WeekDay(IntEnum):
729 SUNDAY = 1
730 MONDAY = 2
731 TUESDAY = 3
732 WEDNESDAY = 4
733 THURSDAY = 5
734 FRIDAY = 6
735 SATURDAY = 7
736
737 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
738 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
739
740 lst = list(WeekDay)
741 self.assertEqual(len(lst), len(WeekDay))
742 self.assertEqual(len(WeekDay), 7)
743 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
744 target = target.split()
745 for i, weekday in enumerate(target, 1):
746 e = WeekDay(i)
747 self.assertEqual(e, i)
748 self.assertEqual(int(e), i)
749 self.assertEqual(e.name, weekday)
750 self.assertIn(e, WeekDay)
751 self.assertEqual(lst.index(e)+1, i)
752 self.assertTrue(0 < e < 8)
753 self.assertIs(type(e), WeekDay)
754 self.assertIsInstance(e, int)
755 self.assertIsInstance(e, Enum)
756
757 def test_intenum_duplicates(self):
758 class WeekDay(IntEnum):
759 SUNDAY = 1
760 MONDAY = 2
761 TUESDAY = TEUSDAY = 3
762 WEDNESDAY = 4
763 THURSDAY = 5
764 FRIDAY = 6
765 SATURDAY = 7
766 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
767 self.assertEqual(WeekDay(3).name, 'TUESDAY')
768 self.assertEqual([k for k,v in WeekDay.__members__.items()
769 if v.name != k], ['TEUSDAY', ])
770
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300771 def test_intenum_from_bytes(self):
772 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
773 with self.assertRaises(ValueError):
774 IntStooges.from_bytes(b'\x00\x05', 'big')
775
776 def test_floatenum_fromhex(self):
777 h = float.hex(FloatStooges.MOE.value)
778 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
779 h = float.hex(FloatStooges.MOE.value + 0.01)
780 with self.assertRaises(ValueError):
781 FloatStooges.fromhex(h)
782
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 def test_pickle_enum(self):
784 if isinstance(Stooges, Exception):
785 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800786 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
787 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700788
789 def test_pickle_int(self):
790 if isinstance(IntStooges, Exception):
791 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800792 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
793 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700794
795 def test_pickle_float(self):
796 if isinstance(FloatStooges, Exception):
797 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800798 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
799 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700800
801 def test_pickle_enum_function(self):
802 if isinstance(Answer, Exception):
803 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800804 test_pickle_dump_load(self.assertIs, Answer.him)
805 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700806
807 def test_pickle_enum_function_with_module(self):
808 if isinstance(Question, Exception):
809 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800810 test_pickle_dump_load(self.assertIs, Question.who)
811 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700812
Ethan Furmanca1b7942014-02-08 11:36:27 -0800813 def test_enum_function_with_qualname(self):
814 if isinstance(Theory, Exception):
815 raise Theory
816 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
817
818 def test_class_nested_enum_and_pickle_protocol_four(self):
819 # would normally just have this directly in the class namespace
820 class NestedEnum(Enum):
821 twigs = 'common'
822 shiny = 'rare'
823
824 self.__class__.NestedEnum = NestedEnum
825 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300826 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800827
Ethan Furman24e837f2015-03-18 17:27:57 -0700828 def test_pickle_by_name(self):
829 class ReplaceGlobalInt(IntEnum):
830 ONE = 1
831 TWO = 2
832 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
833 for proto in range(HIGHEST_PROTOCOL):
834 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
835
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700836 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800837 BadPickle = Enum(
838 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700839 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800840 # now break BadPickle to test exception raising
841 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800842 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
843 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700844
845 def test_string_enum(self):
846 class SkillLevel(str, Enum):
847 master = 'what is the sound of one hand clapping?'
848 journeyman = 'why did the chicken cross the road?'
849 apprentice = 'knock, knock!'
850 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
851
852 def test_getattr_getitem(self):
853 class Period(Enum):
854 morning = 1
855 noon = 2
856 evening = 3
857 night = 4
858 self.assertIs(Period(2), Period.noon)
859 self.assertIs(getattr(Period, 'night'), Period.night)
860 self.assertIs(Period['morning'], Period.morning)
861
862 def test_getattr_dunder(self):
863 Season = self.Season
864 self.assertTrue(getattr(Season, '__eq__'))
865
866 def test_iteration_order(self):
867 class Season(Enum):
868 SUMMER = 2
869 WINTER = 4
870 AUTUMN = 3
871 SPRING = 1
872 self.assertEqual(
873 list(Season),
874 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
875 )
876
Ethan Furman2131a4a2013-09-14 18:11:24 -0700877 def test_reversed_iteration_order(self):
878 self.assertEqual(
879 list(reversed(self.Season)),
880 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
881 self.Season.SPRING]
882 )
883
Martin Pantereb995702016-07-28 01:11:04 +0000884 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700885 SummerMonth = Enum('SummerMonth', 'june july august')
886 lst = list(SummerMonth)
887 self.assertEqual(len(lst), len(SummerMonth))
888 self.assertEqual(len(SummerMonth), 3, SummerMonth)
889 self.assertEqual(
890 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
891 lst,
892 )
893 for i, month in enumerate('june july august'.split(), 1):
894 e = SummerMonth(i)
895 self.assertEqual(int(e.value), i)
896 self.assertNotEqual(e, i)
897 self.assertEqual(e.name, month)
898 self.assertIn(e, SummerMonth)
899 self.assertIs(type(e), SummerMonth)
900
Martin Pantereb995702016-07-28 01:11:04 +0000901 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700902 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
903 lst = list(SummerMonth)
904 self.assertEqual(len(lst), len(SummerMonth))
905 self.assertEqual(len(SummerMonth), 3, SummerMonth)
906 self.assertEqual(
907 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
908 lst,
909 )
910 for i, month in enumerate('june july august'.split(), 10):
911 e = SummerMonth(i)
912 self.assertEqual(int(e.value), i)
913 self.assertNotEqual(e, i)
914 self.assertEqual(e.name, month)
915 self.assertIn(e, SummerMonth)
916 self.assertIs(type(e), SummerMonth)
917
Martin Pantereb995702016-07-28 01:11:04 +0000918 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700919 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
920 lst = list(SummerMonth)
921 self.assertEqual(len(lst), len(SummerMonth))
922 self.assertEqual(len(SummerMonth), 3, SummerMonth)
923 self.assertEqual(
924 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
925 lst,
926 )
927 for i, month in enumerate('june july august'.split(), 1):
928 e = SummerMonth(i)
929 self.assertEqual(int(e.value), i)
930 self.assertNotEqual(e, i)
931 self.assertEqual(e.name, month)
932 self.assertIn(e, SummerMonth)
933 self.assertIs(type(e), SummerMonth)
934
Martin Pantereb995702016-07-28 01:11:04 +0000935 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700936 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
937 lst = list(SummerMonth)
938 self.assertEqual(len(lst), len(SummerMonth))
939 self.assertEqual(len(SummerMonth), 3, SummerMonth)
940 self.assertEqual(
941 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
942 lst,
943 )
944 for i, month in enumerate('june july august'.split(), 20):
945 e = SummerMonth(i)
946 self.assertEqual(int(e.value), i)
947 self.assertNotEqual(e, i)
948 self.assertEqual(e.name, month)
949 self.assertIn(e, SummerMonth)
950 self.assertIs(type(e), SummerMonth)
951
Martin Pantereb995702016-07-28 01:11:04 +0000952 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700953 SummerMonth = Enum(
954 'SummerMonth',
955 (('june', 1), ('july', 2), ('august', 3))
956 )
957 lst = list(SummerMonth)
958 self.assertEqual(len(lst), len(SummerMonth))
959 self.assertEqual(len(SummerMonth), 3, SummerMonth)
960 self.assertEqual(
961 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
962 lst,
963 )
964 for i, month in enumerate('june july august'.split(), 1):
965 e = SummerMonth(i)
966 self.assertEqual(int(e.value), i)
967 self.assertNotEqual(e, i)
968 self.assertEqual(e.name, month)
969 self.assertIn(e, SummerMonth)
970 self.assertIs(type(e), SummerMonth)
971
Martin Pantereb995702016-07-28 01:11:04 +0000972 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700973 SummerMonth = Enum(
974 'SummerMonth',
975 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
976 )
977 lst = list(SummerMonth)
978 self.assertEqual(len(lst), len(SummerMonth))
979 self.assertEqual(len(SummerMonth), 3, SummerMonth)
980 self.assertEqual(
981 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
982 lst,
983 )
984 for i, month in enumerate('june july august'.split(), 1):
985 e = SummerMonth(i)
986 self.assertEqual(int(e.value), i)
987 self.assertNotEqual(e, i)
988 self.assertEqual(e.name, month)
989 self.assertIn(e, SummerMonth)
990 self.assertIs(type(e), SummerMonth)
991
Martin Pantereb995702016-07-28 01:11:04 +0000992 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700993 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
994 lst = list(SummerMonth)
995 self.assertEqual(len(lst), len(SummerMonth))
996 self.assertEqual(len(SummerMonth), 3, SummerMonth)
997 self.assertEqual(
998 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
999 lst,
1000 )
1001 for i, month in enumerate('june july august'.split(), 1):
1002 e = SummerMonth(i)
1003 self.assertEqual(e, i)
1004 self.assertEqual(e.name, month)
1005 self.assertIn(e, SummerMonth)
1006 self.assertIs(type(e), SummerMonth)
1007
Martin Pantereb995702016-07-28 01:11:04 +00001008 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001009 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
1010 lst = list(SummerMonth)
1011 self.assertEqual(len(lst), len(SummerMonth))
1012 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1013 self.assertEqual(
1014 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1015 lst,
1016 )
1017 for i, month in enumerate('june july august'.split(), 30):
1018 e = SummerMonth(i)
1019 self.assertEqual(e, i)
1020 self.assertEqual(e.name, month)
1021 self.assertIn(e, SummerMonth)
1022 self.assertIs(type(e), SummerMonth)
1023
Martin Pantereb995702016-07-28 01:11:04 +00001024 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001025 SummerMonth = IntEnum('SummerMonth', 'june july august')
1026 lst = list(SummerMonth)
1027 self.assertEqual(len(lst), len(SummerMonth))
1028 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1029 self.assertEqual(
1030 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1031 lst,
1032 )
1033 for i, month in enumerate('june july august'.split(), 1):
1034 e = SummerMonth(i)
1035 self.assertEqual(e, i)
1036 self.assertEqual(e.name, month)
1037 self.assertIn(e, SummerMonth)
1038 self.assertIs(type(e), SummerMonth)
1039
Martin Pantereb995702016-07-28 01:11:04 +00001040 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001041 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1042 lst = list(SummerMonth)
1043 self.assertEqual(len(lst), len(SummerMonth))
1044 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1045 self.assertEqual(
1046 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1047 lst,
1048 )
1049 for i, month in enumerate('june july august'.split(), 40):
1050 e = SummerMonth(i)
1051 self.assertEqual(e, i)
1052 self.assertEqual(e.name, month)
1053 self.assertIn(e, SummerMonth)
1054 self.assertIs(type(e), SummerMonth)
1055
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001056 def test_subclassing(self):
1057 if isinstance(Name, Exception):
1058 raise Name
1059 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1060 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1061 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001062 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001063
1064 def test_extending(self):
1065 class Color(Enum):
1066 red = 1
1067 green = 2
1068 blue = 3
1069 with self.assertRaises(TypeError):
1070 class MoreColor(Color):
1071 cyan = 4
1072 magenta = 5
1073 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001074 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1075 class EvenMoreColor(Color, IntEnum):
1076 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001077
1078 def test_exclude_methods(self):
1079 class whatever(Enum):
1080 this = 'that'
1081 these = 'those'
1082 def really(self):
1083 return 'no, not %s' % self.value
1084 self.assertIsNot(type(whatever.really), whatever)
1085 self.assertEqual(whatever.this.really(), 'no, not that')
1086
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001087 def test_wrong_inheritance_order(self):
1088 with self.assertRaises(TypeError):
1089 class Wrong(Enum, str):
1090 NotHere = 'error before this point'
1091
1092 def test_intenum_transitivity(self):
1093 class number(IntEnum):
1094 one = 1
1095 two = 2
1096 three = 3
1097 class numero(IntEnum):
1098 uno = 1
1099 dos = 2
1100 tres = 3
1101 self.assertEqual(number.one, numero.uno)
1102 self.assertEqual(number.two, numero.dos)
1103 self.assertEqual(number.three, numero.tres)
1104
1105 def test_wrong_enum_in_call(self):
1106 class Monochrome(Enum):
1107 black = 0
1108 white = 1
1109 class Gender(Enum):
1110 male = 0
1111 female = 1
1112 self.assertRaises(ValueError, Monochrome, Gender.male)
1113
1114 def test_wrong_enum_in_mixed_call(self):
1115 class Monochrome(IntEnum):
1116 black = 0
1117 white = 1
1118 class Gender(Enum):
1119 male = 0
1120 female = 1
1121 self.assertRaises(ValueError, Monochrome, Gender.male)
1122
1123 def test_mixed_enum_in_call_1(self):
1124 class Monochrome(IntEnum):
1125 black = 0
1126 white = 1
1127 class Gender(IntEnum):
1128 male = 0
1129 female = 1
1130 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1131
1132 def test_mixed_enum_in_call_2(self):
1133 class Monochrome(Enum):
1134 black = 0
1135 white = 1
1136 class Gender(IntEnum):
1137 male = 0
1138 female = 1
1139 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1140
1141 def test_flufl_enum(self):
1142 class Fluflnum(Enum):
1143 def __int__(self):
1144 return int(self.value)
1145 class MailManOptions(Fluflnum):
1146 option1 = 1
1147 option2 = 2
1148 option3 = 3
1149 self.assertEqual(int(MailManOptions.option1), 1)
1150
Ethan Furman5e5a8232013-08-04 08:42:23 -07001151 def test_introspection(self):
1152 class Number(IntEnum):
1153 one = 100
1154 two = 200
1155 self.assertIs(Number.one._member_type_, int)
1156 self.assertIs(Number._member_type_, int)
1157 class String(str, Enum):
1158 yarn = 'soft'
1159 rope = 'rough'
1160 wire = 'hard'
1161 self.assertIs(String.yarn._member_type_, str)
1162 self.assertIs(String._member_type_, str)
1163 class Plain(Enum):
1164 vanilla = 'white'
1165 one = 1
1166 self.assertIs(Plain.vanilla._member_type_, object)
1167 self.assertIs(Plain._member_type_, object)
1168
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001169 def test_no_such_enum_member(self):
1170 class Color(Enum):
1171 red = 1
1172 green = 2
1173 blue = 3
1174 with self.assertRaises(ValueError):
1175 Color(4)
1176 with self.assertRaises(KeyError):
1177 Color['chartreuse']
1178
1179 def test_new_repr(self):
1180 class Color(Enum):
1181 red = 1
1182 green = 2
1183 blue = 3
1184 def __repr__(self):
1185 return "don't you just love shades of %s?" % self.name
1186 self.assertEqual(
1187 repr(Color.blue),
1188 "don't you just love shades of blue?",
1189 )
1190
1191 def test_inherited_repr(self):
1192 class MyEnum(Enum):
1193 def __repr__(self):
1194 return "My name is %s." % self.name
1195 class MyIntEnum(int, MyEnum):
1196 this = 1
1197 that = 2
1198 theother = 3
1199 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1200
1201 def test_multiple_mixin_mro(self):
1202 class auto_enum(type(Enum)):
1203 def __new__(metacls, cls, bases, classdict):
1204 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001205 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001206 names = set(classdict._member_names)
1207 i = 0
1208 for k in classdict._member_names:
1209 v = classdict[k]
1210 if v is Ellipsis:
1211 v = i
1212 else:
1213 i = v
1214 i += 1
1215 temp[k] = v
1216 for k, v in classdict.items():
1217 if k not in names:
1218 temp[k] = v
1219 return super(auto_enum, metacls).__new__(
1220 metacls, cls, bases, temp)
1221
1222 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1223 pass
1224
1225 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1226 pass
1227
1228 class TestAutoNumber(AutoNumberedEnum):
1229 a = ...
1230 b = 3
1231 c = ...
1232
1233 class TestAutoInt(AutoIntEnum):
1234 a = ...
1235 b = 3
1236 c = ...
1237
1238 def test_subclasses_with_getnewargs(self):
1239 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001240 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001241 def __new__(cls, *args):
1242 _args = args
1243 name, *args = args
1244 if len(args) == 0:
1245 raise TypeError("name and value must be specified")
1246 self = int.__new__(cls, *args)
1247 self._intname = name
1248 self._args = _args
1249 return self
1250 def __getnewargs__(self):
1251 return self._args
1252 @property
1253 def __name__(self):
1254 return self._intname
1255 def __repr__(self):
1256 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001257 return "{}({!r}, {})".format(
1258 type(self).__name__,
1259 self.__name__,
1260 int.__repr__(self),
1261 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001262 def __str__(self):
1263 # str() is unchanged, even if it relies on the repr() fallback
1264 base = int
1265 base_str = base.__str__
1266 if base_str.__objclass__ is object:
1267 return base.__repr__(self)
1268 return base_str(self)
1269 # for simplicity, we only define one operator that
1270 # propagates expressions
1271 def __add__(self, other):
1272 temp = int(self) + int( other)
1273 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1274 return NamedInt(
1275 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001276 temp,
1277 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001278 else:
1279 return temp
1280
1281 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001282 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001283 x = ('the-x', 1)
1284 y = ('the-y', 2)
1285
Ethan Furman2aa27322013-07-19 19:35:56 -07001286
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001287 self.assertIs(NEI.__new__, Enum.__new__)
1288 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1289 globals()['NamedInt'] = NamedInt
1290 globals()['NEI'] = NEI
1291 NI5 = NamedInt('test', 5)
1292 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001293 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001294 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001295 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001296 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001297
Ethan Furmanca1b7942014-02-08 11:36:27 -08001298 def test_subclasses_with_getnewargs_ex(self):
1299 class NamedInt(int):
1300 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1301 def __new__(cls, *args):
1302 _args = args
1303 name, *args = args
1304 if len(args) == 0:
1305 raise TypeError("name and value must be specified")
1306 self = int.__new__(cls, *args)
1307 self._intname = name
1308 self._args = _args
1309 return self
1310 def __getnewargs_ex__(self):
1311 return self._args, {}
1312 @property
1313 def __name__(self):
1314 return self._intname
1315 def __repr__(self):
1316 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001317 return "{}({!r}, {})".format(
1318 type(self).__name__,
1319 self.__name__,
1320 int.__repr__(self),
1321 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001322 def __str__(self):
1323 # str() is unchanged, even if it relies on the repr() fallback
1324 base = int
1325 base_str = base.__str__
1326 if base_str.__objclass__ is object:
1327 return base.__repr__(self)
1328 return base_str(self)
1329 # for simplicity, we only define one operator that
1330 # propagates expressions
1331 def __add__(self, other):
1332 temp = int(self) + int( other)
1333 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1334 return NamedInt(
1335 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001336 temp,
1337 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001338 else:
1339 return temp
1340
1341 class NEI(NamedInt, Enum):
1342 __qualname__ = 'NEI' # needed for pickle protocol 4
1343 x = ('the-x', 1)
1344 y = ('the-y', 2)
1345
1346
1347 self.assertIs(NEI.__new__, Enum.__new__)
1348 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1349 globals()['NamedInt'] = NamedInt
1350 globals()['NEI'] = NEI
1351 NI5 = NamedInt('test', 5)
1352 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001353 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001355 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001356 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001357
1358 def test_subclasses_with_reduce(self):
1359 class NamedInt(int):
1360 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1361 def __new__(cls, *args):
1362 _args = args
1363 name, *args = args
1364 if len(args) == 0:
1365 raise TypeError("name and value must be specified")
1366 self = int.__new__(cls, *args)
1367 self._intname = name
1368 self._args = _args
1369 return self
1370 def __reduce__(self):
1371 return self.__class__, self._args
1372 @property
1373 def __name__(self):
1374 return self._intname
1375 def __repr__(self):
1376 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001377 return "{}({!r}, {})".format(
1378 type(self).__name__,
1379 self.__name__,
1380 int.__repr__(self),
1381 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001382 def __str__(self):
1383 # str() is unchanged, even if it relies on the repr() fallback
1384 base = int
1385 base_str = base.__str__
1386 if base_str.__objclass__ is object:
1387 return base.__repr__(self)
1388 return base_str(self)
1389 # for simplicity, we only define one operator that
1390 # propagates expressions
1391 def __add__(self, other):
1392 temp = int(self) + int( other)
1393 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1394 return NamedInt(
1395 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001396 temp,
1397 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001398 else:
1399 return temp
1400
1401 class NEI(NamedInt, Enum):
1402 __qualname__ = 'NEI' # needed for pickle protocol 4
1403 x = ('the-x', 1)
1404 y = ('the-y', 2)
1405
1406
1407 self.assertIs(NEI.__new__, Enum.__new__)
1408 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1409 globals()['NamedInt'] = NamedInt
1410 globals()['NEI'] = NEI
1411 NI5 = NamedInt('test', 5)
1412 self.assertEqual(NI5, 5)
1413 test_pickle_dump_load(self.assertEqual, NI5, 5)
1414 self.assertEqual(NEI.y.value, 2)
1415 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001416 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001417
1418 def test_subclasses_with_reduce_ex(self):
1419 class NamedInt(int):
1420 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1421 def __new__(cls, *args):
1422 _args = args
1423 name, *args = args
1424 if len(args) == 0:
1425 raise TypeError("name and value must be specified")
1426 self = int.__new__(cls, *args)
1427 self._intname = name
1428 self._args = _args
1429 return self
1430 def __reduce_ex__(self, proto):
1431 return self.__class__, self._args
1432 @property
1433 def __name__(self):
1434 return self._intname
1435 def __repr__(self):
1436 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001437 return "{}({!r}, {})".format(
1438 type(self).__name__,
1439 self.__name__,
1440 int.__repr__(self),
1441 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001442 def __str__(self):
1443 # str() is unchanged, even if it relies on the repr() fallback
1444 base = int
1445 base_str = base.__str__
1446 if base_str.__objclass__ is object:
1447 return base.__repr__(self)
1448 return base_str(self)
1449 # for simplicity, we only define one operator that
1450 # propagates expressions
1451 def __add__(self, other):
1452 temp = int(self) + int( other)
1453 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1454 return NamedInt(
1455 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001456 temp,
1457 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001458 else:
1459 return temp
1460
1461 class NEI(NamedInt, Enum):
1462 __qualname__ = 'NEI' # needed for pickle protocol 4
1463 x = ('the-x', 1)
1464 y = ('the-y', 2)
1465
Ethan Furmanca1b7942014-02-08 11:36:27 -08001466 self.assertIs(NEI.__new__, Enum.__new__)
1467 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1468 globals()['NamedInt'] = NamedInt
1469 globals()['NEI'] = NEI
1470 NI5 = NamedInt('test', 5)
1471 self.assertEqual(NI5, 5)
1472 test_pickle_dump_load(self.assertEqual, NI5, 5)
1473 self.assertEqual(NEI.y.value, 2)
1474 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001475 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001476
Ethan Furmandc870522014-02-18 12:37:12 -08001477 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001478 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001479 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001480 def __new__(cls, *args):
1481 _args = args
1482 name, *args = args
1483 if len(args) == 0:
1484 raise TypeError("name and value must be specified")
1485 self = int.__new__(cls, *args)
1486 self._intname = name
1487 self._args = _args
1488 return self
1489 @property
1490 def __name__(self):
1491 return self._intname
1492 def __repr__(self):
1493 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001494 return "{}({!r}, {})".format(
1495 type(self).__name__,
1496 self.__name__,
1497 int.__repr__(self),
1498 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001499 def __str__(self):
1500 # str() is unchanged, even if it relies on the repr() fallback
1501 base = int
1502 base_str = base.__str__
1503 if base_str.__objclass__ is object:
1504 return base.__repr__(self)
1505 return base_str(self)
1506 # for simplicity, we only define one operator that
1507 # propagates expressions
1508 def __add__(self, other):
1509 temp = int(self) + int( other)
1510 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1511 return NamedInt(
1512 '({0} + {1})'.format(self.__name__, other.__name__),
1513 temp )
1514 else:
1515 return temp
1516
1517 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001518 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001519 x = ('the-x', 1)
1520 y = ('the-y', 2)
1521
1522 self.assertIs(NEI.__new__, Enum.__new__)
1523 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1524 globals()['NamedInt'] = NamedInt
1525 globals()['NEI'] = NEI
1526 NI5 = NamedInt('test', 5)
1527 self.assertEqual(NI5, 5)
1528 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001529 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1530 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001531
Ethan Furmandc870522014-02-18 12:37:12 -08001532 def test_subclasses_without_direct_pickle_support_using_name(self):
1533 class NamedInt(int):
1534 __qualname__ = 'NamedInt'
1535 def __new__(cls, *args):
1536 _args = args
1537 name, *args = args
1538 if len(args) == 0:
1539 raise TypeError("name and value must be specified")
1540 self = int.__new__(cls, *args)
1541 self._intname = name
1542 self._args = _args
1543 return self
1544 @property
1545 def __name__(self):
1546 return self._intname
1547 def __repr__(self):
1548 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001549 return "{}({!r}, {})".format(
1550 type(self).__name__,
1551 self.__name__,
1552 int.__repr__(self),
1553 )
Ethan Furmandc870522014-02-18 12:37:12 -08001554 def __str__(self):
1555 # str() is unchanged, even if it relies on the repr() fallback
1556 base = int
1557 base_str = base.__str__
1558 if base_str.__objclass__ is object:
1559 return base.__repr__(self)
1560 return base_str(self)
1561 # for simplicity, we only define one operator that
1562 # propagates expressions
1563 def __add__(self, other):
1564 temp = int(self) + int( other)
1565 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1566 return NamedInt(
1567 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001568 temp,
1569 )
Ethan Furmandc870522014-02-18 12:37:12 -08001570 else:
1571 return temp
1572
1573 class NEI(NamedInt, Enum):
1574 __qualname__ = 'NEI'
1575 x = ('the-x', 1)
1576 y = ('the-y', 2)
1577 def __reduce_ex__(self, proto):
1578 return getattr, (self.__class__, self._name_)
1579
1580 self.assertIs(NEI.__new__, Enum.__new__)
1581 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1582 globals()['NamedInt'] = NamedInt
1583 globals()['NEI'] = NEI
1584 NI5 = NamedInt('test', 5)
1585 self.assertEqual(NI5, 5)
1586 self.assertEqual(NEI.y.value, 2)
1587 test_pickle_dump_load(self.assertIs, NEI.y)
1588 test_pickle_dump_load(self.assertIs, NEI)
1589
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001590 def test_tuple_subclass(self):
1591 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001592 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001593 first = (1, 'for the money')
1594 second = (2, 'for the show')
1595 third = (3, 'for the music')
1596 self.assertIs(type(SomeTuple.first), SomeTuple)
1597 self.assertIsInstance(SomeTuple.second, tuple)
1598 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1599 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001600 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001601
1602 def test_duplicate_values_give_unique_enum_items(self):
1603 class AutoNumber(Enum):
1604 first = ()
1605 second = ()
1606 third = ()
1607 def __new__(cls):
1608 value = len(cls.__members__) + 1
1609 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001610 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001611 return obj
1612 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001613 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 self.assertEqual(
1615 list(AutoNumber),
1616 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1617 )
1618 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001619 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001620 self.assertIs(AutoNumber(1), AutoNumber.first)
1621
1622 def test_inherited_new_from_enhanced_enum(self):
1623 class AutoNumber(Enum):
1624 def __new__(cls):
1625 value = len(cls.__members__) + 1
1626 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001627 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001628 return obj
1629 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001630 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001631 class Color(AutoNumber):
1632 red = ()
1633 green = ()
1634 blue = ()
1635 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1636 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1637
1638 def test_inherited_new_from_mixed_enum(self):
1639 class AutoNumber(IntEnum):
1640 def __new__(cls):
1641 value = len(cls.__members__) + 1
1642 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001643 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001644 return obj
1645 class Color(AutoNumber):
1646 red = ()
1647 green = ()
1648 blue = ()
1649 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1650 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1651
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001652 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001653 class OrdinaryEnum(Enum):
1654 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001655 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1656 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001657
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001658 def test_ordered_mixin(self):
1659 class OrderedEnum(Enum):
1660 def __ge__(self, other):
1661 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001662 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001663 return NotImplemented
1664 def __gt__(self, other):
1665 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001666 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001667 return NotImplemented
1668 def __le__(self, other):
1669 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001670 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001671 return NotImplemented
1672 def __lt__(self, other):
1673 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001674 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001675 return NotImplemented
1676 class Grade(OrderedEnum):
1677 A = 5
1678 B = 4
1679 C = 3
1680 D = 2
1681 F = 1
1682 self.assertGreater(Grade.A, Grade.B)
1683 self.assertLessEqual(Grade.F, Grade.C)
1684 self.assertLess(Grade.D, Grade.A)
1685 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001686 self.assertEqual(Grade.B, Grade.B)
1687 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001688
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001689 def test_extending2(self):
1690 class Shade(Enum):
1691 def shade(self):
1692 print(self.name)
1693 class Color(Shade):
1694 red = 1
1695 green = 2
1696 blue = 3
1697 with self.assertRaises(TypeError):
1698 class MoreColor(Color):
1699 cyan = 4
1700 magenta = 5
1701 yellow = 6
1702
1703 def test_extending3(self):
1704 class Shade(Enum):
1705 def shade(self):
1706 return self.name
1707 class Color(Shade):
1708 def hex(self):
1709 return '%s hexlified!' % self.value
1710 class MoreColor(Color):
1711 cyan = 4
1712 magenta = 5
1713 yellow = 6
1714 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1715
orlnub1230fb9fad2018-09-12 20:28:53 +03001716 def test_subclass_duplicate_name(self):
1717 class Base(Enum):
1718 def test(self):
1719 pass
1720 class Test(Base):
1721 test = 1
1722 self.assertIs(type(Test.test), Test)
1723
1724 def test_subclass_duplicate_name_dynamic(self):
1725 from types import DynamicClassAttribute
1726 class Base(Enum):
1727 @DynamicClassAttribute
1728 def test(self):
1729 return 'dynamic'
1730 class Test(Base):
1731 test = 1
1732 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001733 class Base2(Enum):
1734 @enum.property
1735 def flash(self):
1736 return 'flashy dynamic'
1737 class Test(Base2):
1738 flash = 1
1739 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001740
1741 def test_no_duplicates(self):
1742 class UniqueEnum(Enum):
1743 def __init__(self, *args):
1744 cls = self.__class__
1745 if any(self.value == e.value for e in cls):
1746 a = self.name
1747 e = cls(self.value).name
1748 raise ValueError(
1749 "aliases not allowed in UniqueEnum: %r --> %r"
1750 % (a, e)
1751 )
1752 class Color(UniqueEnum):
1753 red = 1
1754 green = 2
1755 blue = 3
1756 with self.assertRaises(ValueError):
1757 class Color(UniqueEnum):
1758 red = 1
1759 green = 2
1760 blue = 3
1761 grene = 2
1762
1763 def test_init(self):
1764 class Planet(Enum):
1765 MERCURY = (3.303e+23, 2.4397e6)
1766 VENUS = (4.869e+24, 6.0518e6)
1767 EARTH = (5.976e+24, 6.37814e6)
1768 MARS = (6.421e+23, 3.3972e6)
1769 JUPITER = (1.9e+27, 7.1492e7)
1770 SATURN = (5.688e+26, 6.0268e7)
1771 URANUS = (8.686e+25, 2.5559e7)
1772 NEPTUNE = (1.024e+26, 2.4746e7)
1773 def __init__(self, mass, radius):
1774 self.mass = mass # in kilograms
1775 self.radius = radius # in meters
1776 @property
1777 def surface_gravity(self):
1778 # universal gravitational constant (m3 kg-1 s-2)
1779 G = 6.67300E-11
1780 return G * self.mass / (self.radius * self.radius)
1781 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1782 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1783
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001784 def test_ignore(self):
1785 class Period(timedelta, Enum):
1786 '''
1787 different lengths of time
1788 '''
1789 def __new__(cls, value, period):
1790 obj = timedelta.__new__(cls, value)
1791 obj._value_ = value
1792 obj.period = period
1793 return obj
1794 _ignore_ = 'Period i'
1795 Period = vars()
1796 for i in range(13):
1797 Period['month_%d' % i] = i*30, 'month'
1798 for i in range(53):
1799 Period['week_%d' % i] = i*7, 'week'
1800 for i in range(32):
1801 Period['day_%d' % i] = i, 'day'
1802 OneDay = day_1
1803 OneWeek = week_1
1804 OneMonth = month_1
1805 self.assertFalse(hasattr(Period, '_ignore_'))
1806 self.assertFalse(hasattr(Period, 'Period'))
1807 self.assertFalse(hasattr(Period, 'i'))
1808 self.assertTrue(isinstance(Period.day_1, timedelta))
1809 self.assertTrue(Period.month_1 is Period.day_30)
1810 self.assertTrue(Period.week_4 is Period.day_28)
1811
Ethan Furman2aa27322013-07-19 19:35:56 -07001812 def test_nonhash_value(self):
1813 class AutoNumberInAList(Enum):
1814 def __new__(cls):
1815 value = [len(cls.__members__) + 1]
1816 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001817 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001818 return obj
1819 class ColorInAList(AutoNumberInAList):
1820 red = ()
1821 green = ()
1822 blue = ()
1823 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001824 for enum, value in zip(ColorInAList, range(3)):
1825 value += 1
1826 self.assertEqual(enum.value, [value])
1827 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001828
Ethan Furmanb41803e2013-07-25 13:50:45 -07001829 def test_conflicting_types_resolved_in_new(self):
1830 class LabelledIntEnum(int, Enum):
1831 def __new__(cls, *args):
1832 value, label = args
1833 obj = int.__new__(cls, value)
1834 obj.label = label
1835 obj._value_ = value
1836 return obj
1837
1838 class LabelledList(LabelledIntEnum):
1839 unprocessed = (1, "Unprocessed")
1840 payment_complete = (2, "Payment Complete")
1841
1842 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1843 self.assertEqual(LabelledList.unprocessed, 1)
1844 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001845
Ethan Furmanc16595e2016-09-10 23:36:59 -07001846 def test_auto_number(self):
1847 class Color(Enum):
1848 red = auto()
1849 blue = auto()
1850 green = auto()
1851
1852 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1853 self.assertEqual(Color.red.value, 1)
1854 self.assertEqual(Color.blue.value, 2)
1855 self.assertEqual(Color.green.value, 3)
1856
1857 def test_auto_name(self):
1858 class Color(Enum):
1859 def _generate_next_value_(name, start, count, last):
1860 return name
1861 red = auto()
1862 blue = auto()
1863 green = auto()
1864
1865 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1866 self.assertEqual(Color.red.value, 'red')
1867 self.assertEqual(Color.blue.value, 'blue')
1868 self.assertEqual(Color.green.value, 'green')
1869
1870 def test_auto_name_inherit(self):
1871 class AutoNameEnum(Enum):
1872 def _generate_next_value_(name, start, count, last):
1873 return name
1874 class Color(AutoNameEnum):
1875 red = auto()
1876 blue = auto()
1877 green = auto()
1878
1879 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1880 self.assertEqual(Color.red.value, 'red')
1881 self.assertEqual(Color.blue.value, 'blue')
1882 self.assertEqual(Color.green.value, 'green')
1883
1884 def test_auto_garbage(self):
1885 class Color(Enum):
1886 red = 'red'
1887 blue = auto()
1888 self.assertEqual(Color.blue.value, 1)
1889
1890 def test_auto_garbage_corrected(self):
1891 class Color(Enum):
1892 red = 'red'
1893 blue = 2
1894 green = auto()
1895
1896 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1897 self.assertEqual(Color.red.value, 'red')
1898 self.assertEqual(Color.blue.value, 2)
1899 self.assertEqual(Color.green.value, 3)
1900
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001901 def test_auto_order(self):
1902 with self.assertRaises(TypeError):
1903 class Color(Enum):
1904 red = auto()
1905 green = auto()
1906 blue = auto()
1907 def _generate_next_value_(name, start, count, last):
1908 return name
1909
Ethan Furmanfc23a942020-09-16 12:37:54 -07001910 def test_auto_order_wierd(self):
1911 weird_auto = auto()
1912 weird_auto.value = 'pathological case'
1913 class Color(Enum):
1914 red = weird_auto
1915 def _generate_next_value_(name, start, count, last):
1916 return name
1917 blue = auto()
1918 self.assertEqual(list(Color), [Color.red, Color.blue])
1919 self.assertEqual(Color.red.value, 'pathological case')
1920 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001921
Ethan Furman3515dcc2016-09-18 13:15:41 -07001922 def test_duplicate_auto(self):
1923 class Dupes(Enum):
1924 first = primero = auto()
1925 second = auto()
1926 third = auto()
1927 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1928
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001929 def test_default_missing(self):
1930 class Color(Enum):
1931 RED = 1
1932 GREEN = 2
1933 BLUE = 3
1934 try:
1935 Color(7)
1936 except ValueError as exc:
1937 self.assertTrue(exc.__context__ is None)
1938 else:
1939 raise Exception('Exception not raised.')
1940
Ethan Furman019f0a02018-09-12 11:43:34 -07001941 def test_missing(self):
1942 class Color(Enum):
1943 red = 1
1944 green = 2
1945 blue = 3
1946 @classmethod
1947 def _missing_(cls, item):
1948 if item == 'three':
1949 return cls.blue
1950 elif item == 'bad return':
1951 # trigger internal error
1952 return 5
1953 elif item == 'error out':
1954 raise ZeroDivisionError
1955 else:
1956 # trigger not found
1957 return None
1958 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001959 try:
1960 Color(7)
1961 except ValueError as exc:
1962 self.assertTrue(exc.__context__ is None)
1963 else:
1964 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001965 try:
1966 Color('bad return')
1967 except TypeError as exc:
1968 self.assertTrue(isinstance(exc.__context__, ValueError))
1969 else:
1970 raise Exception('Exception not raised.')
1971 try:
1972 Color('error out')
1973 except ZeroDivisionError as exc:
1974 self.assertTrue(isinstance(exc.__context__, ValueError))
1975 else:
1976 raise Exception('Exception not raised.')
1977
Ethan Furman8c14f5a2021-04-12 08:51:20 -07001978 def test_missing_exceptions_reset(self):
1979 import weakref
1980 #
1981 class TestEnum(enum.Enum):
1982 VAL1 = 'val1'
1983 VAL2 = 'val2'
1984 #
1985 class Class1:
1986 def __init__(self):
1987 # Gracefully handle an exception of our own making
1988 try:
1989 raise ValueError()
1990 except ValueError:
1991 pass
1992 #
1993 class Class2:
1994 def __init__(self):
1995 # Gracefully handle an exception of Enum's making
1996 try:
1997 TestEnum('invalid_value')
1998 except ValueError:
1999 pass
2000 # No strong refs here so these are free to die.
2001 class_1_ref = weakref.ref(Class1())
2002 class_2_ref = weakref.ref(Class2())
2003 #
2004 # The exception raised by Enum creates a reference loop and thus
2005 # Class2 instances will stick around until the next gargage collection
2006 # cycle, unlike Class1.
2007 self.assertIs(class_1_ref(), None)
2008 self.assertIs(class_2_ref(), None)
2009
Ethan Furman5bdab642018-09-21 19:03:09 -07002010 def test_multiple_mixin(self):
2011 class MaxMixin:
2012 @classproperty
2013 def MAX(cls):
2014 max = len(cls)
2015 cls.MAX = max
2016 return max
2017 class StrMixin:
2018 def __str__(self):
2019 return self._name_.lower()
2020 class SomeEnum(Enum):
2021 def behavior(self):
2022 return 'booyah'
2023 class AnotherEnum(Enum):
2024 def behavior(self):
2025 return 'nuhuh!'
2026 def social(self):
2027 return "what's up?"
2028 class Color(MaxMixin, Enum):
2029 RED = auto()
2030 GREEN = auto()
2031 BLUE = auto()
2032 self.assertEqual(Color.RED.value, 1)
2033 self.assertEqual(Color.GREEN.value, 2)
2034 self.assertEqual(Color.BLUE.value, 3)
2035 self.assertEqual(Color.MAX, 3)
Ethan Furmanb7751062021-03-30 21:17:26 -07002036 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002037 class Color(MaxMixin, StrMixin, Enum):
2038 RED = auto()
2039 GREEN = auto()
2040 BLUE = auto()
2041 self.assertEqual(Color.RED.value, 1)
2042 self.assertEqual(Color.GREEN.value, 2)
2043 self.assertEqual(Color.BLUE.value, 3)
2044 self.assertEqual(Color.MAX, 3)
2045 self.assertEqual(str(Color.BLUE), 'blue')
2046 class Color(StrMixin, MaxMixin, Enum):
2047 RED = auto()
2048 GREEN = auto()
2049 BLUE = auto()
2050 self.assertEqual(Color.RED.value, 1)
2051 self.assertEqual(Color.GREEN.value, 2)
2052 self.assertEqual(Color.BLUE.value, 3)
2053 self.assertEqual(Color.MAX, 3)
2054 self.assertEqual(str(Color.BLUE), 'blue')
2055 class CoolColor(StrMixin, SomeEnum, Enum):
2056 RED = auto()
2057 GREEN = auto()
2058 BLUE = auto()
2059 self.assertEqual(CoolColor.RED.value, 1)
2060 self.assertEqual(CoolColor.GREEN.value, 2)
2061 self.assertEqual(CoolColor.BLUE.value, 3)
2062 self.assertEqual(str(CoolColor.BLUE), 'blue')
2063 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
2064 class CoolerColor(StrMixin, AnotherEnum, Enum):
2065 RED = auto()
2066 GREEN = auto()
2067 BLUE = auto()
2068 self.assertEqual(CoolerColor.RED.value, 1)
2069 self.assertEqual(CoolerColor.GREEN.value, 2)
2070 self.assertEqual(CoolerColor.BLUE.value, 3)
2071 self.assertEqual(str(CoolerColor.BLUE), 'blue')
2072 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
2073 self.assertEqual(CoolerColor.RED.social(), "what's up?")
2074 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2075 RED = auto()
2076 GREEN = auto()
2077 BLUE = auto()
2078 self.assertEqual(CoolestColor.RED.value, 1)
2079 self.assertEqual(CoolestColor.GREEN.value, 2)
2080 self.assertEqual(CoolestColor.BLUE.value, 3)
2081 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2082 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2083 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2084 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2085 RED = auto()
2086 GREEN = auto()
2087 BLUE = auto()
2088 self.assertEqual(ConfusedColor.RED.value, 1)
2089 self.assertEqual(ConfusedColor.GREEN.value, 2)
2090 self.assertEqual(ConfusedColor.BLUE.value, 3)
2091 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2092 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2093 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2094 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2095 RED = auto()
2096 GREEN = auto()
2097 BLUE = auto()
2098 self.assertEqual(ReformedColor.RED.value, 1)
2099 self.assertEqual(ReformedColor.GREEN.value, 2)
2100 self.assertEqual(ReformedColor.BLUE.value, 3)
2101 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2102 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2103 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2104 self.assertTrue(issubclass(ReformedColor, int))
2105
Ethan Furmancd453852018-10-05 23:29:36 -07002106 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002107 @unique
2108 class Decision1(StrEnum):
2109 REVERT = "REVERT"
2110 REVERT_ALL = "REVERT_ALL"
2111 RETRY = "RETRY"
2112 class MyEnum(StrEnum):
2113 pass
2114 @unique
2115 class Decision2(MyEnum):
2116 REVERT = "REVERT"
2117 REVERT_ALL = "REVERT_ALL"
2118 RETRY = "RETRY"
2119
Ethan Furmanc2667362020-12-07 00:17:31 -08002120 def test_multiple_mixin_inherited(self):
2121 class MyInt(int):
2122 def __new__(cls, value):
2123 return super().__new__(cls, value)
2124
2125 class HexMixin:
2126 def __repr__(self):
2127 return hex(self)
2128
2129 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2130 pass
2131
2132 class Foo(MyIntEnum):
2133 TEST = 1
2134 self.assertTrue(isinstance(Foo.TEST, MyInt))
2135 self.assertEqual(repr(Foo.TEST), "0x1")
2136
2137 class Fee(MyIntEnum):
2138 TEST = 1
2139 def __new__(cls, value):
2140 value += 1
2141 member = int.__new__(cls, value)
2142 member._value_ = value
2143 return member
2144 self.assertEqual(Fee.TEST, 2)
2145
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002146 def test_empty_globals(self):
2147 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2148 # when using compile and exec because f_globals is empty
2149 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2150 code = compile(code, "<string>", "exec")
2151 global_ns = {}
2152 local_ls = {}
2153 exec(code, global_ns, local_ls)
2154
Ethan Furman0063ff42020-09-21 17:23:13 -07002155 def test_strenum(self):
2156 class GoodStrEnum(StrEnum):
2157 one = '1'
2158 two = '2'
2159 three = b'3', 'ascii'
2160 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002161 self.assertEqual(GoodStrEnum.one, '1')
2162 self.assertEqual(str(GoodStrEnum.one), '1')
2163 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2164 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2165 #
2166 class DumbMixin:
2167 def __str__(self):
2168 return "don't do this"
2169 class DumbStrEnum(DumbMixin, StrEnum):
2170 five = '5'
2171 six = '6'
2172 seven = '7'
2173 self.assertEqual(DumbStrEnum.seven, '7')
2174 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2175 #
2176 class EnumMixin(Enum):
2177 def hello(self):
2178 print('hello from %s' % (self, ))
2179 class HelloEnum(EnumMixin, StrEnum):
2180 eight = '8'
2181 self.assertEqual(HelloEnum.eight, '8')
2182 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2183 #
2184 class GoodbyeMixin:
2185 def goodbye(self):
2186 print('%s wishes you a fond farewell')
2187 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2188 nine = '9'
2189 self.assertEqual(GoodbyeEnum.nine, '9')
2190 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2191 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002192 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2193 class FirstFailedStrEnum(StrEnum):
2194 one = 1
2195 two = '2'
2196 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2197 class SecondFailedStrEnum(StrEnum):
2198 one = '1'
2199 two = 2,
2200 three = '3'
2201 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2202 class ThirdFailedStrEnum(StrEnum):
2203 one = '1'
2204 two = 2
2205 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2206 class ThirdFailedStrEnum(StrEnum):
2207 one = '1'
2208 two = b'2', sys.getdefaultencoding
2209 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2210 class ThirdFailedStrEnum(StrEnum):
2211 one = '1'
2212 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002213
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002214 def test_missing_value_error(self):
2215 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
2216 class Combined(str, Enum):
2217 #
2218 def __new__(cls, value, sequence):
2219 enum = str.__new__(cls, value)
2220 if '(' in value:
2221 fis_name, segment = value.split('(', 1)
2222 segment = segment.strip(' )')
2223 else:
2224 fis_name = value
2225 segment = None
2226 enum.fis_name = fis_name
2227 enum.segment = segment
2228 enum.sequence = sequence
2229 return enum
2230 #
2231 def __repr__(self):
2232 return "<%s.%s>" % (self.__class__.__name__, self._name_)
2233 #
2234 key_type = 'An$(1,2)', 0
2235 company_id = 'An$(3,2)', 1
2236 code = 'An$(5,1)', 2
2237 description = 'Bn$', 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002238
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002239 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002240 python_version == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002241 'private variables are now normal attributes',
2242 )
2243 def test_warning_for_private_variables(self):
2244 with self.assertWarns(DeprecationWarning):
2245 class Private(Enum):
2246 __corporal = 'Radar'
2247 self.assertEqual(Private._Private__corporal.value, 'Radar')
2248 try:
2249 with self.assertWarns(DeprecationWarning):
2250 class Private(Enum):
2251 __major_ = 'Hoolihan'
2252 except ValueError:
2253 pass
2254
2255 def test_private_variable_is_normal_attribute(self):
2256 class Private(Enum):
2257 __corporal = 'Radar'
2258 __major_ = 'Hoolihan'
2259 self.assertEqual(Private._Private__corporal, 'Radar')
2260 self.assertEqual(Private._Private__major_, 'Hoolihan')
2261
Ethan Furmand65b9032021-02-08 17:32:38 -08002262 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002263 python_version < (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002264 'member-member access now raises an exception',
2265 )
2266 def test_warning_for_member_from_member_access(self):
2267 with self.assertWarns(DeprecationWarning):
2268 class Di(Enum):
2269 YES = 1
2270 NO = 0
2271 nope = Di.YES.NO
2272 self.assertIs(Di.NO, nope)
2273
2274 @unittest.skipUnless(
Ethan Furman6bd92882021-04-27 13:05:08 -07002275 python_version >= (3, 12),
Ethan Furmand65b9032021-02-08 17:32:38 -08002276 'member-member access currently issues a warning',
2277 )
2278 def test_exception_for_member_from_member_access(self):
2279 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
2280 class Di(Enum):
2281 YES = 1
2282 NO = 0
2283 nope = Di.YES.NO
2284
Ethan Furmanefb13be2020-12-10 12:20:06 -08002285 def test_strenum_auto(self):
2286 class Strings(StrEnum):
2287 ONE = auto()
2288 TWO = auto()
2289 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2290
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002291
Ethan Furmana6582872020-12-10 13:07:00 -08002292 def test_dynamic_members_with_static_methods(self):
2293 #
2294 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2295 class Foo(Enum):
2296 vars().update({
2297 k: v
2298 for k, v in foo_defines.items()
2299 if k.startswith('FOO_')
2300 })
2301 def upper(self):
2302 return self.value.upper()
2303 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2304 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2305 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2306 #
2307 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2308 class FooBar(Enum):
2309 vars().update({
2310 k: v
2311 for k, v in foo_defines.items()
2312 if k.startswith('FOO_')
2313 },
2314 **{'FOO_CAT': 'small'},
2315 )
2316 def upper(self):
2317 return self.value.upper()
2318
2319
Ethan Furmane8e61272016-08-20 07:19:31 -07002320class TestOrder(unittest.TestCase):
2321
2322 def test_same_members(self):
2323 class Color(Enum):
2324 _order_ = 'red green blue'
2325 red = 1
2326 green = 2
2327 blue = 3
2328
2329 def test_same_members_with_aliases(self):
2330 class Color(Enum):
2331 _order_ = 'red green blue'
2332 red = 1
2333 green = 2
2334 blue = 3
2335 verde = green
2336
2337 def test_same_members_wrong_order(self):
2338 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2339 class Color(Enum):
2340 _order_ = 'red green blue'
2341 red = 1
2342 blue = 3
2343 green = 2
2344
2345 def test_order_has_extra_members(self):
2346 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2347 class Color(Enum):
2348 _order_ = 'red green blue purple'
2349 red = 1
2350 green = 2
2351 blue = 3
2352
2353 def test_order_has_extra_members_with_aliases(self):
2354 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2355 class Color(Enum):
2356 _order_ = 'red green blue purple'
2357 red = 1
2358 green = 2
2359 blue = 3
2360 verde = green
2361
2362 def test_enum_has_extra_members(self):
2363 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2364 class Color(Enum):
2365 _order_ = 'red green blue'
2366 red = 1
2367 green = 2
2368 blue = 3
2369 purple = 4
2370
2371 def test_enum_has_extra_members_with_aliases(self):
2372 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2373 class Color(Enum):
2374 _order_ = 'red green blue'
2375 red = 1
2376 green = 2
2377 blue = 3
2378 purple = 4
2379 verde = green
2380
2381
Ethan Furman65a5a472016-09-01 23:55:19 -07002382class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383 """Tests of the Flags."""
2384
Ethan Furman65a5a472016-09-01 23:55:19 -07002385 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002386 R, W, X = 4, 2, 1
2387
Ethan Furman65a5a472016-09-01 23:55:19 -07002388 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002389 RO = 0
2390 WO = 1
2391 RW = 2
2392 AC = 3
2393 CE = 1<<19
2394
Rahul Jha94306522018-09-10 23:51:04 +05302395 class Color(Flag):
2396 BLACK = 0
2397 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002398 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302399 GREEN = 2
2400 BLUE = 4
2401 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002402 WHITE = RED|GREEN|BLUE
2403 BLANCO = RED|GREEN|BLUE
Rahul Jha94306522018-09-10 23:51:04 +05302404
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002405 def test_str(self):
2406 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002407 self.assertEqual(str(Perm.R), 'R')
2408 self.assertEqual(str(Perm.W), 'W')
2409 self.assertEqual(str(Perm.X), 'X')
2410 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2411 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002412 self.assertEqual(str(Perm(0)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002413 self.assertEqual(str(~Perm.R), 'W|X')
2414 self.assertEqual(str(~Perm.W), 'R|X')
2415 self.assertEqual(str(~Perm.X), 'R|W')
2416 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002417 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
Ethan Furmanb7751062021-03-30 21:17:26 -07002418 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002419
2420 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002421 self.assertEqual(str(Open.RO), 'RO')
2422 self.assertEqual(str(Open.WO), 'WO')
2423 self.assertEqual(str(Open.AC), 'AC')
2424 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2425 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
2426 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2427 self.assertEqual(str(~Open.WO), 'RW|CE')
2428 self.assertEqual(str(~Open.AC), 'CE')
2429 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2430 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002431
2432 def test_repr(self):
2433 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002434 self.assertEqual(repr(Perm.R), 'Perm.R')
2435 self.assertEqual(repr(Perm.W), 'Perm.W')
2436 self.assertEqual(repr(Perm.X), 'Perm.X')
2437 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2438 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
2439 self.assertEqual(repr(Perm(0)), '0x0')
2440 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2441 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2442 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2443 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2444 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
2445 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002446
2447 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002448 self.assertEqual(repr(Open.RO), 'Open.RO')
2449 self.assertEqual(repr(Open.WO), 'Open.WO')
2450 self.assertEqual(repr(Open.AC), 'Open.AC')
2451 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
2452 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
2453 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
2454 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
2455 self.assertEqual(repr(~Open.AC), 'Open.CE')
2456 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
2457 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002458
Ethan Furman37440ee2020-12-08 11:14:10 -08002459 def test_format(self):
2460 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002461 self.assertEqual(format(Perm.R, ''), 'R')
2462 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002463
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002464 def test_or(self):
2465 Perm = self.Perm
2466 for i in Perm:
2467 for j in Perm:
2468 self.assertEqual((i | j), Perm(i.value | j.value))
2469 self.assertEqual((i | j).value, i.value | j.value)
2470 self.assertIs(type(i | j), Perm)
2471 for i in Perm:
2472 self.assertIs(i | i, i)
2473 Open = self.Open
2474 self.assertIs(Open.RO | Open.CE, Open.CE)
2475
2476 def test_and(self):
2477 Perm = self.Perm
2478 RW = Perm.R | Perm.W
2479 RX = Perm.R | Perm.X
2480 WX = Perm.W | Perm.X
2481 RWX = Perm.R | Perm.W | Perm.X
2482 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2483 for i in values:
2484 for j in values:
2485 self.assertEqual((i & j).value, i.value & j.value)
2486 self.assertIs(type(i & j), Perm)
2487 for i in Perm:
2488 self.assertIs(i & i, i)
2489 self.assertIs(i & RWX, i)
2490 self.assertIs(RWX & i, i)
2491 Open = self.Open
2492 self.assertIs(Open.RO & Open.CE, Open.RO)
2493
2494 def test_xor(self):
2495 Perm = self.Perm
2496 for i in Perm:
2497 for j in Perm:
2498 self.assertEqual((i ^ j).value, i.value ^ j.value)
2499 self.assertIs(type(i ^ j), Perm)
2500 for i in Perm:
2501 self.assertIs(i ^ Perm(0), i)
2502 self.assertIs(Perm(0) ^ i, i)
2503 Open = self.Open
2504 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2505 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2506
2507 def test_invert(self):
2508 Perm = self.Perm
2509 RW = Perm.R | Perm.W
2510 RX = Perm.R | Perm.X
2511 WX = Perm.W | Perm.X
2512 RWX = Perm.R | Perm.W | Perm.X
2513 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2514 for i in values:
2515 self.assertIs(type(~i), Perm)
2516 self.assertEqual(~~i, i)
2517 for i in Perm:
2518 self.assertIs(~~i, i)
2519 Open = self.Open
2520 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2521 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2522
Ethan Furman25d94bb2016-09-02 16:32:32 -07002523 def test_bool(self):
2524 Perm = self.Perm
2525 for f in Perm:
2526 self.assertTrue(f)
2527 Open = self.Open
2528 for f in Open:
2529 self.assertEqual(bool(f.value), bool(f))
2530
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002531 def test_boundary(self):
2532 self.assertIs(enum.Flag._boundary_, STRICT)
2533 class Iron(Flag, boundary=STRICT):
2534 ONE = 1
2535 TWO = 2
2536 EIGHT = 8
2537 self.assertIs(Iron._boundary_, STRICT)
2538 #
2539 class Water(Flag, boundary=CONFORM):
2540 ONE = 1
2541 TWO = 2
2542 EIGHT = 8
2543 self.assertIs(Water._boundary_, CONFORM)
2544 #
2545 class Space(Flag, boundary=EJECT):
2546 ONE = 1
2547 TWO = 2
2548 EIGHT = 8
2549 self.assertIs(Space._boundary_, EJECT)
2550 #
2551 class Bizarre(Flag, boundary=KEEP):
2552 b = 3
2553 c = 4
2554 d = 6
2555 #
2556 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
Ethan Furmana02cb472021-04-21 10:20:44 -07002557 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002558 self.assertIs(Water(7), Water.ONE|Water.TWO)
2559 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07002560 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002561 self.assertEqual(Space(7), 7)
2562 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07002563 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002564 self.assertEqual(list(Bizarre), [Bizarre.c])
2565 self.assertIs(Bizarre(3), Bizarre.b)
2566 self.assertIs(Bizarre(6), Bizarre.d)
2567
2568 def test_iter(self):
2569 Color = self.Color
2570 Open = self.Open
2571 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
2572 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
2573
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002574 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002575 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002576 lst = list(Perm)
2577 self.assertEqual(len(lst), len(Perm))
2578 self.assertEqual(len(Perm), 3, Perm)
2579 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2580 for i, n in enumerate('R W X'.split()):
2581 v = 1<<i
2582 e = Perm(v)
2583 self.assertEqual(e.value, v)
2584 self.assertEqual(type(e.value), int)
2585 self.assertEqual(e.name, n)
2586 self.assertIn(e, Perm)
2587 self.assertIs(type(e), Perm)
2588
2589 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002590 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002591 lst = list(Perm)
2592 self.assertEqual(len(lst), len(Perm))
2593 self.assertEqual(len(Perm), 3, Perm)
2594 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2595 for i, n in enumerate('R W X'.split()):
2596 v = 8<<i
2597 e = Perm(v)
2598 self.assertEqual(e.value, v)
2599 self.assertEqual(type(e.value), int)
2600 self.assertEqual(e.name, n)
2601 self.assertIn(e, Perm)
2602 self.assertIs(type(e), Perm)
2603
2604 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002605 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002606 lst = list(Perm)
2607 self.assertEqual(len(lst), len(Perm))
2608 self.assertEqual(len(Perm), 3, Perm)
2609 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2610 for i, n in enumerate('R W X'.split()):
2611 v = 1<<i
2612 e = Perm(v)
2613 self.assertEqual(e.value, v)
2614 self.assertEqual(type(e.value), int)
2615 self.assertEqual(e.name, n)
2616 self.assertIn(e, Perm)
2617 self.assertIs(type(e), Perm)
2618
2619 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002620 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002621 lst = list(Perm)
2622 self.assertEqual(len(lst), len(Perm))
2623 self.assertEqual(len(Perm), 3, Perm)
2624 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2625 for i, n in enumerate('R W X'.split()):
2626 v = 1<<(2*i+1)
2627 e = Perm(v)
2628 self.assertEqual(e.value, v)
2629 self.assertEqual(type(e.value), int)
2630 self.assertEqual(e.name, n)
2631 self.assertIn(e, Perm)
2632 self.assertIs(type(e), Perm)
2633
2634 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002635 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002636 lst = list(Perm)
2637 self.assertEqual(len(lst), len(Perm))
2638 self.assertEqual(len(Perm), 3, Perm)
2639 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2640 for i, n in enumerate('R W X'.split()):
2641 v = 1<<(2*i+1)
2642 e = Perm(v)
2643 self.assertEqual(e.value, v)
2644 self.assertEqual(type(e.value), int)
2645 self.assertEqual(e.name, n)
2646 self.assertIn(e, Perm)
2647 self.assertIs(type(e), Perm)
2648
Ethan Furman65a5a472016-09-01 23:55:19 -07002649 def test_pickle(self):
2650 if isinstance(FlagStooges, Exception):
2651 raise FlagStooges
2652 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2653 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002654
Ethan Furman6bd92882021-04-27 13:05:08 -07002655 @unittest.skipIf(
2656 python_version >= (3, 12),
2657 '__contains__ now returns True/False for all inputs',
2658 )
2659 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05302660 Open = self.Open
2661 Color = self.Color
2662 self.assertFalse(Color.BLACK in Open)
2663 self.assertFalse(Open.RO in Color)
2664 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002665 with self.assertWarns(DeprecationWarning):
2666 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302667 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002668 with self.assertWarns(DeprecationWarning):
2669 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302670 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002671 with self.assertWarns(DeprecationWarning):
2672 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302673 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07002674 with self.assertWarns(DeprecationWarning):
2675 1 in Open
2676
2677 @unittest.skipIf(
2678 python_version < (3, 12),
2679 '__contains__ only works with enum memmbers before 3.12',
2680 )
2681 def test_contains_tf(self):
2682 Open = self.Open
2683 Color = self.Color
2684 self.assertFalse(Color.BLACK in Open)
2685 self.assertFalse(Open.RO in Color)
2686 self.assertFalse('BLACK' in Color)
2687 self.assertFalse('RO' in Open)
2688 self.assertTrue(1 in Color)
2689 self.assertTrue(1 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05302690
2691 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002692 Perm = self.Perm
2693 R, W, X = Perm
2694 RW = R | W
2695 RX = R | X
2696 WX = W | X
2697 RWX = R | W | X
2698 self.assertTrue(R in RW)
2699 self.assertTrue(R in RX)
2700 self.assertTrue(R in RWX)
2701 self.assertTrue(W in RW)
2702 self.assertTrue(W in WX)
2703 self.assertTrue(W in RWX)
2704 self.assertTrue(X in RX)
2705 self.assertTrue(X in WX)
2706 self.assertTrue(X in RWX)
2707 self.assertFalse(R in WX)
2708 self.assertFalse(W in RX)
2709 self.assertFalse(X in RW)
2710
Ethan Furman7219e272020-09-16 13:01:00 -07002711 def test_member_iter(self):
2712 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002713 self.assertEqual(list(Color.BLACK), [])
2714 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07002715 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2716 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002717 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2718 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
2719
2720 def test_member_length(self):
2721 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
2722 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
2723 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
2724 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
2725
2726 def test_number_reset_and_order_cleanup(self):
2727 class Confused(Flag):
2728 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
2729 ONE = auto()
2730 TWO = auto()
2731 FOUR = auto()
2732 DOS = 2
2733 EIGHT = auto()
2734 SIXTEEN = auto()
2735 self.assertEqual(
2736 list(Confused),
2737 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
2738 self.assertIs(Confused.TWO, Confused.DOS)
2739 self.assertEqual(Confused.DOS._value_, 2)
2740 self.assertEqual(Confused.EIGHT._value_, 8)
2741 self.assertEqual(Confused.SIXTEEN._value_, 16)
2742
2743 def test_aliases(self):
2744 Color = self.Color
2745 self.assertEqual(Color(1).name, 'RED')
2746 self.assertEqual(Color['ROJO'].name, 'RED')
2747 self.assertEqual(Color(7).name, 'WHITE')
2748 self.assertEqual(Color['BLANCO'].name, 'WHITE')
2749 self.assertIs(Color.BLANCO, Color.WHITE)
2750 Open = self.Open
2751 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07002752
Ethan Furmanc16595e2016-09-10 23:36:59 -07002753 def test_auto_number(self):
2754 class Color(Flag):
2755 red = auto()
2756 blue = auto()
2757 green = auto()
2758
2759 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2760 self.assertEqual(Color.red.value, 1)
2761 self.assertEqual(Color.blue.value, 2)
2762 self.assertEqual(Color.green.value, 4)
2763
2764 def test_auto_number_garbage(self):
2765 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2766 class Color(Flag):
2767 red = 'not an int'
2768 blue = auto()
2769
Ethan Furman3515dcc2016-09-18 13:15:41 -07002770 def test_duplicate_auto(self):
2771 class Dupes(Enum):
2772 first = primero = auto()
2773 second = auto()
2774 third = auto()
2775 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2776
2777 def test_bizarre(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002778 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
2779 class Bizarre(Flag):
2780 b = 3
2781 c = 4
2782 d = 6
Ethan Furman3515dcc2016-09-18 13:15:41 -07002783
Ethan Furman5bdab642018-09-21 19:03:09 -07002784 def test_multiple_mixin(self):
2785 class AllMixin:
2786 @classproperty
2787 def ALL(cls):
2788 members = list(cls)
2789 all_value = None
2790 if members:
2791 all_value = members[0]
2792 for member in members[1:]:
2793 all_value |= member
2794 cls.ALL = all_value
2795 return all_value
2796 class StrMixin:
2797 def __str__(self):
2798 return self._name_.lower()
2799 class Color(AllMixin, Flag):
2800 RED = auto()
2801 GREEN = auto()
2802 BLUE = auto()
2803 self.assertEqual(Color.RED.value, 1)
2804 self.assertEqual(Color.GREEN.value, 2)
2805 self.assertEqual(Color.BLUE.value, 4)
2806 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07002807 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002808 class Color(AllMixin, StrMixin, Flag):
2809 RED = auto()
2810 GREEN = auto()
2811 BLUE = auto()
2812 self.assertEqual(Color.RED.value, 1)
2813 self.assertEqual(Color.GREEN.value, 2)
2814 self.assertEqual(Color.BLUE.value, 4)
2815 self.assertEqual(Color.ALL.value, 7)
2816 self.assertEqual(str(Color.BLUE), 'blue')
2817 class Color(StrMixin, AllMixin, Flag):
2818 RED = auto()
2819 GREEN = auto()
2820 BLUE = auto()
2821 self.assertEqual(Color.RED.value, 1)
2822 self.assertEqual(Color.GREEN.value, 2)
2823 self.assertEqual(Color.BLUE.value, 4)
2824 self.assertEqual(Color.ALL.value, 7)
2825 self.assertEqual(str(Color.BLUE), 'blue')
2826
Hai Shie80697d2020-05-28 06:10:27 +08002827 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002828 def test_unique_composite(self):
2829 # override __eq__ to be identity only
2830 class TestFlag(Flag):
2831 one = auto()
2832 two = auto()
2833 three = auto()
2834 four = auto()
2835 five = auto()
2836 six = auto()
2837 seven = auto()
2838 eight = auto()
2839 def __eq__(self, other):
2840 return self is other
2841 def __hash__(self):
2842 return hash(self._value_)
2843 # have multiple threads competing to complete the composite members
2844 seen = set()
2845 failed = False
2846 def cycle_enum():
2847 nonlocal failed
2848 try:
2849 for i in range(256):
2850 seen.add(TestFlag(i))
2851 except Exception:
2852 failed = True
2853 threads = [
2854 threading.Thread(target=cycle_enum)
2855 for _ in range(8)
2856 ]
Hai Shie80697d2020-05-28 06:10:27 +08002857 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002858 pass
2859 # check that only 248 members were created
2860 self.assertFalse(
2861 failed,
2862 'at least one thread failed while creating composite members')
2863 self.assertEqual(256, len(seen), 'too many composite members created')
2864
Ethan Furman6bd94de2020-12-09 16:41:22 -08002865 def test_init_subclass(self):
2866 class MyEnum(Flag):
2867 def __init_subclass__(cls, **kwds):
2868 super().__init_subclass__(**kwds)
2869 self.assertFalse(cls.__dict__.get('_test', False))
2870 cls._test1 = 'MyEnum'
2871 #
2872 class TheirEnum(MyEnum):
2873 def __init_subclass__(cls, **kwds):
2874 super(TheirEnum, cls).__init_subclass__(**kwds)
2875 cls._test2 = 'TheirEnum'
2876 class WhoseEnum(TheirEnum):
2877 def __init_subclass__(cls, **kwds):
2878 pass
2879 class NoEnum(WhoseEnum):
2880 ONE = 1
2881 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2882 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2883 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2884 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2885 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2886 #
2887 class OurEnum(MyEnum):
2888 def __init_subclass__(cls, **kwds):
2889 cls._test2 = 'OurEnum'
2890 class WhereEnum(OurEnum):
2891 def __init_subclass__(cls, **kwds):
2892 pass
2893 class NeverEnum(WhereEnum):
2894 ONE = 1
2895 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2896 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2897 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2898 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2899 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2900
Ethan Furmanc16595e2016-09-10 23:36:59 -07002901
Ethan Furman65a5a472016-09-01 23:55:19 -07002902class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002903 """Tests of the IntFlags."""
2904
Ethan Furman65a5a472016-09-01 23:55:19 -07002905 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002906 R = 1 << 2
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002907 W = 1 << 1
2908 X = 1 << 0
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002909
Ethan Furman65a5a472016-09-01 23:55:19 -07002910 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002911 RO = 0
2912 WO = 1
2913 RW = 2
2914 AC = 3
2915 CE = 1<<19
2916
Rahul Jha94306522018-09-10 23:51:04 +05302917 class Color(IntFlag):
2918 BLACK = 0
2919 RED = 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002920 ROJO = 1
Rahul Jha94306522018-09-10 23:51:04 +05302921 GREEN = 2
2922 BLUE = 4
2923 PURPLE = RED|BLUE
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002924 WHITE = RED|GREEN|BLUE
2925 BLANCO = RED|GREEN|BLUE
2926
2927 class Skip(IntFlag):
2928 FIRST = 1
2929 SECOND = 2
2930 EIGHTH = 8
Rahul Jha94306522018-09-10 23:51:04 +05302931
Ethan Furman3515dcc2016-09-18 13:15:41 -07002932 def test_type(self):
2933 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002934 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002935 Open = self.Open
2936 for f in Perm:
2937 self.assertTrue(isinstance(f, Perm))
2938 self.assertEqual(f, f.value)
2939 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2940 self.assertEqual(Perm.W | Perm.X, 3)
2941 for f in Open:
2942 self.assertTrue(isinstance(f, Open))
2943 self.assertEqual(f, f.value)
2944 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2945 self.assertEqual(Open.WO | Open.RW, 3)
2946
2947
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002948 def test_str(self):
2949 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002950 self.assertEqual(str(Perm.R), 'R')
2951 self.assertEqual(str(Perm.W), 'W')
2952 self.assertEqual(str(Perm.X), 'X')
2953 self.assertEqual(str(Perm.R | Perm.W), 'R|W')
2954 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002955 self.assertEqual(str(Perm.R | 8), '12')
2956 self.assertEqual(str(Perm(0)), 'Perm(0)')
2957 self.assertEqual(str(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002958 self.assertEqual(str(~Perm.R), 'W|X')
2959 self.assertEqual(str(~Perm.W), 'R|X')
2960 self.assertEqual(str(~Perm.X), 'R|W')
2961 self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002962 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
2963 self.assertEqual(str(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002964 self.assertEqual(str(Perm(~0)), 'R|W|X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002965 self.assertEqual(str(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002966
2967 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07002968 self.assertEqual(str(Open.RO), 'RO')
2969 self.assertEqual(str(Open.WO), 'WO')
2970 self.assertEqual(str(Open.AC), 'AC')
2971 self.assertEqual(str(Open.RO | Open.CE), 'CE')
2972 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002973 self.assertEqual(str(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07002974 self.assertEqual(str(~Open.RO), 'WO|RW|CE')
2975 self.assertEqual(str(~Open.WO), 'RW|CE')
2976 self.assertEqual(str(~Open.AC), 'CE')
2977 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
2978 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002979 self.assertEqual(str(Open(~4)), '-5')
2980
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002981 def test_repr(self):
2982 Perm = self.Perm
Ethan Furmanb7751062021-03-30 21:17:26 -07002983 self.assertEqual(repr(Perm.R), 'Perm.R')
2984 self.assertEqual(repr(Perm.W), 'Perm.W')
2985 self.assertEqual(repr(Perm.X), 'Perm.X')
2986 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
2987 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002988 self.assertEqual(repr(Perm.R | 8), '12')
Ethan Furmanb7751062021-03-30 21:17:26 -07002989 self.assertEqual(repr(Perm(0)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002990 self.assertEqual(repr(Perm(8)), '8')
Ethan Furmanb7751062021-03-30 21:17:26 -07002991 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
2992 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
2993 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
2994 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
2995 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002996 self.assertEqual(repr(~(Perm.R | 8)), '-13')
Ethan Furmanb7751062021-03-30 21:17:26 -07002997 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002998 self.assertEqual(repr(Perm(~8)), '-9')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002999
3000 Open = self.Open
Ethan Furmanb7751062021-03-30 21:17:26 -07003001 self.assertEqual(repr(Open.RO), 'Open.RO')
3002 self.assertEqual(repr(Open.WO), 'Open.WO')
3003 self.assertEqual(repr(Open.AC), 'Open.AC')
3004 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
3005 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003006 self.assertEqual(repr(Open(4)), '4')
Ethan Furmanb7751062021-03-30 21:17:26 -07003007 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
3008 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
3009 self.assertEqual(repr(~Open.AC), 'Open.CE')
3010 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
3011 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003012 self.assertEqual(repr(Open(~4)), '-5')
3013
Ethan Furman6bd92882021-04-27 13:05:08 -07003014 @unittest.skipUnless(
3015 python_version < (3, 12),
3016 'mixin-format now uses member instead of member.value',
3017 )
Ethan Furman37440ee2020-12-08 11:14:10 -08003018 def test_format(self):
Ethan Furman6bd92882021-04-27 13:05:08 -07003019 with self.assertWarns(DeprecationWarning):
3020 Perm = self.Perm
3021 self.assertEqual(format(Perm.R, ''), '4')
3022 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08003023
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003024 def test_or(self):
3025 Perm = self.Perm
3026 for i in Perm:
3027 for j in Perm:
3028 self.assertEqual(i | j, i.value | j.value)
3029 self.assertEqual((i | j).value, i.value | j.value)
3030 self.assertIs(type(i | j), Perm)
3031 for j in range(8):
3032 self.assertEqual(i | j, i.value | j)
3033 self.assertEqual((i | j).value, i.value | j)
3034 self.assertIs(type(i | j), Perm)
3035 self.assertEqual(j | i, j | i.value)
3036 self.assertEqual((j | i).value, j | i.value)
3037 self.assertIs(type(j | i), Perm)
3038 for i in Perm:
3039 self.assertIs(i | i, i)
3040 self.assertIs(i | 0, i)
3041 self.assertIs(0 | i, i)
3042 Open = self.Open
3043 self.assertIs(Open.RO | Open.CE, Open.CE)
3044
3045 def test_and(self):
3046 Perm = self.Perm
3047 RW = Perm.R | Perm.W
3048 RX = Perm.R | Perm.X
3049 WX = Perm.W | Perm.X
3050 RWX = Perm.R | Perm.W | Perm.X
3051 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3052 for i in values:
3053 for j in values:
3054 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
3055 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
3056 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
3057 for j in range(8):
3058 self.assertEqual(i & j, i.value & j)
3059 self.assertEqual((i & j).value, i.value & j)
3060 self.assertIs(type(i & j), Perm)
3061 self.assertEqual(j & i, j & i.value)
3062 self.assertEqual((j & i).value, j & i.value)
3063 self.assertIs(type(j & i), Perm)
3064 for i in Perm:
3065 self.assertIs(i & i, i)
3066 self.assertIs(i & 7, i)
3067 self.assertIs(7 & i, i)
3068 Open = self.Open
3069 self.assertIs(Open.RO & Open.CE, Open.RO)
3070
3071 def test_xor(self):
3072 Perm = self.Perm
3073 for i in Perm:
3074 for j in Perm:
3075 self.assertEqual(i ^ j, i.value ^ j.value)
3076 self.assertEqual((i ^ j).value, i.value ^ j.value)
3077 self.assertIs(type(i ^ j), Perm)
3078 for j in range(8):
3079 self.assertEqual(i ^ j, i.value ^ j)
3080 self.assertEqual((i ^ j).value, i.value ^ j)
3081 self.assertIs(type(i ^ j), Perm)
3082 self.assertEqual(j ^ i, j ^ i.value)
3083 self.assertEqual((j ^ i).value, j ^ i.value)
3084 self.assertIs(type(j ^ i), Perm)
3085 for i in Perm:
3086 self.assertIs(i ^ 0, i)
3087 self.assertIs(0 ^ i, i)
3088 Open = self.Open
3089 self.assertIs(Open.RO ^ Open.CE, Open.CE)
3090 self.assertIs(Open.CE ^ Open.CE, Open.RO)
3091
3092 def test_invert(self):
3093 Perm = self.Perm
3094 RW = Perm.R | Perm.W
3095 RX = Perm.R | Perm.X
3096 WX = Perm.W | Perm.X
3097 RWX = Perm.R | Perm.W | Perm.X
3098 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
3099 for i in values:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003100 self.assertEqual(~i, (~i).value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003101 self.assertIs(type(~i), Perm)
3102 self.assertEqual(~~i, i)
3103 for i in Perm:
3104 self.assertIs(~~i, i)
3105 Open = self.Open
3106 self.assertIs(Open.WO & ~Open.WO, Open.RO)
3107 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3108
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003109 def test_boundary(self):
3110 self.assertIs(enum.IntFlag._boundary_, EJECT)
3111 class Iron(IntFlag, boundary=STRICT):
3112 ONE = 1
3113 TWO = 2
3114 EIGHT = 8
3115 self.assertIs(Iron._boundary_, STRICT)
3116 #
3117 class Water(IntFlag, boundary=CONFORM):
3118 ONE = 1
3119 TWO = 2
3120 EIGHT = 8
3121 self.assertIs(Water._boundary_, CONFORM)
3122 #
3123 class Space(IntFlag, boundary=EJECT):
3124 ONE = 1
3125 TWO = 2
3126 EIGHT = 8
3127 self.assertIs(Space._boundary_, EJECT)
3128 #
Ethan Furmana02cb472021-04-21 10:20:44 -07003129 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003130 class Bizarre(IntFlag, boundary=KEEP):
3131 b = 3
3132 c = 4
3133 d = 6
3134 #
3135 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
Ethan Furmana02cb472021-04-21 10:20:44 -07003136 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003137 self.assertIs(Water(7), Water.ONE|Water.TWO)
3138 self.assertIs(Water(~9), Water.TWO)
Ethan Furmana02cb472021-04-21 10:20:44 -07003139 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003140 self.assertEqual(Space(7), 7)
3141 self.assertTrue(type(Space(7)) is int)
Ethan Furmana02cb472021-04-21 10:20:44 -07003142 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003143 self.assertEqual(list(Bizarre), [Bizarre.c])
3144 self.assertIs(Bizarre(3), Bizarre.b)
3145 self.assertIs(Bizarre(6), Bizarre.d)
3146
3147 def test_iter(self):
3148 Color = self.Color
3149 Open = self.Open
3150 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
3151 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
3152
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003153 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003154 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003155 lst = list(Perm)
3156 self.assertEqual(len(lst), len(Perm))
3157 self.assertEqual(len(Perm), 3, Perm)
3158 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3159 for i, n in enumerate('R W X'.split()):
3160 v = 1<<i
3161 e = Perm(v)
3162 self.assertEqual(e.value, v)
3163 self.assertEqual(type(e.value), int)
3164 self.assertEqual(e, v)
3165 self.assertEqual(e.name, n)
3166 self.assertIn(e, Perm)
3167 self.assertIs(type(e), Perm)
3168
3169 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003170 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003171 lst = list(Perm)
3172 self.assertEqual(len(lst), len(Perm))
3173 self.assertEqual(len(Perm), 3, Perm)
3174 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3175 for i, n in enumerate('R W X'.split()):
3176 v = 8<<i
3177 e = Perm(v)
3178 self.assertEqual(e.value, v)
3179 self.assertEqual(type(e.value), int)
3180 self.assertEqual(e, v)
3181 self.assertEqual(e.name, n)
3182 self.assertIn(e, Perm)
3183 self.assertIs(type(e), Perm)
3184
3185 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003186 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003187 lst = list(Perm)
3188 self.assertEqual(len(lst), len(Perm))
3189 self.assertEqual(len(Perm), 3, Perm)
3190 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3191 for i, n in enumerate('R W X'.split()):
3192 v = 1<<i
3193 e = Perm(v)
3194 self.assertEqual(e.value, v)
3195 self.assertEqual(type(e.value), int)
3196 self.assertEqual(e, v)
3197 self.assertEqual(e.name, n)
3198 self.assertIn(e, Perm)
3199 self.assertIs(type(e), Perm)
3200
3201 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003202 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003203 lst = list(Perm)
3204 self.assertEqual(len(lst), len(Perm))
3205 self.assertEqual(len(Perm), 3, Perm)
3206 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3207 for i, n in enumerate('R W X'.split()):
3208 v = 1<<(2*i+1)
3209 e = Perm(v)
3210 self.assertEqual(e.value, v)
3211 self.assertEqual(type(e.value), int)
3212 self.assertEqual(e, v)
3213 self.assertEqual(e.name, n)
3214 self.assertIn(e, Perm)
3215 self.assertIs(type(e), Perm)
3216
3217 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003218 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07003219 lst = list(Perm)
3220 self.assertEqual(len(lst), len(Perm))
3221 self.assertEqual(len(Perm), 3, Perm)
3222 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
3223 for i, n in enumerate('R W X'.split()):
3224 v = 1<<(2*i+1)
3225 e = Perm(v)
3226 self.assertEqual(e.value, v)
3227 self.assertEqual(type(e.value), int)
3228 self.assertEqual(e, v)
3229 self.assertEqual(e.name, n)
3230 self.assertIn(e, Perm)
3231 self.assertIs(type(e), Perm)
3232
3233
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09003234 def test_programatic_function_from_empty_list(self):
3235 Perm = enum.IntFlag('Perm', [])
3236 lst = list(Perm)
3237 self.assertEqual(len(lst), len(Perm))
3238 self.assertEqual(len(Perm), 0, Perm)
3239 Thing = enum.Enum('Thing', [])
3240 lst = list(Thing)
3241 self.assertEqual(len(lst), len(Thing))
3242 self.assertEqual(len(Thing), 0, Thing)
3243
3244
3245 def test_programatic_function_from_empty_tuple(self):
3246 Perm = enum.IntFlag('Perm', ())
3247 lst = list(Perm)
3248 self.assertEqual(len(lst), len(Perm))
3249 self.assertEqual(len(Perm), 0, Perm)
3250 Thing = enum.Enum('Thing', ())
3251 self.assertEqual(len(lst), len(Thing))
3252 self.assertEqual(len(Thing), 0, Thing)
3253
Ethan Furman6bd92882021-04-27 13:05:08 -07003254 @unittest.skipIf(
3255 python_version >= (3, 12),
3256 '__contains__ now returns True/False for all inputs',
3257 )
3258 def test_contains_er(self):
Rahul Jha94306522018-09-10 23:51:04 +05303259 Open = self.Open
3260 Color = self.Color
3261 self.assertTrue(Color.GREEN in Color)
3262 self.assertTrue(Open.RW in Open)
3263 self.assertFalse(Color.GREEN in Open)
3264 self.assertFalse(Open.RW in Color)
3265 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003266 with self.assertWarns(DeprecationWarning):
3267 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05303268 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003269 with self.assertWarns(DeprecationWarning):
3270 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05303271 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003272 with self.assertWarns(DeprecationWarning):
3273 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05303274 with self.assertRaises(TypeError):
Ethan Furman6bd92882021-04-27 13:05:08 -07003275 with self.assertWarns(DeprecationWarning):
3276 2 in Open
3277
3278 @unittest.skipIf(
3279 python_version < (3, 12),
3280 '__contains__ only works with enum memmbers before 3.12',
3281 )
3282 def test_contains_tf(self):
3283 Open = self.Open
3284 Color = self.Color
3285 self.assertTrue(Color.GREEN in Color)
3286 self.assertTrue(Open.RW in Open)
3287 self.assertTrue(Color.GREEN in Open)
3288 self.assertTrue(Open.RW in Color)
3289 self.assertFalse('GREEN' in Color)
3290 self.assertFalse('RW' in Open)
3291 self.assertTrue(2 in Color)
3292 self.assertTrue(2 in Open)
Rahul Jha94306522018-09-10 23:51:04 +05303293
3294 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003295 Perm = self.Perm
3296 R, W, X = Perm
3297 RW = R | W
3298 RX = R | X
3299 WX = W | X
3300 RWX = R | W | X
3301 self.assertTrue(R in RW)
3302 self.assertTrue(R in RX)
3303 self.assertTrue(R in RWX)
3304 self.assertTrue(W in RW)
3305 self.assertTrue(W in WX)
3306 self.assertTrue(W in RWX)
3307 self.assertTrue(X in RX)
3308 self.assertTrue(X in WX)
3309 self.assertTrue(X in RWX)
3310 self.assertFalse(R in WX)
3311 self.assertFalse(W in RX)
3312 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303313 with self.assertRaises(TypeError):
3314 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003315
Ethan Furman7219e272020-09-16 13:01:00 -07003316 def test_member_iter(self):
3317 Color = self.Color
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003318 self.assertEqual(list(Color.BLACK), [])
3319 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
Ethan Furman7219e272020-09-16 13:01:00 -07003320 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3321 self.assertEqual(list(Color.GREEN), [Color.GREEN])
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003322 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
3323
3324 def test_member_length(self):
3325 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
3326 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
3327 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
3328 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
3329
3330 def test_aliases(self):
3331 Color = self.Color
3332 self.assertEqual(Color(1).name, 'RED')
3333 self.assertEqual(Color['ROJO'].name, 'RED')
3334 self.assertEqual(Color(7).name, 'WHITE')
3335 self.assertEqual(Color['BLANCO'].name, 'WHITE')
3336 self.assertIs(Color.BLANCO, Color.WHITE)
3337 Open = self.Open
3338 self.assertIs(Open['AC'], Open.AC)
Ethan Furman7219e272020-09-16 13:01:00 -07003339
Ethan Furman25d94bb2016-09-02 16:32:32 -07003340 def test_bool(self):
3341 Perm = self.Perm
3342 for f in Perm:
3343 self.assertTrue(f)
3344 Open = self.Open
3345 for f in Open:
3346 self.assertEqual(bool(f.value), bool(f))
3347
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003348 def test_bizarre(self):
3349 with self.assertRaisesRegex(TypeError, "invalid Flag 'Bizarre' -- missing values: 1, 2"):
3350 class Bizarre(IntFlag):
3351 b = 3
3352 c = 4
3353 d = 6
3354
Ethan Furman5bdab642018-09-21 19:03:09 -07003355 def test_multiple_mixin(self):
3356 class AllMixin:
3357 @classproperty
3358 def ALL(cls):
3359 members = list(cls)
3360 all_value = None
3361 if members:
3362 all_value = members[0]
3363 for member in members[1:]:
3364 all_value |= member
3365 cls.ALL = all_value
3366 return all_value
3367 class StrMixin:
3368 def __str__(self):
3369 return self._name_.lower()
3370 class Color(AllMixin, IntFlag):
3371 RED = auto()
3372 GREEN = auto()
3373 BLUE = auto()
3374 self.assertEqual(Color.RED.value, 1)
3375 self.assertEqual(Color.GREEN.value, 2)
3376 self.assertEqual(Color.BLUE.value, 4)
3377 self.assertEqual(Color.ALL.value, 7)
Ethan Furmanb7751062021-03-30 21:17:26 -07003378 self.assertEqual(str(Color.BLUE), 'BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07003379 class Color(AllMixin, StrMixin, IntFlag):
3380 RED = auto()
3381 GREEN = auto()
3382 BLUE = auto()
3383 self.assertEqual(Color.RED.value, 1)
3384 self.assertEqual(Color.GREEN.value, 2)
3385 self.assertEqual(Color.BLUE.value, 4)
3386 self.assertEqual(Color.ALL.value, 7)
3387 self.assertEqual(str(Color.BLUE), 'blue')
3388 class Color(StrMixin, AllMixin, IntFlag):
3389 RED = auto()
3390 GREEN = auto()
3391 BLUE = auto()
3392 self.assertEqual(Color.RED.value, 1)
3393 self.assertEqual(Color.GREEN.value, 2)
3394 self.assertEqual(Color.BLUE.value, 4)
3395 self.assertEqual(Color.ALL.value, 7)
3396 self.assertEqual(str(Color.BLUE), 'blue')
3397
Hai Shie80697d2020-05-28 06:10:27 +08003398 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003399 def test_unique_composite(self):
3400 # override __eq__ to be identity only
3401 class TestFlag(IntFlag):
3402 one = auto()
3403 two = auto()
3404 three = auto()
3405 four = auto()
3406 five = auto()
3407 six = auto()
3408 seven = auto()
3409 eight = auto()
3410 def __eq__(self, other):
3411 return self is other
3412 def __hash__(self):
3413 return hash(self._value_)
3414 # have multiple threads competing to complete the composite members
3415 seen = set()
3416 failed = False
3417 def cycle_enum():
3418 nonlocal failed
3419 try:
3420 for i in range(256):
3421 seen.add(TestFlag(i))
3422 except Exception:
3423 failed = True
3424 threads = [
3425 threading.Thread(target=cycle_enum)
3426 for _ in range(8)
3427 ]
Hai Shie80697d2020-05-28 06:10:27 +08003428 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003429 pass
3430 # check that only 248 members were created
3431 self.assertFalse(
3432 failed,
3433 'at least one thread failed while creating composite members')
3434 self.assertEqual(256, len(seen), 'too many composite members created')
3435
3436
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003437class TestEmptyAndNonLatinStrings(unittest.TestCase):
3438
3439 def test_empty_string(self):
3440 with self.assertRaises(ValueError):
3441 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3442
3443 def test_non_latin_character_string(self):
3444 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3445 item = getattr(greek_abc, '\u03B1')
3446 self.assertEqual(item.value, 1)
3447
3448 def test_non_latin_number_string(self):
3449 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3450 item = getattr(hebrew_123, '\u05D0')
3451 self.assertEqual(item.value, 1)
3452
3453
Ethan Furmanf24bb352013-07-18 17:05:39 -07003454class TestUnique(unittest.TestCase):
3455
3456 def test_unique_clean(self):
3457 @unique
3458 class Clean(Enum):
3459 one = 1
3460 two = 'dos'
3461 tres = 4.0
3462 @unique
3463 class Cleaner(IntEnum):
3464 single = 1
3465 double = 2
3466 triple = 3
3467
3468 def test_unique_dirty(self):
3469 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3470 @unique
3471 class Dirty(Enum):
3472 one = 1
3473 two = 'dos'
3474 tres = 1
3475 with self.assertRaisesRegex(
3476 ValueError,
3477 'double.*single.*turkey.*triple',
3478 ):
3479 @unique
3480 class Dirtier(IntEnum):
3481 single = 1
3482 double = 1
3483 triple = 3
3484 turkey = 3
3485
Ethan Furman3803ad42016-05-01 10:03:53 -07003486 def test_unique_with_name(self):
3487 @unique
3488 class Silly(Enum):
3489 one = 1
3490 two = 'dos'
3491 name = 3
3492 @unique
3493 class Sillier(IntEnum):
3494 single = 1
3495 name = 2
3496 triple = 3
3497 value = 4
3498
Ethan Furmanec099732021-04-15 06:58:33 -07003499class TestHelpers(unittest.TestCase):
3500
3501 sunder_names = '_bad_', '_good_', '_what_ho_'
3502 dunder_names = '__mal__', '__bien__', '__que_que__'
3503 private_names = '_MyEnum__private', '_MyEnum__still_private'
3504 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
3505 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
3506
3507 def test_sunder(self):
3508 for name in self.sunder_names + self.private_and_sunder_names:
3509 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
3510 for name in self.dunder_names + self.private_names + self.random_names:
3511 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
3512
3513 def test_dunder(self):
3514 for name in self.dunder_names:
3515 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
3516 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
3517 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
3518
3519 def test_is_private(self):
3520 for name in self.private_names + self.private_and_sunder_names:
3521 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
3522 for name in self.sunder_names + self.dunder_names + self.random_names:
3523 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
Ethan Furmanf24bb352013-07-18 17:05:39 -07003524
Ethan Furmanb7751062021-03-30 21:17:26 -07003525class TestEnumTypeSubclassing(unittest.TestCase):
3526 pass
Ethan Furman5bdab642018-09-21 19:03:09 -07003527
Ethan Furman3323da92015-04-11 09:39:59 -07003528expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003529Help on class Color in module %s:
3530
3531class Color(enum.Enum)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003532 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003533 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003534 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003535 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003536 | Method resolution order:
3537 | Color
3538 | enum.Enum
3539 | builtins.object
3540 |\x20\x20
3541 | Data and other attributes defined here:
3542 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003543 | blue = Color.blue
Ethan Furman5875d742013-10-21 20:45:55 -07003544 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003545 | green = Color.green
Ethan Furman5875d742013-10-21 20:45:55 -07003546 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003547 | red = Color.red
Ethan Furman5875d742013-10-21 20:45:55 -07003548 |\x20\x20
3549 | ----------------------------------------------------------------------
3550 | Data descriptors inherited from enum.Enum:
3551 |\x20\x20
3552 | name
3553 | The name of the Enum member.
3554 |\x20\x20
3555 | value
3556 | The value of the Enum member.
3557 |\x20\x20
3558 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003559 | Readonly properties inherited from enum.EnumType:
Ethan Furman5875d742013-10-21 20:45:55 -07003560 |\x20\x20
3561 | __members__
3562 | Returns a mapping of member name->value.
3563 |\x20\x20\x20\x20\x20\x20
3564 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003565 | is a read-only view of the internal mapping."""
3566
3567expected_help_output_without_docs = """\
3568Help on class Color in module %s:
3569
3570class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003571 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3572 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003573 | Method resolution order:
3574 | Color
3575 | enum.Enum
3576 | builtins.object
3577 |\x20\x20
3578 | Data and other attributes defined here:
3579 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003580 | blue = Color.blue
Ethan Furman3323da92015-04-11 09:39:59 -07003581 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003582 | green = Color.green
Ethan Furman3323da92015-04-11 09:39:59 -07003583 |\x20\x20
Ethan Furmanb7751062021-03-30 21:17:26 -07003584 | red = Color.red
Ethan Furman3323da92015-04-11 09:39:59 -07003585 |\x20\x20
3586 | ----------------------------------------------------------------------
3587 | Data descriptors inherited from enum.Enum:
3588 |\x20\x20
3589 | name
3590 |\x20\x20
3591 | value
3592 |\x20\x20
3593 | ----------------------------------------------------------------------
Ethan Furmanb7751062021-03-30 21:17:26 -07003594 | Data descriptors inherited from enum.EnumType:
Ethan Furman3323da92015-04-11 09:39:59 -07003595 |\x20\x20
3596 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003597
3598class TestStdLib(unittest.TestCase):
3599
Ethan Furman48a724f2015-04-11 23:23:06 -07003600 maxDiff = None
3601
Ethan Furman5875d742013-10-21 20:45:55 -07003602 class Color(Enum):
3603 red = 1
3604 green = 2
3605 blue = 3
3606
3607 def test_pydoc(self):
3608 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003609 if StrEnum.__doc__ is None:
3610 expected_text = expected_help_output_without_docs % __name__
3611 else:
3612 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003613 output = StringIO()
3614 helper = pydoc.Helper(output=output)
3615 helper(self.Color)
3616 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003617 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003618
3619 def test_inspect_getmembers(self):
3620 values = dict((
Ethan Furmanb7751062021-03-30 21:17:26 -07003621 ('__class__', EnumType),
Ethan Furman48a724f2015-04-11 23:23:06 -07003622 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003623 ('__members__', self.Color.__members__),
3624 ('__module__', __name__),
3625 ('blue', self.Color.blue),
3626 ('green', self.Color.green),
3627 ('name', Enum.__dict__['name']),
3628 ('red', self.Color.red),
3629 ('value', Enum.__dict__['value']),
3630 ))
3631 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003632 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003633 failed = False
3634 for k in values.keys():
3635 if result[k] != values[k]:
3636 print()
3637 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3638 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3639 failed = True
3640 if failed:
3641 self.fail("result does not equal expected, see print above")
3642
3643 def test_inspect_classify_class_attrs(self):
3644 # indirectly test __objclass__
3645 from inspect import Attribute
3646 values = [
3647 Attribute(name='__class__', kind='data',
Ethan Furmanb7751062021-03-30 21:17:26 -07003648 defining_class=object, object=EnumType),
Ethan Furman5875d742013-10-21 20:45:55 -07003649 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003650 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003651 Attribute(name='__members__', kind='property',
Ethan Furmanb7751062021-03-30 21:17:26 -07003652 defining_class=EnumType, object=EnumType.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003653 Attribute(name='__module__', kind='data',
3654 defining_class=self.Color, object=__name__),
3655 Attribute(name='blue', kind='data',
3656 defining_class=self.Color, object=self.Color.blue),
3657 Attribute(name='green', kind='data',
3658 defining_class=self.Color, object=self.Color.green),
3659 Attribute(name='red', kind='data',
3660 defining_class=self.Color, object=self.Color.red),
3661 Attribute(name='name', kind='data',
3662 defining_class=Enum, object=Enum.__dict__['name']),
3663 Attribute(name='value', kind='data',
3664 defining_class=Enum, object=Enum.__dict__['value']),
3665 ]
3666 values.sort(key=lambda item: item.name)
3667 result = list(inspect.classify_class_attrs(self.Color))
3668 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003669 self.assertEqual(
3670 len(values), len(result),
3671 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3672 )
Ethan Furman5875d742013-10-21 20:45:55 -07003673 failed = False
3674 for v, r in zip(values, result):
3675 if r != v:
3676 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3677 failed = True
3678 if failed:
3679 self.fail("result does not equal expected, see print above")
3680
Ethan Furmana02cb472021-04-21 10:20:44 -07003681 def test_test_simple_enum(self):
3682 @_simple_enum(Enum)
3683 class SimpleColor:
3684 RED = 1
3685 GREEN = 2
3686 BLUE = 3
3687 class CheckedColor(Enum):
3688 RED = 1
3689 GREEN = 2
3690 BLUE = 3
3691 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
3692 SimpleColor.GREEN._value_ = 9
3693 self.assertRaisesRegex(
3694 TypeError, "enum mismatch",
3695 _test_simple_enum, CheckedColor, SimpleColor,
3696 )
3697 class CheckedMissing(IntFlag, boundary=KEEP):
3698 SIXTY_FOUR = 64
3699 ONE_TWENTY_EIGHT = 128
3700 TWENTY_FORTY_EIGHT = 2048
3701 ALL = 2048 + 128 + 64 + 12
3702 CM = CheckedMissing
3703 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
3704 #
3705 @_simple_enum(IntFlag, boundary=KEEP)
3706 class Missing:
3707 SIXTY_FOUR = 64
3708 ONE_TWENTY_EIGHT = 128
3709 TWENTY_FORTY_EIGHT = 2048
3710 ALL = 2048 + 128 + 64 + 12
3711 M = Missing
3712 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
3713 #
3714 _test_simple_enum(CheckedMissing, Missing)
3715
Martin Panter19e69c52015-11-14 12:46:42 +00003716
3717class MiscTestCase(unittest.TestCase):
3718 def test__all__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08003719 support.check__all__(self, enum, not_exported={'bin'})
Martin Panter19e69c52015-11-14 12:46:42 +00003720
3721
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003722# These are unordered here on purpose to ensure that declaration order
3723# makes no difference.
3724CONVERT_TEST_NAME_D = 5
3725CONVERT_TEST_NAME_C = 5
3726CONVERT_TEST_NAME_B = 5
3727CONVERT_TEST_NAME_A = 5 # This one should sort first.
3728CONVERT_TEST_NAME_E = 5
3729CONVERT_TEST_NAME_F = 5
3730
Ethan Furmana02cb472021-04-21 10:20:44 -07003731CONVERT_STRING_TEST_NAME_D = 5
3732CONVERT_STRING_TEST_NAME_C = 5
3733CONVERT_STRING_TEST_NAME_B = 5
3734CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
3735CONVERT_STRING_TEST_NAME_E = 5
3736CONVERT_STRING_TEST_NAME_F = 5
3737
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003738class TestIntEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003739 def setUp(self):
3740 # Reset the module-level test variables to their original integer
3741 # values, otherwise the already created enum values get converted
3742 # instead.
3743 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
3744 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5
3745 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5
3746
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003747 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003748 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003749 'UnittestConvert',
3750 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003751 filter=lambda x: x.startswith('CONVERT_TEST_'))
3752 # We don't want the reverse lookup value to vary when there are
3753 # multiple possible names for a given value. It should always
3754 # report the first lexigraphical name in that case.
3755 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3756
3757 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003758 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003759 'UnittestConvert',
3760 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003761 filter=lambda x: x.startswith('CONVERT_TEST_'))
3762 # Ensure that test_type has all of the desired names and values.
3763 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3764 test_type.CONVERT_TEST_NAME_A)
3765 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3766 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3767 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3768 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3769 # Ensure that test_type only picked up names matching the filter.
3770 self.assertEqual([name for name in dir(test_type)
3771 if name[0:2] not in ('CO', '__')],
3772 [], msg='Names other than CONVERT_TEST_* found.')
3773
Ethan Furman6bd92882021-04-27 13:05:08 -07003774 @unittest.skipUnless(python_version == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003775 '_convert was deprecated in 3.8')
3776 def test_convert_warn(self):
3777 with self.assertWarns(DeprecationWarning):
3778 enum.IntEnum._convert(
3779 'UnittestConvert',
3780 ('test.test_enum', '__main__')[__name__=='__main__'],
3781 filter=lambda x: x.startswith('CONVERT_TEST_'))
3782
Ethan Furman6bd92882021-04-27 13:05:08 -07003783 @unittest.skipUnless(python_version >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003784 '_convert was removed in 3.9')
3785 def test_convert_raise(self):
3786 with self.assertRaises(AttributeError):
3787 enum.IntEnum._convert(
3788 'UnittestConvert',
3789 ('test.test_enum', '__main__')[__name__=='__main__'],
3790 filter=lambda x: x.startswith('CONVERT_TEST_'))
3791
Ethan Furman6bd92882021-04-27 13:05:08 -07003792 @unittest.skipUnless(
3793 python_version < (3, 12),
3794 'mixin-format now uses member instead of member.value',
3795 )
Ethan Furmanb7751062021-03-30 21:17:26 -07003796 def test_convert_repr_and_str(self):
3797 module = ('test.test_enum', '__main__')[__name__=='__main__']
3798 test_type = enum.IntEnum._convert_(
3799 'UnittestConvert',
3800 module,
Ethan Furmana02cb472021-04-21 10:20:44 -07003801 filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
3802 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
3803 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
Ethan Furman6bd92882021-04-27 13:05:08 -07003804 with self.assertWarns(DeprecationWarning):
3805 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
Ethan Furmanb7751062021-03-30 21:17:26 -07003806
3807# global names for StrEnum._convert_ test
3808CONVERT_STR_TEST_2 = 'goodbye'
3809CONVERT_STR_TEST_1 = 'hello'
3810
3811class TestStrEnumConvert(unittest.TestCase):
Ammar Askar37b173c2021-04-21 23:22:58 -04003812 def setUp(self):
3813 global CONVERT_STR_TEST_1
3814 global CONVERT_STR_TEST_2
3815 CONVERT_STR_TEST_2 = 'goodbye'
3816 CONVERT_STR_TEST_1 = 'hello'
Ethan Furmanb7751062021-03-30 21:17:26 -07003817
3818 def test_convert(self):
3819 test_type = enum.StrEnum._convert_(
3820 'UnittestConvert',
3821 ('test.test_enum', '__main__')[__name__=='__main__'],
3822 filter=lambda x: x.startswith('CONVERT_STR_'))
3823 # Ensure that test_type has all of the desired names and values.
3824 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
3825 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
3826 # Ensure that test_type only picked up names matching the filter.
3827 self.assertEqual([name for name in dir(test_type)
3828 if name[0:2] not in ('CO', '__')],
3829 [], msg='Names other than CONVERT_STR_* found.')
3830
3831 def test_convert_repr_and_str(self):
3832 module = ('test.test_enum', '__main__')[__name__=='__main__']
3833 test_type = enum.StrEnum._convert_(
3834 'UnittestConvert',
3835 module,
3836 filter=lambda x: x.startswith('CONVERT_STR_'))
3837 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
3838 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
3839 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
3840
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003841
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003842if __name__ == '__main__':
3843 unittest.main()