blob: 3f39073f5d564ed8305f6ba7837af671f81088f2 [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 Furmanc16595e2016-09-10 23:36:59 -07008from enum import Enum, IntEnum, 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
51try:
52 class StrEnum(str, Enum):
53 'accepts only string values'
54 class Name(StrEnum):
55 BDFL = 'Guido van Rossum'
56 FLUFL = 'Barry Warsaw'
57except Exception as exc:
58 Name = exc
59
60try:
61 Question = Enum('Question', 'who what when where why', module=__name__)
62except Exception as exc:
63 Question = exc
64
65try:
66 Answer = Enum('Answer', 'him this then there because')
67except Exception as exc:
68 Answer = exc
69
Ethan Furmanca1b7942014-02-08 11:36:27 -080070try:
71 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
72except Exception as exc:
73 Theory = exc
74
Ethan Furman6b3d64a2013-06-14 16:55:46 -070075# for doctests
76try:
77 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080078 TOMATO = 1
79 BANANA = 2
80 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081except Exception:
82 pass
83
Serhiy Storchakae50e7802015-03-31 16:56:49 +030084def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080085 if target is None:
86 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030087 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080088 assertion(loads(dumps(source, protocol=protocol)), target)
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_exception(assertion, exception, obj):
91 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080092 with assertion(exception):
93 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070094
95class TestHelpers(unittest.TestCase):
96 # _is_descriptor, _is_sunder, _is_dunder
97
98 def test_is_descriptor(self):
99 class foo:
100 pass
101 for attr in ('__get__','__set__','__delete__'):
102 obj = foo()
103 self.assertFalse(enum._is_descriptor(obj))
104 setattr(obj, attr, 1)
105 self.assertTrue(enum._is_descriptor(obj))
106
107 def test_is_sunder(self):
108 for s in ('_a_', '_aa_'):
109 self.assertTrue(enum._is_sunder(s))
110
111 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
112 '__', '___', '____', '_____',):
113 self.assertFalse(enum._is_sunder(s))
114
115 def test_is_dunder(self):
116 for s in ('__a__', '__aa__'):
117 self.assertTrue(enum._is_dunder(s))
118 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
119 '__', '___', '____', '_____',):
120 self.assertFalse(enum._is_dunder(s))
121
Ethan Furman5bdab642018-09-21 19:03:09 -0700122# for subclassing tests
123
124class classproperty:
125
126 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
127 self.fget = fget
128 self.fset = fset
129 self.fdel = fdel
130 if doc is None and fget is not None:
131 doc = fget.__doc__
132 self.__doc__ = doc
133
134 def __get__(self, instance, ownerclass):
135 return self.fget(ownerclass)
136
137
Ethan Furmanc16595e2016-09-10 23:36:59 -0700138# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700139
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700140class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800141
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700142 def setUp(self):
143 class Season(Enum):
144 SPRING = 1
145 SUMMER = 2
146 AUTUMN = 3
147 WINTER = 4
148 self.Season = Season
149
Ethan Furmanec15a822013-08-31 19:17:41 -0700150 class Konstants(float, Enum):
151 E = 2.7182818
152 PI = 3.1415926
153 TAU = 2 * PI
154 self.Konstants = Konstants
155
156 class Grades(IntEnum):
157 A = 5
158 B = 4
159 C = 3
160 D = 2
161 F = 0
162 self.Grades = Grades
163
164 class Directional(str, Enum):
165 EAST = 'east'
166 WEST = 'west'
167 NORTH = 'north'
168 SOUTH = 'south'
169 self.Directional = Directional
170
171 from datetime import date
172 class Holiday(date, Enum):
173 NEW_YEAR = 2013, 1, 1
174 IDES_OF_MARCH = 2013, 3, 15
175 self.Holiday = Holiday
176
Ethan Furman388a3922013-08-12 06:51:41 -0700177 def test_dir_on_class(self):
178 Season = self.Season
179 self.assertEqual(
180 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700181 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700182 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
183 )
184
185 def test_dir_on_item(self):
186 Season = self.Season
187 self.assertEqual(
188 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700189 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700190 )
191
Ethan Furmanc850f342013-09-15 16:59:35 -0700192 def test_dir_with_added_behavior(self):
193 class Test(Enum):
194 this = 'that'
195 these = 'those'
196 def wowser(self):
197 return ("Wowser! I'm %s!" % self.name)
198 self.assertEqual(
199 set(dir(Test)),
200 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
201 )
202 self.assertEqual(
203 set(dir(Test.this)),
204 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
205 )
206
Ethan Furman0ae550b2014-10-14 08:58:32 -0700207 def test_dir_on_sub_with_behavior_on_super(self):
208 # see issue22506
209 class SuperEnum(Enum):
210 def invisible(self):
211 return "did you see me?"
212 class SubEnum(SuperEnum):
213 sample = 5
214 self.assertEqual(
215 set(dir(SubEnum.sample)),
216 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
217 )
218
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200219 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
220 # see issue40084
221 class SuperEnum(IntEnum):
222 def __new__(cls, value, description=""):
223 obj = int.__new__(cls, value)
224 obj._value_ = value
225 obj.description = description
226 return obj
227 class SubEnum(SuperEnum):
228 sample = 5
229 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
230
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700231 def test_enum_in_enum_out(self):
232 Season = self.Season
233 self.assertIs(Season(Season.WINTER), Season.WINTER)
234
235 def test_enum_value(self):
236 Season = self.Season
237 self.assertEqual(Season.SPRING.value, 1)
238
239 def test_intenum_value(self):
240 self.assertEqual(IntStooges.CURLY.value, 2)
241
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700242 def test_enum(self):
243 Season = self.Season
244 lst = list(Season)
245 self.assertEqual(len(lst), len(Season))
246 self.assertEqual(len(Season), 4, Season)
247 self.assertEqual(
248 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
249
250 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
251 e = Season(i)
252 self.assertEqual(e, getattr(Season, season))
253 self.assertEqual(e.value, i)
254 self.assertNotEqual(e, i)
255 self.assertEqual(e.name, season)
256 self.assertIn(e, Season)
257 self.assertIs(type(e), Season)
258 self.assertIsInstance(e, Season)
259 self.assertEqual(str(e), 'Season.' + season)
260 self.assertEqual(
261 repr(e),
262 '<Season.{0}: {1}>'.format(season, i),
263 )
264
265 def test_value_name(self):
266 Season = self.Season
267 self.assertEqual(Season.SPRING.name, 'SPRING')
268 self.assertEqual(Season.SPRING.value, 1)
269 with self.assertRaises(AttributeError):
270 Season.SPRING.name = 'invierno'
271 with self.assertRaises(AttributeError):
272 Season.SPRING.value = 2
273
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700274 def test_changing_member(self):
275 Season = self.Season
276 with self.assertRaises(AttributeError):
277 Season.WINTER = 'really cold'
278
Ethan Furman64a99722013-09-22 16:18:19 -0700279 def test_attribute_deletion(self):
280 class Season(Enum):
281 SPRING = 1
282 SUMMER = 2
283 AUTUMN = 3
284 WINTER = 4
285
286 def spam(cls):
287 pass
288
289 self.assertTrue(hasattr(Season, 'spam'))
290 del Season.spam
291 self.assertFalse(hasattr(Season, 'spam'))
292
293 with self.assertRaises(AttributeError):
294 del Season.SPRING
295 with self.assertRaises(AttributeError):
296 del Season.DRY
297 with self.assertRaises(AttributeError):
298 del Season.SPRING.name
299
Ethan Furman5de67b12016-04-13 23:52:09 -0700300 def test_bool_of_class(self):
301 class Empty(Enum):
302 pass
303 self.assertTrue(bool(Empty))
304
305 def test_bool_of_member(self):
306 class Count(Enum):
307 zero = 0
308 one = 1
309 two = 2
310 for member in Count:
311 self.assertTrue(bool(member))
312
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700313 def test_invalid_names(self):
314 with self.assertRaises(ValueError):
315 class Wrong(Enum):
316 mro = 9
317 with self.assertRaises(ValueError):
318 class Wrong(Enum):
319 _create_= 11
320 with self.assertRaises(ValueError):
321 class Wrong(Enum):
322 _get_mixins_ = 9
323 with self.assertRaises(ValueError):
324 class Wrong(Enum):
325 _find_new_ = 1
326 with self.assertRaises(ValueError):
327 class Wrong(Enum):
328 _any_name_ = 9
329
Ethan Furman6db1fd52015-09-17 21:49:12 -0700330 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800331 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700332 class Logic(Enum):
333 true = True
334 false = False
335 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800336 self.assertTrue(Logic.false)
337 # unless overridden
338 class RealLogic(Enum):
339 true = True
340 false = False
341 def __bool__(self):
342 return bool(self._value_)
343 self.assertTrue(RealLogic.true)
344 self.assertFalse(RealLogic.false)
345 # mixed Enums depend on mixed-in type
346 class IntLogic(int, Enum):
347 true = 1
348 false = 0
349 self.assertTrue(IntLogic.true)
350 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700351
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700352 def test_contains(self):
353 Season = self.Season
354 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530355 with self.assertRaises(TypeError):
356 3 in Season
357 with self.assertRaises(TypeError):
358 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700359
360 val = Season(3)
361 self.assertIn(val, Season)
362
363 class OtherEnum(Enum):
364 one = 1; two = 2
365 self.assertNotIn(OtherEnum.two, Season)
366
367 def test_comparisons(self):
368 Season = self.Season
369 with self.assertRaises(TypeError):
370 Season.SPRING < Season.WINTER
371 with self.assertRaises(TypeError):
372 Season.SPRING > 4
373
374 self.assertNotEqual(Season.SPRING, 1)
375
376 class Part(Enum):
377 SPRING = 1
378 CLIP = 2
379 BARREL = 3
380
381 self.assertNotEqual(Season.SPRING, Part.SPRING)
382 with self.assertRaises(TypeError):
383 Season.SPRING < Part.CLIP
384
385 def test_enum_duplicates(self):
386 class Season(Enum):
387 SPRING = 1
388 SUMMER = 2
389 AUTUMN = FALL = 3
390 WINTER = 4
391 ANOTHER_SPRING = 1
392 lst = list(Season)
393 self.assertEqual(
394 lst,
395 [Season.SPRING, Season.SUMMER,
396 Season.AUTUMN, Season.WINTER,
397 ])
398 self.assertIs(Season.FALL, Season.AUTUMN)
399 self.assertEqual(Season.FALL.value, 3)
400 self.assertEqual(Season.AUTUMN.value, 3)
401 self.assertIs(Season(3), Season.AUTUMN)
402 self.assertIs(Season(1), Season.SPRING)
403 self.assertEqual(Season.FALL.name, 'AUTUMN')
404 self.assertEqual(
405 [k for k,v in Season.__members__.items() if v.name != k],
406 ['FALL', 'ANOTHER_SPRING'],
407 )
408
Ethan Furman101e0742013-09-15 12:34:36 -0700409 def test_duplicate_name(self):
410 with self.assertRaises(TypeError):
411 class Color(Enum):
412 red = 1
413 green = 2
414 blue = 3
415 red = 4
416
417 with self.assertRaises(TypeError):
418 class Color(Enum):
419 red = 1
420 green = 2
421 blue = 3
422 def red(self):
423 return 'red'
424
425 with self.assertRaises(TypeError):
426 class Color(Enum):
427 @property
428 def red(self):
429 return 'redder'
430 red = 1
431 green = 2
432 blue = 3
433
Zackery Spytz2ec67522020-09-13 14:27:51 -0600434 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700435 with self.assertRaisesRegex(
436 ValueError,
437 '_sunder_ names, such as "_bad_", are reserved',
438 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600439 class Bad(Enum):
440 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700441
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700442 def test_enum_with_value_name(self):
443 class Huh(Enum):
444 name = 1
445 value = 2
446 self.assertEqual(
447 list(Huh),
448 [Huh.name, Huh.value],
449 )
450 self.assertIs(type(Huh.name), Huh)
451 self.assertEqual(Huh.name.name, 'name')
452 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700453
454 def test_format_enum(self):
455 Season = self.Season
456 self.assertEqual('{}'.format(Season.SPRING),
457 '{}'.format(str(Season.SPRING)))
458 self.assertEqual( '{:}'.format(Season.SPRING),
459 '{:}'.format(str(Season.SPRING)))
460 self.assertEqual('{:20}'.format(Season.SPRING),
461 '{:20}'.format(str(Season.SPRING)))
462 self.assertEqual('{:^20}'.format(Season.SPRING),
463 '{:^20}'.format(str(Season.SPRING)))
464 self.assertEqual('{:>20}'.format(Season.SPRING),
465 '{:>20}'.format(str(Season.SPRING)))
466 self.assertEqual('{:<20}'.format(Season.SPRING),
467 '{:<20}'.format(str(Season.SPRING)))
468
thatneat2f19e822019-07-04 11:28:37 -0700469 def test_str_override_enum(self):
470 class EnumWithStrOverrides(Enum):
471 one = auto()
472 two = auto()
473
474 def __str__(self):
475 return 'Str!'
476 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
477 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
478
479 def test_format_override_enum(self):
480 class EnumWithFormatOverride(Enum):
481 one = 1.0
482 two = 2.0
483 def __format__(self, spec):
484 return 'Format!!'
485 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
486 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
487
488 def test_str_and_format_override_enum(self):
489 class EnumWithStrFormatOverrides(Enum):
490 one = auto()
491 two = auto()
492 def __str__(self):
493 return 'Str!'
494 def __format__(self, spec):
495 return 'Format!'
496 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
497 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
498
499 def test_str_override_mixin(self):
500 class MixinEnumWithStrOverride(float, Enum):
501 one = 1.0
502 two = 2.0
503 def __str__(self):
504 return 'Overridden!'
505 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
506 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
507
508 def test_str_and_format_override_mixin(self):
509 class MixinWithStrFormatOverrides(float, Enum):
510 one = 1.0
511 two = 2.0
512 def __str__(self):
513 return 'Str!'
514 def __format__(self, spec):
515 return 'Format!'
516 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
517 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
518
519 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700520 class TestFloat(float, Enum):
521 one = 1.0
522 two = 2.0
523 def __format__(self, spec):
524 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700525 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700526 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
527
528 def assertFormatIsValue(self, spec, member):
529 self.assertEqual(spec.format(member), spec.format(member.value))
530
531 def test_format_enum_date(self):
532 Holiday = self.Holiday
533 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
534 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
535 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
536 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
537 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
538 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
539 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
540 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
541
542 def test_format_enum_float(self):
543 Konstants = self.Konstants
544 self.assertFormatIsValue('{}', Konstants.TAU)
545 self.assertFormatIsValue('{:}', Konstants.TAU)
546 self.assertFormatIsValue('{:20}', Konstants.TAU)
547 self.assertFormatIsValue('{:^20}', Konstants.TAU)
548 self.assertFormatIsValue('{:>20}', Konstants.TAU)
549 self.assertFormatIsValue('{:<20}', Konstants.TAU)
550 self.assertFormatIsValue('{:n}', Konstants.TAU)
551 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
552 self.assertFormatIsValue('{:f}', Konstants.TAU)
553
554 def test_format_enum_int(self):
555 Grades = self.Grades
556 self.assertFormatIsValue('{}', Grades.C)
557 self.assertFormatIsValue('{:}', Grades.C)
558 self.assertFormatIsValue('{:20}', Grades.C)
559 self.assertFormatIsValue('{:^20}', Grades.C)
560 self.assertFormatIsValue('{:>20}', Grades.C)
561 self.assertFormatIsValue('{:<20}', Grades.C)
562 self.assertFormatIsValue('{:+}', Grades.C)
563 self.assertFormatIsValue('{:08X}', Grades.C)
564 self.assertFormatIsValue('{:b}', Grades.C)
565
566 def test_format_enum_str(self):
567 Directional = self.Directional
568 self.assertFormatIsValue('{}', Directional.WEST)
569 self.assertFormatIsValue('{:}', Directional.WEST)
570 self.assertFormatIsValue('{:20}', Directional.WEST)
571 self.assertFormatIsValue('{:^20}', Directional.WEST)
572 self.assertFormatIsValue('{:>20}', Directional.WEST)
573 self.assertFormatIsValue('{:<20}', Directional.WEST)
574
Ethan Furman22415ad2020-09-15 16:28:25 -0700575 def test_object_str_override(self):
576 class Colors(Enum):
577 RED, GREEN, BLUE = 1, 2, 3
578 def __repr__(self):
579 return "test.%s" % (self._name_, )
580 __str__ = object.__str__
581 self.assertEqual(str(Colors.RED), 'test.RED')
582
Ethan Furmanbff01f32020-09-15 15:56:26 -0700583 def test_enum_str_override(self):
584 class MyStrEnum(Enum):
585 def __str__(self):
586 return 'MyStr'
587 class MyMethodEnum(Enum):
588 def hello(self):
589 return 'Hello! My name is %s' % self.name
590 class Test1Enum(MyMethodEnum, int, MyStrEnum):
591 One = 1
592 Two = 2
593 self.assertEqual(str(Test1Enum.One), 'MyStr')
594 #
595 class Test2Enum(MyStrEnum, MyMethodEnum):
596 One = 1
597 Two = 2
598 self.assertEqual(str(Test2Enum.One), 'MyStr')
599
600 def test_inherited_data_type(self):
601 class HexInt(int):
602 def __repr__(self):
603 return hex(self)
604 class MyEnum(HexInt, enum.Enum):
605 A = 1
606 B = 2
607 C = 3
608 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
609
610 def test_too_many_data_types(self):
611 with self.assertRaisesRegex(TypeError, 'too many data types'):
612 class Huh(str, int, Enum):
613 One = 1
614
615 class MyStr(str):
616 def hello(self):
617 return 'hello, %s' % self
618 class MyInt(int):
619 def repr(self):
620 return hex(self)
621 with self.assertRaisesRegex(TypeError, 'too many data types'):
622 class Huh(MyStr, MyInt, Enum):
623 One = 1
624
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700625 def test_hash(self):
626 Season = self.Season
627 dates = {}
628 dates[Season.WINTER] = '1225'
629 dates[Season.SPRING] = '0315'
630 dates[Season.SUMMER] = '0704'
631 dates[Season.AUTUMN] = '1031'
632 self.assertEqual(dates[Season.AUTUMN], '1031')
633
634 def test_intenum_from_scratch(self):
635 class phy(int, Enum):
636 pi = 3
637 tau = 2 * pi
638 self.assertTrue(phy.pi < phy.tau)
639
640 def test_intenum_inherited(self):
641 class IntEnum(int, Enum):
642 pass
643 class phy(IntEnum):
644 pi = 3
645 tau = 2 * pi
646 self.assertTrue(phy.pi < phy.tau)
647
648 def test_floatenum_from_scratch(self):
649 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700650 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700651 tau = 2 * pi
652 self.assertTrue(phy.pi < phy.tau)
653
654 def test_floatenum_inherited(self):
655 class FloatEnum(float, Enum):
656 pass
657 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700658 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700659 tau = 2 * pi
660 self.assertTrue(phy.pi < phy.tau)
661
662 def test_strenum_from_scratch(self):
663 class phy(str, Enum):
664 pi = 'Pi'
665 tau = 'Tau'
666 self.assertTrue(phy.pi < phy.tau)
667
668 def test_strenum_inherited(self):
669 class StrEnum(str, Enum):
670 pass
671 class phy(StrEnum):
672 pi = 'Pi'
673 tau = 'Tau'
674 self.assertTrue(phy.pi < phy.tau)
675
676
677 def test_intenum(self):
678 class WeekDay(IntEnum):
679 SUNDAY = 1
680 MONDAY = 2
681 TUESDAY = 3
682 WEDNESDAY = 4
683 THURSDAY = 5
684 FRIDAY = 6
685 SATURDAY = 7
686
687 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
688 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
689
690 lst = list(WeekDay)
691 self.assertEqual(len(lst), len(WeekDay))
692 self.assertEqual(len(WeekDay), 7)
693 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
694 target = target.split()
695 for i, weekday in enumerate(target, 1):
696 e = WeekDay(i)
697 self.assertEqual(e, i)
698 self.assertEqual(int(e), i)
699 self.assertEqual(e.name, weekday)
700 self.assertIn(e, WeekDay)
701 self.assertEqual(lst.index(e)+1, i)
702 self.assertTrue(0 < e < 8)
703 self.assertIs(type(e), WeekDay)
704 self.assertIsInstance(e, int)
705 self.assertIsInstance(e, Enum)
706
707 def test_intenum_duplicates(self):
708 class WeekDay(IntEnum):
709 SUNDAY = 1
710 MONDAY = 2
711 TUESDAY = TEUSDAY = 3
712 WEDNESDAY = 4
713 THURSDAY = 5
714 FRIDAY = 6
715 SATURDAY = 7
716 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
717 self.assertEqual(WeekDay(3).name, 'TUESDAY')
718 self.assertEqual([k for k,v in WeekDay.__members__.items()
719 if v.name != k], ['TEUSDAY', ])
720
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300721 def test_intenum_from_bytes(self):
722 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
723 with self.assertRaises(ValueError):
724 IntStooges.from_bytes(b'\x00\x05', 'big')
725
726 def test_floatenum_fromhex(self):
727 h = float.hex(FloatStooges.MOE.value)
728 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
729 h = float.hex(FloatStooges.MOE.value + 0.01)
730 with self.assertRaises(ValueError):
731 FloatStooges.fromhex(h)
732
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700733 def test_pickle_enum(self):
734 if isinstance(Stooges, Exception):
735 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800736 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
737 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700738
739 def test_pickle_int(self):
740 if isinstance(IntStooges, Exception):
741 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800742 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
743 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700744
745 def test_pickle_float(self):
746 if isinstance(FloatStooges, Exception):
747 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800748 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
749 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750
751 def test_pickle_enum_function(self):
752 if isinstance(Answer, Exception):
753 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800754 test_pickle_dump_load(self.assertIs, Answer.him)
755 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700756
757 def test_pickle_enum_function_with_module(self):
758 if isinstance(Question, Exception):
759 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800760 test_pickle_dump_load(self.assertIs, Question.who)
761 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700762
Ethan Furmanca1b7942014-02-08 11:36:27 -0800763 def test_enum_function_with_qualname(self):
764 if isinstance(Theory, Exception):
765 raise Theory
766 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
767
768 def test_class_nested_enum_and_pickle_protocol_four(self):
769 # would normally just have this directly in the class namespace
770 class NestedEnum(Enum):
771 twigs = 'common'
772 shiny = 'rare'
773
774 self.__class__.NestedEnum = NestedEnum
775 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300776 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800777
Ethan Furman24e837f2015-03-18 17:27:57 -0700778 def test_pickle_by_name(self):
779 class ReplaceGlobalInt(IntEnum):
780 ONE = 1
781 TWO = 2
782 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
783 for proto in range(HIGHEST_PROTOCOL):
784 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
785
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700786 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800787 BadPickle = Enum(
788 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700789 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800790 # now break BadPickle to test exception raising
791 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800792 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
793 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700794
795 def test_string_enum(self):
796 class SkillLevel(str, Enum):
797 master = 'what is the sound of one hand clapping?'
798 journeyman = 'why did the chicken cross the road?'
799 apprentice = 'knock, knock!'
800 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
801
802 def test_getattr_getitem(self):
803 class Period(Enum):
804 morning = 1
805 noon = 2
806 evening = 3
807 night = 4
808 self.assertIs(Period(2), Period.noon)
809 self.assertIs(getattr(Period, 'night'), Period.night)
810 self.assertIs(Period['morning'], Period.morning)
811
812 def test_getattr_dunder(self):
813 Season = self.Season
814 self.assertTrue(getattr(Season, '__eq__'))
815
816 def test_iteration_order(self):
817 class Season(Enum):
818 SUMMER = 2
819 WINTER = 4
820 AUTUMN = 3
821 SPRING = 1
822 self.assertEqual(
823 list(Season),
824 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
825 )
826
Ethan Furman2131a4a2013-09-14 18:11:24 -0700827 def test_reversed_iteration_order(self):
828 self.assertEqual(
829 list(reversed(self.Season)),
830 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
831 self.Season.SPRING]
832 )
833
Martin Pantereb995702016-07-28 01:11:04 +0000834 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700835 SummerMonth = Enum('SummerMonth', 'june july august')
836 lst = list(SummerMonth)
837 self.assertEqual(len(lst), len(SummerMonth))
838 self.assertEqual(len(SummerMonth), 3, SummerMonth)
839 self.assertEqual(
840 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
841 lst,
842 )
843 for i, month in enumerate('june july august'.split(), 1):
844 e = SummerMonth(i)
845 self.assertEqual(int(e.value), i)
846 self.assertNotEqual(e, i)
847 self.assertEqual(e.name, month)
848 self.assertIn(e, SummerMonth)
849 self.assertIs(type(e), SummerMonth)
850
Martin Pantereb995702016-07-28 01:11:04 +0000851 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700852 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
853 lst = list(SummerMonth)
854 self.assertEqual(len(lst), len(SummerMonth))
855 self.assertEqual(len(SummerMonth), 3, SummerMonth)
856 self.assertEqual(
857 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
858 lst,
859 )
860 for i, month in enumerate('june july august'.split(), 10):
861 e = SummerMonth(i)
862 self.assertEqual(int(e.value), i)
863 self.assertNotEqual(e, i)
864 self.assertEqual(e.name, month)
865 self.assertIn(e, SummerMonth)
866 self.assertIs(type(e), SummerMonth)
867
Martin Pantereb995702016-07-28 01:11:04 +0000868 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700869 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
870 lst = list(SummerMonth)
871 self.assertEqual(len(lst), len(SummerMonth))
872 self.assertEqual(len(SummerMonth), 3, SummerMonth)
873 self.assertEqual(
874 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
875 lst,
876 )
877 for i, month in enumerate('june july august'.split(), 1):
878 e = SummerMonth(i)
879 self.assertEqual(int(e.value), i)
880 self.assertNotEqual(e, i)
881 self.assertEqual(e.name, month)
882 self.assertIn(e, SummerMonth)
883 self.assertIs(type(e), SummerMonth)
884
Martin Pantereb995702016-07-28 01:11:04 +0000885 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700886 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
887 lst = list(SummerMonth)
888 self.assertEqual(len(lst), len(SummerMonth))
889 self.assertEqual(len(SummerMonth), 3, SummerMonth)
890 self.assertEqual(
891 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
892 lst,
893 )
894 for i, month in enumerate('june july august'.split(), 20):
895 e = SummerMonth(i)
896 self.assertEqual(int(e.value), i)
897 self.assertNotEqual(e, i)
898 self.assertEqual(e.name, month)
899 self.assertIn(e, SummerMonth)
900 self.assertIs(type(e), SummerMonth)
901
Martin Pantereb995702016-07-28 01:11:04 +0000902 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700903 SummerMonth = Enum(
904 'SummerMonth',
905 (('june', 1), ('july', 2), ('august', 3))
906 )
907 lst = list(SummerMonth)
908 self.assertEqual(len(lst), len(SummerMonth))
909 self.assertEqual(len(SummerMonth), 3, SummerMonth)
910 self.assertEqual(
911 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
912 lst,
913 )
914 for i, month in enumerate('june july august'.split(), 1):
915 e = SummerMonth(i)
916 self.assertEqual(int(e.value), i)
917 self.assertNotEqual(e, i)
918 self.assertEqual(e.name, month)
919 self.assertIn(e, SummerMonth)
920 self.assertIs(type(e), SummerMonth)
921
Martin Pantereb995702016-07-28 01:11:04 +0000922 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700923 SummerMonth = Enum(
924 'SummerMonth',
925 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
926 )
927 lst = list(SummerMonth)
928 self.assertEqual(len(lst), len(SummerMonth))
929 self.assertEqual(len(SummerMonth), 3, SummerMonth)
930 self.assertEqual(
931 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
932 lst,
933 )
934 for i, month in enumerate('june july august'.split(), 1):
935 e = SummerMonth(i)
936 self.assertEqual(int(e.value), i)
937 self.assertNotEqual(e, i)
938 self.assertEqual(e.name, month)
939 self.assertIn(e, SummerMonth)
940 self.assertIs(type(e), SummerMonth)
941
Martin Pantereb995702016-07-28 01:11:04 +0000942 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700943 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
944 lst = list(SummerMonth)
945 self.assertEqual(len(lst), len(SummerMonth))
946 self.assertEqual(len(SummerMonth), 3, SummerMonth)
947 self.assertEqual(
948 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
949 lst,
950 )
951 for i, month in enumerate('june july august'.split(), 1):
952 e = SummerMonth(i)
953 self.assertEqual(e, i)
954 self.assertEqual(e.name, month)
955 self.assertIn(e, SummerMonth)
956 self.assertIs(type(e), SummerMonth)
957
Martin Pantereb995702016-07-28 01:11:04 +0000958 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700959 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
960 lst = list(SummerMonth)
961 self.assertEqual(len(lst), len(SummerMonth))
962 self.assertEqual(len(SummerMonth), 3, SummerMonth)
963 self.assertEqual(
964 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
965 lst,
966 )
967 for i, month in enumerate('june july august'.split(), 30):
968 e = SummerMonth(i)
969 self.assertEqual(e, i)
970 self.assertEqual(e.name, month)
971 self.assertIn(e, SummerMonth)
972 self.assertIs(type(e), SummerMonth)
973
Martin Pantereb995702016-07-28 01:11:04 +0000974 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700975 SummerMonth = IntEnum('SummerMonth', 'june july august')
976 lst = list(SummerMonth)
977 self.assertEqual(len(lst), len(SummerMonth))
978 self.assertEqual(len(SummerMonth), 3, SummerMonth)
979 self.assertEqual(
980 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
981 lst,
982 )
983 for i, month in enumerate('june july august'.split(), 1):
984 e = SummerMonth(i)
985 self.assertEqual(e, i)
986 self.assertEqual(e.name, month)
987 self.assertIn(e, SummerMonth)
988 self.assertIs(type(e), SummerMonth)
989
Martin Pantereb995702016-07-28 01:11:04 +0000990 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700991 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
992 lst = list(SummerMonth)
993 self.assertEqual(len(lst), len(SummerMonth))
994 self.assertEqual(len(SummerMonth), 3, SummerMonth)
995 self.assertEqual(
996 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
997 lst,
998 )
999 for i, month in enumerate('june july august'.split(), 40):
1000 e = SummerMonth(i)
1001 self.assertEqual(e, i)
1002 self.assertEqual(e.name, month)
1003 self.assertIn(e, SummerMonth)
1004 self.assertIs(type(e), SummerMonth)
1005
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001006 def test_subclassing(self):
1007 if isinstance(Name, Exception):
1008 raise Name
1009 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1010 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1011 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001012 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001013
1014 def test_extending(self):
1015 class Color(Enum):
1016 red = 1
1017 green = 2
1018 blue = 3
1019 with self.assertRaises(TypeError):
1020 class MoreColor(Color):
1021 cyan = 4
1022 magenta = 5
1023 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001024 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1025 class EvenMoreColor(Color, IntEnum):
1026 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001027
1028 def test_exclude_methods(self):
1029 class whatever(Enum):
1030 this = 'that'
1031 these = 'those'
1032 def really(self):
1033 return 'no, not %s' % self.value
1034 self.assertIsNot(type(whatever.really), whatever)
1035 self.assertEqual(whatever.this.really(), 'no, not that')
1036
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001037 def test_wrong_inheritance_order(self):
1038 with self.assertRaises(TypeError):
1039 class Wrong(Enum, str):
1040 NotHere = 'error before this point'
1041
1042 def test_intenum_transitivity(self):
1043 class number(IntEnum):
1044 one = 1
1045 two = 2
1046 three = 3
1047 class numero(IntEnum):
1048 uno = 1
1049 dos = 2
1050 tres = 3
1051 self.assertEqual(number.one, numero.uno)
1052 self.assertEqual(number.two, numero.dos)
1053 self.assertEqual(number.three, numero.tres)
1054
1055 def test_wrong_enum_in_call(self):
1056 class Monochrome(Enum):
1057 black = 0
1058 white = 1
1059 class Gender(Enum):
1060 male = 0
1061 female = 1
1062 self.assertRaises(ValueError, Monochrome, Gender.male)
1063
1064 def test_wrong_enum_in_mixed_call(self):
1065 class Monochrome(IntEnum):
1066 black = 0
1067 white = 1
1068 class Gender(Enum):
1069 male = 0
1070 female = 1
1071 self.assertRaises(ValueError, Monochrome, Gender.male)
1072
1073 def test_mixed_enum_in_call_1(self):
1074 class Monochrome(IntEnum):
1075 black = 0
1076 white = 1
1077 class Gender(IntEnum):
1078 male = 0
1079 female = 1
1080 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1081
1082 def test_mixed_enum_in_call_2(self):
1083 class Monochrome(Enum):
1084 black = 0
1085 white = 1
1086 class Gender(IntEnum):
1087 male = 0
1088 female = 1
1089 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1090
1091 def test_flufl_enum(self):
1092 class Fluflnum(Enum):
1093 def __int__(self):
1094 return int(self.value)
1095 class MailManOptions(Fluflnum):
1096 option1 = 1
1097 option2 = 2
1098 option3 = 3
1099 self.assertEqual(int(MailManOptions.option1), 1)
1100
Ethan Furman5e5a8232013-08-04 08:42:23 -07001101 def test_introspection(self):
1102 class Number(IntEnum):
1103 one = 100
1104 two = 200
1105 self.assertIs(Number.one._member_type_, int)
1106 self.assertIs(Number._member_type_, int)
1107 class String(str, Enum):
1108 yarn = 'soft'
1109 rope = 'rough'
1110 wire = 'hard'
1111 self.assertIs(String.yarn._member_type_, str)
1112 self.assertIs(String._member_type_, str)
1113 class Plain(Enum):
1114 vanilla = 'white'
1115 one = 1
1116 self.assertIs(Plain.vanilla._member_type_, object)
1117 self.assertIs(Plain._member_type_, object)
1118
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001119 def test_no_such_enum_member(self):
1120 class Color(Enum):
1121 red = 1
1122 green = 2
1123 blue = 3
1124 with self.assertRaises(ValueError):
1125 Color(4)
1126 with self.assertRaises(KeyError):
1127 Color['chartreuse']
1128
1129 def test_new_repr(self):
1130 class Color(Enum):
1131 red = 1
1132 green = 2
1133 blue = 3
1134 def __repr__(self):
1135 return "don't you just love shades of %s?" % self.name
1136 self.assertEqual(
1137 repr(Color.blue),
1138 "don't you just love shades of blue?",
1139 )
1140
1141 def test_inherited_repr(self):
1142 class MyEnum(Enum):
1143 def __repr__(self):
1144 return "My name is %s." % self.name
1145 class MyIntEnum(int, MyEnum):
1146 this = 1
1147 that = 2
1148 theother = 3
1149 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1150
1151 def test_multiple_mixin_mro(self):
1152 class auto_enum(type(Enum)):
1153 def __new__(metacls, cls, bases, classdict):
1154 temp = type(classdict)()
1155 names = set(classdict._member_names)
1156 i = 0
1157 for k in classdict._member_names:
1158 v = classdict[k]
1159 if v is Ellipsis:
1160 v = i
1161 else:
1162 i = v
1163 i += 1
1164 temp[k] = v
1165 for k, v in classdict.items():
1166 if k not in names:
1167 temp[k] = v
1168 return super(auto_enum, metacls).__new__(
1169 metacls, cls, bases, temp)
1170
1171 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1172 pass
1173
1174 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1175 pass
1176
1177 class TestAutoNumber(AutoNumberedEnum):
1178 a = ...
1179 b = 3
1180 c = ...
1181
1182 class TestAutoInt(AutoIntEnum):
1183 a = ...
1184 b = 3
1185 c = ...
1186
1187 def test_subclasses_with_getnewargs(self):
1188 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001189 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001190 def __new__(cls, *args):
1191 _args = args
1192 name, *args = args
1193 if len(args) == 0:
1194 raise TypeError("name and value must be specified")
1195 self = int.__new__(cls, *args)
1196 self._intname = name
1197 self._args = _args
1198 return self
1199 def __getnewargs__(self):
1200 return self._args
1201 @property
1202 def __name__(self):
1203 return self._intname
1204 def __repr__(self):
1205 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001206 return "{}({!r}, {})".format(
1207 type(self).__name__,
1208 self.__name__,
1209 int.__repr__(self),
1210 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001211 def __str__(self):
1212 # str() is unchanged, even if it relies on the repr() fallback
1213 base = int
1214 base_str = base.__str__
1215 if base_str.__objclass__ is object:
1216 return base.__repr__(self)
1217 return base_str(self)
1218 # for simplicity, we only define one operator that
1219 # propagates expressions
1220 def __add__(self, other):
1221 temp = int(self) + int( other)
1222 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1223 return NamedInt(
1224 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001225 temp,
1226 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001227 else:
1228 return temp
1229
1230 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001231 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001232 x = ('the-x', 1)
1233 y = ('the-y', 2)
1234
Ethan Furman2aa27322013-07-19 19:35:56 -07001235
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001236 self.assertIs(NEI.__new__, Enum.__new__)
1237 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1238 globals()['NamedInt'] = NamedInt
1239 globals()['NEI'] = NEI
1240 NI5 = NamedInt('test', 5)
1241 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001242 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001244 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001245 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001246
Ethan Furmanca1b7942014-02-08 11:36:27 -08001247 def test_subclasses_with_getnewargs_ex(self):
1248 class NamedInt(int):
1249 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1250 def __new__(cls, *args):
1251 _args = args
1252 name, *args = args
1253 if len(args) == 0:
1254 raise TypeError("name and value must be specified")
1255 self = int.__new__(cls, *args)
1256 self._intname = name
1257 self._args = _args
1258 return self
1259 def __getnewargs_ex__(self):
1260 return self._args, {}
1261 @property
1262 def __name__(self):
1263 return self._intname
1264 def __repr__(self):
1265 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001266 return "{}({!r}, {})".format(
1267 type(self).__name__,
1268 self.__name__,
1269 int.__repr__(self),
1270 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001271 def __str__(self):
1272 # str() is unchanged, even if it relies on the repr() fallback
1273 base = int
1274 base_str = base.__str__
1275 if base_str.__objclass__ is object:
1276 return base.__repr__(self)
1277 return base_str(self)
1278 # for simplicity, we only define one operator that
1279 # propagates expressions
1280 def __add__(self, other):
1281 temp = int(self) + int( other)
1282 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1283 return NamedInt(
1284 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001285 temp,
1286 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001287 else:
1288 return temp
1289
1290 class NEI(NamedInt, Enum):
1291 __qualname__ = 'NEI' # needed for pickle protocol 4
1292 x = ('the-x', 1)
1293 y = ('the-y', 2)
1294
1295
1296 self.assertIs(NEI.__new__, Enum.__new__)
1297 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1298 globals()['NamedInt'] = NamedInt
1299 globals()['NEI'] = NEI
1300 NI5 = NamedInt('test', 5)
1301 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001302 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001303 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001304 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001305 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001306
1307 def test_subclasses_with_reduce(self):
1308 class NamedInt(int):
1309 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1310 def __new__(cls, *args):
1311 _args = args
1312 name, *args = args
1313 if len(args) == 0:
1314 raise TypeError("name and value must be specified")
1315 self = int.__new__(cls, *args)
1316 self._intname = name
1317 self._args = _args
1318 return self
1319 def __reduce__(self):
1320 return self.__class__, self._args
1321 @property
1322 def __name__(self):
1323 return self._intname
1324 def __repr__(self):
1325 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001326 return "{}({!r}, {})".format(
1327 type(self).__name__,
1328 self.__name__,
1329 int.__repr__(self),
1330 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001331 def __str__(self):
1332 # str() is unchanged, even if it relies on the repr() fallback
1333 base = int
1334 base_str = base.__str__
1335 if base_str.__objclass__ is object:
1336 return base.__repr__(self)
1337 return base_str(self)
1338 # for simplicity, we only define one operator that
1339 # propagates expressions
1340 def __add__(self, other):
1341 temp = int(self) + int( other)
1342 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1343 return NamedInt(
1344 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001345 temp,
1346 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001347 else:
1348 return temp
1349
1350 class NEI(NamedInt, Enum):
1351 __qualname__ = 'NEI' # needed for pickle protocol 4
1352 x = ('the-x', 1)
1353 y = ('the-y', 2)
1354
1355
1356 self.assertIs(NEI.__new__, Enum.__new__)
1357 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1358 globals()['NamedInt'] = NamedInt
1359 globals()['NEI'] = NEI
1360 NI5 = NamedInt('test', 5)
1361 self.assertEqual(NI5, 5)
1362 test_pickle_dump_load(self.assertEqual, NI5, 5)
1363 self.assertEqual(NEI.y.value, 2)
1364 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001365 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001366
1367 def test_subclasses_with_reduce_ex(self):
1368 class NamedInt(int):
1369 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1370 def __new__(cls, *args):
1371 _args = args
1372 name, *args = args
1373 if len(args) == 0:
1374 raise TypeError("name and value must be specified")
1375 self = int.__new__(cls, *args)
1376 self._intname = name
1377 self._args = _args
1378 return self
1379 def __reduce_ex__(self, proto):
1380 return self.__class__, self._args
1381 @property
1382 def __name__(self):
1383 return self._intname
1384 def __repr__(self):
1385 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001386 return "{}({!r}, {})".format(
1387 type(self).__name__,
1388 self.__name__,
1389 int.__repr__(self),
1390 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001391 def __str__(self):
1392 # str() is unchanged, even if it relies on the repr() fallback
1393 base = int
1394 base_str = base.__str__
1395 if base_str.__objclass__ is object:
1396 return base.__repr__(self)
1397 return base_str(self)
1398 # for simplicity, we only define one operator that
1399 # propagates expressions
1400 def __add__(self, other):
1401 temp = int(self) + int( other)
1402 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1403 return NamedInt(
1404 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001405 temp,
1406 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001407 else:
1408 return temp
1409
1410 class NEI(NamedInt, Enum):
1411 __qualname__ = 'NEI' # needed for pickle protocol 4
1412 x = ('the-x', 1)
1413 y = ('the-y', 2)
1414
Ethan Furmanca1b7942014-02-08 11:36:27 -08001415 self.assertIs(NEI.__new__, Enum.__new__)
1416 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1417 globals()['NamedInt'] = NamedInt
1418 globals()['NEI'] = NEI
1419 NI5 = NamedInt('test', 5)
1420 self.assertEqual(NI5, 5)
1421 test_pickle_dump_load(self.assertEqual, NI5, 5)
1422 self.assertEqual(NEI.y.value, 2)
1423 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001424 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001425
Ethan Furmandc870522014-02-18 12:37:12 -08001426 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001427 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001428 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001429 def __new__(cls, *args):
1430 _args = args
1431 name, *args = args
1432 if len(args) == 0:
1433 raise TypeError("name and value must be specified")
1434 self = int.__new__(cls, *args)
1435 self._intname = name
1436 self._args = _args
1437 return self
1438 @property
1439 def __name__(self):
1440 return self._intname
1441 def __repr__(self):
1442 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001443 return "{}({!r}, {})".format(
1444 type(self).__name__,
1445 self.__name__,
1446 int.__repr__(self),
1447 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001448 def __str__(self):
1449 # str() is unchanged, even if it relies on the repr() fallback
1450 base = int
1451 base_str = base.__str__
1452 if base_str.__objclass__ is object:
1453 return base.__repr__(self)
1454 return base_str(self)
1455 # for simplicity, we only define one operator that
1456 # propagates expressions
1457 def __add__(self, other):
1458 temp = int(self) + int( other)
1459 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1460 return NamedInt(
1461 '({0} + {1})'.format(self.__name__, other.__name__),
1462 temp )
1463 else:
1464 return temp
1465
1466 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001467 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001468 x = ('the-x', 1)
1469 y = ('the-y', 2)
1470
1471 self.assertIs(NEI.__new__, Enum.__new__)
1472 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1473 globals()['NamedInt'] = NamedInt
1474 globals()['NEI'] = NEI
1475 NI5 = NamedInt('test', 5)
1476 self.assertEqual(NI5, 5)
1477 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001478 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1479 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001480
Ethan Furmandc870522014-02-18 12:37:12 -08001481 def test_subclasses_without_direct_pickle_support_using_name(self):
1482 class NamedInt(int):
1483 __qualname__ = 'NamedInt'
1484 def __new__(cls, *args):
1485 _args = args
1486 name, *args = args
1487 if len(args) == 0:
1488 raise TypeError("name and value must be specified")
1489 self = int.__new__(cls, *args)
1490 self._intname = name
1491 self._args = _args
1492 return self
1493 @property
1494 def __name__(self):
1495 return self._intname
1496 def __repr__(self):
1497 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001498 return "{}({!r}, {})".format(
1499 type(self).__name__,
1500 self.__name__,
1501 int.__repr__(self),
1502 )
Ethan Furmandc870522014-02-18 12:37:12 -08001503 def __str__(self):
1504 # str() is unchanged, even if it relies on the repr() fallback
1505 base = int
1506 base_str = base.__str__
1507 if base_str.__objclass__ is object:
1508 return base.__repr__(self)
1509 return base_str(self)
1510 # for simplicity, we only define one operator that
1511 # propagates expressions
1512 def __add__(self, other):
1513 temp = int(self) + int( other)
1514 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1515 return NamedInt(
1516 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001517 temp,
1518 )
Ethan Furmandc870522014-02-18 12:37:12 -08001519 else:
1520 return temp
1521
1522 class NEI(NamedInt, Enum):
1523 __qualname__ = 'NEI'
1524 x = ('the-x', 1)
1525 y = ('the-y', 2)
1526 def __reduce_ex__(self, proto):
1527 return getattr, (self.__class__, self._name_)
1528
1529 self.assertIs(NEI.__new__, Enum.__new__)
1530 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1531 globals()['NamedInt'] = NamedInt
1532 globals()['NEI'] = NEI
1533 NI5 = NamedInt('test', 5)
1534 self.assertEqual(NI5, 5)
1535 self.assertEqual(NEI.y.value, 2)
1536 test_pickle_dump_load(self.assertIs, NEI.y)
1537 test_pickle_dump_load(self.assertIs, NEI)
1538
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001539 def test_tuple_subclass(self):
1540 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001541 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001542 first = (1, 'for the money')
1543 second = (2, 'for the show')
1544 third = (3, 'for the music')
1545 self.assertIs(type(SomeTuple.first), SomeTuple)
1546 self.assertIsInstance(SomeTuple.second, tuple)
1547 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1548 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001549 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001550
1551 def test_duplicate_values_give_unique_enum_items(self):
1552 class AutoNumber(Enum):
1553 first = ()
1554 second = ()
1555 third = ()
1556 def __new__(cls):
1557 value = len(cls.__members__) + 1
1558 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001559 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001560 return obj
1561 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001562 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001563 self.assertEqual(
1564 list(AutoNumber),
1565 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1566 )
1567 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001568 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001569 self.assertIs(AutoNumber(1), AutoNumber.first)
1570
1571 def test_inherited_new_from_enhanced_enum(self):
1572 class AutoNumber(Enum):
1573 def __new__(cls):
1574 value = len(cls.__members__) + 1
1575 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001576 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 return obj
1578 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001579 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001580 class Color(AutoNumber):
1581 red = ()
1582 green = ()
1583 blue = ()
1584 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1585 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1586
1587 def test_inherited_new_from_mixed_enum(self):
1588 class AutoNumber(IntEnum):
1589 def __new__(cls):
1590 value = len(cls.__members__) + 1
1591 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001592 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001593 return obj
1594 class Color(AutoNumber):
1595 red = ()
1596 green = ()
1597 blue = ()
1598 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1599 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1600
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001601 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001602 class OrdinaryEnum(Enum):
1603 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001604 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1605 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001606
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001607 def test_ordered_mixin(self):
1608 class OrderedEnum(Enum):
1609 def __ge__(self, other):
1610 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001611 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001612 return NotImplemented
1613 def __gt__(self, other):
1614 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001615 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001616 return NotImplemented
1617 def __le__(self, other):
1618 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001619 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001620 return NotImplemented
1621 def __lt__(self, other):
1622 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001623 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001624 return NotImplemented
1625 class Grade(OrderedEnum):
1626 A = 5
1627 B = 4
1628 C = 3
1629 D = 2
1630 F = 1
1631 self.assertGreater(Grade.A, Grade.B)
1632 self.assertLessEqual(Grade.F, Grade.C)
1633 self.assertLess(Grade.D, Grade.A)
1634 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001635 self.assertEqual(Grade.B, Grade.B)
1636 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001637
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001638 def test_extending2(self):
1639 class Shade(Enum):
1640 def shade(self):
1641 print(self.name)
1642 class Color(Shade):
1643 red = 1
1644 green = 2
1645 blue = 3
1646 with self.assertRaises(TypeError):
1647 class MoreColor(Color):
1648 cyan = 4
1649 magenta = 5
1650 yellow = 6
1651
1652 def test_extending3(self):
1653 class Shade(Enum):
1654 def shade(self):
1655 return self.name
1656 class Color(Shade):
1657 def hex(self):
1658 return '%s hexlified!' % self.value
1659 class MoreColor(Color):
1660 cyan = 4
1661 magenta = 5
1662 yellow = 6
1663 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1664
orlnub1230fb9fad2018-09-12 20:28:53 +03001665 def test_subclass_duplicate_name(self):
1666 class Base(Enum):
1667 def test(self):
1668 pass
1669 class Test(Base):
1670 test = 1
1671 self.assertIs(type(Test.test), Test)
1672
1673 def test_subclass_duplicate_name_dynamic(self):
1674 from types import DynamicClassAttribute
1675 class Base(Enum):
1676 @DynamicClassAttribute
1677 def test(self):
1678 return 'dynamic'
1679 class Test(Base):
1680 test = 1
1681 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001682
1683 def test_no_duplicates(self):
1684 class UniqueEnum(Enum):
1685 def __init__(self, *args):
1686 cls = self.__class__
1687 if any(self.value == e.value for e in cls):
1688 a = self.name
1689 e = cls(self.value).name
1690 raise ValueError(
1691 "aliases not allowed in UniqueEnum: %r --> %r"
1692 % (a, e)
1693 )
1694 class Color(UniqueEnum):
1695 red = 1
1696 green = 2
1697 blue = 3
1698 with self.assertRaises(ValueError):
1699 class Color(UniqueEnum):
1700 red = 1
1701 green = 2
1702 blue = 3
1703 grene = 2
1704
1705 def test_init(self):
1706 class Planet(Enum):
1707 MERCURY = (3.303e+23, 2.4397e6)
1708 VENUS = (4.869e+24, 6.0518e6)
1709 EARTH = (5.976e+24, 6.37814e6)
1710 MARS = (6.421e+23, 3.3972e6)
1711 JUPITER = (1.9e+27, 7.1492e7)
1712 SATURN = (5.688e+26, 6.0268e7)
1713 URANUS = (8.686e+25, 2.5559e7)
1714 NEPTUNE = (1.024e+26, 2.4746e7)
1715 def __init__(self, mass, radius):
1716 self.mass = mass # in kilograms
1717 self.radius = radius # in meters
1718 @property
1719 def surface_gravity(self):
1720 # universal gravitational constant (m3 kg-1 s-2)
1721 G = 6.67300E-11
1722 return G * self.mass / (self.radius * self.radius)
1723 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1724 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1725
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001726 def test_ignore(self):
1727 class Period(timedelta, Enum):
1728 '''
1729 different lengths of time
1730 '''
1731 def __new__(cls, value, period):
1732 obj = timedelta.__new__(cls, value)
1733 obj._value_ = value
1734 obj.period = period
1735 return obj
1736 _ignore_ = 'Period i'
1737 Period = vars()
1738 for i in range(13):
1739 Period['month_%d' % i] = i*30, 'month'
1740 for i in range(53):
1741 Period['week_%d' % i] = i*7, 'week'
1742 for i in range(32):
1743 Period['day_%d' % i] = i, 'day'
1744 OneDay = day_1
1745 OneWeek = week_1
1746 OneMonth = month_1
1747 self.assertFalse(hasattr(Period, '_ignore_'))
1748 self.assertFalse(hasattr(Period, 'Period'))
1749 self.assertFalse(hasattr(Period, 'i'))
1750 self.assertTrue(isinstance(Period.day_1, timedelta))
1751 self.assertTrue(Period.month_1 is Period.day_30)
1752 self.assertTrue(Period.week_4 is Period.day_28)
1753
Ethan Furman2aa27322013-07-19 19:35:56 -07001754 def test_nonhash_value(self):
1755 class AutoNumberInAList(Enum):
1756 def __new__(cls):
1757 value = [len(cls.__members__) + 1]
1758 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001759 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001760 return obj
1761 class ColorInAList(AutoNumberInAList):
1762 red = ()
1763 green = ()
1764 blue = ()
1765 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001766 for enum, value in zip(ColorInAList, range(3)):
1767 value += 1
1768 self.assertEqual(enum.value, [value])
1769 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001770
Ethan Furmanb41803e2013-07-25 13:50:45 -07001771 def test_conflicting_types_resolved_in_new(self):
1772 class LabelledIntEnum(int, Enum):
1773 def __new__(cls, *args):
1774 value, label = args
1775 obj = int.__new__(cls, value)
1776 obj.label = label
1777 obj._value_ = value
1778 return obj
1779
1780 class LabelledList(LabelledIntEnum):
1781 unprocessed = (1, "Unprocessed")
1782 payment_complete = (2, "Payment Complete")
1783
1784 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1785 self.assertEqual(LabelledList.unprocessed, 1)
1786 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001787
Ethan Furmanc16595e2016-09-10 23:36:59 -07001788 def test_auto_number(self):
1789 class Color(Enum):
1790 red = auto()
1791 blue = auto()
1792 green = auto()
1793
1794 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1795 self.assertEqual(Color.red.value, 1)
1796 self.assertEqual(Color.blue.value, 2)
1797 self.assertEqual(Color.green.value, 3)
1798
1799 def test_auto_name(self):
1800 class Color(Enum):
1801 def _generate_next_value_(name, start, count, last):
1802 return name
1803 red = auto()
1804 blue = auto()
1805 green = auto()
1806
1807 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1808 self.assertEqual(Color.red.value, 'red')
1809 self.assertEqual(Color.blue.value, 'blue')
1810 self.assertEqual(Color.green.value, 'green')
1811
1812 def test_auto_name_inherit(self):
1813 class AutoNameEnum(Enum):
1814 def _generate_next_value_(name, start, count, last):
1815 return name
1816 class Color(AutoNameEnum):
1817 red = auto()
1818 blue = auto()
1819 green = auto()
1820
1821 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1822 self.assertEqual(Color.red.value, 'red')
1823 self.assertEqual(Color.blue.value, 'blue')
1824 self.assertEqual(Color.green.value, 'green')
1825
1826 def test_auto_garbage(self):
1827 class Color(Enum):
1828 red = 'red'
1829 blue = auto()
1830 self.assertEqual(Color.blue.value, 1)
1831
1832 def test_auto_garbage_corrected(self):
1833 class Color(Enum):
1834 red = 'red'
1835 blue = 2
1836 green = auto()
1837
1838 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1839 self.assertEqual(Color.red.value, 'red')
1840 self.assertEqual(Color.blue.value, 2)
1841 self.assertEqual(Color.green.value, 3)
1842
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001843 def test_auto_order(self):
1844 with self.assertRaises(TypeError):
1845 class Color(Enum):
1846 red = auto()
1847 green = auto()
1848 blue = auto()
1849 def _generate_next_value_(name, start, count, last):
1850 return name
1851
Ethan Furmanfc23a942020-09-16 12:37:54 -07001852 def test_auto_order_wierd(self):
1853 weird_auto = auto()
1854 weird_auto.value = 'pathological case'
1855 class Color(Enum):
1856 red = weird_auto
1857 def _generate_next_value_(name, start, count, last):
1858 return name
1859 blue = auto()
1860 self.assertEqual(list(Color), [Color.red, Color.blue])
1861 self.assertEqual(Color.red.value, 'pathological case')
1862 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001863
Ethan Furman3515dcc2016-09-18 13:15:41 -07001864 def test_duplicate_auto(self):
1865 class Dupes(Enum):
1866 first = primero = auto()
1867 second = auto()
1868 third = auto()
1869 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1870
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001871 def test_default_missing(self):
1872 class Color(Enum):
1873 RED = 1
1874 GREEN = 2
1875 BLUE = 3
1876 try:
1877 Color(7)
1878 except ValueError as exc:
1879 self.assertTrue(exc.__context__ is None)
1880 else:
1881 raise Exception('Exception not raised.')
1882
Ethan Furman019f0a02018-09-12 11:43:34 -07001883 def test_missing(self):
1884 class Color(Enum):
1885 red = 1
1886 green = 2
1887 blue = 3
1888 @classmethod
1889 def _missing_(cls, item):
1890 if item == 'three':
1891 return cls.blue
1892 elif item == 'bad return':
1893 # trigger internal error
1894 return 5
1895 elif item == 'error out':
1896 raise ZeroDivisionError
1897 else:
1898 # trigger not found
1899 return None
1900 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001901 try:
1902 Color(7)
1903 except ValueError as exc:
1904 self.assertTrue(exc.__context__ is None)
1905 else:
1906 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001907 try:
1908 Color('bad return')
1909 except TypeError as exc:
1910 self.assertTrue(isinstance(exc.__context__, ValueError))
1911 else:
1912 raise Exception('Exception not raised.')
1913 try:
1914 Color('error out')
1915 except ZeroDivisionError as exc:
1916 self.assertTrue(isinstance(exc.__context__, ValueError))
1917 else:
1918 raise Exception('Exception not raised.')
1919
Ethan Furman5bdab642018-09-21 19:03:09 -07001920 def test_multiple_mixin(self):
1921 class MaxMixin:
1922 @classproperty
1923 def MAX(cls):
1924 max = len(cls)
1925 cls.MAX = max
1926 return max
1927 class StrMixin:
1928 def __str__(self):
1929 return self._name_.lower()
1930 class SomeEnum(Enum):
1931 def behavior(self):
1932 return 'booyah'
1933 class AnotherEnum(Enum):
1934 def behavior(self):
1935 return 'nuhuh!'
1936 def social(self):
1937 return "what's up?"
1938 class Color(MaxMixin, Enum):
1939 RED = auto()
1940 GREEN = auto()
1941 BLUE = auto()
1942 self.assertEqual(Color.RED.value, 1)
1943 self.assertEqual(Color.GREEN.value, 2)
1944 self.assertEqual(Color.BLUE.value, 3)
1945 self.assertEqual(Color.MAX, 3)
1946 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1947 class Color(MaxMixin, StrMixin, Enum):
1948 RED = auto()
1949 GREEN = auto()
1950 BLUE = auto()
1951 self.assertEqual(Color.RED.value, 1)
1952 self.assertEqual(Color.GREEN.value, 2)
1953 self.assertEqual(Color.BLUE.value, 3)
1954 self.assertEqual(Color.MAX, 3)
1955 self.assertEqual(str(Color.BLUE), 'blue')
1956 class Color(StrMixin, MaxMixin, Enum):
1957 RED = auto()
1958 GREEN = auto()
1959 BLUE = auto()
1960 self.assertEqual(Color.RED.value, 1)
1961 self.assertEqual(Color.GREEN.value, 2)
1962 self.assertEqual(Color.BLUE.value, 3)
1963 self.assertEqual(Color.MAX, 3)
1964 self.assertEqual(str(Color.BLUE), 'blue')
1965 class CoolColor(StrMixin, SomeEnum, Enum):
1966 RED = auto()
1967 GREEN = auto()
1968 BLUE = auto()
1969 self.assertEqual(CoolColor.RED.value, 1)
1970 self.assertEqual(CoolColor.GREEN.value, 2)
1971 self.assertEqual(CoolColor.BLUE.value, 3)
1972 self.assertEqual(str(CoolColor.BLUE), 'blue')
1973 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1974 class CoolerColor(StrMixin, AnotherEnum, Enum):
1975 RED = auto()
1976 GREEN = auto()
1977 BLUE = auto()
1978 self.assertEqual(CoolerColor.RED.value, 1)
1979 self.assertEqual(CoolerColor.GREEN.value, 2)
1980 self.assertEqual(CoolerColor.BLUE.value, 3)
1981 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1982 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1983 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1984 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1985 RED = auto()
1986 GREEN = auto()
1987 BLUE = auto()
1988 self.assertEqual(CoolestColor.RED.value, 1)
1989 self.assertEqual(CoolestColor.GREEN.value, 2)
1990 self.assertEqual(CoolestColor.BLUE.value, 3)
1991 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1992 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1993 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1994 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1995 RED = auto()
1996 GREEN = auto()
1997 BLUE = auto()
1998 self.assertEqual(ConfusedColor.RED.value, 1)
1999 self.assertEqual(ConfusedColor.GREEN.value, 2)
2000 self.assertEqual(ConfusedColor.BLUE.value, 3)
2001 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2002 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2003 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2004 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2005 RED = auto()
2006 GREEN = auto()
2007 BLUE = auto()
2008 self.assertEqual(ReformedColor.RED.value, 1)
2009 self.assertEqual(ReformedColor.GREEN.value, 2)
2010 self.assertEqual(ReformedColor.BLUE.value, 3)
2011 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2012 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2013 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2014 self.assertTrue(issubclass(ReformedColor, int))
2015
Ethan Furmancd453852018-10-05 23:29:36 -07002016 def test_multiple_inherited_mixin(self):
2017 class StrEnum(str, Enum):
2018 def __new__(cls, *args, **kwargs):
2019 for a in args:
2020 if not isinstance(a, str):
2021 raise TypeError("Enumeration '%s' (%s) is not"
2022 " a string" % (a, type(a).__name__))
2023 return str.__new__(cls, *args, **kwargs)
2024 @unique
2025 class Decision1(StrEnum):
2026 REVERT = "REVERT"
2027 REVERT_ALL = "REVERT_ALL"
2028 RETRY = "RETRY"
2029 class MyEnum(StrEnum):
2030 pass
2031 @unique
2032 class Decision2(MyEnum):
2033 REVERT = "REVERT"
2034 REVERT_ALL = "REVERT_ALL"
2035 RETRY = "RETRY"
2036
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002037 def test_empty_globals(self):
2038 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2039 # when using compile and exec because f_globals is empty
2040 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2041 code = compile(code, "<string>", "exec")
2042 global_ns = {}
2043 local_ls = {}
2044 exec(code, global_ns, local_ls)
2045
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002046
Ethan Furmane8e61272016-08-20 07:19:31 -07002047class TestOrder(unittest.TestCase):
2048
2049 def test_same_members(self):
2050 class Color(Enum):
2051 _order_ = 'red green blue'
2052 red = 1
2053 green = 2
2054 blue = 3
2055
2056 def test_same_members_with_aliases(self):
2057 class Color(Enum):
2058 _order_ = 'red green blue'
2059 red = 1
2060 green = 2
2061 blue = 3
2062 verde = green
2063
2064 def test_same_members_wrong_order(self):
2065 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2066 class Color(Enum):
2067 _order_ = 'red green blue'
2068 red = 1
2069 blue = 3
2070 green = 2
2071
2072 def test_order_has_extra_members(self):
2073 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2074 class Color(Enum):
2075 _order_ = 'red green blue purple'
2076 red = 1
2077 green = 2
2078 blue = 3
2079
2080 def test_order_has_extra_members_with_aliases(self):
2081 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2082 class Color(Enum):
2083 _order_ = 'red green blue purple'
2084 red = 1
2085 green = 2
2086 blue = 3
2087 verde = green
2088
2089 def test_enum_has_extra_members(self):
2090 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2091 class Color(Enum):
2092 _order_ = 'red green blue'
2093 red = 1
2094 green = 2
2095 blue = 3
2096 purple = 4
2097
2098 def test_enum_has_extra_members_with_aliases(self):
2099 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2100 class Color(Enum):
2101 _order_ = 'red green blue'
2102 red = 1
2103 green = 2
2104 blue = 3
2105 purple = 4
2106 verde = green
2107
2108
Ethan Furman65a5a472016-09-01 23:55:19 -07002109class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002110 """Tests of the Flags."""
2111
Ethan Furman65a5a472016-09-01 23:55:19 -07002112 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002113 R, W, X = 4, 2, 1
2114
Ethan Furman65a5a472016-09-01 23:55:19 -07002115 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002116 RO = 0
2117 WO = 1
2118 RW = 2
2119 AC = 3
2120 CE = 1<<19
2121
Rahul Jha94306522018-09-10 23:51:04 +05302122 class Color(Flag):
2123 BLACK = 0
2124 RED = 1
2125 GREEN = 2
2126 BLUE = 4
2127 PURPLE = RED|BLUE
2128
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002129 def test_str(self):
2130 Perm = self.Perm
2131 self.assertEqual(str(Perm.R), 'Perm.R')
2132 self.assertEqual(str(Perm.W), 'Perm.W')
2133 self.assertEqual(str(Perm.X), 'Perm.X')
2134 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2135 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2136 self.assertEqual(str(Perm(0)), 'Perm.0')
2137 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2138 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2139 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2140 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2141 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2142 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2143
2144 Open = self.Open
2145 self.assertEqual(str(Open.RO), 'Open.RO')
2146 self.assertEqual(str(Open.WO), 'Open.WO')
2147 self.assertEqual(str(Open.AC), 'Open.AC')
2148 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2149 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002150 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002151 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2152 self.assertEqual(str(~Open.AC), 'Open.CE')
2153 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2154 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2155
2156 def test_repr(self):
2157 Perm = self.Perm
2158 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2159 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2160 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2161 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2162 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002163 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002164 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2165 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2166 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2167 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002168 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002169 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2170
2171 Open = self.Open
2172 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2173 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2174 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2175 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2176 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002177 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002178 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2179 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2180 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2181 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2182
2183 def test_or(self):
2184 Perm = self.Perm
2185 for i in Perm:
2186 for j in Perm:
2187 self.assertEqual((i | j), Perm(i.value | j.value))
2188 self.assertEqual((i | j).value, i.value | j.value)
2189 self.assertIs(type(i | j), Perm)
2190 for i in Perm:
2191 self.assertIs(i | i, i)
2192 Open = self.Open
2193 self.assertIs(Open.RO | Open.CE, Open.CE)
2194
2195 def test_and(self):
2196 Perm = self.Perm
2197 RW = Perm.R | Perm.W
2198 RX = Perm.R | Perm.X
2199 WX = Perm.W | Perm.X
2200 RWX = Perm.R | Perm.W | Perm.X
2201 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2202 for i in values:
2203 for j in values:
2204 self.assertEqual((i & j).value, i.value & j.value)
2205 self.assertIs(type(i & j), Perm)
2206 for i in Perm:
2207 self.assertIs(i & i, i)
2208 self.assertIs(i & RWX, i)
2209 self.assertIs(RWX & i, i)
2210 Open = self.Open
2211 self.assertIs(Open.RO & Open.CE, Open.RO)
2212
2213 def test_xor(self):
2214 Perm = self.Perm
2215 for i in Perm:
2216 for j in Perm:
2217 self.assertEqual((i ^ j).value, i.value ^ j.value)
2218 self.assertIs(type(i ^ j), Perm)
2219 for i in Perm:
2220 self.assertIs(i ^ Perm(0), i)
2221 self.assertIs(Perm(0) ^ i, i)
2222 Open = self.Open
2223 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2224 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2225
2226 def test_invert(self):
2227 Perm = self.Perm
2228 RW = Perm.R | Perm.W
2229 RX = Perm.R | Perm.X
2230 WX = Perm.W | Perm.X
2231 RWX = Perm.R | Perm.W | Perm.X
2232 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2233 for i in values:
2234 self.assertIs(type(~i), Perm)
2235 self.assertEqual(~~i, i)
2236 for i in Perm:
2237 self.assertIs(~~i, i)
2238 Open = self.Open
2239 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2240 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2241
Ethan Furman25d94bb2016-09-02 16:32:32 -07002242 def test_bool(self):
2243 Perm = self.Perm
2244 for f in Perm:
2245 self.assertTrue(f)
2246 Open = self.Open
2247 for f in Open:
2248 self.assertEqual(bool(f.value), bool(f))
2249
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002250 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002251 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002252 lst = list(Perm)
2253 self.assertEqual(len(lst), len(Perm))
2254 self.assertEqual(len(Perm), 3, Perm)
2255 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2256 for i, n in enumerate('R W X'.split()):
2257 v = 1<<i
2258 e = Perm(v)
2259 self.assertEqual(e.value, v)
2260 self.assertEqual(type(e.value), int)
2261 self.assertEqual(e.name, n)
2262 self.assertIn(e, Perm)
2263 self.assertIs(type(e), Perm)
2264
2265 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002266 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002267 lst = list(Perm)
2268 self.assertEqual(len(lst), len(Perm))
2269 self.assertEqual(len(Perm), 3, Perm)
2270 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2271 for i, n in enumerate('R W X'.split()):
2272 v = 8<<i
2273 e = Perm(v)
2274 self.assertEqual(e.value, v)
2275 self.assertEqual(type(e.value), int)
2276 self.assertEqual(e.name, n)
2277 self.assertIn(e, Perm)
2278 self.assertIs(type(e), Perm)
2279
2280 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002281 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002282 lst = list(Perm)
2283 self.assertEqual(len(lst), len(Perm))
2284 self.assertEqual(len(Perm), 3, Perm)
2285 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2286 for i, n in enumerate('R W X'.split()):
2287 v = 1<<i
2288 e = Perm(v)
2289 self.assertEqual(e.value, v)
2290 self.assertEqual(type(e.value), int)
2291 self.assertEqual(e.name, n)
2292 self.assertIn(e, Perm)
2293 self.assertIs(type(e), Perm)
2294
2295 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002296 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002297 lst = list(Perm)
2298 self.assertEqual(len(lst), len(Perm))
2299 self.assertEqual(len(Perm), 3, Perm)
2300 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2301 for i, n in enumerate('R W X'.split()):
2302 v = 1<<(2*i+1)
2303 e = Perm(v)
2304 self.assertEqual(e.value, v)
2305 self.assertEqual(type(e.value), int)
2306 self.assertEqual(e.name, n)
2307 self.assertIn(e, Perm)
2308 self.assertIs(type(e), Perm)
2309
2310 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002311 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002312 lst = list(Perm)
2313 self.assertEqual(len(lst), len(Perm))
2314 self.assertEqual(len(Perm), 3, Perm)
2315 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2316 for i, n in enumerate('R W X'.split()):
2317 v = 1<<(2*i+1)
2318 e = Perm(v)
2319 self.assertEqual(e.value, v)
2320 self.assertEqual(type(e.value), int)
2321 self.assertEqual(e.name, n)
2322 self.assertIn(e, Perm)
2323 self.assertIs(type(e), Perm)
2324
Ethan Furman65a5a472016-09-01 23:55:19 -07002325 def test_pickle(self):
2326 if isinstance(FlagStooges, Exception):
2327 raise FlagStooges
2328 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2329 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002330
Rahul Jha94306522018-09-10 23:51:04 +05302331 def test_contains(self):
2332 Open = self.Open
2333 Color = self.Color
2334 self.assertFalse(Color.BLACK in Open)
2335 self.assertFalse(Open.RO in Color)
2336 with self.assertRaises(TypeError):
2337 'BLACK' in Color
2338 with self.assertRaises(TypeError):
2339 'RO' in Open
2340 with self.assertRaises(TypeError):
2341 1 in Color
2342 with self.assertRaises(TypeError):
2343 1 in Open
2344
2345 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002346 Perm = self.Perm
2347 R, W, X = Perm
2348 RW = R | W
2349 RX = R | X
2350 WX = W | X
2351 RWX = R | W | X
2352 self.assertTrue(R in RW)
2353 self.assertTrue(R in RX)
2354 self.assertTrue(R in RWX)
2355 self.assertTrue(W in RW)
2356 self.assertTrue(W in WX)
2357 self.assertTrue(W in RWX)
2358 self.assertTrue(X in RX)
2359 self.assertTrue(X in WX)
2360 self.assertTrue(X in RWX)
2361 self.assertFalse(R in WX)
2362 self.assertFalse(W in RX)
2363 self.assertFalse(X in RW)
2364
Ethan Furman7219e272020-09-16 13:01:00 -07002365 def test_member_iter(self):
2366 Color = self.Color
2367 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2368 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2369 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2370
Ethan Furmanc16595e2016-09-10 23:36:59 -07002371 def test_auto_number(self):
2372 class Color(Flag):
2373 red = auto()
2374 blue = auto()
2375 green = auto()
2376
2377 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2378 self.assertEqual(Color.red.value, 1)
2379 self.assertEqual(Color.blue.value, 2)
2380 self.assertEqual(Color.green.value, 4)
2381
2382 def test_auto_number_garbage(self):
2383 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2384 class Color(Flag):
2385 red = 'not an int'
2386 blue = auto()
2387
Ethan Furman3515dcc2016-09-18 13:15:41 -07002388 def test_cascading_failure(self):
2389 class Bizarre(Flag):
2390 c = 3
2391 d = 4
2392 f = 6
2393 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002394 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2395 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2396 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2397 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2398 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2399 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2400 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002401
2402 def test_duplicate_auto(self):
2403 class Dupes(Enum):
2404 first = primero = auto()
2405 second = auto()
2406 third = auto()
2407 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2408
2409 def test_bizarre(self):
2410 class Bizarre(Flag):
2411 b = 3
2412 c = 4
2413 d = 6
2414 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2415
Ethan Furman5bdab642018-09-21 19:03:09 -07002416 def test_multiple_mixin(self):
2417 class AllMixin:
2418 @classproperty
2419 def ALL(cls):
2420 members = list(cls)
2421 all_value = None
2422 if members:
2423 all_value = members[0]
2424 for member in members[1:]:
2425 all_value |= member
2426 cls.ALL = all_value
2427 return all_value
2428 class StrMixin:
2429 def __str__(self):
2430 return self._name_.lower()
2431 class Color(AllMixin, Flag):
2432 RED = auto()
2433 GREEN = auto()
2434 BLUE = auto()
2435 self.assertEqual(Color.RED.value, 1)
2436 self.assertEqual(Color.GREEN.value, 2)
2437 self.assertEqual(Color.BLUE.value, 4)
2438 self.assertEqual(Color.ALL.value, 7)
2439 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2440 class Color(AllMixin, StrMixin, Flag):
2441 RED = auto()
2442 GREEN = auto()
2443 BLUE = auto()
2444 self.assertEqual(Color.RED.value, 1)
2445 self.assertEqual(Color.GREEN.value, 2)
2446 self.assertEqual(Color.BLUE.value, 4)
2447 self.assertEqual(Color.ALL.value, 7)
2448 self.assertEqual(str(Color.BLUE), 'blue')
2449 class Color(StrMixin, AllMixin, Flag):
2450 RED = auto()
2451 GREEN = auto()
2452 BLUE = auto()
2453 self.assertEqual(Color.RED.value, 1)
2454 self.assertEqual(Color.GREEN.value, 2)
2455 self.assertEqual(Color.BLUE.value, 4)
2456 self.assertEqual(Color.ALL.value, 7)
2457 self.assertEqual(str(Color.BLUE), 'blue')
2458
Hai Shie80697d2020-05-28 06:10:27 +08002459 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002460 def test_unique_composite(self):
2461 # override __eq__ to be identity only
2462 class TestFlag(Flag):
2463 one = auto()
2464 two = auto()
2465 three = auto()
2466 four = auto()
2467 five = auto()
2468 six = auto()
2469 seven = auto()
2470 eight = auto()
2471 def __eq__(self, other):
2472 return self is other
2473 def __hash__(self):
2474 return hash(self._value_)
2475 # have multiple threads competing to complete the composite members
2476 seen = set()
2477 failed = False
2478 def cycle_enum():
2479 nonlocal failed
2480 try:
2481 for i in range(256):
2482 seen.add(TestFlag(i))
2483 except Exception:
2484 failed = True
2485 threads = [
2486 threading.Thread(target=cycle_enum)
2487 for _ in range(8)
2488 ]
Hai Shie80697d2020-05-28 06:10:27 +08002489 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002490 pass
2491 # check that only 248 members were created
2492 self.assertFalse(
2493 failed,
2494 'at least one thread failed while creating composite members')
2495 self.assertEqual(256, len(seen), 'too many composite members created')
2496
Ethan Furmanc16595e2016-09-10 23:36:59 -07002497
Ethan Furman65a5a472016-09-01 23:55:19 -07002498class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002499 """Tests of the IntFlags."""
2500
Ethan Furman65a5a472016-09-01 23:55:19 -07002501 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002502 X = 1 << 0
2503 W = 1 << 1
2504 R = 1 << 2
2505
Ethan Furman65a5a472016-09-01 23:55:19 -07002506 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002507 RO = 0
2508 WO = 1
2509 RW = 2
2510 AC = 3
2511 CE = 1<<19
2512
Rahul Jha94306522018-09-10 23:51:04 +05302513 class Color(IntFlag):
2514 BLACK = 0
2515 RED = 1
2516 GREEN = 2
2517 BLUE = 4
2518 PURPLE = RED|BLUE
2519
Ethan Furman3515dcc2016-09-18 13:15:41 -07002520 def test_type(self):
2521 Perm = self.Perm
2522 Open = self.Open
2523 for f in Perm:
2524 self.assertTrue(isinstance(f, Perm))
2525 self.assertEqual(f, f.value)
2526 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2527 self.assertEqual(Perm.W | Perm.X, 3)
2528 for f in Open:
2529 self.assertTrue(isinstance(f, Open))
2530 self.assertEqual(f, f.value)
2531 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2532 self.assertEqual(Open.WO | Open.RW, 3)
2533
2534
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002535 def test_str(self):
2536 Perm = self.Perm
2537 self.assertEqual(str(Perm.R), 'Perm.R')
2538 self.assertEqual(str(Perm.W), 'Perm.W')
2539 self.assertEqual(str(Perm.X), 'Perm.X')
2540 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2541 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2542 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2543 self.assertEqual(str(Perm(0)), 'Perm.0')
2544 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002545 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2546 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2547 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2548 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002549 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002550 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2551 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2552 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002553
2554 Open = self.Open
2555 self.assertEqual(str(Open.RO), 'Open.RO')
2556 self.assertEqual(str(Open.WO), 'Open.WO')
2557 self.assertEqual(str(Open.AC), 'Open.AC')
2558 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2559 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2560 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002561 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2562 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2563 self.assertEqual(str(~Open.AC), 'Open.CE')
2564 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2565 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2566 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002567
2568 def test_repr(self):
2569 Perm = self.Perm
2570 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2571 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2572 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2573 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2574 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2575 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002576 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2577 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002578 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2579 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2580 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2581 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002582 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002583 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2584 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2585 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002586
2587 Open = self.Open
2588 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2589 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2590 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2591 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2592 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002593 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002594 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2595 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2596 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2597 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2598 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2599 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002600
2601 def test_or(self):
2602 Perm = self.Perm
2603 for i in Perm:
2604 for j in Perm:
2605 self.assertEqual(i | j, i.value | j.value)
2606 self.assertEqual((i | j).value, i.value | j.value)
2607 self.assertIs(type(i | j), Perm)
2608 for j in range(8):
2609 self.assertEqual(i | j, i.value | j)
2610 self.assertEqual((i | j).value, i.value | j)
2611 self.assertIs(type(i | j), Perm)
2612 self.assertEqual(j | i, j | i.value)
2613 self.assertEqual((j | i).value, j | i.value)
2614 self.assertIs(type(j | i), Perm)
2615 for i in Perm:
2616 self.assertIs(i | i, i)
2617 self.assertIs(i | 0, i)
2618 self.assertIs(0 | i, i)
2619 Open = self.Open
2620 self.assertIs(Open.RO | Open.CE, Open.CE)
2621
2622 def test_and(self):
2623 Perm = self.Perm
2624 RW = Perm.R | Perm.W
2625 RX = Perm.R | Perm.X
2626 WX = Perm.W | Perm.X
2627 RWX = Perm.R | Perm.W | Perm.X
2628 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2629 for i in values:
2630 for j in values:
2631 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2632 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2633 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2634 for j in range(8):
2635 self.assertEqual(i & j, i.value & j)
2636 self.assertEqual((i & j).value, i.value & j)
2637 self.assertIs(type(i & j), Perm)
2638 self.assertEqual(j & i, j & i.value)
2639 self.assertEqual((j & i).value, j & i.value)
2640 self.assertIs(type(j & i), Perm)
2641 for i in Perm:
2642 self.assertIs(i & i, i)
2643 self.assertIs(i & 7, i)
2644 self.assertIs(7 & i, i)
2645 Open = self.Open
2646 self.assertIs(Open.RO & Open.CE, Open.RO)
2647
2648 def test_xor(self):
2649 Perm = self.Perm
2650 for i in Perm:
2651 for j in Perm:
2652 self.assertEqual(i ^ j, i.value ^ j.value)
2653 self.assertEqual((i ^ j).value, i.value ^ j.value)
2654 self.assertIs(type(i ^ j), Perm)
2655 for j in range(8):
2656 self.assertEqual(i ^ j, i.value ^ j)
2657 self.assertEqual((i ^ j).value, i.value ^ j)
2658 self.assertIs(type(i ^ j), Perm)
2659 self.assertEqual(j ^ i, j ^ i.value)
2660 self.assertEqual((j ^ i).value, j ^ i.value)
2661 self.assertIs(type(j ^ i), Perm)
2662 for i in Perm:
2663 self.assertIs(i ^ 0, i)
2664 self.assertIs(0 ^ i, i)
2665 Open = self.Open
2666 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2667 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2668
2669 def test_invert(self):
2670 Perm = self.Perm
2671 RW = Perm.R | Perm.W
2672 RX = Perm.R | Perm.X
2673 WX = Perm.W | Perm.X
2674 RWX = Perm.R | Perm.W | Perm.X
2675 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2676 for i in values:
2677 self.assertEqual(~i, ~i.value)
2678 self.assertEqual((~i).value, ~i.value)
2679 self.assertIs(type(~i), Perm)
2680 self.assertEqual(~~i, i)
2681 for i in Perm:
2682 self.assertIs(~~i, i)
2683 Open = self.Open
2684 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2685 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2686
2687 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002688 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002689 lst = list(Perm)
2690 self.assertEqual(len(lst), len(Perm))
2691 self.assertEqual(len(Perm), 3, Perm)
2692 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2693 for i, n in enumerate('R W X'.split()):
2694 v = 1<<i
2695 e = Perm(v)
2696 self.assertEqual(e.value, v)
2697 self.assertEqual(type(e.value), int)
2698 self.assertEqual(e, v)
2699 self.assertEqual(e.name, n)
2700 self.assertIn(e, Perm)
2701 self.assertIs(type(e), Perm)
2702
2703 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002704 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002705 lst = list(Perm)
2706 self.assertEqual(len(lst), len(Perm))
2707 self.assertEqual(len(Perm), 3, Perm)
2708 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2709 for i, n in enumerate('R W X'.split()):
2710 v = 8<<i
2711 e = Perm(v)
2712 self.assertEqual(e.value, v)
2713 self.assertEqual(type(e.value), int)
2714 self.assertEqual(e, v)
2715 self.assertEqual(e.name, n)
2716 self.assertIn(e, Perm)
2717 self.assertIs(type(e), Perm)
2718
2719 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002720 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002721 lst = list(Perm)
2722 self.assertEqual(len(lst), len(Perm))
2723 self.assertEqual(len(Perm), 3, Perm)
2724 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2725 for i, n in enumerate('R W X'.split()):
2726 v = 1<<i
2727 e = Perm(v)
2728 self.assertEqual(e.value, v)
2729 self.assertEqual(type(e.value), int)
2730 self.assertEqual(e, v)
2731 self.assertEqual(e.name, n)
2732 self.assertIn(e, Perm)
2733 self.assertIs(type(e), Perm)
2734
2735 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002736 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002737 lst = list(Perm)
2738 self.assertEqual(len(lst), len(Perm))
2739 self.assertEqual(len(Perm), 3, Perm)
2740 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2741 for i, n in enumerate('R W X'.split()):
2742 v = 1<<(2*i+1)
2743 e = Perm(v)
2744 self.assertEqual(e.value, v)
2745 self.assertEqual(type(e.value), int)
2746 self.assertEqual(e, v)
2747 self.assertEqual(e.name, n)
2748 self.assertIn(e, Perm)
2749 self.assertIs(type(e), Perm)
2750
2751 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002752 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002753 lst = list(Perm)
2754 self.assertEqual(len(lst), len(Perm))
2755 self.assertEqual(len(Perm), 3, Perm)
2756 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2757 for i, n in enumerate('R W X'.split()):
2758 v = 1<<(2*i+1)
2759 e = Perm(v)
2760 self.assertEqual(e.value, v)
2761 self.assertEqual(type(e.value), int)
2762 self.assertEqual(e, v)
2763 self.assertEqual(e.name, n)
2764 self.assertIn(e, Perm)
2765 self.assertIs(type(e), Perm)
2766
2767
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002768 def test_programatic_function_from_empty_list(self):
2769 Perm = enum.IntFlag('Perm', [])
2770 lst = list(Perm)
2771 self.assertEqual(len(lst), len(Perm))
2772 self.assertEqual(len(Perm), 0, Perm)
2773 Thing = enum.Enum('Thing', [])
2774 lst = list(Thing)
2775 self.assertEqual(len(lst), len(Thing))
2776 self.assertEqual(len(Thing), 0, Thing)
2777
2778
2779 def test_programatic_function_from_empty_tuple(self):
2780 Perm = enum.IntFlag('Perm', ())
2781 lst = list(Perm)
2782 self.assertEqual(len(lst), len(Perm))
2783 self.assertEqual(len(Perm), 0, Perm)
2784 Thing = enum.Enum('Thing', ())
2785 self.assertEqual(len(lst), len(Thing))
2786 self.assertEqual(len(Thing), 0, Thing)
2787
Rahul Jha94306522018-09-10 23:51:04 +05302788 def test_contains(self):
2789 Open = self.Open
2790 Color = self.Color
2791 self.assertTrue(Color.GREEN in Color)
2792 self.assertTrue(Open.RW in Open)
2793 self.assertFalse(Color.GREEN in Open)
2794 self.assertFalse(Open.RW in Color)
2795 with self.assertRaises(TypeError):
2796 'GREEN' in Color
2797 with self.assertRaises(TypeError):
2798 'RW' in Open
2799 with self.assertRaises(TypeError):
2800 2 in Color
2801 with self.assertRaises(TypeError):
2802 2 in Open
2803
2804 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002805 Perm = self.Perm
2806 R, W, X = Perm
2807 RW = R | W
2808 RX = R | X
2809 WX = W | X
2810 RWX = R | W | X
2811 self.assertTrue(R in RW)
2812 self.assertTrue(R in RX)
2813 self.assertTrue(R in RWX)
2814 self.assertTrue(W in RW)
2815 self.assertTrue(W in WX)
2816 self.assertTrue(W in RWX)
2817 self.assertTrue(X in RX)
2818 self.assertTrue(X in WX)
2819 self.assertTrue(X in RWX)
2820 self.assertFalse(R in WX)
2821 self.assertFalse(W in RX)
2822 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302823 with self.assertRaises(TypeError):
2824 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002825
Ethan Furman7219e272020-09-16 13:01:00 -07002826 def test_member_iter(self):
2827 Color = self.Color
2828 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2829 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2830 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2831
Ethan Furman25d94bb2016-09-02 16:32:32 -07002832 def test_bool(self):
2833 Perm = self.Perm
2834 for f in Perm:
2835 self.assertTrue(f)
2836 Open = self.Open
2837 for f in Open:
2838 self.assertEqual(bool(f.value), bool(f))
2839
Ethan Furman5bdab642018-09-21 19:03:09 -07002840 def test_multiple_mixin(self):
2841 class AllMixin:
2842 @classproperty
2843 def ALL(cls):
2844 members = list(cls)
2845 all_value = None
2846 if members:
2847 all_value = members[0]
2848 for member in members[1:]:
2849 all_value |= member
2850 cls.ALL = all_value
2851 return all_value
2852 class StrMixin:
2853 def __str__(self):
2854 return self._name_.lower()
2855 class Color(AllMixin, IntFlag):
2856 RED = auto()
2857 GREEN = auto()
2858 BLUE = auto()
2859 self.assertEqual(Color.RED.value, 1)
2860 self.assertEqual(Color.GREEN.value, 2)
2861 self.assertEqual(Color.BLUE.value, 4)
2862 self.assertEqual(Color.ALL.value, 7)
2863 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2864 class Color(AllMixin, StrMixin, IntFlag):
2865 RED = auto()
2866 GREEN = auto()
2867 BLUE = auto()
2868 self.assertEqual(Color.RED.value, 1)
2869 self.assertEqual(Color.GREEN.value, 2)
2870 self.assertEqual(Color.BLUE.value, 4)
2871 self.assertEqual(Color.ALL.value, 7)
2872 self.assertEqual(str(Color.BLUE), 'blue')
2873 class Color(StrMixin, AllMixin, IntFlag):
2874 RED = auto()
2875 GREEN = auto()
2876 BLUE = auto()
2877 self.assertEqual(Color.RED.value, 1)
2878 self.assertEqual(Color.GREEN.value, 2)
2879 self.assertEqual(Color.BLUE.value, 4)
2880 self.assertEqual(Color.ALL.value, 7)
2881 self.assertEqual(str(Color.BLUE), 'blue')
2882
Hai Shie80697d2020-05-28 06:10:27 +08002883 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002884 def test_unique_composite(self):
2885 # override __eq__ to be identity only
2886 class TestFlag(IntFlag):
2887 one = auto()
2888 two = auto()
2889 three = auto()
2890 four = auto()
2891 five = auto()
2892 six = auto()
2893 seven = auto()
2894 eight = auto()
2895 def __eq__(self, other):
2896 return self is other
2897 def __hash__(self):
2898 return hash(self._value_)
2899 # have multiple threads competing to complete the composite members
2900 seen = set()
2901 failed = False
2902 def cycle_enum():
2903 nonlocal failed
2904 try:
2905 for i in range(256):
2906 seen.add(TestFlag(i))
2907 except Exception:
2908 failed = True
2909 threads = [
2910 threading.Thread(target=cycle_enum)
2911 for _ in range(8)
2912 ]
Hai Shie80697d2020-05-28 06:10:27 +08002913 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002914 pass
2915 # check that only 248 members were created
2916 self.assertFalse(
2917 failed,
2918 'at least one thread failed while creating composite members')
2919 self.assertEqual(256, len(seen), 'too many composite members created')
2920
2921
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002922class TestEmptyAndNonLatinStrings(unittest.TestCase):
2923
2924 def test_empty_string(self):
2925 with self.assertRaises(ValueError):
2926 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2927
2928 def test_non_latin_character_string(self):
2929 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2930 item = getattr(greek_abc, '\u03B1')
2931 self.assertEqual(item.value, 1)
2932
2933 def test_non_latin_number_string(self):
2934 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2935 item = getattr(hebrew_123, '\u05D0')
2936 self.assertEqual(item.value, 1)
2937
2938
Ethan Furmanf24bb352013-07-18 17:05:39 -07002939class TestUnique(unittest.TestCase):
2940
2941 def test_unique_clean(self):
2942 @unique
2943 class Clean(Enum):
2944 one = 1
2945 two = 'dos'
2946 tres = 4.0
2947 @unique
2948 class Cleaner(IntEnum):
2949 single = 1
2950 double = 2
2951 triple = 3
2952
2953 def test_unique_dirty(self):
2954 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2955 @unique
2956 class Dirty(Enum):
2957 one = 1
2958 two = 'dos'
2959 tres = 1
2960 with self.assertRaisesRegex(
2961 ValueError,
2962 'double.*single.*turkey.*triple',
2963 ):
2964 @unique
2965 class Dirtier(IntEnum):
2966 single = 1
2967 double = 1
2968 triple = 3
2969 turkey = 3
2970
Ethan Furman3803ad42016-05-01 10:03:53 -07002971 def test_unique_with_name(self):
2972 @unique
2973 class Silly(Enum):
2974 one = 1
2975 two = 'dos'
2976 name = 3
2977 @unique
2978 class Sillier(IntEnum):
2979 single = 1
2980 name = 2
2981 triple = 3
2982 value = 4
2983
Ethan Furmanf24bb352013-07-18 17:05:39 -07002984
Ethan Furman5bdab642018-09-21 19:03:09 -07002985
Ethan Furman3323da92015-04-11 09:39:59 -07002986expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002987Help on class Color in module %s:
2988
2989class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002990 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2991 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002992 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002993 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002994 | Method resolution order:
2995 | Color
2996 | enum.Enum
2997 | builtins.object
2998 |\x20\x20
2999 | Data and other attributes defined here:
3000 |\x20\x20
3001 | blue = <Color.blue: 3>
3002 |\x20\x20
3003 | green = <Color.green: 2>
3004 |\x20\x20
3005 | red = <Color.red: 1>
3006 |\x20\x20
3007 | ----------------------------------------------------------------------
3008 | Data descriptors inherited from enum.Enum:
3009 |\x20\x20
3010 | name
3011 | The name of the Enum member.
3012 |\x20\x20
3013 | value
3014 | The value of the Enum member.
3015 |\x20\x20
3016 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003017 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003018 |\x20\x20
3019 | __members__
3020 | Returns a mapping of member name->value.
3021 |\x20\x20\x20\x20\x20\x20
3022 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003023 | is a read-only view of the internal mapping."""
3024
3025expected_help_output_without_docs = """\
3026Help on class Color in module %s:
3027
3028class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003029 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3030 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003031 | Method resolution order:
3032 | Color
3033 | enum.Enum
3034 | builtins.object
3035 |\x20\x20
3036 | Data and other attributes defined here:
3037 |\x20\x20
3038 | blue = <Color.blue: 3>
3039 |\x20\x20
3040 | green = <Color.green: 2>
3041 |\x20\x20
3042 | red = <Color.red: 1>
3043 |\x20\x20
3044 | ----------------------------------------------------------------------
3045 | Data descriptors inherited from enum.Enum:
3046 |\x20\x20
3047 | name
3048 |\x20\x20
3049 | value
3050 |\x20\x20
3051 | ----------------------------------------------------------------------
3052 | Data descriptors inherited from enum.EnumMeta:
3053 |\x20\x20
3054 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003055
3056class TestStdLib(unittest.TestCase):
3057
Ethan Furman48a724f2015-04-11 23:23:06 -07003058 maxDiff = None
3059
Ethan Furman5875d742013-10-21 20:45:55 -07003060 class Color(Enum):
3061 red = 1
3062 green = 2
3063 blue = 3
3064
3065 def test_pydoc(self):
3066 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003067 if StrEnum.__doc__ is None:
3068 expected_text = expected_help_output_without_docs % __name__
3069 else:
3070 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003071 output = StringIO()
3072 helper = pydoc.Helper(output=output)
3073 helper(self.Color)
3074 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003075 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003076
3077 def test_inspect_getmembers(self):
3078 values = dict((
3079 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003080 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003081 ('__members__', self.Color.__members__),
3082 ('__module__', __name__),
3083 ('blue', self.Color.blue),
3084 ('green', self.Color.green),
3085 ('name', Enum.__dict__['name']),
3086 ('red', self.Color.red),
3087 ('value', Enum.__dict__['value']),
3088 ))
3089 result = dict(inspect.getmembers(self.Color))
3090 self.assertEqual(values.keys(), result.keys())
3091 failed = False
3092 for k in values.keys():
3093 if result[k] != values[k]:
3094 print()
3095 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3096 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3097 failed = True
3098 if failed:
3099 self.fail("result does not equal expected, see print above")
3100
3101 def test_inspect_classify_class_attrs(self):
3102 # indirectly test __objclass__
3103 from inspect import Attribute
3104 values = [
3105 Attribute(name='__class__', kind='data',
3106 defining_class=object, object=EnumMeta),
3107 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003108 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003109 Attribute(name='__members__', kind='property',
3110 defining_class=EnumMeta, object=EnumMeta.__members__),
3111 Attribute(name='__module__', kind='data',
3112 defining_class=self.Color, object=__name__),
3113 Attribute(name='blue', kind='data',
3114 defining_class=self.Color, object=self.Color.blue),
3115 Attribute(name='green', kind='data',
3116 defining_class=self.Color, object=self.Color.green),
3117 Attribute(name='red', kind='data',
3118 defining_class=self.Color, object=self.Color.red),
3119 Attribute(name='name', kind='data',
3120 defining_class=Enum, object=Enum.__dict__['name']),
3121 Attribute(name='value', kind='data',
3122 defining_class=Enum, object=Enum.__dict__['value']),
3123 ]
3124 values.sort(key=lambda item: item.name)
3125 result = list(inspect.classify_class_attrs(self.Color))
3126 result.sort(key=lambda item: item.name)
3127 failed = False
3128 for v, r in zip(values, result):
3129 if r != v:
3130 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3131 failed = True
3132 if failed:
3133 self.fail("result does not equal expected, see print above")
3134
Martin Panter19e69c52015-11-14 12:46:42 +00003135
3136class MiscTestCase(unittest.TestCase):
3137 def test__all__(self):
3138 support.check__all__(self, enum)
3139
3140
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003141# These are unordered here on purpose to ensure that declaration order
3142# makes no difference.
3143CONVERT_TEST_NAME_D = 5
3144CONVERT_TEST_NAME_C = 5
3145CONVERT_TEST_NAME_B = 5
3146CONVERT_TEST_NAME_A = 5 # This one should sort first.
3147CONVERT_TEST_NAME_E = 5
3148CONVERT_TEST_NAME_F = 5
3149
3150class TestIntEnumConvert(unittest.TestCase):
3151 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003152 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003153 'UnittestConvert',
3154 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003155 filter=lambda x: x.startswith('CONVERT_TEST_'))
3156 # We don't want the reverse lookup value to vary when there are
3157 # multiple possible names for a given value. It should always
3158 # report the first lexigraphical name in that case.
3159 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3160
3161 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003162 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003163 'UnittestConvert',
3164 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003165 filter=lambda x: x.startswith('CONVERT_TEST_'))
3166 # Ensure that test_type has all of the desired names and values.
3167 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3168 test_type.CONVERT_TEST_NAME_A)
3169 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3170 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3171 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3172 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3173 # Ensure that test_type only picked up names matching the filter.
3174 self.assertEqual([name for name in dir(test_type)
3175 if name[0:2] not in ('CO', '__')],
3176 [], msg='Names other than CONVERT_TEST_* found.')
3177
orlnub1230fb9fad2018-09-12 20:28:53 +03003178 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3179 '_convert was deprecated in 3.8')
3180 def test_convert_warn(self):
3181 with self.assertWarns(DeprecationWarning):
3182 enum.IntEnum._convert(
3183 'UnittestConvert',
3184 ('test.test_enum', '__main__')[__name__=='__main__'],
3185 filter=lambda x: x.startswith('CONVERT_TEST_'))
3186
3187 @unittest.skipUnless(sys.version_info >= (3, 9),
3188 '_convert was removed in 3.9')
3189 def test_convert_raise(self):
3190 with self.assertRaises(AttributeError):
3191 enum.IntEnum._convert(
3192 'UnittestConvert',
3193 ('test.test_enum', '__main__')[__name__=='__main__'],
3194 filter=lambda x: x.startswith('CONVERT_TEST_'))
3195
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003196
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003197if __name__ == '__main__':
3198 unittest.main()