blob: a909c108833fc08670ccc53a13ec2235935ad6d7 [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
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219 def test_enum_in_enum_out(self):
220 Season = self.Season
221 self.assertIs(Season(Season.WINTER), Season.WINTER)
222
223 def test_enum_value(self):
224 Season = self.Season
225 self.assertEqual(Season.SPRING.value, 1)
226
227 def test_intenum_value(self):
228 self.assertEqual(IntStooges.CURLY.value, 2)
229
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700230 def test_enum(self):
231 Season = self.Season
232 lst = list(Season)
233 self.assertEqual(len(lst), len(Season))
234 self.assertEqual(len(Season), 4, Season)
235 self.assertEqual(
236 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
237
238 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
239 e = Season(i)
240 self.assertEqual(e, getattr(Season, season))
241 self.assertEqual(e.value, i)
242 self.assertNotEqual(e, i)
243 self.assertEqual(e.name, season)
244 self.assertIn(e, Season)
245 self.assertIs(type(e), Season)
246 self.assertIsInstance(e, Season)
247 self.assertEqual(str(e), 'Season.' + season)
248 self.assertEqual(
249 repr(e),
250 '<Season.{0}: {1}>'.format(season, i),
251 )
252
253 def test_value_name(self):
254 Season = self.Season
255 self.assertEqual(Season.SPRING.name, 'SPRING')
256 self.assertEqual(Season.SPRING.value, 1)
257 with self.assertRaises(AttributeError):
258 Season.SPRING.name = 'invierno'
259 with self.assertRaises(AttributeError):
260 Season.SPRING.value = 2
261
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700262 def test_changing_member(self):
263 Season = self.Season
264 with self.assertRaises(AttributeError):
265 Season.WINTER = 'really cold'
266
Ethan Furman64a99722013-09-22 16:18:19 -0700267 def test_attribute_deletion(self):
268 class Season(Enum):
269 SPRING = 1
270 SUMMER = 2
271 AUTUMN = 3
272 WINTER = 4
273
274 def spam(cls):
275 pass
276
277 self.assertTrue(hasattr(Season, 'spam'))
278 del Season.spam
279 self.assertFalse(hasattr(Season, 'spam'))
280
281 with self.assertRaises(AttributeError):
282 del Season.SPRING
283 with self.assertRaises(AttributeError):
284 del Season.DRY
285 with self.assertRaises(AttributeError):
286 del Season.SPRING.name
287
Ethan Furman5de67b12016-04-13 23:52:09 -0700288 def test_bool_of_class(self):
289 class Empty(Enum):
290 pass
291 self.assertTrue(bool(Empty))
292
293 def test_bool_of_member(self):
294 class Count(Enum):
295 zero = 0
296 one = 1
297 two = 2
298 for member in Count:
299 self.assertTrue(bool(member))
300
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700301 def test_invalid_names(self):
302 with self.assertRaises(ValueError):
303 class Wrong(Enum):
304 mro = 9
305 with self.assertRaises(ValueError):
306 class Wrong(Enum):
307 _create_= 11
308 with self.assertRaises(ValueError):
309 class Wrong(Enum):
310 _get_mixins_ = 9
311 with self.assertRaises(ValueError):
312 class Wrong(Enum):
313 _find_new_ = 1
314 with self.assertRaises(ValueError):
315 class Wrong(Enum):
316 _any_name_ = 9
317
Ethan Furman6db1fd52015-09-17 21:49:12 -0700318 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800319 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700320 class Logic(Enum):
321 true = True
322 false = False
323 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800324 self.assertTrue(Logic.false)
325 # unless overridden
326 class RealLogic(Enum):
327 true = True
328 false = False
329 def __bool__(self):
330 return bool(self._value_)
331 self.assertTrue(RealLogic.true)
332 self.assertFalse(RealLogic.false)
333 # mixed Enums depend on mixed-in type
334 class IntLogic(int, Enum):
335 true = 1
336 false = 0
337 self.assertTrue(IntLogic.true)
338 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700339
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700340 def test_contains(self):
341 Season = self.Season
342 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530343 with self.assertRaises(TypeError):
344 3 in Season
345 with self.assertRaises(TypeError):
346 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347
348 val = Season(3)
349 self.assertIn(val, Season)
350
351 class OtherEnum(Enum):
352 one = 1; two = 2
353 self.assertNotIn(OtherEnum.two, Season)
354
355 def test_comparisons(self):
356 Season = self.Season
357 with self.assertRaises(TypeError):
358 Season.SPRING < Season.WINTER
359 with self.assertRaises(TypeError):
360 Season.SPRING > 4
361
362 self.assertNotEqual(Season.SPRING, 1)
363
364 class Part(Enum):
365 SPRING = 1
366 CLIP = 2
367 BARREL = 3
368
369 self.assertNotEqual(Season.SPRING, Part.SPRING)
370 with self.assertRaises(TypeError):
371 Season.SPRING < Part.CLIP
372
373 def test_enum_duplicates(self):
374 class Season(Enum):
375 SPRING = 1
376 SUMMER = 2
377 AUTUMN = FALL = 3
378 WINTER = 4
379 ANOTHER_SPRING = 1
380 lst = list(Season)
381 self.assertEqual(
382 lst,
383 [Season.SPRING, Season.SUMMER,
384 Season.AUTUMN, Season.WINTER,
385 ])
386 self.assertIs(Season.FALL, Season.AUTUMN)
387 self.assertEqual(Season.FALL.value, 3)
388 self.assertEqual(Season.AUTUMN.value, 3)
389 self.assertIs(Season(3), Season.AUTUMN)
390 self.assertIs(Season(1), Season.SPRING)
391 self.assertEqual(Season.FALL.name, 'AUTUMN')
392 self.assertEqual(
393 [k for k,v in Season.__members__.items() if v.name != k],
394 ['FALL', 'ANOTHER_SPRING'],
395 )
396
Ethan Furman101e0742013-09-15 12:34:36 -0700397 def test_duplicate_name(self):
398 with self.assertRaises(TypeError):
399 class Color(Enum):
400 red = 1
401 green = 2
402 blue = 3
403 red = 4
404
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 def red(self):
411 return 'red'
412
413 with self.assertRaises(TypeError):
414 class Color(Enum):
415 @property
416 def red(self):
417 return 'redder'
418 red = 1
419 green = 2
420 blue = 3
421
Zackery Spytz2ec67522020-09-13 14:27:51 -0600422 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700423 with self.assertRaisesRegex(
424 ValueError,
425 '_sunder_ names, such as "_bad_", are reserved',
426 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600427 class Bad(Enum):
428 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700429
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700430 def test_enum_with_value_name(self):
431 class Huh(Enum):
432 name = 1
433 value = 2
434 self.assertEqual(
435 list(Huh),
436 [Huh.name, Huh.value],
437 )
438 self.assertIs(type(Huh.name), Huh)
439 self.assertEqual(Huh.name.name, 'name')
440 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700441
442 def test_format_enum(self):
443 Season = self.Season
444 self.assertEqual('{}'.format(Season.SPRING),
445 '{}'.format(str(Season.SPRING)))
446 self.assertEqual( '{:}'.format(Season.SPRING),
447 '{:}'.format(str(Season.SPRING)))
448 self.assertEqual('{:20}'.format(Season.SPRING),
449 '{:20}'.format(str(Season.SPRING)))
450 self.assertEqual('{:^20}'.format(Season.SPRING),
451 '{:^20}'.format(str(Season.SPRING)))
452 self.assertEqual('{:>20}'.format(Season.SPRING),
453 '{:>20}'.format(str(Season.SPRING)))
454 self.assertEqual('{:<20}'.format(Season.SPRING),
455 '{:<20}'.format(str(Season.SPRING)))
456
thatneat2f19e822019-07-04 11:28:37 -0700457 def test_str_override_enum(self):
458 class EnumWithStrOverrides(Enum):
459 one = auto()
460 two = auto()
461
462 def __str__(self):
463 return 'Str!'
464 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
465 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
466
467 def test_format_override_enum(self):
468 class EnumWithFormatOverride(Enum):
469 one = 1.0
470 two = 2.0
471 def __format__(self, spec):
472 return 'Format!!'
473 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
474 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
475
476 def test_str_and_format_override_enum(self):
477 class EnumWithStrFormatOverrides(Enum):
478 one = auto()
479 two = auto()
480 def __str__(self):
481 return 'Str!'
482 def __format__(self, spec):
483 return 'Format!'
484 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
485 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
486
487 def test_str_override_mixin(self):
488 class MixinEnumWithStrOverride(float, Enum):
489 one = 1.0
490 two = 2.0
491 def __str__(self):
492 return 'Overridden!'
493 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
494 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
495
496 def test_str_and_format_override_mixin(self):
497 class MixinWithStrFormatOverrides(float, Enum):
498 one = 1.0
499 two = 2.0
500 def __str__(self):
501 return 'Str!'
502 def __format__(self, spec):
503 return 'Format!'
504 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
505 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
506
507 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700508 class TestFloat(float, Enum):
509 one = 1.0
510 two = 2.0
511 def __format__(self, spec):
512 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700513 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700514 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
515
516 def assertFormatIsValue(self, spec, member):
517 self.assertEqual(spec.format(member), spec.format(member.value))
518
519 def test_format_enum_date(self):
520 Holiday = self.Holiday
521 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
522 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
523 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
524 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
525 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
526 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
527 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
528 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
529
530 def test_format_enum_float(self):
531 Konstants = self.Konstants
532 self.assertFormatIsValue('{}', Konstants.TAU)
533 self.assertFormatIsValue('{:}', Konstants.TAU)
534 self.assertFormatIsValue('{:20}', Konstants.TAU)
535 self.assertFormatIsValue('{:^20}', Konstants.TAU)
536 self.assertFormatIsValue('{:>20}', Konstants.TAU)
537 self.assertFormatIsValue('{:<20}', Konstants.TAU)
538 self.assertFormatIsValue('{:n}', Konstants.TAU)
539 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
540 self.assertFormatIsValue('{:f}', Konstants.TAU)
541
542 def test_format_enum_int(self):
543 Grades = self.Grades
544 self.assertFormatIsValue('{}', Grades.C)
545 self.assertFormatIsValue('{:}', Grades.C)
546 self.assertFormatIsValue('{:20}', Grades.C)
547 self.assertFormatIsValue('{:^20}', Grades.C)
548 self.assertFormatIsValue('{:>20}', Grades.C)
549 self.assertFormatIsValue('{:<20}', Grades.C)
550 self.assertFormatIsValue('{:+}', Grades.C)
551 self.assertFormatIsValue('{:08X}', Grades.C)
552 self.assertFormatIsValue('{:b}', Grades.C)
553
554 def test_format_enum_str(self):
555 Directional = self.Directional
556 self.assertFormatIsValue('{}', Directional.WEST)
557 self.assertFormatIsValue('{:}', Directional.WEST)
558 self.assertFormatIsValue('{:20}', Directional.WEST)
559 self.assertFormatIsValue('{:^20}', Directional.WEST)
560 self.assertFormatIsValue('{:>20}', Directional.WEST)
561 self.assertFormatIsValue('{:<20}', Directional.WEST)
562
Ethan Furmanbff01f32020-09-15 15:56:26 -0700563 def test_enum_str_override(self):
564 class MyStrEnum(Enum):
565 def __str__(self):
566 return 'MyStr'
567 class MyMethodEnum(Enum):
568 def hello(self):
569 return 'Hello! My name is %s' % self.name
570 class Test1Enum(MyMethodEnum, int, MyStrEnum):
571 One = 1
572 Two = 2
573 self.assertEqual(str(Test1Enum.One), 'MyStr')
574 #
575 class Test2Enum(MyStrEnum, MyMethodEnum):
576 One = 1
577 Two = 2
578 self.assertEqual(str(Test2Enum.One), 'MyStr')
579
580 def test_inherited_data_type(self):
581 class HexInt(int):
582 def __repr__(self):
583 return hex(self)
584 class MyEnum(HexInt, enum.Enum):
585 A = 1
586 B = 2
587 C = 3
588 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
589
590 def test_too_many_data_types(self):
591 with self.assertRaisesRegex(TypeError, 'too many data types'):
592 class Huh(str, int, Enum):
593 One = 1
594
595 class MyStr(str):
596 def hello(self):
597 return 'hello, %s' % self
598 class MyInt(int):
599 def repr(self):
600 return hex(self)
601 with self.assertRaisesRegex(TypeError, 'too many data types'):
602 class Huh(MyStr, MyInt, Enum):
603 One = 1
604
605
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700606 def test_hash(self):
607 Season = self.Season
608 dates = {}
609 dates[Season.WINTER] = '1225'
610 dates[Season.SPRING] = '0315'
611 dates[Season.SUMMER] = '0704'
612 dates[Season.AUTUMN] = '1031'
613 self.assertEqual(dates[Season.AUTUMN], '1031')
614
615 def test_intenum_from_scratch(self):
616 class phy(int, Enum):
617 pi = 3
618 tau = 2 * pi
619 self.assertTrue(phy.pi < phy.tau)
620
621 def test_intenum_inherited(self):
622 class IntEnum(int, Enum):
623 pass
624 class phy(IntEnum):
625 pi = 3
626 tau = 2 * pi
627 self.assertTrue(phy.pi < phy.tau)
628
629 def test_floatenum_from_scratch(self):
630 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700631 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700632 tau = 2 * pi
633 self.assertTrue(phy.pi < phy.tau)
634
635 def test_floatenum_inherited(self):
636 class FloatEnum(float, Enum):
637 pass
638 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700639 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700640 tau = 2 * pi
641 self.assertTrue(phy.pi < phy.tau)
642
643 def test_strenum_from_scratch(self):
644 class phy(str, Enum):
645 pi = 'Pi'
646 tau = 'Tau'
647 self.assertTrue(phy.pi < phy.tau)
648
649 def test_strenum_inherited(self):
650 class StrEnum(str, Enum):
651 pass
652 class phy(StrEnum):
653 pi = 'Pi'
654 tau = 'Tau'
655 self.assertTrue(phy.pi < phy.tau)
656
657
658 def test_intenum(self):
659 class WeekDay(IntEnum):
660 SUNDAY = 1
661 MONDAY = 2
662 TUESDAY = 3
663 WEDNESDAY = 4
664 THURSDAY = 5
665 FRIDAY = 6
666 SATURDAY = 7
667
668 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
669 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
670
671 lst = list(WeekDay)
672 self.assertEqual(len(lst), len(WeekDay))
673 self.assertEqual(len(WeekDay), 7)
674 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
675 target = target.split()
676 for i, weekday in enumerate(target, 1):
677 e = WeekDay(i)
678 self.assertEqual(e, i)
679 self.assertEqual(int(e), i)
680 self.assertEqual(e.name, weekday)
681 self.assertIn(e, WeekDay)
682 self.assertEqual(lst.index(e)+1, i)
683 self.assertTrue(0 < e < 8)
684 self.assertIs(type(e), WeekDay)
685 self.assertIsInstance(e, int)
686 self.assertIsInstance(e, Enum)
687
688 def test_intenum_duplicates(self):
689 class WeekDay(IntEnum):
690 SUNDAY = 1
691 MONDAY = 2
692 TUESDAY = TEUSDAY = 3
693 WEDNESDAY = 4
694 THURSDAY = 5
695 FRIDAY = 6
696 SATURDAY = 7
697 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
698 self.assertEqual(WeekDay(3).name, 'TUESDAY')
699 self.assertEqual([k for k,v in WeekDay.__members__.items()
700 if v.name != k], ['TEUSDAY', ])
701
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300702 def test_intenum_from_bytes(self):
703 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
704 with self.assertRaises(ValueError):
705 IntStooges.from_bytes(b'\x00\x05', 'big')
706
707 def test_floatenum_fromhex(self):
708 h = float.hex(FloatStooges.MOE.value)
709 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
710 h = float.hex(FloatStooges.MOE.value + 0.01)
711 with self.assertRaises(ValueError):
712 FloatStooges.fromhex(h)
713
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700714 def test_pickle_enum(self):
715 if isinstance(Stooges, Exception):
716 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800717 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
718 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700719
720 def test_pickle_int(self):
721 if isinstance(IntStooges, Exception):
722 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800723 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
724 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700725
726 def test_pickle_float(self):
727 if isinstance(FloatStooges, Exception):
728 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800729 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
730 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700731
732 def test_pickle_enum_function(self):
733 if isinstance(Answer, Exception):
734 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800735 test_pickle_dump_load(self.assertIs, Answer.him)
736 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700737
738 def test_pickle_enum_function_with_module(self):
739 if isinstance(Question, Exception):
740 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800741 test_pickle_dump_load(self.assertIs, Question.who)
742 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700743
Ethan Furmanca1b7942014-02-08 11:36:27 -0800744 def test_enum_function_with_qualname(self):
745 if isinstance(Theory, Exception):
746 raise Theory
747 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
748
749 def test_class_nested_enum_and_pickle_protocol_four(self):
750 # would normally just have this directly in the class namespace
751 class NestedEnum(Enum):
752 twigs = 'common'
753 shiny = 'rare'
754
755 self.__class__.NestedEnum = NestedEnum
756 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300757 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800758
Ethan Furman24e837f2015-03-18 17:27:57 -0700759 def test_pickle_by_name(self):
760 class ReplaceGlobalInt(IntEnum):
761 ONE = 1
762 TWO = 2
763 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
764 for proto in range(HIGHEST_PROTOCOL):
765 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
766
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700767 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800768 BadPickle = Enum(
769 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700770 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800771 # now break BadPickle to test exception raising
772 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800773 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
774 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700775
776 def test_string_enum(self):
777 class SkillLevel(str, Enum):
778 master = 'what is the sound of one hand clapping?'
779 journeyman = 'why did the chicken cross the road?'
780 apprentice = 'knock, knock!'
781 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
782
783 def test_getattr_getitem(self):
784 class Period(Enum):
785 morning = 1
786 noon = 2
787 evening = 3
788 night = 4
789 self.assertIs(Period(2), Period.noon)
790 self.assertIs(getattr(Period, 'night'), Period.night)
791 self.assertIs(Period['morning'], Period.morning)
792
793 def test_getattr_dunder(self):
794 Season = self.Season
795 self.assertTrue(getattr(Season, '__eq__'))
796
797 def test_iteration_order(self):
798 class Season(Enum):
799 SUMMER = 2
800 WINTER = 4
801 AUTUMN = 3
802 SPRING = 1
803 self.assertEqual(
804 list(Season),
805 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
806 )
807
Ethan Furman2131a4a2013-09-14 18:11:24 -0700808 def test_reversed_iteration_order(self):
809 self.assertEqual(
810 list(reversed(self.Season)),
811 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
812 self.Season.SPRING]
813 )
814
Martin Pantereb995702016-07-28 01:11:04 +0000815 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700816 SummerMonth = Enum('SummerMonth', 'june july august')
817 lst = list(SummerMonth)
818 self.assertEqual(len(lst), len(SummerMonth))
819 self.assertEqual(len(SummerMonth), 3, SummerMonth)
820 self.assertEqual(
821 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
822 lst,
823 )
824 for i, month in enumerate('june july august'.split(), 1):
825 e = SummerMonth(i)
826 self.assertEqual(int(e.value), i)
827 self.assertNotEqual(e, i)
828 self.assertEqual(e.name, month)
829 self.assertIn(e, SummerMonth)
830 self.assertIs(type(e), SummerMonth)
831
Martin Pantereb995702016-07-28 01:11:04 +0000832 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700833 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
834 lst = list(SummerMonth)
835 self.assertEqual(len(lst), len(SummerMonth))
836 self.assertEqual(len(SummerMonth), 3, SummerMonth)
837 self.assertEqual(
838 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
839 lst,
840 )
841 for i, month in enumerate('june july august'.split(), 10):
842 e = SummerMonth(i)
843 self.assertEqual(int(e.value), i)
844 self.assertNotEqual(e, i)
845 self.assertEqual(e.name, month)
846 self.assertIn(e, SummerMonth)
847 self.assertIs(type(e), SummerMonth)
848
Martin Pantereb995702016-07-28 01:11:04 +0000849 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700850 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
851 lst = list(SummerMonth)
852 self.assertEqual(len(lst), len(SummerMonth))
853 self.assertEqual(len(SummerMonth), 3, SummerMonth)
854 self.assertEqual(
855 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
856 lst,
857 )
858 for i, month in enumerate('june july august'.split(), 1):
859 e = SummerMonth(i)
860 self.assertEqual(int(e.value), i)
861 self.assertNotEqual(e, i)
862 self.assertEqual(e.name, month)
863 self.assertIn(e, SummerMonth)
864 self.assertIs(type(e), SummerMonth)
865
Martin Pantereb995702016-07-28 01:11:04 +0000866 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700867 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
868 lst = list(SummerMonth)
869 self.assertEqual(len(lst), len(SummerMonth))
870 self.assertEqual(len(SummerMonth), 3, SummerMonth)
871 self.assertEqual(
872 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
873 lst,
874 )
875 for i, month in enumerate('june july august'.split(), 20):
876 e = SummerMonth(i)
877 self.assertEqual(int(e.value), i)
878 self.assertNotEqual(e, i)
879 self.assertEqual(e.name, month)
880 self.assertIn(e, SummerMonth)
881 self.assertIs(type(e), SummerMonth)
882
Martin Pantereb995702016-07-28 01:11:04 +0000883 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700884 SummerMonth = Enum(
885 'SummerMonth',
886 (('june', 1), ('july', 2), ('august', 3))
887 )
888 lst = list(SummerMonth)
889 self.assertEqual(len(lst), len(SummerMonth))
890 self.assertEqual(len(SummerMonth), 3, SummerMonth)
891 self.assertEqual(
892 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
893 lst,
894 )
895 for i, month in enumerate('june july august'.split(), 1):
896 e = SummerMonth(i)
897 self.assertEqual(int(e.value), i)
898 self.assertNotEqual(e, i)
899 self.assertEqual(e.name, month)
900 self.assertIn(e, SummerMonth)
901 self.assertIs(type(e), SummerMonth)
902
Martin Pantereb995702016-07-28 01:11:04 +0000903 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700904 SummerMonth = Enum(
905 'SummerMonth',
906 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
907 )
908 lst = list(SummerMonth)
909 self.assertEqual(len(lst), len(SummerMonth))
910 self.assertEqual(len(SummerMonth), 3, SummerMonth)
911 self.assertEqual(
912 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
913 lst,
914 )
915 for i, month in enumerate('june july august'.split(), 1):
916 e = SummerMonth(i)
917 self.assertEqual(int(e.value), i)
918 self.assertNotEqual(e, i)
919 self.assertEqual(e.name, month)
920 self.assertIn(e, SummerMonth)
921 self.assertIs(type(e), SummerMonth)
922
Martin Pantereb995702016-07-28 01:11:04 +0000923 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700924 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
925 lst = list(SummerMonth)
926 self.assertEqual(len(lst), len(SummerMonth))
927 self.assertEqual(len(SummerMonth), 3, SummerMonth)
928 self.assertEqual(
929 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
930 lst,
931 )
932 for i, month in enumerate('june july august'.split(), 1):
933 e = SummerMonth(i)
934 self.assertEqual(e, i)
935 self.assertEqual(e.name, month)
936 self.assertIn(e, SummerMonth)
937 self.assertIs(type(e), SummerMonth)
938
Martin Pantereb995702016-07-28 01:11:04 +0000939 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700940 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
941 lst = list(SummerMonth)
942 self.assertEqual(len(lst), len(SummerMonth))
943 self.assertEqual(len(SummerMonth), 3, SummerMonth)
944 self.assertEqual(
945 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
946 lst,
947 )
948 for i, month in enumerate('june july august'.split(), 30):
949 e = SummerMonth(i)
950 self.assertEqual(e, i)
951 self.assertEqual(e.name, month)
952 self.assertIn(e, SummerMonth)
953 self.assertIs(type(e), SummerMonth)
954
Martin Pantereb995702016-07-28 01:11:04 +0000955 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700956 SummerMonth = IntEnum('SummerMonth', 'june july august')
957 lst = list(SummerMonth)
958 self.assertEqual(len(lst), len(SummerMonth))
959 self.assertEqual(len(SummerMonth), 3, SummerMonth)
960 self.assertEqual(
961 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
962 lst,
963 )
964 for i, month in enumerate('june july august'.split(), 1):
965 e = SummerMonth(i)
966 self.assertEqual(e, i)
967 self.assertEqual(e.name, month)
968 self.assertIn(e, SummerMonth)
969 self.assertIs(type(e), SummerMonth)
970
Martin Pantereb995702016-07-28 01:11:04 +0000971 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700972 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
973 lst = list(SummerMonth)
974 self.assertEqual(len(lst), len(SummerMonth))
975 self.assertEqual(len(SummerMonth), 3, SummerMonth)
976 self.assertEqual(
977 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
978 lst,
979 )
980 for i, month in enumerate('june july august'.split(), 40):
981 e = SummerMonth(i)
982 self.assertEqual(e, i)
983 self.assertEqual(e.name, month)
984 self.assertIn(e, SummerMonth)
985 self.assertIs(type(e), SummerMonth)
986
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700987 def test_subclassing(self):
988 if isinstance(Name, Exception):
989 raise Name
990 self.assertEqual(Name.BDFL, 'Guido van Rossum')
991 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
992 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800993 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700994
995 def test_extending(self):
996 class Color(Enum):
997 red = 1
998 green = 2
999 blue = 3
1000 with self.assertRaises(TypeError):
1001 class MoreColor(Color):
1002 cyan = 4
1003 magenta = 5
1004 yellow = 6
1005
1006 def test_exclude_methods(self):
1007 class whatever(Enum):
1008 this = 'that'
1009 these = 'those'
1010 def really(self):
1011 return 'no, not %s' % self.value
1012 self.assertIsNot(type(whatever.really), whatever)
1013 self.assertEqual(whatever.this.really(), 'no, not that')
1014
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001015 def test_wrong_inheritance_order(self):
1016 with self.assertRaises(TypeError):
1017 class Wrong(Enum, str):
1018 NotHere = 'error before this point'
1019
1020 def test_intenum_transitivity(self):
1021 class number(IntEnum):
1022 one = 1
1023 two = 2
1024 three = 3
1025 class numero(IntEnum):
1026 uno = 1
1027 dos = 2
1028 tres = 3
1029 self.assertEqual(number.one, numero.uno)
1030 self.assertEqual(number.two, numero.dos)
1031 self.assertEqual(number.three, numero.tres)
1032
1033 def test_wrong_enum_in_call(self):
1034 class Monochrome(Enum):
1035 black = 0
1036 white = 1
1037 class Gender(Enum):
1038 male = 0
1039 female = 1
1040 self.assertRaises(ValueError, Monochrome, Gender.male)
1041
1042 def test_wrong_enum_in_mixed_call(self):
1043 class Monochrome(IntEnum):
1044 black = 0
1045 white = 1
1046 class Gender(Enum):
1047 male = 0
1048 female = 1
1049 self.assertRaises(ValueError, Monochrome, Gender.male)
1050
1051 def test_mixed_enum_in_call_1(self):
1052 class Monochrome(IntEnum):
1053 black = 0
1054 white = 1
1055 class Gender(IntEnum):
1056 male = 0
1057 female = 1
1058 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1059
1060 def test_mixed_enum_in_call_2(self):
1061 class Monochrome(Enum):
1062 black = 0
1063 white = 1
1064 class Gender(IntEnum):
1065 male = 0
1066 female = 1
1067 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1068
1069 def test_flufl_enum(self):
1070 class Fluflnum(Enum):
1071 def __int__(self):
1072 return int(self.value)
1073 class MailManOptions(Fluflnum):
1074 option1 = 1
1075 option2 = 2
1076 option3 = 3
1077 self.assertEqual(int(MailManOptions.option1), 1)
1078
Ethan Furman5e5a8232013-08-04 08:42:23 -07001079 def test_introspection(self):
1080 class Number(IntEnum):
1081 one = 100
1082 two = 200
1083 self.assertIs(Number.one._member_type_, int)
1084 self.assertIs(Number._member_type_, int)
1085 class String(str, Enum):
1086 yarn = 'soft'
1087 rope = 'rough'
1088 wire = 'hard'
1089 self.assertIs(String.yarn._member_type_, str)
1090 self.assertIs(String._member_type_, str)
1091 class Plain(Enum):
1092 vanilla = 'white'
1093 one = 1
1094 self.assertIs(Plain.vanilla._member_type_, object)
1095 self.assertIs(Plain._member_type_, object)
1096
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001097 def test_no_such_enum_member(self):
1098 class Color(Enum):
1099 red = 1
1100 green = 2
1101 blue = 3
1102 with self.assertRaises(ValueError):
1103 Color(4)
1104 with self.assertRaises(KeyError):
1105 Color['chartreuse']
1106
1107 def test_new_repr(self):
1108 class Color(Enum):
1109 red = 1
1110 green = 2
1111 blue = 3
1112 def __repr__(self):
1113 return "don't you just love shades of %s?" % self.name
1114 self.assertEqual(
1115 repr(Color.blue),
1116 "don't you just love shades of blue?",
1117 )
1118
1119 def test_inherited_repr(self):
1120 class MyEnum(Enum):
1121 def __repr__(self):
1122 return "My name is %s." % self.name
1123 class MyIntEnum(int, MyEnum):
1124 this = 1
1125 that = 2
1126 theother = 3
1127 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1128
1129 def test_multiple_mixin_mro(self):
1130 class auto_enum(type(Enum)):
1131 def __new__(metacls, cls, bases, classdict):
1132 temp = type(classdict)()
1133 names = set(classdict._member_names)
1134 i = 0
1135 for k in classdict._member_names:
1136 v = classdict[k]
1137 if v is Ellipsis:
1138 v = i
1139 else:
1140 i = v
1141 i += 1
1142 temp[k] = v
1143 for k, v in classdict.items():
1144 if k not in names:
1145 temp[k] = v
1146 return super(auto_enum, metacls).__new__(
1147 metacls, cls, bases, temp)
1148
1149 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1150 pass
1151
1152 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1153 pass
1154
1155 class TestAutoNumber(AutoNumberedEnum):
1156 a = ...
1157 b = 3
1158 c = ...
1159
1160 class TestAutoInt(AutoIntEnum):
1161 a = ...
1162 b = 3
1163 c = ...
1164
1165 def test_subclasses_with_getnewargs(self):
1166 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001167 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001168 def __new__(cls, *args):
1169 _args = args
1170 name, *args = args
1171 if len(args) == 0:
1172 raise TypeError("name and value must be specified")
1173 self = int.__new__(cls, *args)
1174 self._intname = name
1175 self._args = _args
1176 return self
1177 def __getnewargs__(self):
1178 return self._args
1179 @property
1180 def __name__(self):
1181 return self._intname
1182 def __repr__(self):
1183 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001184 return "{}({!r}, {})".format(
1185 type(self).__name__,
1186 self.__name__,
1187 int.__repr__(self),
1188 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001189 def __str__(self):
1190 # str() is unchanged, even if it relies on the repr() fallback
1191 base = int
1192 base_str = base.__str__
1193 if base_str.__objclass__ is object:
1194 return base.__repr__(self)
1195 return base_str(self)
1196 # for simplicity, we only define one operator that
1197 # propagates expressions
1198 def __add__(self, other):
1199 temp = int(self) + int( other)
1200 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1201 return NamedInt(
1202 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001203 temp,
1204 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001205 else:
1206 return temp
1207
1208 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001209 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001210 x = ('the-x', 1)
1211 y = ('the-y', 2)
1212
Ethan Furman2aa27322013-07-19 19:35:56 -07001213
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001214 self.assertIs(NEI.__new__, Enum.__new__)
1215 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1216 globals()['NamedInt'] = NamedInt
1217 globals()['NEI'] = NEI
1218 NI5 = NamedInt('test', 5)
1219 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001220 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001221 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001222 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001223 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001224
Ethan Furmanca1b7942014-02-08 11:36:27 -08001225 def test_subclasses_with_getnewargs_ex(self):
1226 class NamedInt(int):
1227 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1228 def __new__(cls, *args):
1229 _args = args
1230 name, *args = args
1231 if len(args) == 0:
1232 raise TypeError("name and value must be specified")
1233 self = int.__new__(cls, *args)
1234 self._intname = name
1235 self._args = _args
1236 return self
1237 def __getnewargs_ex__(self):
1238 return self._args, {}
1239 @property
1240 def __name__(self):
1241 return self._intname
1242 def __repr__(self):
1243 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001244 return "{}({!r}, {})".format(
1245 type(self).__name__,
1246 self.__name__,
1247 int.__repr__(self),
1248 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001249 def __str__(self):
1250 # str() is unchanged, even if it relies on the repr() fallback
1251 base = int
1252 base_str = base.__str__
1253 if base_str.__objclass__ is object:
1254 return base.__repr__(self)
1255 return base_str(self)
1256 # for simplicity, we only define one operator that
1257 # propagates expressions
1258 def __add__(self, other):
1259 temp = int(self) + int( other)
1260 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1261 return NamedInt(
1262 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001263 temp,
1264 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001265 else:
1266 return temp
1267
1268 class NEI(NamedInt, Enum):
1269 __qualname__ = 'NEI' # needed for pickle protocol 4
1270 x = ('the-x', 1)
1271 y = ('the-y', 2)
1272
1273
1274 self.assertIs(NEI.__new__, Enum.__new__)
1275 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1276 globals()['NamedInt'] = NamedInt
1277 globals()['NEI'] = NEI
1278 NI5 = NamedInt('test', 5)
1279 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001280 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001281 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001282 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001283 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001284
1285 def test_subclasses_with_reduce(self):
1286 class NamedInt(int):
1287 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1288 def __new__(cls, *args):
1289 _args = args
1290 name, *args = args
1291 if len(args) == 0:
1292 raise TypeError("name and value must be specified")
1293 self = int.__new__(cls, *args)
1294 self._intname = name
1295 self._args = _args
1296 return self
1297 def __reduce__(self):
1298 return self.__class__, self._args
1299 @property
1300 def __name__(self):
1301 return self._intname
1302 def __repr__(self):
1303 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001304 return "{}({!r}, {})".format(
1305 type(self).__name__,
1306 self.__name__,
1307 int.__repr__(self),
1308 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001309 def __str__(self):
1310 # str() is unchanged, even if it relies on the repr() fallback
1311 base = int
1312 base_str = base.__str__
1313 if base_str.__objclass__ is object:
1314 return base.__repr__(self)
1315 return base_str(self)
1316 # for simplicity, we only define one operator that
1317 # propagates expressions
1318 def __add__(self, other):
1319 temp = int(self) + int( other)
1320 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1321 return NamedInt(
1322 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001323 temp,
1324 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001325 else:
1326 return temp
1327
1328 class NEI(NamedInt, Enum):
1329 __qualname__ = 'NEI' # needed for pickle protocol 4
1330 x = ('the-x', 1)
1331 y = ('the-y', 2)
1332
1333
1334 self.assertIs(NEI.__new__, Enum.__new__)
1335 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1336 globals()['NamedInt'] = NamedInt
1337 globals()['NEI'] = NEI
1338 NI5 = NamedInt('test', 5)
1339 self.assertEqual(NI5, 5)
1340 test_pickle_dump_load(self.assertEqual, NI5, 5)
1341 self.assertEqual(NEI.y.value, 2)
1342 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001343 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001344
1345 def test_subclasses_with_reduce_ex(self):
1346 class NamedInt(int):
1347 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1348 def __new__(cls, *args):
1349 _args = args
1350 name, *args = args
1351 if len(args) == 0:
1352 raise TypeError("name and value must be specified")
1353 self = int.__new__(cls, *args)
1354 self._intname = name
1355 self._args = _args
1356 return self
1357 def __reduce_ex__(self, proto):
1358 return self.__class__, self._args
1359 @property
1360 def __name__(self):
1361 return self._intname
1362 def __repr__(self):
1363 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001364 return "{}({!r}, {})".format(
1365 type(self).__name__,
1366 self.__name__,
1367 int.__repr__(self),
1368 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001369 def __str__(self):
1370 # str() is unchanged, even if it relies on the repr() fallback
1371 base = int
1372 base_str = base.__str__
1373 if base_str.__objclass__ is object:
1374 return base.__repr__(self)
1375 return base_str(self)
1376 # for simplicity, we only define one operator that
1377 # propagates expressions
1378 def __add__(self, other):
1379 temp = int(self) + int( other)
1380 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1381 return NamedInt(
1382 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001383 temp,
1384 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001385 else:
1386 return temp
1387
1388 class NEI(NamedInt, Enum):
1389 __qualname__ = 'NEI' # needed for pickle protocol 4
1390 x = ('the-x', 1)
1391 y = ('the-y', 2)
1392
Ethan Furmanca1b7942014-02-08 11:36:27 -08001393 self.assertIs(NEI.__new__, Enum.__new__)
1394 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1395 globals()['NamedInt'] = NamedInt
1396 globals()['NEI'] = NEI
1397 NI5 = NamedInt('test', 5)
1398 self.assertEqual(NI5, 5)
1399 test_pickle_dump_load(self.assertEqual, NI5, 5)
1400 self.assertEqual(NEI.y.value, 2)
1401 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001402 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001403
Ethan Furmandc870522014-02-18 12:37:12 -08001404 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001405 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001406 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001407 def __new__(cls, *args):
1408 _args = args
1409 name, *args = args
1410 if len(args) == 0:
1411 raise TypeError("name and value must be specified")
1412 self = int.__new__(cls, *args)
1413 self._intname = name
1414 self._args = _args
1415 return self
1416 @property
1417 def __name__(self):
1418 return self._intname
1419 def __repr__(self):
1420 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001421 return "{}({!r}, {})".format(
1422 type(self).__name__,
1423 self.__name__,
1424 int.__repr__(self),
1425 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001426 def __str__(self):
1427 # str() is unchanged, even if it relies on the repr() fallback
1428 base = int
1429 base_str = base.__str__
1430 if base_str.__objclass__ is object:
1431 return base.__repr__(self)
1432 return base_str(self)
1433 # for simplicity, we only define one operator that
1434 # propagates expressions
1435 def __add__(self, other):
1436 temp = int(self) + int( other)
1437 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1438 return NamedInt(
1439 '({0} + {1})'.format(self.__name__, other.__name__),
1440 temp )
1441 else:
1442 return temp
1443
1444 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001445 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001446 x = ('the-x', 1)
1447 y = ('the-y', 2)
1448
1449 self.assertIs(NEI.__new__, Enum.__new__)
1450 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1451 globals()['NamedInt'] = NamedInt
1452 globals()['NEI'] = NEI
1453 NI5 = NamedInt('test', 5)
1454 self.assertEqual(NI5, 5)
1455 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001456 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1457 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001458
Ethan Furmandc870522014-02-18 12:37:12 -08001459 def test_subclasses_without_direct_pickle_support_using_name(self):
1460 class NamedInt(int):
1461 __qualname__ = 'NamedInt'
1462 def __new__(cls, *args):
1463 _args = args
1464 name, *args = args
1465 if len(args) == 0:
1466 raise TypeError("name and value must be specified")
1467 self = int.__new__(cls, *args)
1468 self._intname = name
1469 self._args = _args
1470 return self
1471 @property
1472 def __name__(self):
1473 return self._intname
1474 def __repr__(self):
1475 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001476 return "{}({!r}, {})".format(
1477 type(self).__name__,
1478 self.__name__,
1479 int.__repr__(self),
1480 )
Ethan Furmandc870522014-02-18 12:37:12 -08001481 def __str__(self):
1482 # str() is unchanged, even if it relies on the repr() fallback
1483 base = int
1484 base_str = base.__str__
1485 if base_str.__objclass__ is object:
1486 return base.__repr__(self)
1487 return base_str(self)
1488 # for simplicity, we only define one operator that
1489 # propagates expressions
1490 def __add__(self, other):
1491 temp = int(self) + int( other)
1492 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1493 return NamedInt(
1494 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001495 temp,
1496 )
Ethan Furmandc870522014-02-18 12:37:12 -08001497 else:
1498 return temp
1499
1500 class NEI(NamedInt, Enum):
1501 __qualname__ = 'NEI'
1502 x = ('the-x', 1)
1503 y = ('the-y', 2)
1504 def __reduce_ex__(self, proto):
1505 return getattr, (self.__class__, self._name_)
1506
1507 self.assertIs(NEI.__new__, Enum.__new__)
1508 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1509 globals()['NamedInt'] = NamedInt
1510 globals()['NEI'] = NEI
1511 NI5 = NamedInt('test', 5)
1512 self.assertEqual(NI5, 5)
1513 self.assertEqual(NEI.y.value, 2)
1514 test_pickle_dump_load(self.assertIs, NEI.y)
1515 test_pickle_dump_load(self.assertIs, NEI)
1516
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001517 def test_tuple_subclass(self):
1518 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001519 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001520 first = (1, 'for the money')
1521 second = (2, 'for the show')
1522 third = (3, 'for the music')
1523 self.assertIs(type(SomeTuple.first), SomeTuple)
1524 self.assertIsInstance(SomeTuple.second, tuple)
1525 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1526 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001527 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001528
1529 def test_duplicate_values_give_unique_enum_items(self):
1530 class AutoNumber(Enum):
1531 first = ()
1532 second = ()
1533 third = ()
1534 def __new__(cls):
1535 value = len(cls.__members__) + 1
1536 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001537 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001538 return obj
1539 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001540 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001541 self.assertEqual(
1542 list(AutoNumber),
1543 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1544 )
1545 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001546 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 self.assertIs(AutoNumber(1), AutoNumber.first)
1548
1549 def test_inherited_new_from_enhanced_enum(self):
1550 class AutoNumber(Enum):
1551 def __new__(cls):
1552 value = len(cls.__members__) + 1
1553 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001554 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001555 return obj
1556 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001557 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558 class Color(AutoNumber):
1559 red = ()
1560 green = ()
1561 blue = ()
1562 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1563 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1564
1565 def test_inherited_new_from_mixed_enum(self):
1566 class AutoNumber(IntEnum):
1567 def __new__(cls):
1568 value = len(cls.__members__) + 1
1569 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001570 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001571 return obj
1572 class Color(AutoNumber):
1573 red = ()
1574 green = ()
1575 blue = ()
1576 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1577 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1578
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001579 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001580 class OrdinaryEnum(Enum):
1581 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001582 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1583 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001584
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001585 def test_ordered_mixin(self):
1586 class OrderedEnum(Enum):
1587 def __ge__(self, other):
1588 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001589 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001590 return NotImplemented
1591 def __gt__(self, other):
1592 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001593 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001594 return NotImplemented
1595 def __le__(self, other):
1596 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001597 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001598 return NotImplemented
1599 def __lt__(self, other):
1600 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001601 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001602 return NotImplemented
1603 class Grade(OrderedEnum):
1604 A = 5
1605 B = 4
1606 C = 3
1607 D = 2
1608 F = 1
1609 self.assertGreater(Grade.A, Grade.B)
1610 self.assertLessEqual(Grade.F, Grade.C)
1611 self.assertLess(Grade.D, Grade.A)
1612 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001613 self.assertEqual(Grade.B, Grade.B)
1614 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001615
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001616 def test_extending2(self):
1617 class Shade(Enum):
1618 def shade(self):
1619 print(self.name)
1620 class Color(Shade):
1621 red = 1
1622 green = 2
1623 blue = 3
1624 with self.assertRaises(TypeError):
1625 class MoreColor(Color):
1626 cyan = 4
1627 magenta = 5
1628 yellow = 6
1629
1630 def test_extending3(self):
1631 class Shade(Enum):
1632 def shade(self):
1633 return self.name
1634 class Color(Shade):
1635 def hex(self):
1636 return '%s hexlified!' % self.value
1637 class MoreColor(Color):
1638 cyan = 4
1639 magenta = 5
1640 yellow = 6
1641 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1642
orlnub1230fb9fad2018-09-12 20:28:53 +03001643 def test_subclass_duplicate_name(self):
1644 class Base(Enum):
1645 def test(self):
1646 pass
1647 class Test(Base):
1648 test = 1
1649 self.assertIs(type(Test.test), Test)
1650
1651 def test_subclass_duplicate_name_dynamic(self):
1652 from types import DynamicClassAttribute
1653 class Base(Enum):
1654 @DynamicClassAttribute
1655 def test(self):
1656 return 'dynamic'
1657 class Test(Base):
1658 test = 1
1659 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001660
1661 def test_no_duplicates(self):
1662 class UniqueEnum(Enum):
1663 def __init__(self, *args):
1664 cls = self.__class__
1665 if any(self.value == e.value for e in cls):
1666 a = self.name
1667 e = cls(self.value).name
1668 raise ValueError(
1669 "aliases not allowed in UniqueEnum: %r --> %r"
1670 % (a, e)
1671 )
1672 class Color(UniqueEnum):
1673 red = 1
1674 green = 2
1675 blue = 3
1676 with self.assertRaises(ValueError):
1677 class Color(UniqueEnum):
1678 red = 1
1679 green = 2
1680 blue = 3
1681 grene = 2
1682
1683 def test_init(self):
1684 class Planet(Enum):
1685 MERCURY = (3.303e+23, 2.4397e6)
1686 VENUS = (4.869e+24, 6.0518e6)
1687 EARTH = (5.976e+24, 6.37814e6)
1688 MARS = (6.421e+23, 3.3972e6)
1689 JUPITER = (1.9e+27, 7.1492e7)
1690 SATURN = (5.688e+26, 6.0268e7)
1691 URANUS = (8.686e+25, 2.5559e7)
1692 NEPTUNE = (1.024e+26, 2.4746e7)
1693 def __init__(self, mass, radius):
1694 self.mass = mass # in kilograms
1695 self.radius = radius # in meters
1696 @property
1697 def surface_gravity(self):
1698 # universal gravitational constant (m3 kg-1 s-2)
1699 G = 6.67300E-11
1700 return G * self.mass / (self.radius * self.radius)
1701 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1702 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1703
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001704 def test_ignore(self):
1705 class Period(timedelta, Enum):
1706 '''
1707 different lengths of time
1708 '''
1709 def __new__(cls, value, period):
1710 obj = timedelta.__new__(cls, value)
1711 obj._value_ = value
1712 obj.period = period
1713 return obj
1714 _ignore_ = 'Period i'
1715 Period = vars()
1716 for i in range(13):
1717 Period['month_%d' % i] = i*30, 'month'
1718 for i in range(53):
1719 Period['week_%d' % i] = i*7, 'week'
1720 for i in range(32):
1721 Period['day_%d' % i] = i, 'day'
1722 OneDay = day_1
1723 OneWeek = week_1
1724 OneMonth = month_1
1725 self.assertFalse(hasattr(Period, '_ignore_'))
1726 self.assertFalse(hasattr(Period, 'Period'))
1727 self.assertFalse(hasattr(Period, 'i'))
1728 self.assertTrue(isinstance(Period.day_1, timedelta))
1729 self.assertTrue(Period.month_1 is Period.day_30)
1730 self.assertTrue(Period.week_4 is Period.day_28)
1731
Ethan Furman2aa27322013-07-19 19:35:56 -07001732 def test_nonhash_value(self):
1733 class AutoNumberInAList(Enum):
1734 def __new__(cls):
1735 value = [len(cls.__members__) + 1]
1736 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001737 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001738 return obj
1739 class ColorInAList(AutoNumberInAList):
1740 red = ()
1741 green = ()
1742 blue = ()
1743 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001744 for enum, value in zip(ColorInAList, range(3)):
1745 value += 1
1746 self.assertEqual(enum.value, [value])
1747 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001748
Ethan Furmanb41803e2013-07-25 13:50:45 -07001749 def test_conflicting_types_resolved_in_new(self):
1750 class LabelledIntEnum(int, Enum):
1751 def __new__(cls, *args):
1752 value, label = args
1753 obj = int.__new__(cls, value)
1754 obj.label = label
1755 obj._value_ = value
1756 return obj
1757
1758 class LabelledList(LabelledIntEnum):
1759 unprocessed = (1, "Unprocessed")
1760 payment_complete = (2, "Payment Complete")
1761
1762 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1763 self.assertEqual(LabelledList.unprocessed, 1)
1764 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001765
Ethan Furmanc16595e2016-09-10 23:36:59 -07001766 def test_auto_number(self):
1767 class Color(Enum):
1768 red = auto()
1769 blue = auto()
1770 green = auto()
1771
1772 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1773 self.assertEqual(Color.red.value, 1)
1774 self.assertEqual(Color.blue.value, 2)
1775 self.assertEqual(Color.green.value, 3)
1776
1777 def test_auto_name(self):
1778 class Color(Enum):
1779 def _generate_next_value_(name, start, count, last):
1780 return name
1781 red = auto()
1782 blue = auto()
1783 green = auto()
1784
1785 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1786 self.assertEqual(Color.red.value, 'red')
1787 self.assertEqual(Color.blue.value, 'blue')
1788 self.assertEqual(Color.green.value, 'green')
1789
1790 def test_auto_name_inherit(self):
1791 class AutoNameEnum(Enum):
1792 def _generate_next_value_(name, start, count, last):
1793 return name
1794 class Color(AutoNameEnum):
1795 red = auto()
1796 blue = auto()
1797 green = auto()
1798
1799 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1800 self.assertEqual(Color.red.value, 'red')
1801 self.assertEqual(Color.blue.value, 'blue')
1802 self.assertEqual(Color.green.value, 'green')
1803
1804 def test_auto_garbage(self):
1805 class Color(Enum):
1806 red = 'red'
1807 blue = auto()
1808 self.assertEqual(Color.blue.value, 1)
1809
1810 def test_auto_garbage_corrected(self):
1811 class Color(Enum):
1812 red = 'red'
1813 blue = 2
1814 green = auto()
1815
1816 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1817 self.assertEqual(Color.red.value, 'red')
1818 self.assertEqual(Color.blue.value, 2)
1819 self.assertEqual(Color.green.value, 3)
1820
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001821 def test_auto_order(self):
1822 with self.assertRaises(TypeError):
1823 class Color(Enum):
1824 red = auto()
1825 green = auto()
1826 blue = auto()
1827 def _generate_next_value_(name, start, count, last):
1828 return name
1829
1830
Ethan Furman3515dcc2016-09-18 13:15:41 -07001831 def test_duplicate_auto(self):
1832 class Dupes(Enum):
1833 first = primero = auto()
1834 second = auto()
1835 third = auto()
1836 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1837
Ethan Furman019f0a02018-09-12 11:43:34 -07001838 def test_missing(self):
1839 class Color(Enum):
1840 red = 1
1841 green = 2
1842 blue = 3
1843 @classmethod
1844 def _missing_(cls, item):
1845 if item == 'three':
1846 return cls.blue
1847 elif item == 'bad return':
1848 # trigger internal error
1849 return 5
1850 elif item == 'error out':
1851 raise ZeroDivisionError
1852 else:
1853 # trigger not found
1854 return None
1855 self.assertIs(Color('three'), Color.blue)
1856 self.assertRaises(ValueError, Color, 7)
1857 try:
1858 Color('bad return')
1859 except TypeError as exc:
1860 self.assertTrue(isinstance(exc.__context__, ValueError))
1861 else:
1862 raise Exception('Exception not raised.')
1863 try:
1864 Color('error out')
1865 except ZeroDivisionError as exc:
1866 self.assertTrue(isinstance(exc.__context__, ValueError))
1867 else:
1868 raise Exception('Exception not raised.')
1869
Ethan Furman5bdab642018-09-21 19:03:09 -07001870 def test_multiple_mixin(self):
1871 class MaxMixin:
1872 @classproperty
1873 def MAX(cls):
1874 max = len(cls)
1875 cls.MAX = max
1876 return max
1877 class StrMixin:
1878 def __str__(self):
1879 return self._name_.lower()
1880 class SomeEnum(Enum):
1881 def behavior(self):
1882 return 'booyah'
1883 class AnotherEnum(Enum):
1884 def behavior(self):
1885 return 'nuhuh!'
1886 def social(self):
1887 return "what's up?"
1888 class Color(MaxMixin, Enum):
1889 RED = auto()
1890 GREEN = auto()
1891 BLUE = auto()
1892 self.assertEqual(Color.RED.value, 1)
1893 self.assertEqual(Color.GREEN.value, 2)
1894 self.assertEqual(Color.BLUE.value, 3)
1895 self.assertEqual(Color.MAX, 3)
1896 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1897 class Color(MaxMixin, StrMixin, Enum):
1898 RED = auto()
1899 GREEN = auto()
1900 BLUE = auto()
1901 self.assertEqual(Color.RED.value, 1)
1902 self.assertEqual(Color.GREEN.value, 2)
1903 self.assertEqual(Color.BLUE.value, 3)
1904 self.assertEqual(Color.MAX, 3)
1905 self.assertEqual(str(Color.BLUE), 'blue')
1906 class Color(StrMixin, MaxMixin, Enum):
1907 RED = auto()
1908 GREEN = auto()
1909 BLUE = auto()
1910 self.assertEqual(Color.RED.value, 1)
1911 self.assertEqual(Color.GREEN.value, 2)
1912 self.assertEqual(Color.BLUE.value, 3)
1913 self.assertEqual(Color.MAX, 3)
1914 self.assertEqual(str(Color.BLUE), 'blue')
1915 class CoolColor(StrMixin, SomeEnum, Enum):
1916 RED = auto()
1917 GREEN = auto()
1918 BLUE = auto()
1919 self.assertEqual(CoolColor.RED.value, 1)
1920 self.assertEqual(CoolColor.GREEN.value, 2)
1921 self.assertEqual(CoolColor.BLUE.value, 3)
1922 self.assertEqual(str(CoolColor.BLUE), 'blue')
1923 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1924 class CoolerColor(StrMixin, AnotherEnum, Enum):
1925 RED = auto()
1926 GREEN = auto()
1927 BLUE = auto()
1928 self.assertEqual(CoolerColor.RED.value, 1)
1929 self.assertEqual(CoolerColor.GREEN.value, 2)
1930 self.assertEqual(CoolerColor.BLUE.value, 3)
1931 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1932 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1933 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1934 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1935 RED = auto()
1936 GREEN = auto()
1937 BLUE = auto()
1938 self.assertEqual(CoolestColor.RED.value, 1)
1939 self.assertEqual(CoolestColor.GREEN.value, 2)
1940 self.assertEqual(CoolestColor.BLUE.value, 3)
1941 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1942 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1943 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1944 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1945 RED = auto()
1946 GREEN = auto()
1947 BLUE = auto()
1948 self.assertEqual(ConfusedColor.RED.value, 1)
1949 self.assertEqual(ConfusedColor.GREEN.value, 2)
1950 self.assertEqual(ConfusedColor.BLUE.value, 3)
1951 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1952 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1953 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1954 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1955 RED = auto()
1956 GREEN = auto()
1957 BLUE = auto()
1958 self.assertEqual(ReformedColor.RED.value, 1)
1959 self.assertEqual(ReformedColor.GREEN.value, 2)
1960 self.assertEqual(ReformedColor.BLUE.value, 3)
1961 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1962 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1963 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1964 self.assertTrue(issubclass(ReformedColor, int))
1965
Ethan Furmancd453852018-10-05 23:29:36 -07001966 def test_multiple_inherited_mixin(self):
1967 class StrEnum(str, Enum):
1968 def __new__(cls, *args, **kwargs):
1969 for a in args:
1970 if not isinstance(a, str):
1971 raise TypeError("Enumeration '%s' (%s) is not"
1972 " a string" % (a, type(a).__name__))
1973 return str.__new__(cls, *args, **kwargs)
1974 @unique
1975 class Decision1(StrEnum):
1976 REVERT = "REVERT"
1977 REVERT_ALL = "REVERT_ALL"
1978 RETRY = "RETRY"
1979 class MyEnum(StrEnum):
1980 pass
1981 @unique
1982 class Decision2(MyEnum):
1983 REVERT = "REVERT"
1984 REVERT_ALL = "REVERT_ALL"
1985 RETRY = "RETRY"
1986
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001987 def test_empty_globals(self):
1988 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1989 # when using compile and exec because f_globals is empty
1990 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1991 code = compile(code, "<string>", "exec")
1992 global_ns = {}
1993 local_ls = {}
1994 exec(code, global_ns, local_ls)
1995
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001996
Ethan Furmane8e61272016-08-20 07:19:31 -07001997class TestOrder(unittest.TestCase):
1998
1999 def test_same_members(self):
2000 class Color(Enum):
2001 _order_ = 'red green blue'
2002 red = 1
2003 green = 2
2004 blue = 3
2005
2006 def test_same_members_with_aliases(self):
2007 class Color(Enum):
2008 _order_ = 'red green blue'
2009 red = 1
2010 green = 2
2011 blue = 3
2012 verde = green
2013
2014 def test_same_members_wrong_order(self):
2015 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2016 class Color(Enum):
2017 _order_ = 'red green blue'
2018 red = 1
2019 blue = 3
2020 green = 2
2021
2022 def test_order_has_extra_members(self):
2023 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2024 class Color(Enum):
2025 _order_ = 'red green blue purple'
2026 red = 1
2027 green = 2
2028 blue = 3
2029
2030 def test_order_has_extra_members_with_aliases(self):
2031 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2032 class Color(Enum):
2033 _order_ = 'red green blue purple'
2034 red = 1
2035 green = 2
2036 blue = 3
2037 verde = green
2038
2039 def test_enum_has_extra_members(self):
2040 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2041 class Color(Enum):
2042 _order_ = 'red green blue'
2043 red = 1
2044 green = 2
2045 blue = 3
2046 purple = 4
2047
2048 def test_enum_has_extra_members_with_aliases(self):
2049 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2050 class Color(Enum):
2051 _order_ = 'red green blue'
2052 red = 1
2053 green = 2
2054 blue = 3
2055 purple = 4
2056 verde = green
2057
2058
Ethan Furman65a5a472016-09-01 23:55:19 -07002059class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002060 """Tests of the Flags."""
2061
Ethan Furman65a5a472016-09-01 23:55:19 -07002062 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002063 R, W, X = 4, 2, 1
2064
Ethan Furman65a5a472016-09-01 23:55:19 -07002065 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002066 RO = 0
2067 WO = 1
2068 RW = 2
2069 AC = 3
2070 CE = 1<<19
2071
Rahul Jha94306522018-09-10 23:51:04 +05302072 class Color(Flag):
2073 BLACK = 0
2074 RED = 1
2075 GREEN = 2
2076 BLUE = 4
2077 PURPLE = RED|BLUE
2078
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002079 def test_str(self):
2080 Perm = self.Perm
2081 self.assertEqual(str(Perm.R), 'Perm.R')
2082 self.assertEqual(str(Perm.W), 'Perm.W')
2083 self.assertEqual(str(Perm.X), 'Perm.X')
2084 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2085 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2086 self.assertEqual(str(Perm(0)), 'Perm.0')
2087 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2088 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2089 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2090 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2091 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2092 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2093
2094 Open = self.Open
2095 self.assertEqual(str(Open.RO), 'Open.RO')
2096 self.assertEqual(str(Open.WO), 'Open.WO')
2097 self.assertEqual(str(Open.AC), 'Open.AC')
2098 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2099 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002100 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002101 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2102 self.assertEqual(str(~Open.AC), 'Open.CE')
2103 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2104 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2105
2106 def test_repr(self):
2107 Perm = self.Perm
2108 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2109 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2110 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2111 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2112 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002113 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002114 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2115 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2116 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2117 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002118 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002119 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2120
2121 Open = self.Open
2122 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2123 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2124 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2125 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2126 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002127 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002128 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2129 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2130 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2131 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2132
2133 def test_or(self):
2134 Perm = self.Perm
2135 for i in Perm:
2136 for j in Perm:
2137 self.assertEqual((i | j), Perm(i.value | j.value))
2138 self.assertEqual((i | j).value, i.value | j.value)
2139 self.assertIs(type(i | j), Perm)
2140 for i in Perm:
2141 self.assertIs(i | i, i)
2142 Open = self.Open
2143 self.assertIs(Open.RO | Open.CE, Open.CE)
2144
2145 def test_and(self):
2146 Perm = self.Perm
2147 RW = Perm.R | Perm.W
2148 RX = Perm.R | Perm.X
2149 WX = Perm.W | Perm.X
2150 RWX = Perm.R | Perm.W | Perm.X
2151 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2152 for i in values:
2153 for j in values:
2154 self.assertEqual((i & j).value, i.value & j.value)
2155 self.assertIs(type(i & j), Perm)
2156 for i in Perm:
2157 self.assertIs(i & i, i)
2158 self.assertIs(i & RWX, i)
2159 self.assertIs(RWX & i, i)
2160 Open = self.Open
2161 self.assertIs(Open.RO & Open.CE, Open.RO)
2162
2163 def test_xor(self):
2164 Perm = self.Perm
2165 for i in Perm:
2166 for j in Perm:
2167 self.assertEqual((i ^ j).value, i.value ^ j.value)
2168 self.assertIs(type(i ^ j), Perm)
2169 for i in Perm:
2170 self.assertIs(i ^ Perm(0), i)
2171 self.assertIs(Perm(0) ^ i, i)
2172 Open = self.Open
2173 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2174 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2175
2176 def test_invert(self):
2177 Perm = self.Perm
2178 RW = Perm.R | Perm.W
2179 RX = Perm.R | Perm.X
2180 WX = Perm.W | Perm.X
2181 RWX = Perm.R | Perm.W | Perm.X
2182 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2183 for i in values:
2184 self.assertIs(type(~i), Perm)
2185 self.assertEqual(~~i, i)
2186 for i in Perm:
2187 self.assertIs(~~i, i)
2188 Open = self.Open
2189 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2190 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2191
Ethan Furman25d94bb2016-09-02 16:32:32 -07002192 def test_bool(self):
2193 Perm = self.Perm
2194 for f in Perm:
2195 self.assertTrue(f)
2196 Open = self.Open
2197 for f in Open:
2198 self.assertEqual(bool(f.value), bool(f))
2199
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002200 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002201 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002202 lst = list(Perm)
2203 self.assertEqual(len(lst), len(Perm))
2204 self.assertEqual(len(Perm), 3, Perm)
2205 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2206 for i, n in enumerate('R W X'.split()):
2207 v = 1<<i
2208 e = Perm(v)
2209 self.assertEqual(e.value, v)
2210 self.assertEqual(type(e.value), int)
2211 self.assertEqual(e.name, n)
2212 self.assertIn(e, Perm)
2213 self.assertIs(type(e), Perm)
2214
2215 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002216 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002217 lst = list(Perm)
2218 self.assertEqual(len(lst), len(Perm))
2219 self.assertEqual(len(Perm), 3, Perm)
2220 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2221 for i, n in enumerate('R W X'.split()):
2222 v = 8<<i
2223 e = Perm(v)
2224 self.assertEqual(e.value, v)
2225 self.assertEqual(type(e.value), int)
2226 self.assertEqual(e.name, n)
2227 self.assertIn(e, Perm)
2228 self.assertIs(type(e), Perm)
2229
2230 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002231 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002232 lst = list(Perm)
2233 self.assertEqual(len(lst), len(Perm))
2234 self.assertEqual(len(Perm), 3, Perm)
2235 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2236 for i, n in enumerate('R W X'.split()):
2237 v = 1<<i
2238 e = Perm(v)
2239 self.assertEqual(e.value, v)
2240 self.assertEqual(type(e.value), int)
2241 self.assertEqual(e.name, n)
2242 self.assertIn(e, Perm)
2243 self.assertIs(type(e), Perm)
2244
2245 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002246 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002247 lst = list(Perm)
2248 self.assertEqual(len(lst), len(Perm))
2249 self.assertEqual(len(Perm), 3, Perm)
2250 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2251 for i, n in enumerate('R W X'.split()):
2252 v = 1<<(2*i+1)
2253 e = Perm(v)
2254 self.assertEqual(e.value, v)
2255 self.assertEqual(type(e.value), int)
2256 self.assertEqual(e.name, n)
2257 self.assertIn(e, Perm)
2258 self.assertIs(type(e), Perm)
2259
2260 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002261 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002262 lst = list(Perm)
2263 self.assertEqual(len(lst), len(Perm))
2264 self.assertEqual(len(Perm), 3, Perm)
2265 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2266 for i, n in enumerate('R W X'.split()):
2267 v = 1<<(2*i+1)
2268 e = Perm(v)
2269 self.assertEqual(e.value, v)
2270 self.assertEqual(type(e.value), int)
2271 self.assertEqual(e.name, n)
2272 self.assertIn(e, Perm)
2273 self.assertIs(type(e), Perm)
2274
Ethan Furman65a5a472016-09-01 23:55:19 -07002275 def test_pickle(self):
2276 if isinstance(FlagStooges, Exception):
2277 raise FlagStooges
2278 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2279 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002280
Rahul Jha94306522018-09-10 23:51:04 +05302281 def test_contains(self):
2282 Open = self.Open
2283 Color = self.Color
2284 self.assertFalse(Color.BLACK in Open)
2285 self.assertFalse(Open.RO in Color)
2286 with self.assertRaises(TypeError):
2287 'BLACK' in Color
2288 with self.assertRaises(TypeError):
2289 'RO' in Open
2290 with self.assertRaises(TypeError):
2291 1 in Color
2292 with self.assertRaises(TypeError):
2293 1 in Open
2294
2295 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002296 Perm = self.Perm
2297 R, W, X = Perm
2298 RW = R | W
2299 RX = R | X
2300 WX = W | X
2301 RWX = R | W | X
2302 self.assertTrue(R in RW)
2303 self.assertTrue(R in RX)
2304 self.assertTrue(R in RWX)
2305 self.assertTrue(W in RW)
2306 self.assertTrue(W in WX)
2307 self.assertTrue(W in RWX)
2308 self.assertTrue(X in RX)
2309 self.assertTrue(X in WX)
2310 self.assertTrue(X in RWX)
2311 self.assertFalse(R in WX)
2312 self.assertFalse(W in RX)
2313 self.assertFalse(X in RW)
2314
Ethan Furmanc16595e2016-09-10 23:36:59 -07002315 def test_auto_number(self):
2316 class Color(Flag):
2317 red = auto()
2318 blue = auto()
2319 green = auto()
2320
2321 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2322 self.assertEqual(Color.red.value, 1)
2323 self.assertEqual(Color.blue.value, 2)
2324 self.assertEqual(Color.green.value, 4)
2325
2326 def test_auto_number_garbage(self):
2327 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2328 class Color(Flag):
2329 red = 'not an int'
2330 blue = auto()
2331
Ethan Furman3515dcc2016-09-18 13:15:41 -07002332 def test_cascading_failure(self):
2333 class Bizarre(Flag):
2334 c = 3
2335 d = 4
2336 f = 6
2337 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002338 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2339 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2340 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2341 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2342 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2343 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2344 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002345
2346 def test_duplicate_auto(self):
2347 class Dupes(Enum):
2348 first = primero = auto()
2349 second = auto()
2350 third = auto()
2351 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2352
2353 def test_bizarre(self):
2354 class Bizarre(Flag):
2355 b = 3
2356 c = 4
2357 d = 6
2358 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2359
Ethan Furman5bdab642018-09-21 19:03:09 -07002360 def test_multiple_mixin(self):
2361 class AllMixin:
2362 @classproperty
2363 def ALL(cls):
2364 members = list(cls)
2365 all_value = None
2366 if members:
2367 all_value = members[0]
2368 for member in members[1:]:
2369 all_value |= member
2370 cls.ALL = all_value
2371 return all_value
2372 class StrMixin:
2373 def __str__(self):
2374 return self._name_.lower()
2375 class Color(AllMixin, Flag):
2376 RED = auto()
2377 GREEN = auto()
2378 BLUE = auto()
2379 self.assertEqual(Color.RED.value, 1)
2380 self.assertEqual(Color.GREEN.value, 2)
2381 self.assertEqual(Color.BLUE.value, 4)
2382 self.assertEqual(Color.ALL.value, 7)
2383 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2384 class Color(AllMixin, StrMixin, Flag):
2385 RED = auto()
2386 GREEN = auto()
2387 BLUE = auto()
2388 self.assertEqual(Color.RED.value, 1)
2389 self.assertEqual(Color.GREEN.value, 2)
2390 self.assertEqual(Color.BLUE.value, 4)
2391 self.assertEqual(Color.ALL.value, 7)
2392 self.assertEqual(str(Color.BLUE), 'blue')
2393 class Color(StrMixin, AllMixin, Flag):
2394 RED = auto()
2395 GREEN = auto()
2396 BLUE = auto()
2397 self.assertEqual(Color.RED.value, 1)
2398 self.assertEqual(Color.GREEN.value, 2)
2399 self.assertEqual(Color.BLUE.value, 4)
2400 self.assertEqual(Color.ALL.value, 7)
2401 self.assertEqual(str(Color.BLUE), 'blue')
2402
Hai Shie80697d2020-05-28 06:10:27 +08002403 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002404 def test_unique_composite(self):
2405 # override __eq__ to be identity only
2406 class TestFlag(Flag):
2407 one = auto()
2408 two = auto()
2409 three = auto()
2410 four = auto()
2411 five = auto()
2412 six = auto()
2413 seven = auto()
2414 eight = auto()
2415 def __eq__(self, other):
2416 return self is other
2417 def __hash__(self):
2418 return hash(self._value_)
2419 # have multiple threads competing to complete the composite members
2420 seen = set()
2421 failed = False
2422 def cycle_enum():
2423 nonlocal failed
2424 try:
2425 for i in range(256):
2426 seen.add(TestFlag(i))
2427 except Exception:
2428 failed = True
2429 threads = [
2430 threading.Thread(target=cycle_enum)
2431 for _ in range(8)
2432 ]
Hai Shie80697d2020-05-28 06:10:27 +08002433 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002434 pass
2435 # check that only 248 members were created
2436 self.assertFalse(
2437 failed,
2438 'at least one thread failed while creating composite members')
2439 self.assertEqual(256, len(seen), 'too many composite members created')
2440
Ethan Furmanc16595e2016-09-10 23:36:59 -07002441
Ethan Furman65a5a472016-09-01 23:55:19 -07002442class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002443 """Tests of the IntFlags."""
2444
Ethan Furman65a5a472016-09-01 23:55:19 -07002445 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002446 X = 1 << 0
2447 W = 1 << 1
2448 R = 1 << 2
2449
Ethan Furman65a5a472016-09-01 23:55:19 -07002450 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002451 RO = 0
2452 WO = 1
2453 RW = 2
2454 AC = 3
2455 CE = 1<<19
2456
Rahul Jha94306522018-09-10 23:51:04 +05302457 class Color(IntFlag):
2458 BLACK = 0
2459 RED = 1
2460 GREEN = 2
2461 BLUE = 4
2462 PURPLE = RED|BLUE
2463
Ethan Furman3515dcc2016-09-18 13:15:41 -07002464 def test_type(self):
2465 Perm = self.Perm
2466 Open = self.Open
2467 for f in Perm:
2468 self.assertTrue(isinstance(f, Perm))
2469 self.assertEqual(f, f.value)
2470 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2471 self.assertEqual(Perm.W | Perm.X, 3)
2472 for f in Open:
2473 self.assertTrue(isinstance(f, Open))
2474 self.assertEqual(f, f.value)
2475 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2476 self.assertEqual(Open.WO | Open.RW, 3)
2477
2478
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002479 def test_str(self):
2480 Perm = self.Perm
2481 self.assertEqual(str(Perm.R), 'Perm.R')
2482 self.assertEqual(str(Perm.W), 'Perm.W')
2483 self.assertEqual(str(Perm.X), 'Perm.X')
2484 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2485 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2486 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2487 self.assertEqual(str(Perm(0)), 'Perm.0')
2488 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002489 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2490 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2491 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2492 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002493 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002494 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2495 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2496 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002497
2498 Open = self.Open
2499 self.assertEqual(str(Open.RO), 'Open.RO')
2500 self.assertEqual(str(Open.WO), 'Open.WO')
2501 self.assertEqual(str(Open.AC), 'Open.AC')
2502 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2503 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2504 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002505 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2506 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2507 self.assertEqual(str(~Open.AC), 'Open.CE')
2508 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2509 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2510 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002511
2512 def test_repr(self):
2513 Perm = self.Perm
2514 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2515 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2516 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2517 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2518 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2519 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002520 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2521 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002522 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2523 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2524 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2525 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002526 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002527 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2528 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2529 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002530
2531 Open = self.Open
2532 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2533 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2534 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2535 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2536 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002537 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002538 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2539 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2540 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2541 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2542 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2543 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002544
2545 def test_or(self):
2546 Perm = self.Perm
2547 for i in Perm:
2548 for j in Perm:
2549 self.assertEqual(i | j, i.value | j.value)
2550 self.assertEqual((i | j).value, i.value | j.value)
2551 self.assertIs(type(i | j), Perm)
2552 for j in range(8):
2553 self.assertEqual(i | j, i.value | j)
2554 self.assertEqual((i | j).value, i.value | j)
2555 self.assertIs(type(i | j), Perm)
2556 self.assertEqual(j | i, j | i.value)
2557 self.assertEqual((j | i).value, j | i.value)
2558 self.assertIs(type(j | i), Perm)
2559 for i in Perm:
2560 self.assertIs(i | i, i)
2561 self.assertIs(i | 0, i)
2562 self.assertIs(0 | i, i)
2563 Open = self.Open
2564 self.assertIs(Open.RO | Open.CE, Open.CE)
2565
2566 def test_and(self):
2567 Perm = self.Perm
2568 RW = Perm.R | Perm.W
2569 RX = Perm.R | Perm.X
2570 WX = Perm.W | Perm.X
2571 RWX = Perm.R | Perm.W | Perm.X
2572 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2573 for i in values:
2574 for j in values:
2575 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2576 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2577 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2578 for j in range(8):
2579 self.assertEqual(i & j, i.value & j)
2580 self.assertEqual((i & j).value, i.value & j)
2581 self.assertIs(type(i & j), Perm)
2582 self.assertEqual(j & i, j & i.value)
2583 self.assertEqual((j & i).value, j & i.value)
2584 self.assertIs(type(j & i), Perm)
2585 for i in Perm:
2586 self.assertIs(i & i, i)
2587 self.assertIs(i & 7, i)
2588 self.assertIs(7 & i, i)
2589 Open = self.Open
2590 self.assertIs(Open.RO & Open.CE, Open.RO)
2591
2592 def test_xor(self):
2593 Perm = self.Perm
2594 for i in Perm:
2595 for j in Perm:
2596 self.assertEqual(i ^ j, i.value ^ j.value)
2597 self.assertEqual((i ^ j).value, i.value ^ j.value)
2598 self.assertIs(type(i ^ j), Perm)
2599 for j in range(8):
2600 self.assertEqual(i ^ j, i.value ^ j)
2601 self.assertEqual((i ^ j).value, i.value ^ j)
2602 self.assertIs(type(i ^ j), Perm)
2603 self.assertEqual(j ^ i, j ^ i.value)
2604 self.assertEqual((j ^ i).value, j ^ i.value)
2605 self.assertIs(type(j ^ i), Perm)
2606 for i in Perm:
2607 self.assertIs(i ^ 0, i)
2608 self.assertIs(0 ^ i, i)
2609 Open = self.Open
2610 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2611 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2612
2613 def test_invert(self):
2614 Perm = self.Perm
2615 RW = Perm.R | Perm.W
2616 RX = Perm.R | Perm.X
2617 WX = Perm.W | Perm.X
2618 RWX = Perm.R | Perm.W | Perm.X
2619 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2620 for i in values:
2621 self.assertEqual(~i, ~i.value)
2622 self.assertEqual((~i).value, ~i.value)
2623 self.assertIs(type(~i), Perm)
2624 self.assertEqual(~~i, i)
2625 for i in Perm:
2626 self.assertIs(~~i, i)
2627 Open = self.Open
2628 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2629 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2630
2631 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002632 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002633 lst = list(Perm)
2634 self.assertEqual(len(lst), len(Perm))
2635 self.assertEqual(len(Perm), 3, Perm)
2636 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2637 for i, n in enumerate('R W X'.split()):
2638 v = 1<<i
2639 e = Perm(v)
2640 self.assertEqual(e.value, v)
2641 self.assertEqual(type(e.value), int)
2642 self.assertEqual(e, v)
2643 self.assertEqual(e.name, n)
2644 self.assertIn(e, Perm)
2645 self.assertIs(type(e), Perm)
2646
2647 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002648 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002649 lst = list(Perm)
2650 self.assertEqual(len(lst), len(Perm))
2651 self.assertEqual(len(Perm), 3, Perm)
2652 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2653 for i, n in enumerate('R W X'.split()):
2654 v = 8<<i
2655 e = Perm(v)
2656 self.assertEqual(e.value, v)
2657 self.assertEqual(type(e.value), int)
2658 self.assertEqual(e, v)
2659 self.assertEqual(e.name, n)
2660 self.assertIn(e, Perm)
2661 self.assertIs(type(e), Perm)
2662
2663 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002664 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002665 lst = list(Perm)
2666 self.assertEqual(len(lst), len(Perm))
2667 self.assertEqual(len(Perm), 3, Perm)
2668 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2669 for i, n in enumerate('R W X'.split()):
2670 v = 1<<i
2671 e = Perm(v)
2672 self.assertEqual(e.value, v)
2673 self.assertEqual(type(e.value), int)
2674 self.assertEqual(e, v)
2675 self.assertEqual(e.name, n)
2676 self.assertIn(e, Perm)
2677 self.assertIs(type(e), Perm)
2678
2679 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002680 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002681 lst = list(Perm)
2682 self.assertEqual(len(lst), len(Perm))
2683 self.assertEqual(len(Perm), 3, Perm)
2684 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2685 for i, n in enumerate('R W X'.split()):
2686 v = 1<<(2*i+1)
2687 e = Perm(v)
2688 self.assertEqual(e.value, v)
2689 self.assertEqual(type(e.value), int)
2690 self.assertEqual(e, v)
2691 self.assertEqual(e.name, n)
2692 self.assertIn(e, Perm)
2693 self.assertIs(type(e), Perm)
2694
2695 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002696 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002697 lst = list(Perm)
2698 self.assertEqual(len(lst), len(Perm))
2699 self.assertEqual(len(Perm), 3, Perm)
2700 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2701 for i, n in enumerate('R W X'.split()):
2702 v = 1<<(2*i+1)
2703 e = Perm(v)
2704 self.assertEqual(e.value, v)
2705 self.assertEqual(type(e.value), int)
2706 self.assertEqual(e, v)
2707 self.assertEqual(e.name, n)
2708 self.assertIn(e, Perm)
2709 self.assertIs(type(e), Perm)
2710
2711
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002712 def test_programatic_function_from_empty_list(self):
2713 Perm = enum.IntFlag('Perm', [])
2714 lst = list(Perm)
2715 self.assertEqual(len(lst), len(Perm))
2716 self.assertEqual(len(Perm), 0, Perm)
2717 Thing = enum.Enum('Thing', [])
2718 lst = list(Thing)
2719 self.assertEqual(len(lst), len(Thing))
2720 self.assertEqual(len(Thing), 0, Thing)
2721
2722
2723 def test_programatic_function_from_empty_tuple(self):
2724 Perm = enum.IntFlag('Perm', ())
2725 lst = list(Perm)
2726 self.assertEqual(len(lst), len(Perm))
2727 self.assertEqual(len(Perm), 0, Perm)
2728 Thing = enum.Enum('Thing', ())
2729 self.assertEqual(len(lst), len(Thing))
2730 self.assertEqual(len(Thing), 0, Thing)
2731
Rahul Jha94306522018-09-10 23:51:04 +05302732 def test_contains(self):
2733 Open = self.Open
2734 Color = self.Color
2735 self.assertTrue(Color.GREEN in Color)
2736 self.assertTrue(Open.RW in Open)
2737 self.assertFalse(Color.GREEN in Open)
2738 self.assertFalse(Open.RW in Color)
2739 with self.assertRaises(TypeError):
2740 'GREEN' in Color
2741 with self.assertRaises(TypeError):
2742 'RW' in Open
2743 with self.assertRaises(TypeError):
2744 2 in Color
2745 with self.assertRaises(TypeError):
2746 2 in Open
2747
2748 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002749 Perm = self.Perm
2750 R, W, X = Perm
2751 RW = R | W
2752 RX = R | X
2753 WX = W | X
2754 RWX = R | W | X
2755 self.assertTrue(R in RW)
2756 self.assertTrue(R in RX)
2757 self.assertTrue(R in RWX)
2758 self.assertTrue(W in RW)
2759 self.assertTrue(W in WX)
2760 self.assertTrue(W in RWX)
2761 self.assertTrue(X in RX)
2762 self.assertTrue(X in WX)
2763 self.assertTrue(X in RWX)
2764 self.assertFalse(R in WX)
2765 self.assertFalse(W in RX)
2766 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302767 with self.assertRaises(TypeError):
2768 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002769
Ethan Furman25d94bb2016-09-02 16:32:32 -07002770 def test_bool(self):
2771 Perm = self.Perm
2772 for f in Perm:
2773 self.assertTrue(f)
2774 Open = self.Open
2775 for f in Open:
2776 self.assertEqual(bool(f.value), bool(f))
2777
Ethan Furman5bdab642018-09-21 19:03:09 -07002778 def test_multiple_mixin(self):
2779 class AllMixin:
2780 @classproperty
2781 def ALL(cls):
2782 members = list(cls)
2783 all_value = None
2784 if members:
2785 all_value = members[0]
2786 for member in members[1:]:
2787 all_value |= member
2788 cls.ALL = all_value
2789 return all_value
2790 class StrMixin:
2791 def __str__(self):
2792 return self._name_.lower()
2793 class Color(AllMixin, IntFlag):
2794 RED = auto()
2795 GREEN = auto()
2796 BLUE = auto()
2797 self.assertEqual(Color.RED.value, 1)
2798 self.assertEqual(Color.GREEN.value, 2)
2799 self.assertEqual(Color.BLUE.value, 4)
2800 self.assertEqual(Color.ALL.value, 7)
2801 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2802 class Color(AllMixin, StrMixin, IntFlag):
2803 RED = auto()
2804 GREEN = auto()
2805 BLUE = auto()
2806 self.assertEqual(Color.RED.value, 1)
2807 self.assertEqual(Color.GREEN.value, 2)
2808 self.assertEqual(Color.BLUE.value, 4)
2809 self.assertEqual(Color.ALL.value, 7)
2810 self.assertEqual(str(Color.BLUE), 'blue')
2811 class Color(StrMixin, AllMixin, IntFlag):
2812 RED = auto()
2813 GREEN = auto()
2814 BLUE = auto()
2815 self.assertEqual(Color.RED.value, 1)
2816 self.assertEqual(Color.GREEN.value, 2)
2817 self.assertEqual(Color.BLUE.value, 4)
2818 self.assertEqual(Color.ALL.value, 7)
2819 self.assertEqual(str(Color.BLUE), 'blue')
2820
Hai Shie80697d2020-05-28 06:10:27 +08002821 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002822 def test_unique_composite(self):
2823 # override __eq__ to be identity only
2824 class TestFlag(IntFlag):
2825 one = auto()
2826 two = auto()
2827 three = auto()
2828 four = auto()
2829 five = auto()
2830 six = auto()
2831 seven = auto()
2832 eight = auto()
2833 def __eq__(self, other):
2834 return self is other
2835 def __hash__(self):
2836 return hash(self._value_)
2837 # have multiple threads competing to complete the composite members
2838 seen = set()
2839 failed = False
2840 def cycle_enum():
2841 nonlocal failed
2842 try:
2843 for i in range(256):
2844 seen.add(TestFlag(i))
2845 except Exception:
2846 failed = True
2847 threads = [
2848 threading.Thread(target=cycle_enum)
2849 for _ in range(8)
2850 ]
Hai Shie80697d2020-05-28 06:10:27 +08002851 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002852 pass
2853 # check that only 248 members were created
2854 self.assertFalse(
2855 failed,
2856 'at least one thread failed while creating composite members')
2857 self.assertEqual(256, len(seen), 'too many composite members created')
2858
2859
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002860class TestEmptyAndNonLatinStrings(unittest.TestCase):
2861
2862 def test_empty_string(self):
2863 with self.assertRaises(ValueError):
2864 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2865
2866 def test_non_latin_character_string(self):
2867 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2868 item = getattr(greek_abc, '\u03B1')
2869 self.assertEqual(item.value, 1)
2870
2871 def test_non_latin_number_string(self):
2872 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2873 item = getattr(hebrew_123, '\u05D0')
2874 self.assertEqual(item.value, 1)
2875
2876
Ethan Furmanf24bb352013-07-18 17:05:39 -07002877class TestUnique(unittest.TestCase):
2878
2879 def test_unique_clean(self):
2880 @unique
2881 class Clean(Enum):
2882 one = 1
2883 two = 'dos'
2884 tres = 4.0
2885 @unique
2886 class Cleaner(IntEnum):
2887 single = 1
2888 double = 2
2889 triple = 3
2890
2891 def test_unique_dirty(self):
2892 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2893 @unique
2894 class Dirty(Enum):
2895 one = 1
2896 two = 'dos'
2897 tres = 1
2898 with self.assertRaisesRegex(
2899 ValueError,
2900 'double.*single.*turkey.*triple',
2901 ):
2902 @unique
2903 class Dirtier(IntEnum):
2904 single = 1
2905 double = 1
2906 triple = 3
2907 turkey = 3
2908
Ethan Furman3803ad42016-05-01 10:03:53 -07002909 def test_unique_with_name(self):
2910 @unique
2911 class Silly(Enum):
2912 one = 1
2913 two = 'dos'
2914 name = 3
2915 @unique
2916 class Sillier(IntEnum):
2917 single = 1
2918 name = 2
2919 triple = 3
2920 value = 4
2921
Ethan Furmanf24bb352013-07-18 17:05:39 -07002922
Ethan Furman5bdab642018-09-21 19:03:09 -07002923
Ethan Furman3323da92015-04-11 09:39:59 -07002924expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002925Help on class Color in module %s:
2926
2927class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002928 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2929 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002930 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002931 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002932 | Method resolution order:
2933 | Color
2934 | enum.Enum
2935 | builtins.object
2936 |\x20\x20
2937 | Data and other attributes defined here:
2938 |\x20\x20
2939 | blue = <Color.blue: 3>
2940 |\x20\x20
2941 | green = <Color.green: 2>
2942 |\x20\x20
2943 | red = <Color.red: 1>
2944 |\x20\x20
2945 | ----------------------------------------------------------------------
2946 | Data descriptors inherited from enum.Enum:
2947 |\x20\x20
2948 | name
2949 | The name of the Enum member.
2950 |\x20\x20
2951 | value
2952 | The value of the Enum member.
2953 |\x20\x20
2954 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002955 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002956 |\x20\x20
2957 | __members__
2958 | Returns a mapping of member name->value.
2959 |\x20\x20\x20\x20\x20\x20
2960 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002961 | is a read-only view of the internal mapping."""
2962
2963expected_help_output_without_docs = """\
2964Help on class Color in module %s:
2965
2966class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002967 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2968 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002969 | Method resolution order:
2970 | Color
2971 | enum.Enum
2972 | builtins.object
2973 |\x20\x20
2974 | Data and other attributes defined here:
2975 |\x20\x20
2976 | blue = <Color.blue: 3>
2977 |\x20\x20
2978 | green = <Color.green: 2>
2979 |\x20\x20
2980 | red = <Color.red: 1>
2981 |\x20\x20
2982 | ----------------------------------------------------------------------
2983 | Data descriptors inherited from enum.Enum:
2984 |\x20\x20
2985 | name
2986 |\x20\x20
2987 | value
2988 |\x20\x20
2989 | ----------------------------------------------------------------------
2990 | Data descriptors inherited from enum.EnumMeta:
2991 |\x20\x20
2992 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002993
2994class TestStdLib(unittest.TestCase):
2995
Ethan Furman48a724f2015-04-11 23:23:06 -07002996 maxDiff = None
2997
Ethan Furman5875d742013-10-21 20:45:55 -07002998 class Color(Enum):
2999 red = 1
3000 green = 2
3001 blue = 3
3002
3003 def test_pydoc(self):
3004 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003005 if StrEnum.__doc__ is None:
3006 expected_text = expected_help_output_without_docs % __name__
3007 else:
3008 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003009 output = StringIO()
3010 helper = pydoc.Helper(output=output)
3011 helper(self.Color)
3012 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003013 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003014
3015 def test_inspect_getmembers(self):
3016 values = dict((
3017 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003018 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003019 ('__members__', self.Color.__members__),
3020 ('__module__', __name__),
3021 ('blue', self.Color.blue),
3022 ('green', self.Color.green),
3023 ('name', Enum.__dict__['name']),
3024 ('red', self.Color.red),
3025 ('value', Enum.__dict__['value']),
3026 ))
3027 result = dict(inspect.getmembers(self.Color))
3028 self.assertEqual(values.keys(), result.keys())
3029 failed = False
3030 for k in values.keys():
3031 if result[k] != values[k]:
3032 print()
3033 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3034 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3035 failed = True
3036 if failed:
3037 self.fail("result does not equal expected, see print above")
3038
3039 def test_inspect_classify_class_attrs(self):
3040 # indirectly test __objclass__
3041 from inspect import Attribute
3042 values = [
3043 Attribute(name='__class__', kind='data',
3044 defining_class=object, object=EnumMeta),
3045 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003046 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003047 Attribute(name='__members__', kind='property',
3048 defining_class=EnumMeta, object=EnumMeta.__members__),
3049 Attribute(name='__module__', kind='data',
3050 defining_class=self.Color, object=__name__),
3051 Attribute(name='blue', kind='data',
3052 defining_class=self.Color, object=self.Color.blue),
3053 Attribute(name='green', kind='data',
3054 defining_class=self.Color, object=self.Color.green),
3055 Attribute(name='red', kind='data',
3056 defining_class=self.Color, object=self.Color.red),
3057 Attribute(name='name', kind='data',
3058 defining_class=Enum, object=Enum.__dict__['name']),
3059 Attribute(name='value', kind='data',
3060 defining_class=Enum, object=Enum.__dict__['value']),
3061 ]
3062 values.sort(key=lambda item: item.name)
3063 result = list(inspect.classify_class_attrs(self.Color))
3064 result.sort(key=lambda item: item.name)
3065 failed = False
3066 for v, r in zip(values, result):
3067 if r != v:
3068 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3069 failed = True
3070 if failed:
3071 self.fail("result does not equal expected, see print above")
3072
Martin Panter19e69c52015-11-14 12:46:42 +00003073
3074class MiscTestCase(unittest.TestCase):
3075 def test__all__(self):
3076 support.check__all__(self, enum)
3077
3078
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003079# These are unordered here on purpose to ensure that declaration order
3080# makes no difference.
3081CONVERT_TEST_NAME_D = 5
3082CONVERT_TEST_NAME_C = 5
3083CONVERT_TEST_NAME_B = 5
3084CONVERT_TEST_NAME_A = 5 # This one should sort first.
3085CONVERT_TEST_NAME_E = 5
3086CONVERT_TEST_NAME_F = 5
3087
3088class TestIntEnumConvert(unittest.TestCase):
3089 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003090 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003091 'UnittestConvert',
3092 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003093 filter=lambda x: x.startswith('CONVERT_TEST_'))
3094 # We don't want the reverse lookup value to vary when there are
3095 # multiple possible names for a given value. It should always
3096 # report the first lexigraphical name in that case.
3097 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3098
3099 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003100 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003101 'UnittestConvert',
3102 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003103 filter=lambda x: x.startswith('CONVERT_TEST_'))
3104 # Ensure that test_type has all of the desired names and values.
3105 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3106 test_type.CONVERT_TEST_NAME_A)
3107 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3108 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3109 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3110 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3111 # Ensure that test_type only picked up names matching the filter.
3112 self.assertEqual([name for name in dir(test_type)
3113 if name[0:2] not in ('CO', '__')],
3114 [], msg='Names other than CONVERT_TEST_* found.')
3115
orlnub1230fb9fad2018-09-12 20:28:53 +03003116 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3117 '_convert was deprecated in 3.8')
3118 def test_convert_warn(self):
3119 with self.assertWarns(DeprecationWarning):
3120 enum.IntEnum._convert(
3121 'UnittestConvert',
3122 ('test.test_enum', '__main__')[__name__=='__main__'],
3123 filter=lambda x: x.startswith('CONVERT_TEST_'))
3124
3125 @unittest.skipUnless(sys.version_info >= (3, 9),
3126 '_convert was removed in 3.9')
3127 def test_convert_raise(self):
3128 with self.assertRaises(AttributeError):
3129 enum.IntEnum._convert(
3130 'UnittestConvert',
3131 ('test.test_enum', '__main__')[__name__=='__main__'],
3132 filter=lambda x: x.startswith('CONVERT_TEST_'))
3133
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003134
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003135if __name__ == '__main__':
3136 unittest.main()