blob: 3ea623e9c883c01701097d37aeccbcdb00461868 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furman0063ff42020-09-21 17:23:13 -07008from enum import Enum, IntEnum, StrEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000011from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030012from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080013from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080014from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080015
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016
17# for pickle tests
18try:
19 class Stooges(Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23except Exception as exc:
24 Stooges = exc
25
26try:
27 class IntStooges(int, Enum):
28 LARRY = 1
29 CURLY = 2
30 MOE = 3
31except Exception as exc:
32 IntStooges = exc
33
34try:
35 class FloatStooges(float, Enum):
36 LARRY = 1.39
37 CURLY = 2.72
38 MOE = 3.142596
39except Exception as exc:
40 FloatStooges = exc
41
Ethan Furman65a5a472016-09-01 23:55:19 -070042try:
43 class FlagStooges(Flag):
44 LARRY = 1
45 CURLY = 2
46 MOE = 3
47except Exception as exc:
48 FlagStooges = exc
49
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070051class Name(StrEnum):
52 BDFL = 'Guido van Rossum'
53 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070054
55try:
56 Question = Enum('Question', 'who what when where why', module=__name__)
57except Exception as exc:
58 Question = exc
59
60try:
61 Answer = Enum('Answer', 'him this then there because')
62except Exception as exc:
63 Answer = exc
64
Ethan Furmanca1b7942014-02-08 11:36:27 -080065try:
66 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
67except Exception as exc:
68 Theory = exc
69
Ethan Furman6b3d64a2013-06-14 16:55:46 -070070# for doctests
71try:
72 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080073 TOMATO = 1
74 BANANA = 2
75 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076except Exception:
77 pass
78
Serhiy Storchakae50e7802015-03-31 16:56:49 +030079def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080080 if target is None:
81 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030082 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080083 assertion(loads(dumps(source, protocol=protocol)), target)
84
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085def test_pickle_exception(assertion, exception, obj):
86 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 with assertion(exception):
88 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070089
90class TestHelpers(unittest.TestCase):
91 # _is_descriptor, _is_sunder, _is_dunder
92
93 def test_is_descriptor(self):
94 class foo:
95 pass
96 for attr in ('__get__','__set__','__delete__'):
97 obj = foo()
98 self.assertFalse(enum._is_descriptor(obj))
99 setattr(obj, attr, 1)
100 self.assertTrue(enum._is_descriptor(obj))
101
102 def test_is_sunder(self):
103 for s in ('_a_', '_aa_'):
104 self.assertTrue(enum._is_sunder(s))
105
106 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
107 '__', '___', '____', '_____',):
108 self.assertFalse(enum._is_sunder(s))
109
110 def test_is_dunder(self):
111 for s in ('__a__', '__aa__'):
112 self.assertTrue(enum._is_dunder(s))
113 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
114 '__', '___', '____', '_____',):
115 self.assertFalse(enum._is_dunder(s))
116
Ethan Furman5bdab642018-09-21 19:03:09 -0700117# for subclassing tests
118
119class classproperty:
120
121 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
122 self.fget = fget
123 self.fset = fset
124 self.fdel = fdel
125 if doc is None and fget is not None:
126 doc = fget.__doc__
127 self.__doc__ = doc
128
129 def __get__(self, instance, ownerclass):
130 return self.fget(ownerclass)
131
132
Ethan Furmanc16595e2016-09-10 23:36:59 -0700133# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700134
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700135class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800136
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700137 def setUp(self):
138 class Season(Enum):
139 SPRING = 1
140 SUMMER = 2
141 AUTUMN = 3
142 WINTER = 4
143 self.Season = Season
144
Ethan Furmanec15a822013-08-31 19:17:41 -0700145 class Konstants(float, Enum):
146 E = 2.7182818
147 PI = 3.1415926
148 TAU = 2 * PI
149 self.Konstants = Konstants
150
151 class Grades(IntEnum):
152 A = 5
153 B = 4
154 C = 3
155 D = 2
156 F = 0
157 self.Grades = Grades
158
159 class Directional(str, Enum):
160 EAST = 'east'
161 WEST = 'west'
162 NORTH = 'north'
163 SOUTH = 'south'
164 self.Directional = Directional
165
166 from datetime import date
167 class Holiday(date, Enum):
168 NEW_YEAR = 2013, 1, 1
169 IDES_OF_MARCH = 2013, 3, 15
170 self.Holiday = Holiday
171
Ethan Furman388a3922013-08-12 06:51:41 -0700172 def test_dir_on_class(self):
173 Season = self.Season
174 self.assertEqual(
175 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700176 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700177 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
178 )
179
180 def test_dir_on_item(self):
181 Season = self.Season
182 self.assertEqual(
183 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700184 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700185 )
186
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 def test_dir_with_added_behavior(self):
188 class Test(Enum):
189 this = 'that'
190 these = 'those'
191 def wowser(self):
192 return ("Wowser! I'm %s!" % self.name)
193 self.assertEqual(
194 set(dir(Test)),
195 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
196 )
197 self.assertEqual(
198 set(dir(Test.this)),
199 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
200 )
201
Ethan Furman0ae550b2014-10-14 08:58:32 -0700202 def test_dir_on_sub_with_behavior_on_super(self):
203 # see issue22506
204 class SuperEnum(Enum):
205 def invisible(self):
206 return "did you see me?"
207 class SubEnum(SuperEnum):
208 sample = 5
209 self.assertEqual(
210 set(dir(SubEnum.sample)),
211 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
212 )
213
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200214 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
215 # see issue40084
216 class SuperEnum(IntEnum):
217 def __new__(cls, value, description=""):
218 obj = int.__new__(cls, value)
219 obj._value_ = value
220 obj.description = description
221 return obj
222 class SubEnum(SuperEnum):
223 sample = 5
224 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
225
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700226 def test_enum_in_enum_out(self):
227 Season = self.Season
228 self.assertIs(Season(Season.WINTER), Season.WINTER)
229
230 def test_enum_value(self):
231 Season = self.Season
232 self.assertEqual(Season.SPRING.value, 1)
233
234 def test_intenum_value(self):
235 self.assertEqual(IntStooges.CURLY.value, 2)
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum(self):
238 Season = self.Season
239 lst = list(Season)
240 self.assertEqual(len(lst), len(Season))
241 self.assertEqual(len(Season), 4, Season)
242 self.assertEqual(
243 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
244
245 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
246 e = Season(i)
247 self.assertEqual(e, getattr(Season, season))
248 self.assertEqual(e.value, i)
249 self.assertNotEqual(e, i)
250 self.assertEqual(e.name, season)
251 self.assertIn(e, Season)
252 self.assertIs(type(e), Season)
253 self.assertIsInstance(e, Season)
254 self.assertEqual(str(e), 'Season.' + season)
255 self.assertEqual(
256 repr(e),
257 '<Season.{0}: {1}>'.format(season, i),
258 )
259
260 def test_value_name(self):
261 Season = self.Season
262 self.assertEqual(Season.SPRING.name, 'SPRING')
263 self.assertEqual(Season.SPRING.value, 1)
264 with self.assertRaises(AttributeError):
265 Season.SPRING.name = 'invierno'
266 with self.assertRaises(AttributeError):
267 Season.SPRING.value = 2
268
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700269 def test_changing_member(self):
270 Season = self.Season
271 with self.assertRaises(AttributeError):
272 Season.WINTER = 'really cold'
273
Ethan Furman64a99722013-09-22 16:18:19 -0700274 def test_attribute_deletion(self):
275 class Season(Enum):
276 SPRING = 1
277 SUMMER = 2
278 AUTUMN = 3
279 WINTER = 4
280
281 def spam(cls):
282 pass
283
284 self.assertTrue(hasattr(Season, 'spam'))
285 del Season.spam
286 self.assertFalse(hasattr(Season, 'spam'))
287
288 with self.assertRaises(AttributeError):
289 del Season.SPRING
290 with self.assertRaises(AttributeError):
291 del Season.DRY
292 with self.assertRaises(AttributeError):
293 del Season.SPRING.name
294
Ethan Furman5de67b12016-04-13 23:52:09 -0700295 def test_bool_of_class(self):
296 class Empty(Enum):
297 pass
298 self.assertTrue(bool(Empty))
299
300 def test_bool_of_member(self):
301 class Count(Enum):
302 zero = 0
303 one = 1
304 two = 2
305 for member in Count:
306 self.assertTrue(bool(member))
307
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700308 def test_invalid_names(self):
309 with self.assertRaises(ValueError):
310 class Wrong(Enum):
311 mro = 9
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 _create_= 11
315 with self.assertRaises(ValueError):
316 class Wrong(Enum):
317 _get_mixins_ = 9
318 with self.assertRaises(ValueError):
319 class Wrong(Enum):
320 _find_new_ = 1
321 with self.assertRaises(ValueError):
322 class Wrong(Enum):
323 _any_name_ = 9
324
Ethan Furman6db1fd52015-09-17 21:49:12 -0700325 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800326 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700327 class Logic(Enum):
328 true = True
329 false = False
330 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800331 self.assertTrue(Logic.false)
332 # unless overridden
333 class RealLogic(Enum):
334 true = True
335 false = False
336 def __bool__(self):
337 return bool(self._value_)
338 self.assertTrue(RealLogic.true)
339 self.assertFalse(RealLogic.false)
340 # mixed Enums depend on mixed-in type
341 class IntLogic(int, Enum):
342 true = 1
343 false = 0
344 self.assertTrue(IntLogic.true)
345 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700346
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347 def test_contains(self):
348 Season = self.Season
349 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530350 with self.assertRaises(TypeError):
351 3 in Season
352 with self.assertRaises(TypeError):
353 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700354
355 val = Season(3)
356 self.assertIn(val, Season)
357
358 class OtherEnum(Enum):
359 one = 1; two = 2
360 self.assertNotIn(OtherEnum.two, Season)
361
362 def test_comparisons(self):
363 Season = self.Season
364 with self.assertRaises(TypeError):
365 Season.SPRING < Season.WINTER
366 with self.assertRaises(TypeError):
367 Season.SPRING > 4
368
369 self.assertNotEqual(Season.SPRING, 1)
370
371 class Part(Enum):
372 SPRING = 1
373 CLIP = 2
374 BARREL = 3
375
376 self.assertNotEqual(Season.SPRING, Part.SPRING)
377 with self.assertRaises(TypeError):
378 Season.SPRING < Part.CLIP
379
380 def test_enum_duplicates(self):
381 class Season(Enum):
382 SPRING = 1
383 SUMMER = 2
384 AUTUMN = FALL = 3
385 WINTER = 4
386 ANOTHER_SPRING = 1
387 lst = list(Season)
388 self.assertEqual(
389 lst,
390 [Season.SPRING, Season.SUMMER,
391 Season.AUTUMN, Season.WINTER,
392 ])
393 self.assertIs(Season.FALL, Season.AUTUMN)
394 self.assertEqual(Season.FALL.value, 3)
395 self.assertEqual(Season.AUTUMN.value, 3)
396 self.assertIs(Season(3), Season.AUTUMN)
397 self.assertIs(Season(1), Season.SPRING)
398 self.assertEqual(Season.FALL.name, 'AUTUMN')
399 self.assertEqual(
400 [k for k,v in Season.__members__.items() if v.name != k],
401 ['FALL', 'ANOTHER_SPRING'],
402 )
403
Ethan Furman101e0742013-09-15 12:34:36 -0700404 def test_duplicate_name(self):
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 red = 4
411
412 with self.assertRaises(TypeError):
413 class Color(Enum):
414 red = 1
415 green = 2
416 blue = 3
417 def red(self):
418 return 'red'
419
420 with self.assertRaises(TypeError):
421 class Color(Enum):
422 @property
423 def red(self):
424 return 'redder'
425 red = 1
426 green = 2
427 blue = 3
428
Zackery Spytz2ec67522020-09-13 14:27:51 -0600429 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700430 with self.assertRaisesRegex(
431 ValueError,
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800432 "_sunder_ names, such as '_bad_', are reserved",
Ethan Furman5a565b32020-09-15 12:27:06 -0700433 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600434 class Bad(Enum):
435 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700436
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700437 def test_enum_with_value_name(self):
438 class Huh(Enum):
439 name = 1
440 value = 2
441 self.assertEqual(
442 list(Huh),
443 [Huh.name, Huh.value],
444 )
445 self.assertIs(type(Huh.name), Huh)
446 self.assertEqual(Huh.name.name, 'name')
447 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700448
449 def test_format_enum(self):
450 Season = self.Season
451 self.assertEqual('{}'.format(Season.SPRING),
452 '{}'.format(str(Season.SPRING)))
453 self.assertEqual( '{:}'.format(Season.SPRING),
454 '{:}'.format(str(Season.SPRING)))
455 self.assertEqual('{:20}'.format(Season.SPRING),
456 '{:20}'.format(str(Season.SPRING)))
457 self.assertEqual('{:^20}'.format(Season.SPRING),
458 '{:^20}'.format(str(Season.SPRING)))
459 self.assertEqual('{:>20}'.format(Season.SPRING),
460 '{:>20}'.format(str(Season.SPRING)))
461 self.assertEqual('{:<20}'.format(Season.SPRING),
462 '{:<20}'.format(str(Season.SPRING)))
463
thatneat2f19e822019-07-04 11:28:37 -0700464 def test_str_override_enum(self):
465 class EnumWithStrOverrides(Enum):
466 one = auto()
467 two = auto()
468
469 def __str__(self):
470 return 'Str!'
471 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
472 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
473
474 def test_format_override_enum(self):
475 class EnumWithFormatOverride(Enum):
476 one = 1.0
477 two = 2.0
478 def __format__(self, spec):
479 return 'Format!!'
480 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
481 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
482
483 def test_str_and_format_override_enum(self):
484 class EnumWithStrFormatOverrides(Enum):
485 one = auto()
486 two = auto()
487 def __str__(self):
488 return 'Str!'
489 def __format__(self, spec):
490 return 'Format!'
491 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
492 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
493
494 def test_str_override_mixin(self):
495 class MixinEnumWithStrOverride(float, Enum):
496 one = 1.0
497 two = 2.0
498 def __str__(self):
499 return 'Overridden!'
500 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
501 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
502
503 def test_str_and_format_override_mixin(self):
504 class MixinWithStrFormatOverrides(float, Enum):
505 one = 1.0
506 two = 2.0
507 def __str__(self):
508 return 'Str!'
509 def __format__(self, spec):
510 return 'Format!'
511 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
512 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
513
514 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700515 class TestFloat(float, Enum):
516 one = 1.0
517 two = 2.0
518 def __format__(self, spec):
519 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700520 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700521 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
522
523 def assertFormatIsValue(self, spec, member):
524 self.assertEqual(spec.format(member), spec.format(member.value))
525
526 def test_format_enum_date(self):
527 Holiday = self.Holiday
528 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
529 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
530 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
531 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
532 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
533 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
534 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
535 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
536
537 def test_format_enum_float(self):
538 Konstants = self.Konstants
539 self.assertFormatIsValue('{}', Konstants.TAU)
540 self.assertFormatIsValue('{:}', Konstants.TAU)
541 self.assertFormatIsValue('{:20}', Konstants.TAU)
542 self.assertFormatIsValue('{:^20}', Konstants.TAU)
543 self.assertFormatIsValue('{:>20}', Konstants.TAU)
544 self.assertFormatIsValue('{:<20}', Konstants.TAU)
545 self.assertFormatIsValue('{:n}', Konstants.TAU)
546 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
547 self.assertFormatIsValue('{:f}', Konstants.TAU)
548
549 def test_format_enum_int(self):
550 Grades = self.Grades
551 self.assertFormatIsValue('{}', Grades.C)
552 self.assertFormatIsValue('{:}', Grades.C)
553 self.assertFormatIsValue('{:20}', Grades.C)
554 self.assertFormatIsValue('{:^20}', Grades.C)
555 self.assertFormatIsValue('{:>20}', Grades.C)
556 self.assertFormatIsValue('{:<20}', Grades.C)
557 self.assertFormatIsValue('{:+}', Grades.C)
558 self.assertFormatIsValue('{:08X}', Grades.C)
559 self.assertFormatIsValue('{:b}', Grades.C)
560
561 def test_format_enum_str(self):
562 Directional = self.Directional
563 self.assertFormatIsValue('{}', Directional.WEST)
564 self.assertFormatIsValue('{:}', Directional.WEST)
565 self.assertFormatIsValue('{:20}', Directional.WEST)
566 self.assertFormatIsValue('{:^20}', Directional.WEST)
567 self.assertFormatIsValue('{:>20}', Directional.WEST)
568 self.assertFormatIsValue('{:<20}', Directional.WEST)
569
Ethan Furman22415ad2020-09-15 16:28:25 -0700570 def test_object_str_override(self):
571 class Colors(Enum):
572 RED, GREEN, BLUE = 1, 2, 3
573 def __repr__(self):
574 return "test.%s" % (self._name_, )
575 __str__ = object.__str__
576 self.assertEqual(str(Colors.RED), 'test.RED')
577
Ethan Furmanbff01f32020-09-15 15:56:26 -0700578 def test_enum_str_override(self):
579 class MyStrEnum(Enum):
580 def __str__(self):
581 return 'MyStr'
582 class MyMethodEnum(Enum):
583 def hello(self):
584 return 'Hello! My name is %s' % self.name
585 class Test1Enum(MyMethodEnum, int, MyStrEnum):
586 One = 1
587 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800588 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700589 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800590 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700591 #
592 class Test2Enum(MyStrEnum, MyMethodEnum):
593 One = 1
594 Two = 2
595 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800596 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597
598 def test_inherited_data_type(self):
599 class HexInt(int):
600 def __repr__(self):
601 return hex(self)
602 class MyEnum(HexInt, enum.Enum):
603 A = 1
604 B = 2
605 C = 3
606 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
607
608 def test_too_many_data_types(self):
609 with self.assertRaisesRegex(TypeError, 'too many data types'):
610 class Huh(str, int, Enum):
611 One = 1
612
613 class MyStr(str):
614 def hello(self):
615 return 'hello, %s' % self
616 class MyInt(int):
617 def repr(self):
618 return hex(self)
619 with self.assertRaisesRegex(TypeError, 'too many data types'):
620 class Huh(MyStr, MyInt, Enum):
621 One = 1
622
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700623 def test_hash(self):
624 Season = self.Season
625 dates = {}
626 dates[Season.WINTER] = '1225'
627 dates[Season.SPRING] = '0315'
628 dates[Season.SUMMER] = '0704'
629 dates[Season.AUTUMN] = '1031'
630 self.assertEqual(dates[Season.AUTUMN], '1031')
631
632 def test_intenum_from_scratch(self):
633 class phy(int, Enum):
634 pi = 3
635 tau = 2 * pi
636 self.assertTrue(phy.pi < phy.tau)
637
638 def test_intenum_inherited(self):
639 class IntEnum(int, Enum):
640 pass
641 class phy(IntEnum):
642 pi = 3
643 tau = 2 * pi
644 self.assertTrue(phy.pi < phy.tau)
645
646 def test_floatenum_from_scratch(self):
647 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700648 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700649 tau = 2 * pi
650 self.assertTrue(phy.pi < phy.tau)
651
652 def test_floatenum_inherited(self):
653 class FloatEnum(float, Enum):
654 pass
655 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700656 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700657 tau = 2 * pi
658 self.assertTrue(phy.pi < phy.tau)
659
660 def test_strenum_from_scratch(self):
661 class phy(str, Enum):
662 pi = 'Pi'
663 tau = 'Tau'
664 self.assertTrue(phy.pi < phy.tau)
665
Ethan Furman0063ff42020-09-21 17:23:13 -0700666 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 class phy(StrEnum):
668 pi = 'Pi'
669 tau = 'Tau'
670 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700671 self.assertEqual(phy.pi.upper(), 'PI')
672 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700673
674 def test_intenum(self):
675 class WeekDay(IntEnum):
676 SUNDAY = 1
677 MONDAY = 2
678 TUESDAY = 3
679 WEDNESDAY = 4
680 THURSDAY = 5
681 FRIDAY = 6
682 SATURDAY = 7
683
684 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
685 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
686
687 lst = list(WeekDay)
688 self.assertEqual(len(lst), len(WeekDay))
689 self.assertEqual(len(WeekDay), 7)
690 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
691 target = target.split()
692 for i, weekday in enumerate(target, 1):
693 e = WeekDay(i)
694 self.assertEqual(e, i)
695 self.assertEqual(int(e), i)
696 self.assertEqual(e.name, weekday)
697 self.assertIn(e, WeekDay)
698 self.assertEqual(lst.index(e)+1, i)
699 self.assertTrue(0 < e < 8)
700 self.assertIs(type(e), WeekDay)
701 self.assertIsInstance(e, int)
702 self.assertIsInstance(e, Enum)
703
704 def test_intenum_duplicates(self):
705 class WeekDay(IntEnum):
706 SUNDAY = 1
707 MONDAY = 2
708 TUESDAY = TEUSDAY = 3
709 WEDNESDAY = 4
710 THURSDAY = 5
711 FRIDAY = 6
712 SATURDAY = 7
713 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
714 self.assertEqual(WeekDay(3).name, 'TUESDAY')
715 self.assertEqual([k for k,v in WeekDay.__members__.items()
716 if v.name != k], ['TEUSDAY', ])
717
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300718 def test_intenum_from_bytes(self):
719 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
720 with self.assertRaises(ValueError):
721 IntStooges.from_bytes(b'\x00\x05', 'big')
722
723 def test_floatenum_fromhex(self):
724 h = float.hex(FloatStooges.MOE.value)
725 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
726 h = float.hex(FloatStooges.MOE.value + 0.01)
727 with self.assertRaises(ValueError):
728 FloatStooges.fromhex(h)
729
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700730 def test_pickle_enum(self):
731 if isinstance(Stooges, Exception):
732 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800733 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
734 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700735
736 def test_pickle_int(self):
737 if isinstance(IntStooges, Exception):
738 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800739 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
740 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700741
742 def test_pickle_float(self):
743 if isinstance(FloatStooges, Exception):
744 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800745 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
746 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700747
748 def test_pickle_enum_function(self):
749 if isinstance(Answer, Exception):
750 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800751 test_pickle_dump_load(self.assertIs, Answer.him)
752 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700753
754 def test_pickle_enum_function_with_module(self):
755 if isinstance(Question, Exception):
756 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800757 test_pickle_dump_load(self.assertIs, Question.who)
758 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700759
Ethan Furmanca1b7942014-02-08 11:36:27 -0800760 def test_enum_function_with_qualname(self):
761 if isinstance(Theory, Exception):
762 raise Theory
763 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
764
765 def test_class_nested_enum_and_pickle_protocol_four(self):
766 # would normally just have this directly in the class namespace
767 class NestedEnum(Enum):
768 twigs = 'common'
769 shiny = 'rare'
770
771 self.__class__.NestedEnum = NestedEnum
772 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300773 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800774
Ethan Furman24e837f2015-03-18 17:27:57 -0700775 def test_pickle_by_name(self):
776 class ReplaceGlobalInt(IntEnum):
777 ONE = 1
778 TWO = 2
779 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
780 for proto in range(HIGHEST_PROTOCOL):
781 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
782
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784 BadPickle = Enum(
785 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700786 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800787 # now break BadPickle to test exception raising
788 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800789 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
790 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700791
792 def test_string_enum(self):
793 class SkillLevel(str, Enum):
794 master = 'what is the sound of one hand clapping?'
795 journeyman = 'why did the chicken cross the road?'
796 apprentice = 'knock, knock!'
797 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
798
799 def test_getattr_getitem(self):
800 class Period(Enum):
801 morning = 1
802 noon = 2
803 evening = 3
804 night = 4
805 self.assertIs(Period(2), Period.noon)
806 self.assertIs(getattr(Period, 'night'), Period.night)
807 self.assertIs(Period['morning'], Period.morning)
808
809 def test_getattr_dunder(self):
810 Season = self.Season
811 self.assertTrue(getattr(Season, '__eq__'))
812
813 def test_iteration_order(self):
814 class Season(Enum):
815 SUMMER = 2
816 WINTER = 4
817 AUTUMN = 3
818 SPRING = 1
819 self.assertEqual(
820 list(Season),
821 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
822 )
823
Ethan Furman2131a4a2013-09-14 18:11:24 -0700824 def test_reversed_iteration_order(self):
825 self.assertEqual(
826 list(reversed(self.Season)),
827 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
828 self.Season.SPRING]
829 )
830
Martin Pantereb995702016-07-28 01:11:04 +0000831 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832 SummerMonth = Enum('SummerMonth', 'june july august')
833 lst = list(SummerMonth)
834 self.assertEqual(len(lst), len(SummerMonth))
835 self.assertEqual(len(SummerMonth), 3, SummerMonth)
836 self.assertEqual(
837 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
838 lst,
839 )
840 for i, month in enumerate('june july august'.split(), 1):
841 e = SummerMonth(i)
842 self.assertEqual(int(e.value), i)
843 self.assertNotEqual(e, i)
844 self.assertEqual(e.name, month)
845 self.assertIn(e, SummerMonth)
846 self.assertIs(type(e), SummerMonth)
847
Martin Pantereb995702016-07-28 01:11:04 +0000848 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700849 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
850 lst = list(SummerMonth)
851 self.assertEqual(len(lst), len(SummerMonth))
852 self.assertEqual(len(SummerMonth), 3, SummerMonth)
853 self.assertEqual(
854 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
855 lst,
856 )
857 for i, month in enumerate('june july august'.split(), 10):
858 e = SummerMonth(i)
859 self.assertEqual(int(e.value), i)
860 self.assertNotEqual(e, i)
861 self.assertEqual(e.name, month)
862 self.assertIn(e, SummerMonth)
863 self.assertIs(type(e), SummerMonth)
864
Martin Pantereb995702016-07-28 01:11:04 +0000865 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700866 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
867 lst = list(SummerMonth)
868 self.assertEqual(len(lst), len(SummerMonth))
869 self.assertEqual(len(SummerMonth), 3, SummerMonth)
870 self.assertEqual(
871 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
872 lst,
873 )
874 for i, month in enumerate('june july august'.split(), 1):
875 e = SummerMonth(i)
876 self.assertEqual(int(e.value), i)
877 self.assertNotEqual(e, i)
878 self.assertEqual(e.name, month)
879 self.assertIn(e, SummerMonth)
880 self.assertIs(type(e), SummerMonth)
881
Martin Pantereb995702016-07-28 01:11:04 +0000882 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700883 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
884 lst = list(SummerMonth)
885 self.assertEqual(len(lst), len(SummerMonth))
886 self.assertEqual(len(SummerMonth), 3, SummerMonth)
887 self.assertEqual(
888 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
889 lst,
890 )
891 for i, month in enumerate('june july august'.split(), 20):
892 e = SummerMonth(i)
893 self.assertEqual(int(e.value), i)
894 self.assertNotEqual(e, i)
895 self.assertEqual(e.name, month)
896 self.assertIn(e, SummerMonth)
897 self.assertIs(type(e), SummerMonth)
898
Martin Pantereb995702016-07-28 01:11:04 +0000899 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700900 SummerMonth = Enum(
901 'SummerMonth',
902 (('june', 1), ('july', 2), ('august', 3))
903 )
904 lst = list(SummerMonth)
905 self.assertEqual(len(lst), len(SummerMonth))
906 self.assertEqual(len(SummerMonth), 3, SummerMonth)
907 self.assertEqual(
908 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
909 lst,
910 )
911 for i, month in enumerate('june july august'.split(), 1):
912 e = SummerMonth(i)
913 self.assertEqual(int(e.value), i)
914 self.assertNotEqual(e, i)
915 self.assertEqual(e.name, month)
916 self.assertIn(e, SummerMonth)
917 self.assertIs(type(e), SummerMonth)
918
Martin Pantereb995702016-07-28 01:11:04 +0000919 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700920 SummerMonth = Enum(
921 'SummerMonth',
922 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
923 )
924 lst = list(SummerMonth)
925 self.assertEqual(len(lst), len(SummerMonth))
926 self.assertEqual(len(SummerMonth), 3, SummerMonth)
927 self.assertEqual(
928 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
929 lst,
930 )
931 for i, month in enumerate('june july august'.split(), 1):
932 e = SummerMonth(i)
933 self.assertEqual(int(e.value), i)
934 self.assertNotEqual(e, i)
935 self.assertEqual(e.name, month)
936 self.assertIn(e, SummerMonth)
937 self.assertIs(type(e), SummerMonth)
938
Martin Pantereb995702016-07-28 01:11:04 +0000939 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700940 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
941 lst = list(SummerMonth)
942 self.assertEqual(len(lst), len(SummerMonth))
943 self.assertEqual(len(SummerMonth), 3, SummerMonth)
944 self.assertEqual(
945 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
946 lst,
947 )
948 for i, month in enumerate('june july august'.split(), 1):
949 e = SummerMonth(i)
950 self.assertEqual(e, i)
951 self.assertEqual(e.name, month)
952 self.assertIn(e, SummerMonth)
953 self.assertIs(type(e), SummerMonth)
954
Martin Pantereb995702016-07-28 01:11:04 +0000955 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700956 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
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(), 30):
965 e = SummerMonth(i)
966 self.assertEqual(e, i)
967 self.assertEqual(e.name, month)
968 self.assertIn(e, SummerMonth)
969 self.assertIs(type(e), SummerMonth)
970
Martin Pantereb995702016-07-28 01:11:04 +0000971 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700972 SummerMonth = IntEnum('SummerMonth', 'june july august')
973 lst = list(SummerMonth)
974 self.assertEqual(len(lst), len(SummerMonth))
975 self.assertEqual(len(SummerMonth), 3, SummerMonth)
976 self.assertEqual(
977 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
978 lst,
979 )
980 for i, month in enumerate('june july august'.split(), 1):
981 e = SummerMonth(i)
982 self.assertEqual(e, i)
983 self.assertEqual(e.name, month)
984 self.assertIn(e, SummerMonth)
985 self.assertIs(type(e), SummerMonth)
986
Martin Pantereb995702016-07-28 01:11:04 +0000987 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700988 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
989 lst = list(SummerMonth)
990 self.assertEqual(len(lst), len(SummerMonth))
991 self.assertEqual(len(SummerMonth), 3, SummerMonth)
992 self.assertEqual(
993 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
994 lst,
995 )
996 for i, month in enumerate('june july august'.split(), 40):
997 e = SummerMonth(i)
998 self.assertEqual(e, i)
999 self.assertEqual(e.name, month)
1000 self.assertIn(e, SummerMonth)
1001 self.assertIs(type(e), SummerMonth)
1002
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001003 def test_subclassing(self):
1004 if isinstance(Name, Exception):
1005 raise Name
1006 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1007 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1008 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001009 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001010
1011 def test_extending(self):
1012 class Color(Enum):
1013 red = 1
1014 green = 2
1015 blue = 3
1016 with self.assertRaises(TypeError):
1017 class MoreColor(Color):
1018 cyan = 4
1019 magenta = 5
1020 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001021 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1022 class EvenMoreColor(Color, IntEnum):
1023 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001024
1025 def test_exclude_methods(self):
1026 class whatever(Enum):
1027 this = 'that'
1028 these = 'those'
1029 def really(self):
1030 return 'no, not %s' % self.value
1031 self.assertIsNot(type(whatever.really), whatever)
1032 self.assertEqual(whatever.this.really(), 'no, not that')
1033
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034 def test_wrong_inheritance_order(self):
1035 with self.assertRaises(TypeError):
1036 class Wrong(Enum, str):
1037 NotHere = 'error before this point'
1038
1039 def test_intenum_transitivity(self):
1040 class number(IntEnum):
1041 one = 1
1042 two = 2
1043 three = 3
1044 class numero(IntEnum):
1045 uno = 1
1046 dos = 2
1047 tres = 3
1048 self.assertEqual(number.one, numero.uno)
1049 self.assertEqual(number.two, numero.dos)
1050 self.assertEqual(number.three, numero.tres)
1051
1052 def test_wrong_enum_in_call(self):
1053 class Monochrome(Enum):
1054 black = 0
1055 white = 1
1056 class Gender(Enum):
1057 male = 0
1058 female = 1
1059 self.assertRaises(ValueError, Monochrome, Gender.male)
1060
1061 def test_wrong_enum_in_mixed_call(self):
1062 class Monochrome(IntEnum):
1063 black = 0
1064 white = 1
1065 class Gender(Enum):
1066 male = 0
1067 female = 1
1068 self.assertRaises(ValueError, Monochrome, Gender.male)
1069
1070 def test_mixed_enum_in_call_1(self):
1071 class Monochrome(IntEnum):
1072 black = 0
1073 white = 1
1074 class Gender(IntEnum):
1075 male = 0
1076 female = 1
1077 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1078
1079 def test_mixed_enum_in_call_2(self):
1080 class Monochrome(Enum):
1081 black = 0
1082 white = 1
1083 class Gender(IntEnum):
1084 male = 0
1085 female = 1
1086 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1087
1088 def test_flufl_enum(self):
1089 class Fluflnum(Enum):
1090 def __int__(self):
1091 return int(self.value)
1092 class MailManOptions(Fluflnum):
1093 option1 = 1
1094 option2 = 2
1095 option3 = 3
1096 self.assertEqual(int(MailManOptions.option1), 1)
1097
Ethan Furman5e5a8232013-08-04 08:42:23 -07001098 def test_introspection(self):
1099 class Number(IntEnum):
1100 one = 100
1101 two = 200
1102 self.assertIs(Number.one._member_type_, int)
1103 self.assertIs(Number._member_type_, int)
1104 class String(str, Enum):
1105 yarn = 'soft'
1106 rope = 'rough'
1107 wire = 'hard'
1108 self.assertIs(String.yarn._member_type_, str)
1109 self.assertIs(String._member_type_, str)
1110 class Plain(Enum):
1111 vanilla = 'white'
1112 one = 1
1113 self.assertIs(Plain.vanilla._member_type_, object)
1114 self.assertIs(Plain._member_type_, object)
1115
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001116 def test_no_such_enum_member(self):
1117 class Color(Enum):
1118 red = 1
1119 green = 2
1120 blue = 3
1121 with self.assertRaises(ValueError):
1122 Color(4)
1123 with self.assertRaises(KeyError):
1124 Color['chartreuse']
1125
1126 def test_new_repr(self):
1127 class Color(Enum):
1128 red = 1
1129 green = 2
1130 blue = 3
1131 def __repr__(self):
1132 return "don't you just love shades of %s?" % self.name
1133 self.assertEqual(
1134 repr(Color.blue),
1135 "don't you just love shades of blue?",
1136 )
1137
1138 def test_inherited_repr(self):
1139 class MyEnum(Enum):
1140 def __repr__(self):
1141 return "My name is %s." % self.name
1142 class MyIntEnum(int, MyEnum):
1143 this = 1
1144 that = 2
1145 theother = 3
1146 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1147
1148 def test_multiple_mixin_mro(self):
1149 class auto_enum(type(Enum)):
1150 def __new__(metacls, cls, bases, classdict):
1151 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001152 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001153 names = set(classdict._member_names)
1154 i = 0
1155 for k in classdict._member_names:
1156 v = classdict[k]
1157 if v is Ellipsis:
1158 v = i
1159 else:
1160 i = v
1161 i += 1
1162 temp[k] = v
1163 for k, v in classdict.items():
1164 if k not in names:
1165 temp[k] = v
1166 return super(auto_enum, metacls).__new__(
1167 metacls, cls, bases, temp)
1168
1169 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1170 pass
1171
1172 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1173 pass
1174
1175 class TestAutoNumber(AutoNumberedEnum):
1176 a = ...
1177 b = 3
1178 c = ...
1179
1180 class TestAutoInt(AutoIntEnum):
1181 a = ...
1182 b = 3
1183 c = ...
1184
1185 def test_subclasses_with_getnewargs(self):
1186 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001187 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001188 def __new__(cls, *args):
1189 _args = args
1190 name, *args = args
1191 if len(args) == 0:
1192 raise TypeError("name and value must be specified")
1193 self = int.__new__(cls, *args)
1194 self._intname = name
1195 self._args = _args
1196 return self
1197 def __getnewargs__(self):
1198 return self._args
1199 @property
1200 def __name__(self):
1201 return self._intname
1202 def __repr__(self):
1203 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001204 return "{}({!r}, {})".format(
1205 type(self).__name__,
1206 self.__name__,
1207 int.__repr__(self),
1208 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001209 def __str__(self):
1210 # str() is unchanged, even if it relies on the repr() fallback
1211 base = int
1212 base_str = base.__str__
1213 if base_str.__objclass__ is object:
1214 return base.__repr__(self)
1215 return base_str(self)
1216 # for simplicity, we only define one operator that
1217 # propagates expressions
1218 def __add__(self, other):
1219 temp = int(self) + int( other)
1220 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1221 return NamedInt(
1222 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001223 temp,
1224 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001225 else:
1226 return temp
1227
1228 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001229 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001230 x = ('the-x', 1)
1231 y = ('the-y', 2)
1232
Ethan Furman2aa27322013-07-19 19:35:56 -07001233
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001234 self.assertIs(NEI.__new__, Enum.__new__)
1235 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1236 globals()['NamedInt'] = NamedInt
1237 globals()['NEI'] = NEI
1238 NI5 = NamedInt('test', 5)
1239 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001240 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001241 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001242 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001243 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001244
Ethan Furmanca1b7942014-02-08 11:36:27 -08001245 def test_subclasses_with_getnewargs_ex(self):
1246 class NamedInt(int):
1247 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1248 def __new__(cls, *args):
1249 _args = args
1250 name, *args = args
1251 if len(args) == 0:
1252 raise TypeError("name and value must be specified")
1253 self = int.__new__(cls, *args)
1254 self._intname = name
1255 self._args = _args
1256 return self
1257 def __getnewargs_ex__(self):
1258 return self._args, {}
1259 @property
1260 def __name__(self):
1261 return self._intname
1262 def __repr__(self):
1263 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001264 return "{}({!r}, {})".format(
1265 type(self).__name__,
1266 self.__name__,
1267 int.__repr__(self),
1268 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001269 def __str__(self):
1270 # str() is unchanged, even if it relies on the repr() fallback
1271 base = int
1272 base_str = base.__str__
1273 if base_str.__objclass__ is object:
1274 return base.__repr__(self)
1275 return base_str(self)
1276 # for simplicity, we only define one operator that
1277 # propagates expressions
1278 def __add__(self, other):
1279 temp = int(self) + int( other)
1280 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1281 return NamedInt(
1282 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001283 temp,
1284 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001285 else:
1286 return temp
1287
1288 class NEI(NamedInt, Enum):
1289 __qualname__ = 'NEI' # needed for pickle protocol 4
1290 x = ('the-x', 1)
1291 y = ('the-y', 2)
1292
1293
1294 self.assertIs(NEI.__new__, Enum.__new__)
1295 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1296 globals()['NamedInt'] = NamedInt
1297 globals()['NEI'] = NEI
1298 NI5 = NamedInt('test', 5)
1299 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001300 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001301 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001302 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001303 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001304
1305 def test_subclasses_with_reduce(self):
1306 class NamedInt(int):
1307 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1308 def __new__(cls, *args):
1309 _args = args
1310 name, *args = args
1311 if len(args) == 0:
1312 raise TypeError("name and value must be specified")
1313 self = int.__new__(cls, *args)
1314 self._intname = name
1315 self._args = _args
1316 return self
1317 def __reduce__(self):
1318 return self.__class__, self._args
1319 @property
1320 def __name__(self):
1321 return self._intname
1322 def __repr__(self):
1323 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001324 return "{}({!r}, {})".format(
1325 type(self).__name__,
1326 self.__name__,
1327 int.__repr__(self),
1328 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001329 def __str__(self):
1330 # str() is unchanged, even if it relies on the repr() fallback
1331 base = int
1332 base_str = base.__str__
1333 if base_str.__objclass__ is object:
1334 return base.__repr__(self)
1335 return base_str(self)
1336 # for simplicity, we only define one operator that
1337 # propagates expressions
1338 def __add__(self, other):
1339 temp = int(self) + int( other)
1340 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1341 return NamedInt(
1342 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001343 temp,
1344 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001345 else:
1346 return temp
1347
1348 class NEI(NamedInt, Enum):
1349 __qualname__ = 'NEI' # needed for pickle protocol 4
1350 x = ('the-x', 1)
1351 y = ('the-y', 2)
1352
1353
1354 self.assertIs(NEI.__new__, Enum.__new__)
1355 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1356 globals()['NamedInt'] = NamedInt
1357 globals()['NEI'] = NEI
1358 NI5 = NamedInt('test', 5)
1359 self.assertEqual(NI5, 5)
1360 test_pickle_dump_load(self.assertEqual, NI5, 5)
1361 self.assertEqual(NEI.y.value, 2)
1362 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001363 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001364
1365 def test_subclasses_with_reduce_ex(self):
1366 class NamedInt(int):
1367 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1368 def __new__(cls, *args):
1369 _args = args
1370 name, *args = args
1371 if len(args) == 0:
1372 raise TypeError("name and value must be specified")
1373 self = int.__new__(cls, *args)
1374 self._intname = name
1375 self._args = _args
1376 return self
1377 def __reduce_ex__(self, proto):
1378 return self.__class__, self._args
1379 @property
1380 def __name__(self):
1381 return self._intname
1382 def __repr__(self):
1383 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001384 return "{}({!r}, {})".format(
1385 type(self).__name__,
1386 self.__name__,
1387 int.__repr__(self),
1388 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001389 def __str__(self):
1390 # str() is unchanged, even if it relies on the repr() fallback
1391 base = int
1392 base_str = base.__str__
1393 if base_str.__objclass__ is object:
1394 return base.__repr__(self)
1395 return base_str(self)
1396 # for simplicity, we only define one operator that
1397 # propagates expressions
1398 def __add__(self, other):
1399 temp = int(self) + int( other)
1400 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1401 return NamedInt(
1402 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001403 temp,
1404 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001405 else:
1406 return temp
1407
1408 class NEI(NamedInt, Enum):
1409 __qualname__ = 'NEI' # needed for pickle protocol 4
1410 x = ('the-x', 1)
1411 y = ('the-y', 2)
1412
Ethan Furmanca1b7942014-02-08 11:36:27 -08001413 self.assertIs(NEI.__new__, Enum.__new__)
1414 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1415 globals()['NamedInt'] = NamedInt
1416 globals()['NEI'] = NEI
1417 NI5 = NamedInt('test', 5)
1418 self.assertEqual(NI5, 5)
1419 test_pickle_dump_load(self.assertEqual, NI5, 5)
1420 self.assertEqual(NEI.y.value, 2)
1421 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001422 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001423
Ethan Furmandc870522014-02-18 12:37:12 -08001424 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001425 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001426 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001427 def __new__(cls, *args):
1428 _args = args
1429 name, *args = args
1430 if len(args) == 0:
1431 raise TypeError("name and value must be specified")
1432 self = int.__new__(cls, *args)
1433 self._intname = name
1434 self._args = _args
1435 return self
1436 @property
1437 def __name__(self):
1438 return self._intname
1439 def __repr__(self):
1440 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001441 return "{}({!r}, {})".format(
1442 type(self).__name__,
1443 self.__name__,
1444 int.__repr__(self),
1445 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001446 def __str__(self):
1447 # str() is unchanged, even if it relies on the repr() fallback
1448 base = int
1449 base_str = base.__str__
1450 if base_str.__objclass__ is object:
1451 return base.__repr__(self)
1452 return base_str(self)
1453 # for simplicity, we only define one operator that
1454 # propagates expressions
1455 def __add__(self, other):
1456 temp = int(self) + int( other)
1457 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1458 return NamedInt(
1459 '({0} + {1})'.format(self.__name__, other.__name__),
1460 temp )
1461 else:
1462 return temp
1463
1464 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001465 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001466 x = ('the-x', 1)
1467 y = ('the-y', 2)
1468
1469 self.assertIs(NEI.__new__, Enum.__new__)
1470 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1471 globals()['NamedInt'] = NamedInt
1472 globals()['NEI'] = NEI
1473 NI5 = NamedInt('test', 5)
1474 self.assertEqual(NI5, 5)
1475 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001476 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1477 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001478
Ethan Furmandc870522014-02-18 12:37:12 -08001479 def test_subclasses_without_direct_pickle_support_using_name(self):
1480 class NamedInt(int):
1481 __qualname__ = 'NamedInt'
1482 def __new__(cls, *args):
1483 _args = args
1484 name, *args = args
1485 if len(args) == 0:
1486 raise TypeError("name and value must be specified")
1487 self = int.__new__(cls, *args)
1488 self._intname = name
1489 self._args = _args
1490 return self
1491 @property
1492 def __name__(self):
1493 return self._intname
1494 def __repr__(self):
1495 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001496 return "{}({!r}, {})".format(
1497 type(self).__name__,
1498 self.__name__,
1499 int.__repr__(self),
1500 )
Ethan Furmandc870522014-02-18 12:37:12 -08001501 def __str__(self):
1502 # str() is unchanged, even if it relies on the repr() fallback
1503 base = int
1504 base_str = base.__str__
1505 if base_str.__objclass__ is object:
1506 return base.__repr__(self)
1507 return base_str(self)
1508 # for simplicity, we only define one operator that
1509 # propagates expressions
1510 def __add__(self, other):
1511 temp = int(self) + int( other)
1512 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1513 return NamedInt(
1514 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001515 temp,
1516 )
Ethan Furmandc870522014-02-18 12:37:12 -08001517 else:
1518 return temp
1519
1520 class NEI(NamedInt, Enum):
1521 __qualname__ = 'NEI'
1522 x = ('the-x', 1)
1523 y = ('the-y', 2)
1524 def __reduce_ex__(self, proto):
1525 return getattr, (self.__class__, self._name_)
1526
1527 self.assertIs(NEI.__new__, Enum.__new__)
1528 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1529 globals()['NamedInt'] = NamedInt
1530 globals()['NEI'] = NEI
1531 NI5 = NamedInt('test', 5)
1532 self.assertEqual(NI5, 5)
1533 self.assertEqual(NEI.y.value, 2)
1534 test_pickle_dump_load(self.assertIs, NEI.y)
1535 test_pickle_dump_load(self.assertIs, NEI)
1536
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001537 def test_tuple_subclass(self):
1538 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001539 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001540 first = (1, 'for the money')
1541 second = (2, 'for the show')
1542 third = (3, 'for the music')
1543 self.assertIs(type(SomeTuple.first), SomeTuple)
1544 self.assertIsInstance(SomeTuple.second, tuple)
1545 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1546 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001547 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548
1549 def test_duplicate_values_give_unique_enum_items(self):
1550 class AutoNumber(Enum):
1551 first = ()
1552 second = ()
1553 third = ()
1554 def __new__(cls):
1555 value = len(cls.__members__) + 1
1556 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001557 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558 return obj
1559 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001560 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001561 self.assertEqual(
1562 list(AutoNumber),
1563 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1564 )
1565 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001566 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001567 self.assertIs(AutoNumber(1), AutoNumber.first)
1568
1569 def test_inherited_new_from_enhanced_enum(self):
1570 class AutoNumber(Enum):
1571 def __new__(cls):
1572 value = len(cls.__members__) + 1
1573 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001574 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001575 return obj
1576 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001577 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001578 class Color(AutoNumber):
1579 red = ()
1580 green = ()
1581 blue = ()
1582 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1583 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1584
1585 def test_inherited_new_from_mixed_enum(self):
1586 class AutoNumber(IntEnum):
1587 def __new__(cls):
1588 value = len(cls.__members__) + 1
1589 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001590 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001591 return obj
1592 class Color(AutoNumber):
1593 red = ()
1594 green = ()
1595 blue = ()
1596 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1597 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1598
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001599 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001600 class OrdinaryEnum(Enum):
1601 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001602 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1603 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001604
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001605 def test_ordered_mixin(self):
1606 class OrderedEnum(Enum):
1607 def __ge__(self, other):
1608 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001609 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001610 return NotImplemented
1611 def __gt__(self, other):
1612 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001613 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 return NotImplemented
1615 def __le__(self, other):
1616 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001617 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001618 return NotImplemented
1619 def __lt__(self, other):
1620 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001621 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001622 return NotImplemented
1623 class Grade(OrderedEnum):
1624 A = 5
1625 B = 4
1626 C = 3
1627 D = 2
1628 F = 1
1629 self.assertGreater(Grade.A, Grade.B)
1630 self.assertLessEqual(Grade.F, Grade.C)
1631 self.assertLess(Grade.D, Grade.A)
1632 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001633 self.assertEqual(Grade.B, Grade.B)
1634 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001635
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001636 def test_extending2(self):
1637 class Shade(Enum):
1638 def shade(self):
1639 print(self.name)
1640 class Color(Shade):
1641 red = 1
1642 green = 2
1643 blue = 3
1644 with self.assertRaises(TypeError):
1645 class MoreColor(Color):
1646 cyan = 4
1647 magenta = 5
1648 yellow = 6
1649
1650 def test_extending3(self):
1651 class Shade(Enum):
1652 def shade(self):
1653 return self.name
1654 class Color(Shade):
1655 def hex(self):
1656 return '%s hexlified!' % self.value
1657 class MoreColor(Color):
1658 cyan = 4
1659 magenta = 5
1660 yellow = 6
1661 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1662
orlnub1230fb9fad2018-09-12 20:28:53 +03001663 def test_subclass_duplicate_name(self):
1664 class Base(Enum):
1665 def test(self):
1666 pass
1667 class Test(Base):
1668 test = 1
1669 self.assertIs(type(Test.test), Test)
1670
1671 def test_subclass_duplicate_name_dynamic(self):
1672 from types import DynamicClassAttribute
1673 class Base(Enum):
1674 @DynamicClassAttribute
1675 def test(self):
1676 return 'dynamic'
1677 class Test(Base):
1678 test = 1
1679 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furmanc314e602021-01-12 23:47:57 -08001680 class Base2(Enum):
1681 @enum.property
1682 def flash(self):
1683 return 'flashy dynamic'
1684 class Test(Base2):
1685 flash = 1
1686 self.assertEqual(Test.flash.flash, 'flashy dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001687
1688 def test_no_duplicates(self):
1689 class UniqueEnum(Enum):
1690 def __init__(self, *args):
1691 cls = self.__class__
1692 if any(self.value == e.value for e in cls):
1693 a = self.name
1694 e = cls(self.value).name
1695 raise ValueError(
1696 "aliases not allowed in UniqueEnum: %r --> %r"
1697 % (a, e)
1698 )
1699 class Color(UniqueEnum):
1700 red = 1
1701 green = 2
1702 blue = 3
1703 with self.assertRaises(ValueError):
1704 class Color(UniqueEnum):
1705 red = 1
1706 green = 2
1707 blue = 3
1708 grene = 2
1709
1710 def test_init(self):
1711 class Planet(Enum):
1712 MERCURY = (3.303e+23, 2.4397e6)
1713 VENUS = (4.869e+24, 6.0518e6)
1714 EARTH = (5.976e+24, 6.37814e6)
1715 MARS = (6.421e+23, 3.3972e6)
1716 JUPITER = (1.9e+27, 7.1492e7)
1717 SATURN = (5.688e+26, 6.0268e7)
1718 URANUS = (8.686e+25, 2.5559e7)
1719 NEPTUNE = (1.024e+26, 2.4746e7)
1720 def __init__(self, mass, radius):
1721 self.mass = mass # in kilograms
1722 self.radius = radius # in meters
1723 @property
1724 def surface_gravity(self):
1725 # universal gravitational constant (m3 kg-1 s-2)
1726 G = 6.67300E-11
1727 return G * self.mass / (self.radius * self.radius)
1728 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1729 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1730
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001731 def test_ignore(self):
1732 class Period(timedelta, Enum):
1733 '''
1734 different lengths of time
1735 '''
1736 def __new__(cls, value, period):
1737 obj = timedelta.__new__(cls, value)
1738 obj._value_ = value
1739 obj.period = period
1740 return obj
1741 _ignore_ = 'Period i'
1742 Period = vars()
1743 for i in range(13):
1744 Period['month_%d' % i] = i*30, 'month'
1745 for i in range(53):
1746 Period['week_%d' % i] = i*7, 'week'
1747 for i in range(32):
1748 Period['day_%d' % i] = i, 'day'
1749 OneDay = day_1
1750 OneWeek = week_1
1751 OneMonth = month_1
1752 self.assertFalse(hasattr(Period, '_ignore_'))
1753 self.assertFalse(hasattr(Period, 'Period'))
1754 self.assertFalse(hasattr(Period, 'i'))
1755 self.assertTrue(isinstance(Period.day_1, timedelta))
1756 self.assertTrue(Period.month_1 is Period.day_30)
1757 self.assertTrue(Period.week_4 is Period.day_28)
1758
Ethan Furman2aa27322013-07-19 19:35:56 -07001759 def test_nonhash_value(self):
1760 class AutoNumberInAList(Enum):
1761 def __new__(cls):
1762 value = [len(cls.__members__) + 1]
1763 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001764 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001765 return obj
1766 class ColorInAList(AutoNumberInAList):
1767 red = ()
1768 green = ()
1769 blue = ()
1770 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001771 for enum, value in zip(ColorInAList, range(3)):
1772 value += 1
1773 self.assertEqual(enum.value, [value])
1774 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001775
Ethan Furmanb41803e2013-07-25 13:50:45 -07001776 def test_conflicting_types_resolved_in_new(self):
1777 class LabelledIntEnum(int, Enum):
1778 def __new__(cls, *args):
1779 value, label = args
1780 obj = int.__new__(cls, value)
1781 obj.label = label
1782 obj._value_ = value
1783 return obj
1784
1785 class LabelledList(LabelledIntEnum):
1786 unprocessed = (1, "Unprocessed")
1787 payment_complete = (2, "Payment Complete")
1788
1789 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1790 self.assertEqual(LabelledList.unprocessed, 1)
1791 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001792
Ethan Furmanc16595e2016-09-10 23:36:59 -07001793 def test_auto_number(self):
1794 class Color(Enum):
1795 red = auto()
1796 blue = auto()
1797 green = auto()
1798
1799 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1800 self.assertEqual(Color.red.value, 1)
1801 self.assertEqual(Color.blue.value, 2)
1802 self.assertEqual(Color.green.value, 3)
1803
1804 def test_auto_name(self):
1805 class Color(Enum):
1806 def _generate_next_value_(name, start, count, last):
1807 return name
1808 red = auto()
1809 blue = auto()
1810 green = auto()
1811
1812 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1813 self.assertEqual(Color.red.value, 'red')
1814 self.assertEqual(Color.blue.value, 'blue')
1815 self.assertEqual(Color.green.value, 'green')
1816
1817 def test_auto_name_inherit(self):
1818 class AutoNameEnum(Enum):
1819 def _generate_next_value_(name, start, count, last):
1820 return name
1821 class Color(AutoNameEnum):
1822 red = auto()
1823 blue = auto()
1824 green = auto()
1825
1826 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1827 self.assertEqual(Color.red.value, 'red')
1828 self.assertEqual(Color.blue.value, 'blue')
1829 self.assertEqual(Color.green.value, 'green')
1830
1831 def test_auto_garbage(self):
1832 class Color(Enum):
1833 red = 'red'
1834 blue = auto()
1835 self.assertEqual(Color.blue.value, 1)
1836
1837 def test_auto_garbage_corrected(self):
1838 class Color(Enum):
1839 red = 'red'
1840 blue = 2
1841 green = auto()
1842
1843 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1844 self.assertEqual(Color.red.value, 'red')
1845 self.assertEqual(Color.blue.value, 2)
1846 self.assertEqual(Color.green.value, 3)
1847
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001848 def test_auto_order(self):
1849 with self.assertRaises(TypeError):
1850 class Color(Enum):
1851 red = auto()
1852 green = auto()
1853 blue = auto()
1854 def _generate_next_value_(name, start, count, last):
1855 return name
1856
Ethan Furmanfc23a942020-09-16 12:37:54 -07001857 def test_auto_order_wierd(self):
1858 weird_auto = auto()
1859 weird_auto.value = 'pathological case'
1860 class Color(Enum):
1861 red = weird_auto
1862 def _generate_next_value_(name, start, count, last):
1863 return name
1864 blue = auto()
1865 self.assertEqual(list(Color), [Color.red, Color.blue])
1866 self.assertEqual(Color.red.value, 'pathological case')
1867 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001868
Ethan Furman3515dcc2016-09-18 13:15:41 -07001869 def test_duplicate_auto(self):
1870 class Dupes(Enum):
1871 first = primero = auto()
1872 second = auto()
1873 third = auto()
1874 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1875
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001876 def test_default_missing(self):
1877 class Color(Enum):
1878 RED = 1
1879 GREEN = 2
1880 BLUE = 3
1881 try:
1882 Color(7)
1883 except ValueError as exc:
1884 self.assertTrue(exc.__context__ is None)
1885 else:
1886 raise Exception('Exception not raised.')
1887
Ethan Furman019f0a02018-09-12 11:43:34 -07001888 def test_missing(self):
1889 class Color(Enum):
1890 red = 1
1891 green = 2
1892 blue = 3
1893 @classmethod
1894 def _missing_(cls, item):
1895 if item == 'three':
1896 return cls.blue
1897 elif item == 'bad return':
1898 # trigger internal error
1899 return 5
1900 elif item == 'error out':
1901 raise ZeroDivisionError
1902 else:
1903 # trigger not found
1904 return None
1905 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001906 try:
1907 Color(7)
1908 except ValueError as exc:
1909 self.assertTrue(exc.__context__ is None)
1910 else:
1911 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001912 try:
1913 Color('bad return')
1914 except TypeError as exc:
1915 self.assertTrue(isinstance(exc.__context__, ValueError))
1916 else:
1917 raise Exception('Exception not raised.')
1918 try:
1919 Color('error out')
1920 except ZeroDivisionError as exc:
1921 self.assertTrue(isinstance(exc.__context__, ValueError))
1922 else:
1923 raise Exception('Exception not raised.')
1924
Ethan Furman5bdab642018-09-21 19:03:09 -07001925 def test_multiple_mixin(self):
1926 class MaxMixin:
1927 @classproperty
1928 def MAX(cls):
1929 max = len(cls)
1930 cls.MAX = max
1931 return max
1932 class StrMixin:
1933 def __str__(self):
1934 return self._name_.lower()
1935 class SomeEnum(Enum):
1936 def behavior(self):
1937 return 'booyah'
1938 class AnotherEnum(Enum):
1939 def behavior(self):
1940 return 'nuhuh!'
1941 def social(self):
1942 return "what's up?"
1943 class Color(MaxMixin, Enum):
1944 RED = auto()
1945 GREEN = auto()
1946 BLUE = auto()
1947 self.assertEqual(Color.RED.value, 1)
1948 self.assertEqual(Color.GREEN.value, 2)
1949 self.assertEqual(Color.BLUE.value, 3)
1950 self.assertEqual(Color.MAX, 3)
1951 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1952 class Color(MaxMixin, StrMixin, Enum):
1953 RED = auto()
1954 GREEN = auto()
1955 BLUE = auto()
1956 self.assertEqual(Color.RED.value, 1)
1957 self.assertEqual(Color.GREEN.value, 2)
1958 self.assertEqual(Color.BLUE.value, 3)
1959 self.assertEqual(Color.MAX, 3)
1960 self.assertEqual(str(Color.BLUE), 'blue')
1961 class Color(StrMixin, MaxMixin, Enum):
1962 RED = auto()
1963 GREEN = auto()
1964 BLUE = auto()
1965 self.assertEqual(Color.RED.value, 1)
1966 self.assertEqual(Color.GREEN.value, 2)
1967 self.assertEqual(Color.BLUE.value, 3)
1968 self.assertEqual(Color.MAX, 3)
1969 self.assertEqual(str(Color.BLUE), 'blue')
1970 class CoolColor(StrMixin, SomeEnum, Enum):
1971 RED = auto()
1972 GREEN = auto()
1973 BLUE = auto()
1974 self.assertEqual(CoolColor.RED.value, 1)
1975 self.assertEqual(CoolColor.GREEN.value, 2)
1976 self.assertEqual(CoolColor.BLUE.value, 3)
1977 self.assertEqual(str(CoolColor.BLUE), 'blue')
1978 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1979 class CoolerColor(StrMixin, AnotherEnum, Enum):
1980 RED = auto()
1981 GREEN = auto()
1982 BLUE = auto()
1983 self.assertEqual(CoolerColor.RED.value, 1)
1984 self.assertEqual(CoolerColor.GREEN.value, 2)
1985 self.assertEqual(CoolerColor.BLUE.value, 3)
1986 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1987 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1988 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1989 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1990 RED = auto()
1991 GREEN = auto()
1992 BLUE = auto()
1993 self.assertEqual(CoolestColor.RED.value, 1)
1994 self.assertEqual(CoolestColor.GREEN.value, 2)
1995 self.assertEqual(CoolestColor.BLUE.value, 3)
1996 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1997 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1998 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1999 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2000 RED = auto()
2001 GREEN = auto()
2002 BLUE = auto()
2003 self.assertEqual(ConfusedColor.RED.value, 1)
2004 self.assertEqual(ConfusedColor.GREEN.value, 2)
2005 self.assertEqual(ConfusedColor.BLUE.value, 3)
2006 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2007 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2008 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2009 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2010 RED = auto()
2011 GREEN = auto()
2012 BLUE = auto()
2013 self.assertEqual(ReformedColor.RED.value, 1)
2014 self.assertEqual(ReformedColor.GREEN.value, 2)
2015 self.assertEqual(ReformedColor.BLUE.value, 3)
2016 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2017 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2018 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2019 self.assertTrue(issubclass(ReformedColor, int))
2020
Ethan Furmancd453852018-10-05 23:29:36 -07002021 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002022 @unique
2023 class Decision1(StrEnum):
2024 REVERT = "REVERT"
2025 REVERT_ALL = "REVERT_ALL"
2026 RETRY = "RETRY"
2027 class MyEnum(StrEnum):
2028 pass
2029 @unique
2030 class Decision2(MyEnum):
2031 REVERT = "REVERT"
2032 REVERT_ALL = "REVERT_ALL"
2033 RETRY = "RETRY"
2034
Ethan Furmanc2667362020-12-07 00:17:31 -08002035 def test_multiple_mixin_inherited(self):
2036 class MyInt(int):
2037 def __new__(cls, value):
2038 return super().__new__(cls, value)
2039
2040 class HexMixin:
2041 def __repr__(self):
2042 return hex(self)
2043
2044 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2045 pass
2046
2047 class Foo(MyIntEnum):
2048 TEST = 1
2049 self.assertTrue(isinstance(Foo.TEST, MyInt))
2050 self.assertEqual(repr(Foo.TEST), "0x1")
2051
2052 class Fee(MyIntEnum):
2053 TEST = 1
2054 def __new__(cls, value):
2055 value += 1
2056 member = int.__new__(cls, value)
2057 member._value_ = value
2058 return member
2059 self.assertEqual(Fee.TEST, 2)
2060
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002061 def test_empty_globals(self):
2062 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2063 # when using compile and exec because f_globals is empty
2064 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2065 code = compile(code, "<string>", "exec")
2066 global_ns = {}
2067 local_ls = {}
2068 exec(code, global_ns, local_ls)
2069
Ethan Furman0063ff42020-09-21 17:23:13 -07002070 def test_strenum(self):
2071 class GoodStrEnum(StrEnum):
2072 one = '1'
2073 two = '2'
2074 three = b'3', 'ascii'
2075 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002076 self.assertEqual(GoodStrEnum.one, '1')
2077 self.assertEqual(str(GoodStrEnum.one), '1')
2078 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2079 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2080 #
2081 class DumbMixin:
2082 def __str__(self):
2083 return "don't do this"
2084 class DumbStrEnum(DumbMixin, StrEnum):
2085 five = '5'
2086 six = '6'
2087 seven = '7'
2088 self.assertEqual(DumbStrEnum.seven, '7')
2089 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2090 #
2091 class EnumMixin(Enum):
2092 def hello(self):
2093 print('hello from %s' % (self, ))
2094 class HelloEnum(EnumMixin, StrEnum):
2095 eight = '8'
2096 self.assertEqual(HelloEnum.eight, '8')
2097 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2098 #
2099 class GoodbyeMixin:
2100 def goodbye(self):
2101 print('%s wishes you a fond farewell')
2102 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2103 nine = '9'
2104 self.assertEqual(GoodbyeEnum.nine, '9')
2105 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2106 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002107 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2108 class FirstFailedStrEnum(StrEnum):
2109 one = 1
2110 two = '2'
2111 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2112 class SecondFailedStrEnum(StrEnum):
2113 one = '1'
2114 two = 2,
2115 three = '3'
2116 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2117 class ThirdFailedStrEnum(StrEnum):
2118 one = '1'
2119 two = 2
2120 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2121 class ThirdFailedStrEnum(StrEnum):
2122 one = '1'
2123 two = b'2', sys.getdefaultencoding
2124 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2125 class ThirdFailedStrEnum(StrEnum):
2126 one = '1'
2127 two = b'2', 'ascii', 9
Ethan Furmanc314e602021-01-12 23:47:57 -08002128
Ethan Furman6bd94de2020-12-09 16:41:22 -08002129
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002130
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002131 @unittest.skipUnless(
2132 sys.version_info[:2] == (3, 9),
2133 'private variables are now normal attributes',
2134 )
2135 def test_warning_for_private_variables(self):
2136 with self.assertWarns(DeprecationWarning):
2137 class Private(Enum):
2138 __corporal = 'Radar'
2139 self.assertEqual(Private._Private__corporal.value, 'Radar')
2140 try:
2141 with self.assertWarns(DeprecationWarning):
2142 class Private(Enum):
2143 __major_ = 'Hoolihan'
2144 except ValueError:
2145 pass
2146
2147 def test_private_variable_is_normal_attribute(self):
2148 class Private(Enum):
2149 __corporal = 'Radar'
2150 __major_ = 'Hoolihan'
2151 self.assertEqual(Private._Private__corporal, 'Radar')
2152 self.assertEqual(Private._Private__major_, 'Hoolihan')
2153
Ethan Furmanefb13be2020-12-10 12:20:06 -08002154 def test_strenum_auto(self):
2155 class Strings(StrEnum):
2156 ONE = auto()
2157 TWO = auto()
2158 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2159
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002160
Ethan Furmana6582872020-12-10 13:07:00 -08002161 def test_dynamic_members_with_static_methods(self):
2162 #
2163 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2164 class Foo(Enum):
2165 vars().update({
2166 k: v
2167 for k, v in foo_defines.items()
2168 if k.startswith('FOO_')
2169 })
2170 def upper(self):
2171 return self.value.upper()
2172 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2173 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2174 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2175 #
2176 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2177 class FooBar(Enum):
2178 vars().update({
2179 k: v
2180 for k, v in foo_defines.items()
2181 if k.startswith('FOO_')
2182 },
2183 **{'FOO_CAT': 'small'},
2184 )
2185 def upper(self):
2186 return self.value.upper()
2187
2188
Ethan Furmane8e61272016-08-20 07:19:31 -07002189class TestOrder(unittest.TestCase):
2190
2191 def test_same_members(self):
2192 class Color(Enum):
2193 _order_ = 'red green blue'
2194 red = 1
2195 green = 2
2196 blue = 3
2197
2198 def test_same_members_with_aliases(self):
2199 class Color(Enum):
2200 _order_ = 'red green blue'
2201 red = 1
2202 green = 2
2203 blue = 3
2204 verde = green
2205
2206 def test_same_members_wrong_order(self):
2207 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2208 class Color(Enum):
2209 _order_ = 'red green blue'
2210 red = 1
2211 blue = 3
2212 green = 2
2213
2214 def test_order_has_extra_members(self):
2215 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2216 class Color(Enum):
2217 _order_ = 'red green blue purple'
2218 red = 1
2219 green = 2
2220 blue = 3
2221
2222 def test_order_has_extra_members_with_aliases(self):
2223 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2224 class Color(Enum):
2225 _order_ = 'red green blue purple'
2226 red = 1
2227 green = 2
2228 blue = 3
2229 verde = green
2230
2231 def test_enum_has_extra_members(self):
2232 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2233 class Color(Enum):
2234 _order_ = 'red green blue'
2235 red = 1
2236 green = 2
2237 blue = 3
2238 purple = 4
2239
2240 def test_enum_has_extra_members_with_aliases(self):
2241 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2242 class Color(Enum):
2243 _order_ = 'red green blue'
2244 red = 1
2245 green = 2
2246 blue = 3
2247 purple = 4
2248 verde = green
2249
2250
Ethan Furman65a5a472016-09-01 23:55:19 -07002251class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002252 """Tests of the Flags."""
2253
Ethan Furman65a5a472016-09-01 23:55:19 -07002254 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002255 R, W, X = 4, 2, 1
2256
Ethan Furman65a5a472016-09-01 23:55:19 -07002257 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002258 RO = 0
2259 WO = 1
2260 RW = 2
2261 AC = 3
2262 CE = 1<<19
2263
Rahul Jha94306522018-09-10 23:51:04 +05302264 class Color(Flag):
2265 BLACK = 0
2266 RED = 1
2267 GREEN = 2
2268 BLUE = 4
2269 PURPLE = RED|BLUE
2270
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002271 def test_str(self):
2272 Perm = self.Perm
2273 self.assertEqual(str(Perm.R), 'Perm.R')
2274 self.assertEqual(str(Perm.W), 'Perm.W')
2275 self.assertEqual(str(Perm.X), 'Perm.X')
2276 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2277 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2278 self.assertEqual(str(Perm(0)), 'Perm.0')
2279 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2280 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2281 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2282 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2283 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2284 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2285
2286 Open = self.Open
2287 self.assertEqual(str(Open.RO), 'Open.RO')
2288 self.assertEqual(str(Open.WO), 'Open.WO')
2289 self.assertEqual(str(Open.AC), 'Open.AC')
2290 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2291 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002292 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002293 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2294 self.assertEqual(str(~Open.AC), 'Open.CE')
2295 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2296 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2297
2298 def test_repr(self):
2299 Perm = self.Perm
2300 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2301 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2302 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2303 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2304 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002305 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002306 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2307 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2308 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2309 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002310 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002311 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2312
2313 Open = self.Open
2314 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2315 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2316 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2317 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2318 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002319 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002320 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2321 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2322 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2323 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2324
Ethan Furman37440ee2020-12-08 11:14:10 -08002325 def test_format(self):
2326 Perm = self.Perm
2327 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2328 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2329
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002330 def test_or(self):
2331 Perm = self.Perm
2332 for i in Perm:
2333 for j in Perm:
2334 self.assertEqual((i | j), Perm(i.value | j.value))
2335 self.assertEqual((i | j).value, i.value | j.value)
2336 self.assertIs(type(i | j), Perm)
2337 for i in Perm:
2338 self.assertIs(i | i, i)
2339 Open = self.Open
2340 self.assertIs(Open.RO | Open.CE, Open.CE)
2341
2342 def test_and(self):
2343 Perm = self.Perm
2344 RW = Perm.R | Perm.W
2345 RX = Perm.R | Perm.X
2346 WX = Perm.W | Perm.X
2347 RWX = Perm.R | Perm.W | Perm.X
2348 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2349 for i in values:
2350 for j in values:
2351 self.assertEqual((i & j).value, i.value & j.value)
2352 self.assertIs(type(i & j), Perm)
2353 for i in Perm:
2354 self.assertIs(i & i, i)
2355 self.assertIs(i & RWX, i)
2356 self.assertIs(RWX & i, i)
2357 Open = self.Open
2358 self.assertIs(Open.RO & Open.CE, Open.RO)
2359
2360 def test_xor(self):
2361 Perm = self.Perm
2362 for i in Perm:
2363 for j in Perm:
2364 self.assertEqual((i ^ j).value, i.value ^ j.value)
2365 self.assertIs(type(i ^ j), Perm)
2366 for i in Perm:
2367 self.assertIs(i ^ Perm(0), i)
2368 self.assertIs(Perm(0) ^ i, i)
2369 Open = self.Open
2370 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2371 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2372
2373 def test_invert(self):
2374 Perm = self.Perm
2375 RW = Perm.R | Perm.W
2376 RX = Perm.R | Perm.X
2377 WX = Perm.W | Perm.X
2378 RWX = Perm.R | Perm.W | Perm.X
2379 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2380 for i in values:
2381 self.assertIs(type(~i), Perm)
2382 self.assertEqual(~~i, i)
2383 for i in Perm:
2384 self.assertIs(~~i, i)
2385 Open = self.Open
2386 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2387 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2388
Ethan Furman25d94bb2016-09-02 16:32:32 -07002389 def test_bool(self):
2390 Perm = self.Perm
2391 for f in Perm:
2392 self.assertTrue(f)
2393 Open = self.Open
2394 for f in Open:
2395 self.assertEqual(bool(f.value), bool(f))
2396
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002397 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002398 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002399 lst = list(Perm)
2400 self.assertEqual(len(lst), len(Perm))
2401 self.assertEqual(len(Perm), 3, Perm)
2402 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2403 for i, n in enumerate('R W X'.split()):
2404 v = 1<<i
2405 e = Perm(v)
2406 self.assertEqual(e.value, v)
2407 self.assertEqual(type(e.value), int)
2408 self.assertEqual(e.name, n)
2409 self.assertIn(e, Perm)
2410 self.assertIs(type(e), Perm)
2411
2412 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002413 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002414 lst = list(Perm)
2415 self.assertEqual(len(lst), len(Perm))
2416 self.assertEqual(len(Perm), 3, Perm)
2417 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2418 for i, n in enumerate('R W X'.split()):
2419 v = 8<<i
2420 e = Perm(v)
2421 self.assertEqual(e.value, v)
2422 self.assertEqual(type(e.value), int)
2423 self.assertEqual(e.name, n)
2424 self.assertIn(e, Perm)
2425 self.assertIs(type(e), Perm)
2426
2427 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002428 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002429 lst = list(Perm)
2430 self.assertEqual(len(lst), len(Perm))
2431 self.assertEqual(len(Perm), 3, Perm)
2432 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2433 for i, n in enumerate('R W X'.split()):
2434 v = 1<<i
2435 e = Perm(v)
2436 self.assertEqual(e.value, v)
2437 self.assertEqual(type(e.value), int)
2438 self.assertEqual(e.name, n)
2439 self.assertIn(e, Perm)
2440 self.assertIs(type(e), Perm)
2441
2442 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002443 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002444 lst = list(Perm)
2445 self.assertEqual(len(lst), len(Perm))
2446 self.assertEqual(len(Perm), 3, Perm)
2447 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2448 for i, n in enumerate('R W X'.split()):
2449 v = 1<<(2*i+1)
2450 e = Perm(v)
2451 self.assertEqual(e.value, v)
2452 self.assertEqual(type(e.value), int)
2453 self.assertEqual(e.name, n)
2454 self.assertIn(e, Perm)
2455 self.assertIs(type(e), Perm)
2456
2457 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002458 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002459 lst = list(Perm)
2460 self.assertEqual(len(lst), len(Perm))
2461 self.assertEqual(len(Perm), 3, Perm)
2462 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2463 for i, n in enumerate('R W X'.split()):
2464 v = 1<<(2*i+1)
2465 e = Perm(v)
2466 self.assertEqual(e.value, v)
2467 self.assertEqual(type(e.value), int)
2468 self.assertEqual(e.name, n)
2469 self.assertIn(e, Perm)
2470 self.assertIs(type(e), Perm)
2471
Ethan Furman65a5a472016-09-01 23:55:19 -07002472 def test_pickle(self):
2473 if isinstance(FlagStooges, Exception):
2474 raise FlagStooges
2475 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2476 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002477
Rahul Jha94306522018-09-10 23:51:04 +05302478 def test_contains(self):
2479 Open = self.Open
2480 Color = self.Color
2481 self.assertFalse(Color.BLACK in Open)
2482 self.assertFalse(Open.RO in Color)
2483 with self.assertRaises(TypeError):
2484 'BLACK' in Color
2485 with self.assertRaises(TypeError):
2486 'RO' in Open
2487 with self.assertRaises(TypeError):
2488 1 in Color
2489 with self.assertRaises(TypeError):
2490 1 in Open
2491
2492 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002493 Perm = self.Perm
2494 R, W, X = Perm
2495 RW = R | W
2496 RX = R | X
2497 WX = W | X
2498 RWX = R | W | X
2499 self.assertTrue(R in RW)
2500 self.assertTrue(R in RX)
2501 self.assertTrue(R in RWX)
2502 self.assertTrue(W in RW)
2503 self.assertTrue(W in WX)
2504 self.assertTrue(W in RWX)
2505 self.assertTrue(X in RX)
2506 self.assertTrue(X in WX)
2507 self.assertTrue(X in RWX)
2508 self.assertFalse(R in WX)
2509 self.assertFalse(W in RX)
2510 self.assertFalse(X in RW)
2511
Ethan Furman7219e272020-09-16 13:01:00 -07002512 def test_member_iter(self):
2513 Color = self.Color
2514 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2515 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2516 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2517
Ethan Furmanc16595e2016-09-10 23:36:59 -07002518 def test_auto_number(self):
2519 class Color(Flag):
2520 red = auto()
2521 blue = auto()
2522 green = auto()
2523
2524 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2525 self.assertEqual(Color.red.value, 1)
2526 self.assertEqual(Color.blue.value, 2)
2527 self.assertEqual(Color.green.value, 4)
2528
2529 def test_auto_number_garbage(self):
2530 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2531 class Color(Flag):
2532 red = 'not an int'
2533 blue = auto()
2534
Ethan Furman3515dcc2016-09-18 13:15:41 -07002535 def test_cascading_failure(self):
2536 class Bizarre(Flag):
2537 c = 3
2538 d = 4
2539 f = 6
2540 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002541 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2542 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2543 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2544 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2545 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2546 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2547 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002548
2549 def test_duplicate_auto(self):
2550 class Dupes(Enum):
2551 first = primero = auto()
2552 second = auto()
2553 third = auto()
2554 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2555
2556 def test_bizarre(self):
2557 class Bizarre(Flag):
2558 b = 3
2559 c = 4
2560 d = 6
2561 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2562
Ethan Furman5bdab642018-09-21 19:03:09 -07002563 def test_multiple_mixin(self):
2564 class AllMixin:
2565 @classproperty
2566 def ALL(cls):
2567 members = list(cls)
2568 all_value = None
2569 if members:
2570 all_value = members[0]
2571 for member in members[1:]:
2572 all_value |= member
2573 cls.ALL = all_value
2574 return all_value
2575 class StrMixin:
2576 def __str__(self):
2577 return self._name_.lower()
2578 class Color(AllMixin, Flag):
2579 RED = auto()
2580 GREEN = auto()
2581 BLUE = auto()
2582 self.assertEqual(Color.RED.value, 1)
2583 self.assertEqual(Color.GREEN.value, 2)
2584 self.assertEqual(Color.BLUE.value, 4)
2585 self.assertEqual(Color.ALL.value, 7)
2586 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2587 class Color(AllMixin, StrMixin, Flag):
2588 RED = auto()
2589 GREEN = auto()
2590 BLUE = auto()
2591 self.assertEqual(Color.RED.value, 1)
2592 self.assertEqual(Color.GREEN.value, 2)
2593 self.assertEqual(Color.BLUE.value, 4)
2594 self.assertEqual(Color.ALL.value, 7)
2595 self.assertEqual(str(Color.BLUE), 'blue')
2596 class Color(StrMixin, AllMixin, Flag):
2597 RED = auto()
2598 GREEN = auto()
2599 BLUE = auto()
2600 self.assertEqual(Color.RED.value, 1)
2601 self.assertEqual(Color.GREEN.value, 2)
2602 self.assertEqual(Color.BLUE.value, 4)
2603 self.assertEqual(Color.ALL.value, 7)
2604 self.assertEqual(str(Color.BLUE), 'blue')
2605
Hai Shie80697d2020-05-28 06:10:27 +08002606 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002607 def test_unique_composite(self):
2608 # override __eq__ to be identity only
2609 class TestFlag(Flag):
2610 one = auto()
2611 two = auto()
2612 three = auto()
2613 four = auto()
2614 five = auto()
2615 six = auto()
2616 seven = auto()
2617 eight = auto()
2618 def __eq__(self, other):
2619 return self is other
2620 def __hash__(self):
2621 return hash(self._value_)
2622 # have multiple threads competing to complete the composite members
2623 seen = set()
2624 failed = False
2625 def cycle_enum():
2626 nonlocal failed
2627 try:
2628 for i in range(256):
2629 seen.add(TestFlag(i))
2630 except Exception:
2631 failed = True
2632 threads = [
2633 threading.Thread(target=cycle_enum)
2634 for _ in range(8)
2635 ]
Hai Shie80697d2020-05-28 06:10:27 +08002636 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002637 pass
2638 # check that only 248 members were created
2639 self.assertFalse(
2640 failed,
2641 'at least one thread failed while creating composite members')
2642 self.assertEqual(256, len(seen), 'too many composite members created')
2643
Ethan Furman6bd94de2020-12-09 16:41:22 -08002644 def test_init_subclass(self):
2645 class MyEnum(Flag):
2646 def __init_subclass__(cls, **kwds):
2647 super().__init_subclass__(**kwds)
2648 self.assertFalse(cls.__dict__.get('_test', False))
2649 cls._test1 = 'MyEnum'
2650 #
2651 class TheirEnum(MyEnum):
2652 def __init_subclass__(cls, **kwds):
2653 super(TheirEnum, cls).__init_subclass__(**kwds)
2654 cls._test2 = 'TheirEnum'
2655 class WhoseEnum(TheirEnum):
2656 def __init_subclass__(cls, **kwds):
2657 pass
2658 class NoEnum(WhoseEnum):
2659 ONE = 1
2660 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2661 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2662 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2663 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2664 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2665 #
2666 class OurEnum(MyEnum):
2667 def __init_subclass__(cls, **kwds):
2668 cls._test2 = 'OurEnum'
2669 class WhereEnum(OurEnum):
2670 def __init_subclass__(cls, **kwds):
2671 pass
2672 class NeverEnum(WhereEnum):
2673 ONE = 1
2674 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2675 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2676 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2677 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2678 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2679
Ethan Furmanc16595e2016-09-10 23:36:59 -07002680
Ethan Furman65a5a472016-09-01 23:55:19 -07002681class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002682 """Tests of the IntFlags."""
2683
Ethan Furman65a5a472016-09-01 23:55:19 -07002684 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002685 X = 1 << 0
2686 W = 1 << 1
2687 R = 1 << 2
2688
Ethan Furman65a5a472016-09-01 23:55:19 -07002689 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002690 RO = 0
2691 WO = 1
2692 RW = 2
2693 AC = 3
2694 CE = 1<<19
2695
Rahul Jha94306522018-09-10 23:51:04 +05302696 class Color(IntFlag):
2697 BLACK = 0
2698 RED = 1
2699 GREEN = 2
2700 BLUE = 4
2701 PURPLE = RED|BLUE
2702
Ethan Furman3515dcc2016-09-18 13:15:41 -07002703 def test_type(self):
2704 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002705 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002706 Open = self.Open
2707 for f in Perm:
2708 self.assertTrue(isinstance(f, Perm))
2709 self.assertEqual(f, f.value)
2710 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2711 self.assertEqual(Perm.W | Perm.X, 3)
2712 for f in Open:
2713 self.assertTrue(isinstance(f, Open))
2714 self.assertEqual(f, f.value)
2715 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2716 self.assertEqual(Open.WO | Open.RW, 3)
2717
2718
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002719 def test_str(self):
2720 Perm = self.Perm
2721 self.assertEqual(str(Perm.R), 'Perm.R')
2722 self.assertEqual(str(Perm.W), 'Perm.W')
2723 self.assertEqual(str(Perm.X), 'Perm.X')
2724 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2725 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2726 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2727 self.assertEqual(str(Perm(0)), 'Perm.0')
2728 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002729 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2730 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2731 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2732 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002733 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002734 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2735 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2736 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002737
2738 Open = self.Open
2739 self.assertEqual(str(Open.RO), 'Open.RO')
2740 self.assertEqual(str(Open.WO), 'Open.WO')
2741 self.assertEqual(str(Open.AC), 'Open.AC')
2742 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2743 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2744 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002745 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2746 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2747 self.assertEqual(str(~Open.AC), 'Open.CE')
2748 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2749 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2750 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002751
2752 def test_repr(self):
2753 Perm = self.Perm
2754 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2755 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2756 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2757 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2758 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2759 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002760 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2761 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002762 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2763 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2764 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2765 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002766 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002767 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2768 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2769 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002770
2771 Open = self.Open
2772 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2773 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2774 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2775 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2776 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002777 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002778 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2779 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2780 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2781 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2782 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2783 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002784
Ethan Furman37440ee2020-12-08 11:14:10 -08002785 def test_format(self):
2786 Perm = self.Perm
2787 self.assertEqual(format(Perm.R, ''), '4')
2788 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2789
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002790 def test_or(self):
2791 Perm = self.Perm
2792 for i in Perm:
2793 for j in Perm:
2794 self.assertEqual(i | j, i.value | j.value)
2795 self.assertEqual((i | j).value, i.value | j.value)
2796 self.assertIs(type(i | j), Perm)
2797 for j in range(8):
2798 self.assertEqual(i | j, i.value | j)
2799 self.assertEqual((i | j).value, i.value | j)
2800 self.assertIs(type(i | j), Perm)
2801 self.assertEqual(j | i, j | i.value)
2802 self.assertEqual((j | i).value, j | i.value)
2803 self.assertIs(type(j | i), Perm)
2804 for i in Perm:
2805 self.assertIs(i | i, i)
2806 self.assertIs(i | 0, i)
2807 self.assertIs(0 | i, i)
2808 Open = self.Open
2809 self.assertIs(Open.RO | Open.CE, Open.CE)
2810
2811 def test_and(self):
2812 Perm = self.Perm
2813 RW = Perm.R | Perm.W
2814 RX = Perm.R | Perm.X
2815 WX = Perm.W | Perm.X
2816 RWX = Perm.R | Perm.W | Perm.X
2817 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2818 for i in values:
2819 for j in values:
2820 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2821 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2822 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2823 for j in range(8):
2824 self.assertEqual(i & j, i.value & j)
2825 self.assertEqual((i & j).value, i.value & j)
2826 self.assertIs(type(i & j), Perm)
2827 self.assertEqual(j & i, j & i.value)
2828 self.assertEqual((j & i).value, j & i.value)
2829 self.assertIs(type(j & i), Perm)
2830 for i in Perm:
2831 self.assertIs(i & i, i)
2832 self.assertIs(i & 7, i)
2833 self.assertIs(7 & i, i)
2834 Open = self.Open
2835 self.assertIs(Open.RO & Open.CE, Open.RO)
2836
2837 def test_xor(self):
2838 Perm = self.Perm
2839 for i in Perm:
2840 for j in Perm:
2841 self.assertEqual(i ^ j, i.value ^ j.value)
2842 self.assertEqual((i ^ j).value, i.value ^ j.value)
2843 self.assertIs(type(i ^ j), Perm)
2844 for j in range(8):
2845 self.assertEqual(i ^ j, i.value ^ j)
2846 self.assertEqual((i ^ j).value, i.value ^ j)
2847 self.assertIs(type(i ^ j), Perm)
2848 self.assertEqual(j ^ i, j ^ i.value)
2849 self.assertEqual((j ^ i).value, j ^ i.value)
2850 self.assertIs(type(j ^ i), Perm)
2851 for i in Perm:
2852 self.assertIs(i ^ 0, i)
2853 self.assertIs(0 ^ i, i)
2854 Open = self.Open
2855 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2856 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2857
2858 def test_invert(self):
2859 Perm = self.Perm
2860 RW = Perm.R | Perm.W
2861 RX = Perm.R | Perm.X
2862 WX = Perm.W | Perm.X
2863 RWX = Perm.R | Perm.W | Perm.X
2864 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2865 for i in values:
2866 self.assertEqual(~i, ~i.value)
2867 self.assertEqual((~i).value, ~i.value)
2868 self.assertIs(type(~i), Perm)
2869 self.assertEqual(~~i, i)
2870 for i in Perm:
2871 self.assertIs(~~i, i)
2872 Open = self.Open
2873 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2874 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2875
2876 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002877 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002878 lst = list(Perm)
2879 self.assertEqual(len(lst), len(Perm))
2880 self.assertEqual(len(Perm), 3, Perm)
2881 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2882 for i, n in enumerate('R W X'.split()):
2883 v = 1<<i
2884 e = Perm(v)
2885 self.assertEqual(e.value, v)
2886 self.assertEqual(type(e.value), int)
2887 self.assertEqual(e, v)
2888 self.assertEqual(e.name, n)
2889 self.assertIn(e, Perm)
2890 self.assertIs(type(e), Perm)
2891
2892 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002893 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002894 lst = list(Perm)
2895 self.assertEqual(len(lst), len(Perm))
2896 self.assertEqual(len(Perm), 3, Perm)
2897 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2898 for i, n in enumerate('R W X'.split()):
2899 v = 8<<i
2900 e = Perm(v)
2901 self.assertEqual(e.value, v)
2902 self.assertEqual(type(e.value), int)
2903 self.assertEqual(e, v)
2904 self.assertEqual(e.name, n)
2905 self.assertIn(e, Perm)
2906 self.assertIs(type(e), Perm)
2907
2908 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002909 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002910 lst = list(Perm)
2911 self.assertEqual(len(lst), len(Perm))
2912 self.assertEqual(len(Perm), 3, Perm)
2913 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2914 for i, n in enumerate('R W X'.split()):
2915 v = 1<<i
2916 e = Perm(v)
2917 self.assertEqual(e.value, v)
2918 self.assertEqual(type(e.value), int)
2919 self.assertEqual(e, v)
2920 self.assertEqual(e.name, n)
2921 self.assertIn(e, Perm)
2922 self.assertIs(type(e), Perm)
2923
2924 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002925 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002926 lst = list(Perm)
2927 self.assertEqual(len(lst), len(Perm))
2928 self.assertEqual(len(Perm), 3, Perm)
2929 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2930 for i, n in enumerate('R W X'.split()):
2931 v = 1<<(2*i+1)
2932 e = Perm(v)
2933 self.assertEqual(e.value, v)
2934 self.assertEqual(type(e.value), int)
2935 self.assertEqual(e, v)
2936 self.assertEqual(e.name, n)
2937 self.assertIn(e, Perm)
2938 self.assertIs(type(e), Perm)
2939
2940 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002941 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002942 lst = list(Perm)
2943 self.assertEqual(len(lst), len(Perm))
2944 self.assertEqual(len(Perm), 3, Perm)
2945 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2946 for i, n in enumerate('R W X'.split()):
2947 v = 1<<(2*i+1)
2948 e = Perm(v)
2949 self.assertEqual(e.value, v)
2950 self.assertEqual(type(e.value), int)
2951 self.assertEqual(e, v)
2952 self.assertEqual(e.name, n)
2953 self.assertIn(e, Perm)
2954 self.assertIs(type(e), Perm)
2955
2956
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002957 def test_programatic_function_from_empty_list(self):
2958 Perm = enum.IntFlag('Perm', [])
2959 lst = list(Perm)
2960 self.assertEqual(len(lst), len(Perm))
2961 self.assertEqual(len(Perm), 0, Perm)
2962 Thing = enum.Enum('Thing', [])
2963 lst = list(Thing)
2964 self.assertEqual(len(lst), len(Thing))
2965 self.assertEqual(len(Thing), 0, Thing)
2966
2967
2968 def test_programatic_function_from_empty_tuple(self):
2969 Perm = enum.IntFlag('Perm', ())
2970 lst = list(Perm)
2971 self.assertEqual(len(lst), len(Perm))
2972 self.assertEqual(len(Perm), 0, Perm)
2973 Thing = enum.Enum('Thing', ())
2974 self.assertEqual(len(lst), len(Thing))
2975 self.assertEqual(len(Thing), 0, Thing)
2976
Rahul Jha94306522018-09-10 23:51:04 +05302977 def test_contains(self):
2978 Open = self.Open
2979 Color = self.Color
2980 self.assertTrue(Color.GREEN in Color)
2981 self.assertTrue(Open.RW in Open)
2982 self.assertFalse(Color.GREEN in Open)
2983 self.assertFalse(Open.RW in Color)
2984 with self.assertRaises(TypeError):
2985 'GREEN' in Color
2986 with self.assertRaises(TypeError):
2987 'RW' in Open
2988 with self.assertRaises(TypeError):
2989 2 in Color
2990 with self.assertRaises(TypeError):
2991 2 in Open
2992
2993 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002994 Perm = self.Perm
2995 R, W, X = Perm
2996 RW = R | W
2997 RX = R | X
2998 WX = W | X
2999 RWX = R | W | X
3000 self.assertTrue(R in RW)
3001 self.assertTrue(R in RX)
3002 self.assertTrue(R in RWX)
3003 self.assertTrue(W in RW)
3004 self.assertTrue(W in WX)
3005 self.assertTrue(W in RWX)
3006 self.assertTrue(X in RX)
3007 self.assertTrue(X in WX)
3008 self.assertTrue(X in RWX)
3009 self.assertFalse(R in WX)
3010 self.assertFalse(W in RX)
3011 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303012 with self.assertRaises(TypeError):
3013 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003014
Ethan Furman7219e272020-09-16 13:01:00 -07003015 def test_member_iter(self):
3016 Color = self.Color
3017 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
3018 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3019 self.assertEqual(list(Color.GREEN), [Color.GREEN])
3020
Ethan Furman25d94bb2016-09-02 16:32:32 -07003021 def test_bool(self):
3022 Perm = self.Perm
3023 for f in Perm:
3024 self.assertTrue(f)
3025 Open = self.Open
3026 for f in Open:
3027 self.assertEqual(bool(f.value), bool(f))
3028
Ethan Furman5bdab642018-09-21 19:03:09 -07003029 def test_multiple_mixin(self):
3030 class AllMixin:
3031 @classproperty
3032 def ALL(cls):
3033 members = list(cls)
3034 all_value = None
3035 if members:
3036 all_value = members[0]
3037 for member in members[1:]:
3038 all_value |= member
3039 cls.ALL = all_value
3040 return all_value
3041 class StrMixin:
3042 def __str__(self):
3043 return self._name_.lower()
3044 class Color(AllMixin, IntFlag):
3045 RED = auto()
3046 GREEN = auto()
3047 BLUE = auto()
3048 self.assertEqual(Color.RED.value, 1)
3049 self.assertEqual(Color.GREEN.value, 2)
3050 self.assertEqual(Color.BLUE.value, 4)
3051 self.assertEqual(Color.ALL.value, 7)
3052 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3053 class Color(AllMixin, StrMixin, IntFlag):
3054 RED = auto()
3055 GREEN = auto()
3056 BLUE = auto()
3057 self.assertEqual(Color.RED.value, 1)
3058 self.assertEqual(Color.GREEN.value, 2)
3059 self.assertEqual(Color.BLUE.value, 4)
3060 self.assertEqual(Color.ALL.value, 7)
3061 self.assertEqual(str(Color.BLUE), 'blue')
3062 class Color(StrMixin, AllMixin, IntFlag):
3063 RED = auto()
3064 GREEN = auto()
3065 BLUE = auto()
3066 self.assertEqual(Color.RED.value, 1)
3067 self.assertEqual(Color.GREEN.value, 2)
3068 self.assertEqual(Color.BLUE.value, 4)
3069 self.assertEqual(Color.ALL.value, 7)
3070 self.assertEqual(str(Color.BLUE), 'blue')
3071
Hai Shie80697d2020-05-28 06:10:27 +08003072 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003073 def test_unique_composite(self):
3074 # override __eq__ to be identity only
3075 class TestFlag(IntFlag):
3076 one = auto()
3077 two = auto()
3078 three = auto()
3079 four = auto()
3080 five = auto()
3081 six = auto()
3082 seven = auto()
3083 eight = auto()
3084 def __eq__(self, other):
3085 return self is other
3086 def __hash__(self):
3087 return hash(self._value_)
3088 # have multiple threads competing to complete the composite members
3089 seen = set()
3090 failed = False
3091 def cycle_enum():
3092 nonlocal failed
3093 try:
3094 for i in range(256):
3095 seen.add(TestFlag(i))
3096 except Exception:
3097 failed = True
3098 threads = [
3099 threading.Thread(target=cycle_enum)
3100 for _ in range(8)
3101 ]
Hai Shie80697d2020-05-28 06:10:27 +08003102 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003103 pass
3104 # check that only 248 members were created
3105 self.assertFalse(
3106 failed,
3107 'at least one thread failed while creating composite members')
3108 self.assertEqual(256, len(seen), 'too many composite members created')
3109
3110
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003111class TestEmptyAndNonLatinStrings(unittest.TestCase):
3112
3113 def test_empty_string(self):
3114 with self.assertRaises(ValueError):
3115 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3116
3117 def test_non_latin_character_string(self):
3118 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3119 item = getattr(greek_abc, '\u03B1')
3120 self.assertEqual(item.value, 1)
3121
3122 def test_non_latin_number_string(self):
3123 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3124 item = getattr(hebrew_123, '\u05D0')
3125 self.assertEqual(item.value, 1)
3126
3127
Ethan Furmanf24bb352013-07-18 17:05:39 -07003128class TestUnique(unittest.TestCase):
3129
3130 def test_unique_clean(self):
3131 @unique
3132 class Clean(Enum):
3133 one = 1
3134 two = 'dos'
3135 tres = 4.0
3136 @unique
3137 class Cleaner(IntEnum):
3138 single = 1
3139 double = 2
3140 triple = 3
3141
3142 def test_unique_dirty(self):
3143 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3144 @unique
3145 class Dirty(Enum):
3146 one = 1
3147 two = 'dos'
3148 tres = 1
3149 with self.assertRaisesRegex(
3150 ValueError,
3151 'double.*single.*turkey.*triple',
3152 ):
3153 @unique
3154 class Dirtier(IntEnum):
3155 single = 1
3156 double = 1
3157 triple = 3
3158 turkey = 3
3159
Ethan Furman3803ad42016-05-01 10:03:53 -07003160 def test_unique_with_name(self):
3161 @unique
3162 class Silly(Enum):
3163 one = 1
3164 two = 'dos'
3165 name = 3
3166 @unique
3167 class Sillier(IntEnum):
3168 single = 1
3169 name = 2
3170 triple = 3
3171 value = 4
3172
Ethan Furmanf24bb352013-07-18 17:05:39 -07003173
Ethan Furman5bdab642018-09-21 19:03:09 -07003174
Ethan Furman3323da92015-04-11 09:39:59 -07003175expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003176Help on class Color in module %s:
3177
3178class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003179 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3180 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003181 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003182 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003183 | Method resolution order:
3184 | Color
3185 | enum.Enum
3186 | builtins.object
3187 |\x20\x20
3188 | Data and other attributes defined here:
3189 |\x20\x20
3190 | blue = <Color.blue: 3>
3191 |\x20\x20
3192 | green = <Color.green: 2>
3193 |\x20\x20
3194 | red = <Color.red: 1>
3195 |\x20\x20
3196 | ----------------------------------------------------------------------
3197 | Data descriptors inherited from enum.Enum:
3198 |\x20\x20
3199 | name
3200 | The name of the Enum member.
3201 |\x20\x20
3202 | value
3203 | The value of the Enum member.
3204 |\x20\x20
3205 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003206 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003207 |\x20\x20
3208 | __members__
3209 | Returns a mapping of member name->value.
3210 |\x20\x20\x20\x20\x20\x20
3211 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003212 | is a read-only view of the internal mapping."""
3213
3214expected_help_output_without_docs = """\
3215Help on class Color in module %s:
3216
3217class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003218 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3219 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003220 | Method resolution order:
3221 | Color
3222 | enum.Enum
3223 | builtins.object
3224 |\x20\x20
3225 | Data and other attributes defined here:
3226 |\x20\x20
3227 | blue = <Color.blue: 3>
3228 |\x20\x20
3229 | green = <Color.green: 2>
3230 |\x20\x20
3231 | red = <Color.red: 1>
3232 |\x20\x20
3233 | ----------------------------------------------------------------------
3234 | Data descriptors inherited from enum.Enum:
3235 |\x20\x20
3236 | name
3237 |\x20\x20
3238 | value
3239 |\x20\x20
3240 | ----------------------------------------------------------------------
3241 | Data descriptors inherited from enum.EnumMeta:
3242 |\x20\x20
3243 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003244
3245class TestStdLib(unittest.TestCase):
3246
Ethan Furman48a724f2015-04-11 23:23:06 -07003247 maxDiff = None
3248
Ethan Furman5875d742013-10-21 20:45:55 -07003249 class Color(Enum):
3250 red = 1
3251 green = 2
3252 blue = 3
3253
3254 def test_pydoc(self):
3255 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003256 if StrEnum.__doc__ is None:
3257 expected_text = expected_help_output_without_docs % __name__
3258 else:
3259 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003260 output = StringIO()
3261 helper = pydoc.Helper(output=output)
3262 helper(self.Color)
3263 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003264 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003265
3266 def test_inspect_getmembers(self):
3267 values = dict((
3268 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003269 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003270 ('__members__', self.Color.__members__),
3271 ('__module__', __name__),
3272 ('blue', self.Color.blue),
3273 ('green', self.Color.green),
3274 ('name', Enum.__dict__['name']),
3275 ('red', self.Color.red),
3276 ('value', Enum.__dict__['value']),
3277 ))
3278 result = dict(inspect.getmembers(self.Color))
Ethan Furmanc314e602021-01-12 23:47:57 -08003279 self.assertEqual(set(values.keys()), set(result.keys()))
Ethan Furman5875d742013-10-21 20:45:55 -07003280 failed = False
3281 for k in values.keys():
3282 if result[k] != values[k]:
3283 print()
3284 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3285 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3286 failed = True
3287 if failed:
3288 self.fail("result does not equal expected, see print above")
3289
3290 def test_inspect_classify_class_attrs(self):
3291 # indirectly test __objclass__
3292 from inspect import Attribute
3293 values = [
3294 Attribute(name='__class__', kind='data',
3295 defining_class=object, object=EnumMeta),
3296 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003297 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003298 Attribute(name='__members__', kind='property',
3299 defining_class=EnumMeta, object=EnumMeta.__members__),
3300 Attribute(name='__module__', kind='data',
3301 defining_class=self.Color, object=__name__),
3302 Attribute(name='blue', kind='data',
3303 defining_class=self.Color, object=self.Color.blue),
3304 Attribute(name='green', kind='data',
3305 defining_class=self.Color, object=self.Color.green),
3306 Attribute(name='red', kind='data',
3307 defining_class=self.Color, object=self.Color.red),
3308 Attribute(name='name', kind='data',
3309 defining_class=Enum, object=Enum.__dict__['name']),
3310 Attribute(name='value', kind='data',
3311 defining_class=Enum, object=Enum.__dict__['value']),
3312 ]
3313 values.sort(key=lambda item: item.name)
3314 result = list(inspect.classify_class_attrs(self.Color))
3315 result.sort(key=lambda item: item.name)
Ethan Furmanc314e602021-01-12 23:47:57 -08003316 self.assertEqual(
3317 len(values), len(result),
3318 "%s != %s" % ([a.name for a in values], [a.name for a in result])
3319 )
Ethan Furman5875d742013-10-21 20:45:55 -07003320 failed = False
3321 for v, r in zip(values, result):
3322 if r != v:
3323 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3324 failed = True
3325 if failed:
3326 self.fail("result does not equal expected, see print above")
3327
Martin Panter19e69c52015-11-14 12:46:42 +00003328
3329class MiscTestCase(unittest.TestCase):
3330 def test__all__(self):
3331 support.check__all__(self, enum)
3332
3333
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003334# These are unordered here on purpose to ensure that declaration order
3335# makes no difference.
3336CONVERT_TEST_NAME_D = 5
3337CONVERT_TEST_NAME_C = 5
3338CONVERT_TEST_NAME_B = 5
3339CONVERT_TEST_NAME_A = 5 # This one should sort first.
3340CONVERT_TEST_NAME_E = 5
3341CONVERT_TEST_NAME_F = 5
3342
3343class TestIntEnumConvert(unittest.TestCase):
3344 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003345 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003346 'UnittestConvert',
3347 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003348 filter=lambda x: x.startswith('CONVERT_TEST_'))
3349 # We don't want the reverse lookup value to vary when there are
3350 # multiple possible names for a given value. It should always
3351 # report the first lexigraphical name in that case.
3352 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3353
3354 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003355 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003356 'UnittestConvert',
3357 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003358 filter=lambda x: x.startswith('CONVERT_TEST_'))
3359 # Ensure that test_type has all of the desired names and values.
3360 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3361 test_type.CONVERT_TEST_NAME_A)
3362 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3363 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3364 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3365 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3366 # Ensure that test_type only picked up names matching the filter.
3367 self.assertEqual([name for name in dir(test_type)
3368 if name[0:2] not in ('CO', '__')],
3369 [], msg='Names other than CONVERT_TEST_* found.')
3370
orlnub1230fb9fad2018-09-12 20:28:53 +03003371 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3372 '_convert was deprecated in 3.8')
3373 def test_convert_warn(self):
3374 with self.assertWarns(DeprecationWarning):
3375 enum.IntEnum._convert(
3376 'UnittestConvert',
3377 ('test.test_enum', '__main__')[__name__=='__main__'],
3378 filter=lambda x: x.startswith('CONVERT_TEST_'))
3379
3380 @unittest.skipUnless(sys.version_info >= (3, 9),
3381 '_convert was removed in 3.9')
3382 def test_convert_raise(self):
3383 with self.assertRaises(AttributeError):
3384 enum.IntEnum._convert(
3385 'UnittestConvert',
3386 ('test.test_enum', '__main__')[__name__=='__main__'],
3387 filter=lambda x: x.startswith('CONVERT_TEST_'))
3388
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003389
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003390if __name__ == '__main__':
3391 unittest.main()