blob: ebf76047972dc0b7e5cfedb2ff1a119e0e1a2e40 [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 Furman22415ad2020-09-15 16:28:25 -0700563 def test_object_str_override(self):
564 class Colors(Enum):
565 RED, GREEN, BLUE = 1, 2, 3
566 def __repr__(self):
567 return "test.%s" % (self._name_, )
568 __str__ = object.__str__
569 self.assertEqual(str(Colors.RED), 'test.RED')
570
Ethan Furmanbff01f32020-09-15 15:56:26 -0700571 def test_enum_str_override(self):
572 class MyStrEnum(Enum):
573 def __str__(self):
574 return 'MyStr'
575 class MyMethodEnum(Enum):
576 def hello(self):
577 return 'Hello! My name is %s' % self.name
578 class Test1Enum(MyMethodEnum, int, MyStrEnum):
579 One = 1
580 Two = 2
581 self.assertEqual(str(Test1Enum.One), 'MyStr')
582 #
583 class Test2Enum(MyStrEnum, MyMethodEnum):
584 One = 1
585 Two = 2
586 self.assertEqual(str(Test2Enum.One), 'MyStr')
587
588 def test_inherited_data_type(self):
589 class HexInt(int):
590 def __repr__(self):
591 return hex(self)
592 class MyEnum(HexInt, enum.Enum):
593 A = 1
594 B = 2
595 C = 3
596 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
597
598 def test_too_many_data_types(self):
599 with self.assertRaisesRegex(TypeError, 'too many data types'):
600 class Huh(str, int, Enum):
601 One = 1
602
603 class MyStr(str):
604 def hello(self):
605 return 'hello, %s' % self
606 class MyInt(int):
607 def repr(self):
608 return hex(self)
609 with self.assertRaisesRegex(TypeError, 'too many data types'):
610 class Huh(MyStr, MyInt, Enum):
611 One = 1
612
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700613 def test_hash(self):
614 Season = self.Season
615 dates = {}
616 dates[Season.WINTER] = '1225'
617 dates[Season.SPRING] = '0315'
618 dates[Season.SUMMER] = '0704'
619 dates[Season.AUTUMN] = '1031'
620 self.assertEqual(dates[Season.AUTUMN], '1031')
621
622 def test_intenum_from_scratch(self):
623 class phy(int, Enum):
624 pi = 3
625 tau = 2 * pi
626 self.assertTrue(phy.pi < phy.tau)
627
628 def test_intenum_inherited(self):
629 class IntEnum(int, Enum):
630 pass
631 class phy(IntEnum):
632 pi = 3
633 tau = 2 * pi
634 self.assertTrue(phy.pi < phy.tau)
635
636 def test_floatenum_from_scratch(self):
637 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700638 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700639 tau = 2 * pi
640 self.assertTrue(phy.pi < phy.tau)
641
642 def test_floatenum_inherited(self):
643 class FloatEnum(float, Enum):
644 pass
645 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700646 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700647 tau = 2 * pi
648 self.assertTrue(phy.pi < phy.tau)
649
650 def test_strenum_from_scratch(self):
651 class phy(str, Enum):
652 pi = 'Pi'
653 tau = 'Tau'
654 self.assertTrue(phy.pi < phy.tau)
655
656 def test_strenum_inherited(self):
657 class StrEnum(str, Enum):
658 pass
659 class phy(StrEnum):
660 pi = 'Pi'
661 tau = 'Tau'
662 self.assertTrue(phy.pi < phy.tau)
663
664
665 def test_intenum(self):
666 class WeekDay(IntEnum):
667 SUNDAY = 1
668 MONDAY = 2
669 TUESDAY = 3
670 WEDNESDAY = 4
671 THURSDAY = 5
672 FRIDAY = 6
673 SATURDAY = 7
674
675 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
676 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
677
678 lst = list(WeekDay)
679 self.assertEqual(len(lst), len(WeekDay))
680 self.assertEqual(len(WeekDay), 7)
681 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
682 target = target.split()
683 for i, weekday in enumerate(target, 1):
684 e = WeekDay(i)
685 self.assertEqual(e, i)
686 self.assertEqual(int(e), i)
687 self.assertEqual(e.name, weekday)
688 self.assertIn(e, WeekDay)
689 self.assertEqual(lst.index(e)+1, i)
690 self.assertTrue(0 < e < 8)
691 self.assertIs(type(e), WeekDay)
692 self.assertIsInstance(e, int)
693 self.assertIsInstance(e, Enum)
694
695 def test_intenum_duplicates(self):
696 class WeekDay(IntEnum):
697 SUNDAY = 1
698 MONDAY = 2
699 TUESDAY = TEUSDAY = 3
700 WEDNESDAY = 4
701 THURSDAY = 5
702 FRIDAY = 6
703 SATURDAY = 7
704 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
705 self.assertEqual(WeekDay(3).name, 'TUESDAY')
706 self.assertEqual([k for k,v in WeekDay.__members__.items()
707 if v.name != k], ['TEUSDAY', ])
708
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300709 def test_intenum_from_bytes(self):
710 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
711 with self.assertRaises(ValueError):
712 IntStooges.from_bytes(b'\x00\x05', 'big')
713
714 def test_floatenum_fromhex(self):
715 h = float.hex(FloatStooges.MOE.value)
716 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
717 h = float.hex(FloatStooges.MOE.value + 0.01)
718 with self.assertRaises(ValueError):
719 FloatStooges.fromhex(h)
720
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700721 def test_pickle_enum(self):
722 if isinstance(Stooges, Exception):
723 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800724 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
725 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700726
727 def test_pickle_int(self):
728 if isinstance(IntStooges, Exception):
729 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800730 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
731 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700732
733 def test_pickle_float(self):
734 if isinstance(FloatStooges, Exception):
735 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800736 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
737 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700738
739 def test_pickle_enum_function(self):
740 if isinstance(Answer, Exception):
741 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800742 test_pickle_dump_load(self.assertIs, Answer.him)
743 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700744
745 def test_pickle_enum_function_with_module(self):
746 if isinstance(Question, Exception):
747 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800748 test_pickle_dump_load(self.assertIs, Question.who)
749 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750
Ethan Furmanca1b7942014-02-08 11:36:27 -0800751 def test_enum_function_with_qualname(self):
752 if isinstance(Theory, Exception):
753 raise Theory
754 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
755
756 def test_class_nested_enum_and_pickle_protocol_four(self):
757 # would normally just have this directly in the class namespace
758 class NestedEnum(Enum):
759 twigs = 'common'
760 shiny = 'rare'
761
762 self.__class__.NestedEnum = NestedEnum
763 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300764 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800765
Ethan Furman24e837f2015-03-18 17:27:57 -0700766 def test_pickle_by_name(self):
767 class ReplaceGlobalInt(IntEnum):
768 ONE = 1
769 TWO = 2
770 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
771 for proto in range(HIGHEST_PROTOCOL):
772 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
773
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700774 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800775 BadPickle = Enum(
776 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700777 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800778 # now break BadPickle to test exception raising
779 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800780 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
781 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700782
783 def test_string_enum(self):
784 class SkillLevel(str, Enum):
785 master = 'what is the sound of one hand clapping?'
786 journeyman = 'why did the chicken cross the road?'
787 apprentice = 'knock, knock!'
788 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
789
790 def test_getattr_getitem(self):
791 class Period(Enum):
792 morning = 1
793 noon = 2
794 evening = 3
795 night = 4
796 self.assertIs(Period(2), Period.noon)
797 self.assertIs(getattr(Period, 'night'), Period.night)
798 self.assertIs(Period['morning'], Period.morning)
799
800 def test_getattr_dunder(self):
801 Season = self.Season
802 self.assertTrue(getattr(Season, '__eq__'))
803
804 def test_iteration_order(self):
805 class Season(Enum):
806 SUMMER = 2
807 WINTER = 4
808 AUTUMN = 3
809 SPRING = 1
810 self.assertEqual(
811 list(Season),
812 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
813 )
814
Ethan Furman2131a4a2013-09-14 18:11:24 -0700815 def test_reversed_iteration_order(self):
816 self.assertEqual(
817 list(reversed(self.Season)),
818 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
819 self.Season.SPRING]
820 )
821
Martin Pantereb995702016-07-28 01:11:04 +0000822 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700823 SummerMonth = Enum('SummerMonth', 'june july august')
824 lst = list(SummerMonth)
825 self.assertEqual(len(lst), len(SummerMonth))
826 self.assertEqual(len(SummerMonth), 3, SummerMonth)
827 self.assertEqual(
828 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
829 lst,
830 )
831 for i, month in enumerate('june july august'.split(), 1):
832 e = SummerMonth(i)
833 self.assertEqual(int(e.value), i)
834 self.assertNotEqual(e, i)
835 self.assertEqual(e.name, month)
836 self.assertIn(e, SummerMonth)
837 self.assertIs(type(e), SummerMonth)
838
Martin Pantereb995702016-07-28 01:11:04 +0000839 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700840 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
841 lst = list(SummerMonth)
842 self.assertEqual(len(lst), len(SummerMonth))
843 self.assertEqual(len(SummerMonth), 3, SummerMonth)
844 self.assertEqual(
845 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
846 lst,
847 )
848 for i, month in enumerate('june july august'.split(), 10):
849 e = SummerMonth(i)
850 self.assertEqual(int(e.value), i)
851 self.assertNotEqual(e, i)
852 self.assertEqual(e.name, month)
853 self.assertIn(e, SummerMonth)
854 self.assertIs(type(e), SummerMonth)
855
Martin Pantereb995702016-07-28 01:11:04 +0000856 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700857 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
858 lst = list(SummerMonth)
859 self.assertEqual(len(lst), len(SummerMonth))
860 self.assertEqual(len(SummerMonth), 3, SummerMonth)
861 self.assertEqual(
862 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
863 lst,
864 )
865 for i, month in enumerate('june july august'.split(), 1):
866 e = SummerMonth(i)
867 self.assertEqual(int(e.value), i)
868 self.assertNotEqual(e, i)
869 self.assertEqual(e.name, month)
870 self.assertIn(e, SummerMonth)
871 self.assertIs(type(e), SummerMonth)
872
Martin Pantereb995702016-07-28 01:11:04 +0000873 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700874 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
875 lst = list(SummerMonth)
876 self.assertEqual(len(lst), len(SummerMonth))
877 self.assertEqual(len(SummerMonth), 3, SummerMonth)
878 self.assertEqual(
879 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
880 lst,
881 )
882 for i, month in enumerate('june july august'.split(), 20):
883 e = SummerMonth(i)
884 self.assertEqual(int(e.value), i)
885 self.assertNotEqual(e, i)
886 self.assertEqual(e.name, month)
887 self.assertIn(e, SummerMonth)
888 self.assertIs(type(e), SummerMonth)
889
Martin Pantereb995702016-07-28 01:11:04 +0000890 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700891 SummerMonth = Enum(
892 'SummerMonth',
893 (('june', 1), ('july', 2), ('august', 3))
894 )
895 lst = list(SummerMonth)
896 self.assertEqual(len(lst), len(SummerMonth))
897 self.assertEqual(len(SummerMonth), 3, SummerMonth)
898 self.assertEqual(
899 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
900 lst,
901 )
902 for i, month in enumerate('june july august'.split(), 1):
903 e = SummerMonth(i)
904 self.assertEqual(int(e.value), i)
905 self.assertNotEqual(e, i)
906 self.assertEqual(e.name, month)
907 self.assertIn(e, SummerMonth)
908 self.assertIs(type(e), SummerMonth)
909
Martin Pantereb995702016-07-28 01:11:04 +0000910 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700911 SummerMonth = Enum(
912 'SummerMonth',
913 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
914 )
915 lst = list(SummerMonth)
916 self.assertEqual(len(lst), len(SummerMonth))
917 self.assertEqual(len(SummerMonth), 3, SummerMonth)
918 self.assertEqual(
919 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
920 lst,
921 )
922 for i, month in enumerate('june july august'.split(), 1):
923 e = SummerMonth(i)
924 self.assertEqual(int(e.value), i)
925 self.assertNotEqual(e, i)
926 self.assertEqual(e.name, month)
927 self.assertIn(e, SummerMonth)
928 self.assertIs(type(e), SummerMonth)
929
Martin Pantereb995702016-07-28 01:11:04 +0000930 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700931 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
932 lst = list(SummerMonth)
933 self.assertEqual(len(lst), len(SummerMonth))
934 self.assertEqual(len(SummerMonth), 3, SummerMonth)
935 self.assertEqual(
936 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
937 lst,
938 )
939 for i, month in enumerate('june july august'.split(), 1):
940 e = SummerMonth(i)
941 self.assertEqual(e, i)
942 self.assertEqual(e.name, month)
943 self.assertIn(e, SummerMonth)
944 self.assertIs(type(e), SummerMonth)
945
Martin Pantereb995702016-07-28 01:11:04 +0000946 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700947 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
948 lst = list(SummerMonth)
949 self.assertEqual(len(lst), len(SummerMonth))
950 self.assertEqual(len(SummerMonth), 3, SummerMonth)
951 self.assertEqual(
952 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
953 lst,
954 )
955 for i, month in enumerate('june july august'.split(), 30):
956 e = SummerMonth(i)
957 self.assertEqual(e, i)
958 self.assertEqual(e.name, month)
959 self.assertIn(e, SummerMonth)
960 self.assertIs(type(e), SummerMonth)
961
Martin Pantereb995702016-07-28 01:11:04 +0000962 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700963 SummerMonth = IntEnum('SummerMonth', 'june july august')
964 lst = list(SummerMonth)
965 self.assertEqual(len(lst), len(SummerMonth))
966 self.assertEqual(len(SummerMonth), 3, SummerMonth)
967 self.assertEqual(
968 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
969 lst,
970 )
971 for i, month in enumerate('june july august'.split(), 1):
972 e = SummerMonth(i)
973 self.assertEqual(e, i)
974 self.assertEqual(e.name, month)
975 self.assertIn(e, SummerMonth)
976 self.assertIs(type(e), SummerMonth)
977
Martin Pantereb995702016-07-28 01:11:04 +0000978 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700979 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
980 lst = list(SummerMonth)
981 self.assertEqual(len(lst), len(SummerMonth))
982 self.assertEqual(len(SummerMonth), 3, SummerMonth)
983 self.assertEqual(
984 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
985 lst,
986 )
987 for i, month in enumerate('june july august'.split(), 40):
988 e = SummerMonth(i)
989 self.assertEqual(e, i)
990 self.assertEqual(e.name, month)
991 self.assertIn(e, SummerMonth)
992 self.assertIs(type(e), SummerMonth)
993
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700994 def test_subclassing(self):
995 if isinstance(Name, Exception):
996 raise Name
997 self.assertEqual(Name.BDFL, 'Guido van Rossum')
998 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
999 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001000 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001001
1002 def test_extending(self):
1003 class Color(Enum):
1004 red = 1
1005 green = 2
1006 blue = 3
1007 with self.assertRaises(TypeError):
1008 class MoreColor(Color):
1009 cyan = 4
1010 magenta = 5
1011 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001012 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1013 class EvenMoreColor(Color, IntEnum):
1014 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001015
1016 def test_exclude_methods(self):
1017 class whatever(Enum):
1018 this = 'that'
1019 these = 'those'
1020 def really(self):
1021 return 'no, not %s' % self.value
1022 self.assertIsNot(type(whatever.really), whatever)
1023 self.assertEqual(whatever.this.really(), 'no, not that')
1024
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001025 def test_wrong_inheritance_order(self):
1026 with self.assertRaises(TypeError):
1027 class Wrong(Enum, str):
1028 NotHere = 'error before this point'
1029
1030 def test_intenum_transitivity(self):
1031 class number(IntEnum):
1032 one = 1
1033 two = 2
1034 three = 3
1035 class numero(IntEnum):
1036 uno = 1
1037 dos = 2
1038 tres = 3
1039 self.assertEqual(number.one, numero.uno)
1040 self.assertEqual(number.two, numero.dos)
1041 self.assertEqual(number.three, numero.tres)
1042
1043 def test_wrong_enum_in_call(self):
1044 class Monochrome(Enum):
1045 black = 0
1046 white = 1
1047 class Gender(Enum):
1048 male = 0
1049 female = 1
1050 self.assertRaises(ValueError, Monochrome, Gender.male)
1051
1052 def test_wrong_enum_in_mixed_call(self):
1053 class Monochrome(IntEnum):
1054 black = 0
1055 white = 1
1056 class Gender(Enum):
1057 male = 0
1058 female = 1
1059 self.assertRaises(ValueError, Monochrome, Gender.male)
1060
1061 def test_mixed_enum_in_call_1(self):
1062 class Monochrome(IntEnum):
1063 black = 0
1064 white = 1
1065 class Gender(IntEnum):
1066 male = 0
1067 female = 1
1068 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1069
1070 def test_mixed_enum_in_call_2(self):
1071 class Monochrome(Enum):
1072 black = 0
1073 white = 1
1074 class Gender(IntEnum):
1075 male = 0
1076 female = 1
1077 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1078
1079 def test_flufl_enum(self):
1080 class Fluflnum(Enum):
1081 def __int__(self):
1082 return int(self.value)
1083 class MailManOptions(Fluflnum):
1084 option1 = 1
1085 option2 = 2
1086 option3 = 3
1087 self.assertEqual(int(MailManOptions.option1), 1)
1088
Ethan Furman5e5a8232013-08-04 08:42:23 -07001089 def test_introspection(self):
1090 class Number(IntEnum):
1091 one = 100
1092 two = 200
1093 self.assertIs(Number.one._member_type_, int)
1094 self.assertIs(Number._member_type_, int)
1095 class String(str, Enum):
1096 yarn = 'soft'
1097 rope = 'rough'
1098 wire = 'hard'
1099 self.assertIs(String.yarn._member_type_, str)
1100 self.assertIs(String._member_type_, str)
1101 class Plain(Enum):
1102 vanilla = 'white'
1103 one = 1
1104 self.assertIs(Plain.vanilla._member_type_, object)
1105 self.assertIs(Plain._member_type_, object)
1106
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001107 def test_no_such_enum_member(self):
1108 class Color(Enum):
1109 red = 1
1110 green = 2
1111 blue = 3
1112 with self.assertRaises(ValueError):
1113 Color(4)
1114 with self.assertRaises(KeyError):
1115 Color['chartreuse']
1116
1117 def test_new_repr(self):
1118 class Color(Enum):
1119 red = 1
1120 green = 2
1121 blue = 3
1122 def __repr__(self):
1123 return "don't you just love shades of %s?" % self.name
1124 self.assertEqual(
1125 repr(Color.blue),
1126 "don't you just love shades of blue?",
1127 )
1128
1129 def test_inherited_repr(self):
1130 class MyEnum(Enum):
1131 def __repr__(self):
1132 return "My name is %s." % self.name
1133 class MyIntEnum(int, MyEnum):
1134 this = 1
1135 that = 2
1136 theother = 3
1137 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1138
1139 def test_multiple_mixin_mro(self):
1140 class auto_enum(type(Enum)):
1141 def __new__(metacls, cls, bases, classdict):
1142 temp = type(classdict)()
1143 names = set(classdict._member_names)
1144 i = 0
1145 for k in classdict._member_names:
1146 v = classdict[k]
1147 if v is Ellipsis:
1148 v = i
1149 else:
1150 i = v
1151 i += 1
1152 temp[k] = v
1153 for k, v in classdict.items():
1154 if k not in names:
1155 temp[k] = v
1156 return super(auto_enum, metacls).__new__(
1157 metacls, cls, bases, temp)
1158
1159 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1160 pass
1161
1162 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1163 pass
1164
1165 class TestAutoNumber(AutoNumberedEnum):
1166 a = ...
1167 b = 3
1168 c = ...
1169
1170 class TestAutoInt(AutoIntEnum):
1171 a = ...
1172 b = 3
1173 c = ...
1174
1175 def test_subclasses_with_getnewargs(self):
1176 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001177 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001178 def __new__(cls, *args):
1179 _args = args
1180 name, *args = args
1181 if len(args) == 0:
1182 raise TypeError("name and value must be specified")
1183 self = int.__new__(cls, *args)
1184 self._intname = name
1185 self._args = _args
1186 return self
1187 def __getnewargs__(self):
1188 return self._args
1189 @property
1190 def __name__(self):
1191 return self._intname
1192 def __repr__(self):
1193 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001194 return "{}({!r}, {})".format(
1195 type(self).__name__,
1196 self.__name__,
1197 int.__repr__(self),
1198 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001199 def __str__(self):
1200 # str() is unchanged, even if it relies on the repr() fallback
1201 base = int
1202 base_str = base.__str__
1203 if base_str.__objclass__ is object:
1204 return base.__repr__(self)
1205 return base_str(self)
1206 # for simplicity, we only define one operator that
1207 # propagates expressions
1208 def __add__(self, other):
1209 temp = int(self) + int( other)
1210 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1211 return NamedInt(
1212 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001213 temp,
1214 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001215 else:
1216 return temp
1217
1218 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001219 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001220 x = ('the-x', 1)
1221 y = ('the-y', 2)
1222
Ethan Furman2aa27322013-07-19 19:35:56 -07001223
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001224 self.assertIs(NEI.__new__, Enum.__new__)
1225 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1226 globals()['NamedInt'] = NamedInt
1227 globals()['NEI'] = NEI
1228 NI5 = NamedInt('test', 5)
1229 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001230 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001231 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001232 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001233 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001234
Ethan Furmanca1b7942014-02-08 11:36:27 -08001235 def test_subclasses_with_getnewargs_ex(self):
1236 class NamedInt(int):
1237 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1238 def __new__(cls, *args):
1239 _args = args
1240 name, *args = args
1241 if len(args) == 0:
1242 raise TypeError("name and value must be specified")
1243 self = int.__new__(cls, *args)
1244 self._intname = name
1245 self._args = _args
1246 return self
1247 def __getnewargs_ex__(self):
1248 return self._args, {}
1249 @property
1250 def __name__(self):
1251 return self._intname
1252 def __repr__(self):
1253 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001254 return "{}({!r}, {})".format(
1255 type(self).__name__,
1256 self.__name__,
1257 int.__repr__(self),
1258 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001259 def __str__(self):
1260 # str() is unchanged, even if it relies on the repr() fallback
1261 base = int
1262 base_str = base.__str__
1263 if base_str.__objclass__ is object:
1264 return base.__repr__(self)
1265 return base_str(self)
1266 # for simplicity, we only define one operator that
1267 # propagates expressions
1268 def __add__(self, other):
1269 temp = int(self) + int( other)
1270 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1271 return NamedInt(
1272 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001273 temp,
1274 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001275 else:
1276 return temp
1277
1278 class NEI(NamedInt, Enum):
1279 __qualname__ = 'NEI' # needed for pickle protocol 4
1280 x = ('the-x', 1)
1281 y = ('the-y', 2)
1282
1283
1284 self.assertIs(NEI.__new__, Enum.__new__)
1285 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1286 globals()['NamedInt'] = NamedInt
1287 globals()['NEI'] = NEI
1288 NI5 = NamedInt('test', 5)
1289 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001290 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001291 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001292 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001293 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001294
1295 def test_subclasses_with_reduce(self):
1296 class NamedInt(int):
1297 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1298 def __new__(cls, *args):
1299 _args = args
1300 name, *args = args
1301 if len(args) == 0:
1302 raise TypeError("name and value must be specified")
1303 self = int.__new__(cls, *args)
1304 self._intname = name
1305 self._args = _args
1306 return self
1307 def __reduce__(self):
1308 return self.__class__, self._args
1309 @property
1310 def __name__(self):
1311 return self._intname
1312 def __repr__(self):
1313 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001314 return "{}({!r}, {})".format(
1315 type(self).__name__,
1316 self.__name__,
1317 int.__repr__(self),
1318 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001319 def __str__(self):
1320 # str() is unchanged, even if it relies on the repr() fallback
1321 base = int
1322 base_str = base.__str__
1323 if base_str.__objclass__ is object:
1324 return base.__repr__(self)
1325 return base_str(self)
1326 # for simplicity, we only define one operator that
1327 # propagates expressions
1328 def __add__(self, other):
1329 temp = int(self) + int( other)
1330 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1331 return NamedInt(
1332 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001333 temp,
1334 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001335 else:
1336 return temp
1337
1338 class NEI(NamedInt, Enum):
1339 __qualname__ = 'NEI' # needed for pickle protocol 4
1340 x = ('the-x', 1)
1341 y = ('the-y', 2)
1342
1343
1344 self.assertIs(NEI.__new__, Enum.__new__)
1345 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1346 globals()['NamedInt'] = NamedInt
1347 globals()['NEI'] = NEI
1348 NI5 = NamedInt('test', 5)
1349 self.assertEqual(NI5, 5)
1350 test_pickle_dump_load(self.assertEqual, NI5, 5)
1351 self.assertEqual(NEI.y.value, 2)
1352 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001353 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354
1355 def test_subclasses_with_reduce_ex(self):
1356 class NamedInt(int):
1357 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1358 def __new__(cls, *args):
1359 _args = args
1360 name, *args = args
1361 if len(args) == 0:
1362 raise TypeError("name and value must be specified")
1363 self = int.__new__(cls, *args)
1364 self._intname = name
1365 self._args = _args
1366 return self
1367 def __reduce_ex__(self, proto):
1368 return self.__class__, self._args
1369 @property
1370 def __name__(self):
1371 return self._intname
1372 def __repr__(self):
1373 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001374 return "{}({!r}, {})".format(
1375 type(self).__name__,
1376 self.__name__,
1377 int.__repr__(self),
1378 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001379 def __str__(self):
1380 # str() is unchanged, even if it relies on the repr() fallback
1381 base = int
1382 base_str = base.__str__
1383 if base_str.__objclass__ is object:
1384 return base.__repr__(self)
1385 return base_str(self)
1386 # for simplicity, we only define one operator that
1387 # propagates expressions
1388 def __add__(self, other):
1389 temp = int(self) + int( other)
1390 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1391 return NamedInt(
1392 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001393 temp,
1394 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001395 else:
1396 return temp
1397
1398 class NEI(NamedInt, Enum):
1399 __qualname__ = 'NEI' # needed for pickle protocol 4
1400 x = ('the-x', 1)
1401 y = ('the-y', 2)
1402
Ethan Furmanca1b7942014-02-08 11:36:27 -08001403 self.assertIs(NEI.__new__, Enum.__new__)
1404 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1405 globals()['NamedInt'] = NamedInt
1406 globals()['NEI'] = NEI
1407 NI5 = NamedInt('test', 5)
1408 self.assertEqual(NI5, 5)
1409 test_pickle_dump_load(self.assertEqual, NI5, 5)
1410 self.assertEqual(NEI.y.value, 2)
1411 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001412 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001413
Ethan Furmandc870522014-02-18 12:37:12 -08001414 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001415 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001416 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001417 def __new__(cls, *args):
1418 _args = args
1419 name, *args = args
1420 if len(args) == 0:
1421 raise TypeError("name and value must be specified")
1422 self = int.__new__(cls, *args)
1423 self._intname = name
1424 self._args = _args
1425 return self
1426 @property
1427 def __name__(self):
1428 return self._intname
1429 def __repr__(self):
1430 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001431 return "{}({!r}, {})".format(
1432 type(self).__name__,
1433 self.__name__,
1434 int.__repr__(self),
1435 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 def __str__(self):
1437 # str() is unchanged, even if it relies on the repr() fallback
1438 base = int
1439 base_str = base.__str__
1440 if base_str.__objclass__ is object:
1441 return base.__repr__(self)
1442 return base_str(self)
1443 # for simplicity, we only define one operator that
1444 # propagates expressions
1445 def __add__(self, other):
1446 temp = int(self) + int( other)
1447 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1448 return NamedInt(
1449 '({0} + {1})'.format(self.__name__, other.__name__),
1450 temp )
1451 else:
1452 return temp
1453
1454 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001455 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 x = ('the-x', 1)
1457 y = ('the-y', 2)
1458
1459 self.assertIs(NEI.__new__, Enum.__new__)
1460 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1461 globals()['NamedInt'] = NamedInt
1462 globals()['NEI'] = NEI
1463 NI5 = NamedInt('test', 5)
1464 self.assertEqual(NI5, 5)
1465 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001466 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1467 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001468
Ethan Furmandc870522014-02-18 12:37:12 -08001469 def test_subclasses_without_direct_pickle_support_using_name(self):
1470 class NamedInt(int):
1471 __qualname__ = 'NamedInt'
1472 def __new__(cls, *args):
1473 _args = args
1474 name, *args = args
1475 if len(args) == 0:
1476 raise TypeError("name and value must be specified")
1477 self = int.__new__(cls, *args)
1478 self._intname = name
1479 self._args = _args
1480 return self
1481 @property
1482 def __name__(self):
1483 return self._intname
1484 def __repr__(self):
1485 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001486 return "{}({!r}, {})".format(
1487 type(self).__name__,
1488 self.__name__,
1489 int.__repr__(self),
1490 )
Ethan Furmandc870522014-02-18 12:37:12 -08001491 def __str__(self):
1492 # str() is unchanged, even if it relies on the repr() fallback
1493 base = int
1494 base_str = base.__str__
1495 if base_str.__objclass__ is object:
1496 return base.__repr__(self)
1497 return base_str(self)
1498 # for simplicity, we only define one operator that
1499 # propagates expressions
1500 def __add__(self, other):
1501 temp = int(self) + int( other)
1502 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1503 return NamedInt(
1504 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001505 temp,
1506 )
Ethan Furmandc870522014-02-18 12:37:12 -08001507 else:
1508 return temp
1509
1510 class NEI(NamedInt, Enum):
1511 __qualname__ = 'NEI'
1512 x = ('the-x', 1)
1513 y = ('the-y', 2)
1514 def __reduce_ex__(self, proto):
1515 return getattr, (self.__class__, self._name_)
1516
1517 self.assertIs(NEI.__new__, Enum.__new__)
1518 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1519 globals()['NamedInt'] = NamedInt
1520 globals()['NEI'] = NEI
1521 NI5 = NamedInt('test', 5)
1522 self.assertEqual(NI5, 5)
1523 self.assertEqual(NEI.y.value, 2)
1524 test_pickle_dump_load(self.assertIs, NEI.y)
1525 test_pickle_dump_load(self.assertIs, NEI)
1526
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001527 def test_tuple_subclass(self):
1528 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001529 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001530 first = (1, 'for the money')
1531 second = (2, 'for the show')
1532 third = (3, 'for the music')
1533 self.assertIs(type(SomeTuple.first), SomeTuple)
1534 self.assertIsInstance(SomeTuple.second, tuple)
1535 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1536 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001537 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001538
1539 def test_duplicate_values_give_unique_enum_items(self):
1540 class AutoNumber(Enum):
1541 first = ()
1542 second = ()
1543 third = ()
1544 def __new__(cls):
1545 value = len(cls.__members__) + 1
1546 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001547 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548 return obj
1549 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001550 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001551 self.assertEqual(
1552 list(AutoNumber),
1553 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1554 )
1555 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001556 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 self.assertIs(AutoNumber(1), AutoNumber.first)
1558
1559 def test_inherited_new_from_enhanced_enum(self):
1560 class AutoNumber(Enum):
1561 def __new__(cls):
1562 value = len(cls.__members__) + 1
1563 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001564 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001565 return obj
1566 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001567 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001568 class Color(AutoNumber):
1569 red = ()
1570 green = ()
1571 blue = ()
1572 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1573 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1574
1575 def test_inherited_new_from_mixed_enum(self):
1576 class AutoNumber(IntEnum):
1577 def __new__(cls):
1578 value = len(cls.__members__) + 1
1579 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001580 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001581 return obj
1582 class Color(AutoNumber):
1583 red = ()
1584 green = ()
1585 blue = ()
1586 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1587 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1588
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001589 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001590 class OrdinaryEnum(Enum):
1591 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001592 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1593 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001594
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001595 def test_ordered_mixin(self):
1596 class OrderedEnum(Enum):
1597 def __ge__(self, other):
1598 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001599 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001600 return NotImplemented
1601 def __gt__(self, other):
1602 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001603 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001604 return NotImplemented
1605 def __le__(self, other):
1606 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001607 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001608 return NotImplemented
1609 def __lt__(self, other):
1610 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001611 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001612 return NotImplemented
1613 class Grade(OrderedEnum):
1614 A = 5
1615 B = 4
1616 C = 3
1617 D = 2
1618 F = 1
1619 self.assertGreater(Grade.A, Grade.B)
1620 self.assertLessEqual(Grade.F, Grade.C)
1621 self.assertLess(Grade.D, Grade.A)
1622 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001623 self.assertEqual(Grade.B, Grade.B)
1624 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001625
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001626 def test_extending2(self):
1627 class Shade(Enum):
1628 def shade(self):
1629 print(self.name)
1630 class Color(Shade):
1631 red = 1
1632 green = 2
1633 blue = 3
1634 with self.assertRaises(TypeError):
1635 class MoreColor(Color):
1636 cyan = 4
1637 magenta = 5
1638 yellow = 6
1639
1640 def test_extending3(self):
1641 class Shade(Enum):
1642 def shade(self):
1643 return self.name
1644 class Color(Shade):
1645 def hex(self):
1646 return '%s hexlified!' % self.value
1647 class MoreColor(Color):
1648 cyan = 4
1649 magenta = 5
1650 yellow = 6
1651 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1652
orlnub1230fb9fad2018-09-12 20:28:53 +03001653 def test_subclass_duplicate_name(self):
1654 class Base(Enum):
1655 def test(self):
1656 pass
1657 class Test(Base):
1658 test = 1
1659 self.assertIs(type(Test.test), Test)
1660
1661 def test_subclass_duplicate_name_dynamic(self):
1662 from types import DynamicClassAttribute
1663 class Base(Enum):
1664 @DynamicClassAttribute
1665 def test(self):
1666 return 'dynamic'
1667 class Test(Base):
1668 test = 1
1669 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001670
1671 def test_no_duplicates(self):
1672 class UniqueEnum(Enum):
1673 def __init__(self, *args):
1674 cls = self.__class__
1675 if any(self.value == e.value for e in cls):
1676 a = self.name
1677 e = cls(self.value).name
1678 raise ValueError(
1679 "aliases not allowed in UniqueEnum: %r --> %r"
1680 % (a, e)
1681 )
1682 class Color(UniqueEnum):
1683 red = 1
1684 green = 2
1685 blue = 3
1686 with self.assertRaises(ValueError):
1687 class Color(UniqueEnum):
1688 red = 1
1689 green = 2
1690 blue = 3
1691 grene = 2
1692
1693 def test_init(self):
1694 class Planet(Enum):
1695 MERCURY = (3.303e+23, 2.4397e6)
1696 VENUS = (4.869e+24, 6.0518e6)
1697 EARTH = (5.976e+24, 6.37814e6)
1698 MARS = (6.421e+23, 3.3972e6)
1699 JUPITER = (1.9e+27, 7.1492e7)
1700 SATURN = (5.688e+26, 6.0268e7)
1701 URANUS = (8.686e+25, 2.5559e7)
1702 NEPTUNE = (1.024e+26, 2.4746e7)
1703 def __init__(self, mass, radius):
1704 self.mass = mass # in kilograms
1705 self.radius = radius # in meters
1706 @property
1707 def surface_gravity(self):
1708 # universal gravitational constant (m3 kg-1 s-2)
1709 G = 6.67300E-11
1710 return G * self.mass / (self.radius * self.radius)
1711 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1712 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1713
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001714 def test_ignore(self):
1715 class Period(timedelta, Enum):
1716 '''
1717 different lengths of time
1718 '''
1719 def __new__(cls, value, period):
1720 obj = timedelta.__new__(cls, value)
1721 obj._value_ = value
1722 obj.period = period
1723 return obj
1724 _ignore_ = 'Period i'
1725 Period = vars()
1726 for i in range(13):
1727 Period['month_%d' % i] = i*30, 'month'
1728 for i in range(53):
1729 Period['week_%d' % i] = i*7, 'week'
1730 for i in range(32):
1731 Period['day_%d' % i] = i, 'day'
1732 OneDay = day_1
1733 OneWeek = week_1
1734 OneMonth = month_1
1735 self.assertFalse(hasattr(Period, '_ignore_'))
1736 self.assertFalse(hasattr(Period, 'Period'))
1737 self.assertFalse(hasattr(Period, 'i'))
1738 self.assertTrue(isinstance(Period.day_1, timedelta))
1739 self.assertTrue(Period.month_1 is Period.day_30)
1740 self.assertTrue(Period.week_4 is Period.day_28)
1741
Ethan Furman2aa27322013-07-19 19:35:56 -07001742 def test_nonhash_value(self):
1743 class AutoNumberInAList(Enum):
1744 def __new__(cls):
1745 value = [len(cls.__members__) + 1]
1746 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001747 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001748 return obj
1749 class ColorInAList(AutoNumberInAList):
1750 red = ()
1751 green = ()
1752 blue = ()
1753 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001754 for enum, value in zip(ColorInAList, range(3)):
1755 value += 1
1756 self.assertEqual(enum.value, [value])
1757 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001758
Ethan Furmanb41803e2013-07-25 13:50:45 -07001759 def test_conflicting_types_resolved_in_new(self):
1760 class LabelledIntEnum(int, Enum):
1761 def __new__(cls, *args):
1762 value, label = args
1763 obj = int.__new__(cls, value)
1764 obj.label = label
1765 obj._value_ = value
1766 return obj
1767
1768 class LabelledList(LabelledIntEnum):
1769 unprocessed = (1, "Unprocessed")
1770 payment_complete = (2, "Payment Complete")
1771
1772 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1773 self.assertEqual(LabelledList.unprocessed, 1)
1774 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001775
Ethan Furmanc16595e2016-09-10 23:36:59 -07001776 def test_auto_number(self):
1777 class Color(Enum):
1778 red = auto()
1779 blue = auto()
1780 green = auto()
1781
1782 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1783 self.assertEqual(Color.red.value, 1)
1784 self.assertEqual(Color.blue.value, 2)
1785 self.assertEqual(Color.green.value, 3)
1786
1787 def test_auto_name(self):
1788 class Color(Enum):
1789 def _generate_next_value_(name, start, count, last):
1790 return name
1791 red = auto()
1792 blue = auto()
1793 green = auto()
1794
1795 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1796 self.assertEqual(Color.red.value, 'red')
1797 self.assertEqual(Color.blue.value, 'blue')
1798 self.assertEqual(Color.green.value, 'green')
1799
1800 def test_auto_name_inherit(self):
1801 class AutoNameEnum(Enum):
1802 def _generate_next_value_(name, start, count, last):
1803 return name
1804 class Color(AutoNameEnum):
1805 red = auto()
1806 blue = auto()
1807 green = auto()
1808
1809 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1810 self.assertEqual(Color.red.value, 'red')
1811 self.assertEqual(Color.blue.value, 'blue')
1812 self.assertEqual(Color.green.value, 'green')
1813
1814 def test_auto_garbage(self):
1815 class Color(Enum):
1816 red = 'red'
1817 blue = auto()
1818 self.assertEqual(Color.blue.value, 1)
1819
1820 def test_auto_garbage_corrected(self):
1821 class Color(Enum):
1822 red = 'red'
1823 blue = 2
1824 green = auto()
1825
1826 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1827 self.assertEqual(Color.red.value, 'red')
1828 self.assertEqual(Color.blue.value, 2)
1829 self.assertEqual(Color.green.value, 3)
1830
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001831 def test_auto_order(self):
1832 with self.assertRaises(TypeError):
1833 class Color(Enum):
1834 red = auto()
1835 green = auto()
1836 blue = auto()
1837 def _generate_next_value_(name, start, count, last):
1838 return name
1839
Ethan Furmanfc23a942020-09-16 12:37:54 -07001840 def test_auto_order_wierd(self):
1841 weird_auto = auto()
1842 weird_auto.value = 'pathological case'
1843 class Color(Enum):
1844 red = weird_auto
1845 def _generate_next_value_(name, start, count, last):
1846 return name
1847 blue = auto()
1848 self.assertEqual(list(Color), [Color.red, Color.blue])
1849 self.assertEqual(Color.red.value, 'pathological case')
1850 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001851
Ethan Furman3515dcc2016-09-18 13:15:41 -07001852 def test_duplicate_auto(self):
1853 class Dupes(Enum):
1854 first = primero = auto()
1855 second = auto()
1856 third = auto()
1857 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1858
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001859 def test_default_missing(self):
1860 class Color(Enum):
1861 RED = 1
1862 GREEN = 2
1863 BLUE = 3
1864 try:
1865 Color(7)
1866 except ValueError as exc:
1867 self.assertTrue(exc.__context__ is None)
1868 else:
1869 raise Exception('Exception not raised.')
1870
Ethan Furman019f0a02018-09-12 11:43:34 -07001871 def test_missing(self):
1872 class Color(Enum):
1873 red = 1
1874 green = 2
1875 blue = 3
1876 @classmethod
1877 def _missing_(cls, item):
1878 if item == 'three':
1879 return cls.blue
1880 elif item == 'bad return':
1881 # trigger internal error
1882 return 5
1883 elif item == 'error out':
1884 raise ZeroDivisionError
1885 else:
1886 # trigger not found
1887 return None
1888 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001889 try:
1890 Color(7)
1891 except ValueError as exc:
1892 self.assertTrue(exc.__context__ is None)
1893 else:
1894 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001895 try:
1896 Color('bad return')
1897 except TypeError as exc:
1898 self.assertTrue(isinstance(exc.__context__, ValueError))
1899 else:
1900 raise Exception('Exception not raised.')
1901 try:
1902 Color('error out')
1903 except ZeroDivisionError as exc:
1904 self.assertTrue(isinstance(exc.__context__, ValueError))
1905 else:
1906 raise Exception('Exception not raised.')
1907
Ethan Furman5bdab642018-09-21 19:03:09 -07001908 def test_multiple_mixin(self):
1909 class MaxMixin:
1910 @classproperty
1911 def MAX(cls):
1912 max = len(cls)
1913 cls.MAX = max
1914 return max
1915 class StrMixin:
1916 def __str__(self):
1917 return self._name_.lower()
1918 class SomeEnum(Enum):
1919 def behavior(self):
1920 return 'booyah'
1921 class AnotherEnum(Enum):
1922 def behavior(self):
1923 return 'nuhuh!'
1924 def social(self):
1925 return "what's up?"
1926 class Color(MaxMixin, Enum):
1927 RED = auto()
1928 GREEN = auto()
1929 BLUE = auto()
1930 self.assertEqual(Color.RED.value, 1)
1931 self.assertEqual(Color.GREEN.value, 2)
1932 self.assertEqual(Color.BLUE.value, 3)
1933 self.assertEqual(Color.MAX, 3)
1934 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1935 class Color(MaxMixin, StrMixin, Enum):
1936 RED = auto()
1937 GREEN = auto()
1938 BLUE = auto()
1939 self.assertEqual(Color.RED.value, 1)
1940 self.assertEqual(Color.GREEN.value, 2)
1941 self.assertEqual(Color.BLUE.value, 3)
1942 self.assertEqual(Color.MAX, 3)
1943 self.assertEqual(str(Color.BLUE), 'blue')
1944 class Color(StrMixin, MaxMixin, Enum):
1945 RED = auto()
1946 GREEN = auto()
1947 BLUE = auto()
1948 self.assertEqual(Color.RED.value, 1)
1949 self.assertEqual(Color.GREEN.value, 2)
1950 self.assertEqual(Color.BLUE.value, 3)
1951 self.assertEqual(Color.MAX, 3)
1952 self.assertEqual(str(Color.BLUE), 'blue')
1953 class CoolColor(StrMixin, SomeEnum, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(CoolColor.RED.value, 1)
1958 self.assertEqual(CoolColor.GREEN.value, 2)
1959 self.assertEqual(CoolColor.BLUE.value, 3)
1960 self.assertEqual(str(CoolColor.BLUE), 'blue')
1961 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1962 class CoolerColor(StrMixin, AnotherEnum, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(CoolerColor.RED.value, 1)
1967 self.assertEqual(CoolerColor.GREEN.value, 2)
1968 self.assertEqual(CoolerColor.BLUE.value, 3)
1969 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1970 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1971 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1972 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1973 RED = auto()
1974 GREEN = auto()
1975 BLUE = auto()
1976 self.assertEqual(CoolestColor.RED.value, 1)
1977 self.assertEqual(CoolestColor.GREEN.value, 2)
1978 self.assertEqual(CoolestColor.BLUE.value, 3)
1979 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1980 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1981 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1982 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1983 RED = auto()
1984 GREEN = auto()
1985 BLUE = auto()
1986 self.assertEqual(ConfusedColor.RED.value, 1)
1987 self.assertEqual(ConfusedColor.GREEN.value, 2)
1988 self.assertEqual(ConfusedColor.BLUE.value, 3)
1989 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1990 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1991 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1992 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1993 RED = auto()
1994 GREEN = auto()
1995 BLUE = auto()
1996 self.assertEqual(ReformedColor.RED.value, 1)
1997 self.assertEqual(ReformedColor.GREEN.value, 2)
1998 self.assertEqual(ReformedColor.BLUE.value, 3)
1999 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2000 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2001 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2002 self.assertTrue(issubclass(ReformedColor, int))
2003
Ethan Furmancd453852018-10-05 23:29:36 -07002004 def test_multiple_inherited_mixin(self):
2005 class StrEnum(str, Enum):
2006 def __new__(cls, *args, **kwargs):
2007 for a in args:
2008 if not isinstance(a, str):
2009 raise TypeError("Enumeration '%s' (%s) is not"
2010 " a string" % (a, type(a).__name__))
2011 return str.__new__(cls, *args, **kwargs)
2012 @unique
2013 class Decision1(StrEnum):
2014 REVERT = "REVERT"
2015 REVERT_ALL = "REVERT_ALL"
2016 RETRY = "RETRY"
2017 class MyEnum(StrEnum):
2018 pass
2019 @unique
2020 class Decision2(MyEnum):
2021 REVERT = "REVERT"
2022 REVERT_ALL = "REVERT_ALL"
2023 RETRY = "RETRY"
2024
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002025 def test_empty_globals(self):
2026 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2027 # when using compile and exec because f_globals is empty
2028 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2029 code = compile(code, "<string>", "exec")
2030 global_ns = {}
2031 local_ls = {}
2032 exec(code, global_ns, local_ls)
2033
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002034
Ethan Furmane8e61272016-08-20 07:19:31 -07002035class TestOrder(unittest.TestCase):
2036
2037 def test_same_members(self):
2038 class Color(Enum):
2039 _order_ = 'red green blue'
2040 red = 1
2041 green = 2
2042 blue = 3
2043
2044 def test_same_members_with_aliases(self):
2045 class Color(Enum):
2046 _order_ = 'red green blue'
2047 red = 1
2048 green = 2
2049 blue = 3
2050 verde = green
2051
2052 def test_same_members_wrong_order(self):
2053 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2054 class Color(Enum):
2055 _order_ = 'red green blue'
2056 red = 1
2057 blue = 3
2058 green = 2
2059
2060 def test_order_has_extra_members(self):
2061 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2062 class Color(Enum):
2063 _order_ = 'red green blue purple'
2064 red = 1
2065 green = 2
2066 blue = 3
2067
2068 def test_order_has_extra_members_with_aliases(self):
2069 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2070 class Color(Enum):
2071 _order_ = 'red green blue purple'
2072 red = 1
2073 green = 2
2074 blue = 3
2075 verde = green
2076
2077 def test_enum_has_extra_members(self):
2078 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2079 class Color(Enum):
2080 _order_ = 'red green blue'
2081 red = 1
2082 green = 2
2083 blue = 3
2084 purple = 4
2085
2086 def test_enum_has_extra_members_with_aliases(self):
2087 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2088 class Color(Enum):
2089 _order_ = 'red green blue'
2090 red = 1
2091 green = 2
2092 blue = 3
2093 purple = 4
2094 verde = green
2095
2096
Ethan Furman65a5a472016-09-01 23:55:19 -07002097class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002098 """Tests of the Flags."""
2099
Ethan Furman65a5a472016-09-01 23:55:19 -07002100 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002101 R, W, X = 4, 2, 1
2102
Ethan Furman65a5a472016-09-01 23:55:19 -07002103 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002104 RO = 0
2105 WO = 1
2106 RW = 2
2107 AC = 3
2108 CE = 1<<19
2109
Rahul Jha94306522018-09-10 23:51:04 +05302110 class Color(Flag):
2111 BLACK = 0
2112 RED = 1
2113 GREEN = 2
2114 BLUE = 4
2115 PURPLE = RED|BLUE
2116
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002117 def test_str(self):
2118 Perm = self.Perm
2119 self.assertEqual(str(Perm.R), 'Perm.R')
2120 self.assertEqual(str(Perm.W), 'Perm.W')
2121 self.assertEqual(str(Perm.X), 'Perm.X')
2122 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2123 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2124 self.assertEqual(str(Perm(0)), 'Perm.0')
2125 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2126 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2127 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2128 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2129 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2130 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2131
2132 Open = self.Open
2133 self.assertEqual(str(Open.RO), 'Open.RO')
2134 self.assertEqual(str(Open.WO), 'Open.WO')
2135 self.assertEqual(str(Open.AC), 'Open.AC')
2136 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2137 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002138 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002139 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2140 self.assertEqual(str(~Open.AC), 'Open.CE')
2141 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2142 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2143
2144 def test_repr(self):
2145 Perm = self.Perm
2146 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2147 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2148 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2149 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2150 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002151 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002152 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2153 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2154 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2155 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002156 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002157 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2158
2159 Open = self.Open
2160 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2161 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2162 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2163 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2164 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002165 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002166 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2167 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2168 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2169 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2170
2171 def test_or(self):
2172 Perm = self.Perm
2173 for i in Perm:
2174 for j in Perm:
2175 self.assertEqual((i | j), Perm(i.value | j.value))
2176 self.assertEqual((i | j).value, i.value | j.value)
2177 self.assertIs(type(i | j), Perm)
2178 for i in Perm:
2179 self.assertIs(i | i, i)
2180 Open = self.Open
2181 self.assertIs(Open.RO | Open.CE, Open.CE)
2182
2183 def test_and(self):
2184 Perm = self.Perm
2185 RW = Perm.R | Perm.W
2186 RX = Perm.R | Perm.X
2187 WX = Perm.W | Perm.X
2188 RWX = Perm.R | Perm.W | Perm.X
2189 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2190 for i in values:
2191 for j in values:
2192 self.assertEqual((i & j).value, i.value & j.value)
2193 self.assertIs(type(i & j), Perm)
2194 for i in Perm:
2195 self.assertIs(i & i, i)
2196 self.assertIs(i & RWX, i)
2197 self.assertIs(RWX & i, i)
2198 Open = self.Open
2199 self.assertIs(Open.RO & Open.CE, Open.RO)
2200
2201 def test_xor(self):
2202 Perm = self.Perm
2203 for i in Perm:
2204 for j in Perm:
2205 self.assertEqual((i ^ j).value, i.value ^ j.value)
2206 self.assertIs(type(i ^ j), Perm)
2207 for i in Perm:
2208 self.assertIs(i ^ Perm(0), i)
2209 self.assertIs(Perm(0) ^ i, i)
2210 Open = self.Open
2211 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2212 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2213
2214 def test_invert(self):
2215 Perm = self.Perm
2216 RW = Perm.R | Perm.W
2217 RX = Perm.R | Perm.X
2218 WX = Perm.W | Perm.X
2219 RWX = Perm.R | Perm.W | Perm.X
2220 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2221 for i in values:
2222 self.assertIs(type(~i), Perm)
2223 self.assertEqual(~~i, i)
2224 for i in Perm:
2225 self.assertIs(~~i, i)
2226 Open = self.Open
2227 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2228 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2229
Ethan Furman25d94bb2016-09-02 16:32:32 -07002230 def test_bool(self):
2231 Perm = self.Perm
2232 for f in Perm:
2233 self.assertTrue(f)
2234 Open = self.Open
2235 for f in Open:
2236 self.assertEqual(bool(f.value), bool(f))
2237
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002238 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002239 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002240 lst = list(Perm)
2241 self.assertEqual(len(lst), len(Perm))
2242 self.assertEqual(len(Perm), 3, Perm)
2243 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2244 for i, n in enumerate('R W X'.split()):
2245 v = 1<<i
2246 e = Perm(v)
2247 self.assertEqual(e.value, v)
2248 self.assertEqual(type(e.value), int)
2249 self.assertEqual(e.name, n)
2250 self.assertIn(e, Perm)
2251 self.assertIs(type(e), Perm)
2252
2253 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002254 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002255 lst = list(Perm)
2256 self.assertEqual(len(lst), len(Perm))
2257 self.assertEqual(len(Perm), 3, Perm)
2258 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2259 for i, n in enumerate('R W X'.split()):
2260 v = 8<<i
2261 e = Perm(v)
2262 self.assertEqual(e.value, v)
2263 self.assertEqual(type(e.value), int)
2264 self.assertEqual(e.name, n)
2265 self.assertIn(e, Perm)
2266 self.assertIs(type(e), Perm)
2267
2268 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002269 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002270 lst = list(Perm)
2271 self.assertEqual(len(lst), len(Perm))
2272 self.assertEqual(len(Perm), 3, Perm)
2273 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2274 for i, n in enumerate('R W X'.split()):
2275 v = 1<<i
2276 e = Perm(v)
2277 self.assertEqual(e.value, v)
2278 self.assertEqual(type(e.value), int)
2279 self.assertEqual(e.name, n)
2280 self.assertIn(e, Perm)
2281 self.assertIs(type(e), Perm)
2282
2283 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002284 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002285 lst = list(Perm)
2286 self.assertEqual(len(lst), len(Perm))
2287 self.assertEqual(len(Perm), 3, Perm)
2288 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2289 for i, n in enumerate('R W X'.split()):
2290 v = 1<<(2*i+1)
2291 e = Perm(v)
2292 self.assertEqual(e.value, v)
2293 self.assertEqual(type(e.value), int)
2294 self.assertEqual(e.name, n)
2295 self.assertIn(e, Perm)
2296 self.assertIs(type(e), Perm)
2297
2298 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002299 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002300 lst = list(Perm)
2301 self.assertEqual(len(lst), len(Perm))
2302 self.assertEqual(len(Perm), 3, Perm)
2303 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2304 for i, n in enumerate('R W X'.split()):
2305 v = 1<<(2*i+1)
2306 e = Perm(v)
2307 self.assertEqual(e.value, v)
2308 self.assertEqual(type(e.value), int)
2309 self.assertEqual(e.name, n)
2310 self.assertIn(e, Perm)
2311 self.assertIs(type(e), Perm)
2312
Ethan Furman65a5a472016-09-01 23:55:19 -07002313 def test_pickle(self):
2314 if isinstance(FlagStooges, Exception):
2315 raise FlagStooges
2316 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2317 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002318
Rahul Jha94306522018-09-10 23:51:04 +05302319 def test_contains(self):
2320 Open = self.Open
2321 Color = self.Color
2322 self.assertFalse(Color.BLACK in Open)
2323 self.assertFalse(Open.RO in Color)
2324 with self.assertRaises(TypeError):
2325 'BLACK' in Color
2326 with self.assertRaises(TypeError):
2327 'RO' in Open
2328 with self.assertRaises(TypeError):
2329 1 in Color
2330 with self.assertRaises(TypeError):
2331 1 in Open
2332
2333 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002334 Perm = self.Perm
2335 R, W, X = Perm
2336 RW = R | W
2337 RX = R | X
2338 WX = W | X
2339 RWX = R | W | X
2340 self.assertTrue(R in RW)
2341 self.assertTrue(R in RX)
2342 self.assertTrue(R in RWX)
2343 self.assertTrue(W in RW)
2344 self.assertTrue(W in WX)
2345 self.assertTrue(W in RWX)
2346 self.assertTrue(X in RX)
2347 self.assertTrue(X in WX)
2348 self.assertTrue(X in RWX)
2349 self.assertFalse(R in WX)
2350 self.assertFalse(W in RX)
2351 self.assertFalse(X in RW)
2352
Ethan Furmanc16595e2016-09-10 23:36:59 -07002353 def test_auto_number(self):
2354 class Color(Flag):
2355 red = auto()
2356 blue = auto()
2357 green = auto()
2358
2359 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2360 self.assertEqual(Color.red.value, 1)
2361 self.assertEqual(Color.blue.value, 2)
2362 self.assertEqual(Color.green.value, 4)
2363
2364 def test_auto_number_garbage(self):
2365 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2366 class Color(Flag):
2367 red = 'not an int'
2368 blue = auto()
2369
Ethan Furman3515dcc2016-09-18 13:15:41 -07002370 def test_cascading_failure(self):
2371 class Bizarre(Flag):
2372 c = 3
2373 d = 4
2374 f = 6
2375 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002376 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2377 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2378 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2379 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2380 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2381 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2382 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002383
2384 def test_duplicate_auto(self):
2385 class Dupes(Enum):
2386 first = primero = auto()
2387 second = auto()
2388 third = auto()
2389 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2390
2391 def test_bizarre(self):
2392 class Bizarre(Flag):
2393 b = 3
2394 c = 4
2395 d = 6
2396 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2397
Ethan Furman5bdab642018-09-21 19:03:09 -07002398 def test_multiple_mixin(self):
2399 class AllMixin:
2400 @classproperty
2401 def ALL(cls):
2402 members = list(cls)
2403 all_value = None
2404 if members:
2405 all_value = members[0]
2406 for member in members[1:]:
2407 all_value |= member
2408 cls.ALL = all_value
2409 return all_value
2410 class StrMixin:
2411 def __str__(self):
2412 return self._name_.lower()
2413 class Color(AllMixin, Flag):
2414 RED = auto()
2415 GREEN = auto()
2416 BLUE = auto()
2417 self.assertEqual(Color.RED.value, 1)
2418 self.assertEqual(Color.GREEN.value, 2)
2419 self.assertEqual(Color.BLUE.value, 4)
2420 self.assertEqual(Color.ALL.value, 7)
2421 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2422 class Color(AllMixin, StrMixin, Flag):
2423 RED = auto()
2424 GREEN = auto()
2425 BLUE = auto()
2426 self.assertEqual(Color.RED.value, 1)
2427 self.assertEqual(Color.GREEN.value, 2)
2428 self.assertEqual(Color.BLUE.value, 4)
2429 self.assertEqual(Color.ALL.value, 7)
2430 self.assertEqual(str(Color.BLUE), 'blue')
2431 class Color(StrMixin, AllMixin, Flag):
2432 RED = auto()
2433 GREEN = auto()
2434 BLUE = auto()
2435 self.assertEqual(Color.RED.value, 1)
2436 self.assertEqual(Color.GREEN.value, 2)
2437 self.assertEqual(Color.BLUE.value, 4)
2438 self.assertEqual(Color.ALL.value, 7)
2439 self.assertEqual(str(Color.BLUE), 'blue')
2440
Hai Shie80697d2020-05-28 06:10:27 +08002441 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002442 def test_unique_composite(self):
2443 # override __eq__ to be identity only
2444 class TestFlag(Flag):
2445 one = auto()
2446 two = auto()
2447 three = auto()
2448 four = auto()
2449 five = auto()
2450 six = auto()
2451 seven = auto()
2452 eight = auto()
2453 def __eq__(self, other):
2454 return self is other
2455 def __hash__(self):
2456 return hash(self._value_)
2457 # have multiple threads competing to complete the composite members
2458 seen = set()
2459 failed = False
2460 def cycle_enum():
2461 nonlocal failed
2462 try:
2463 for i in range(256):
2464 seen.add(TestFlag(i))
2465 except Exception:
2466 failed = True
2467 threads = [
2468 threading.Thread(target=cycle_enum)
2469 for _ in range(8)
2470 ]
Hai Shie80697d2020-05-28 06:10:27 +08002471 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002472 pass
2473 # check that only 248 members were created
2474 self.assertFalse(
2475 failed,
2476 'at least one thread failed while creating composite members')
2477 self.assertEqual(256, len(seen), 'too many composite members created')
2478
Ethan Furmanc16595e2016-09-10 23:36:59 -07002479
Ethan Furman65a5a472016-09-01 23:55:19 -07002480class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002481 """Tests of the IntFlags."""
2482
Ethan Furman65a5a472016-09-01 23:55:19 -07002483 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002484 X = 1 << 0
2485 W = 1 << 1
2486 R = 1 << 2
2487
Ethan Furman65a5a472016-09-01 23:55:19 -07002488 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002489 RO = 0
2490 WO = 1
2491 RW = 2
2492 AC = 3
2493 CE = 1<<19
2494
Rahul Jha94306522018-09-10 23:51:04 +05302495 class Color(IntFlag):
2496 BLACK = 0
2497 RED = 1
2498 GREEN = 2
2499 BLUE = 4
2500 PURPLE = RED|BLUE
2501
Ethan Furman3515dcc2016-09-18 13:15:41 -07002502 def test_type(self):
2503 Perm = self.Perm
2504 Open = self.Open
2505 for f in Perm:
2506 self.assertTrue(isinstance(f, Perm))
2507 self.assertEqual(f, f.value)
2508 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2509 self.assertEqual(Perm.W | Perm.X, 3)
2510 for f in Open:
2511 self.assertTrue(isinstance(f, Open))
2512 self.assertEqual(f, f.value)
2513 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2514 self.assertEqual(Open.WO | Open.RW, 3)
2515
2516
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002517 def test_str(self):
2518 Perm = self.Perm
2519 self.assertEqual(str(Perm.R), 'Perm.R')
2520 self.assertEqual(str(Perm.W), 'Perm.W')
2521 self.assertEqual(str(Perm.X), 'Perm.X')
2522 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2523 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2524 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2525 self.assertEqual(str(Perm(0)), 'Perm.0')
2526 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002527 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2528 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2529 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2530 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002531 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002532 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2533 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2534 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002535
2536 Open = self.Open
2537 self.assertEqual(str(Open.RO), 'Open.RO')
2538 self.assertEqual(str(Open.WO), 'Open.WO')
2539 self.assertEqual(str(Open.AC), 'Open.AC')
2540 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2541 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2542 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002543 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2544 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2545 self.assertEqual(str(~Open.AC), 'Open.CE')
2546 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2547 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2548 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002549
2550 def test_repr(self):
2551 Perm = self.Perm
2552 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2553 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2554 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2555 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2556 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2557 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002558 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2559 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002560 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2561 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2562 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2563 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002564 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002565 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2566 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2567 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002568
2569 Open = self.Open
2570 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2571 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2572 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2573 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2574 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002575 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002576 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2577 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2578 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2579 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2580 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2581 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002582
2583 def test_or(self):
2584 Perm = self.Perm
2585 for i in Perm:
2586 for j in Perm:
2587 self.assertEqual(i | j, i.value | j.value)
2588 self.assertEqual((i | j).value, i.value | j.value)
2589 self.assertIs(type(i | j), Perm)
2590 for j in range(8):
2591 self.assertEqual(i | j, i.value | j)
2592 self.assertEqual((i | j).value, i.value | j)
2593 self.assertIs(type(i | j), Perm)
2594 self.assertEqual(j | i, j | i.value)
2595 self.assertEqual((j | i).value, j | i.value)
2596 self.assertIs(type(j | i), Perm)
2597 for i in Perm:
2598 self.assertIs(i | i, i)
2599 self.assertIs(i | 0, i)
2600 self.assertIs(0 | i, i)
2601 Open = self.Open
2602 self.assertIs(Open.RO | Open.CE, Open.CE)
2603
2604 def test_and(self):
2605 Perm = self.Perm
2606 RW = Perm.R | Perm.W
2607 RX = Perm.R | Perm.X
2608 WX = Perm.W | Perm.X
2609 RWX = Perm.R | Perm.W | Perm.X
2610 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2611 for i in values:
2612 for j in values:
2613 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2614 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2615 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2616 for j in range(8):
2617 self.assertEqual(i & j, i.value & j)
2618 self.assertEqual((i & j).value, i.value & j)
2619 self.assertIs(type(i & j), Perm)
2620 self.assertEqual(j & i, j & i.value)
2621 self.assertEqual((j & i).value, j & i.value)
2622 self.assertIs(type(j & i), Perm)
2623 for i in Perm:
2624 self.assertIs(i & i, i)
2625 self.assertIs(i & 7, i)
2626 self.assertIs(7 & i, i)
2627 Open = self.Open
2628 self.assertIs(Open.RO & Open.CE, Open.RO)
2629
2630 def test_xor(self):
2631 Perm = self.Perm
2632 for i in Perm:
2633 for j in Perm:
2634 self.assertEqual(i ^ j, i.value ^ j.value)
2635 self.assertEqual((i ^ j).value, i.value ^ j.value)
2636 self.assertIs(type(i ^ j), Perm)
2637 for j in range(8):
2638 self.assertEqual(i ^ j, i.value ^ j)
2639 self.assertEqual((i ^ j).value, i.value ^ j)
2640 self.assertIs(type(i ^ j), Perm)
2641 self.assertEqual(j ^ i, j ^ i.value)
2642 self.assertEqual((j ^ i).value, j ^ i.value)
2643 self.assertIs(type(j ^ i), Perm)
2644 for i in Perm:
2645 self.assertIs(i ^ 0, i)
2646 self.assertIs(0 ^ i, i)
2647 Open = self.Open
2648 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2649 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2650
2651 def test_invert(self):
2652 Perm = self.Perm
2653 RW = Perm.R | Perm.W
2654 RX = Perm.R | Perm.X
2655 WX = Perm.W | Perm.X
2656 RWX = Perm.R | Perm.W | Perm.X
2657 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2658 for i in values:
2659 self.assertEqual(~i, ~i.value)
2660 self.assertEqual((~i).value, ~i.value)
2661 self.assertIs(type(~i), Perm)
2662 self.assertEqual(~~i, i)
2663 for i in Perm:
2664 self.assertIs(~~i, i)
2665 Open = self.Open
2666 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2667 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2668
2669 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002670 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002671 lst = list(Perm)
2672 self.assertEqual(len(lst), len(Perm))
2673 self.assertEqual(len(Perm), 3, Perm)
2674 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2675 for i, n in enumerate('R W X'.split()):
2676 v = 1<<i
2677 e = Perm(v)
2678 self.assertEqual(e.value, v)
2679 self.assertEqual(type(e.value), int)
2680 self.assertEqual(e, v)
2681 self.assertEqual(e.name, n)
2682 self.assertIn(e, Perm)
2683 self.assertIs(type(e), Perm)
2684
2685 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002686 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002687 lst = list(Perm)
2688 self.assertEqual(len(lst), len(Perm))
2689 self.assertEqual(len(Perm), 3, Perm)
2690 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2691 for i, n in enumerate('R W X'.split()):
2692 v = 8<<i
2693 e = Perm(v)
2694 self.assertEqual(e.value, v)
2695 self.assertEqual(type(e.value), int)
2696 self.assertEqual(e, v)
2697 self.assertEqual(e.name, n)
2698 self.assertIn(e, Perm)
2699 self.assertIs(type(e), Perm)
2700
2701 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002702 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002703 lst = list(Perm)
2704 self.assertEqual(len(lst), len(Perm))
2705 self.assertEqual(len(Perm), 3, Perm)
2706 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2707 for i, n in enumerate('R W X'.split()):
2708 v = 1<<i
2709 e = Perm(v)
2710 self.assertEqual(e.value, v)
2711 self.assertEqual(type(e.value), int)
2712 self.assertEqual(e, v)
2713 self.assertEqual(e.name, n)
2714 self.assertIn(e, Perm)
2715 self.assertIs(type(e), Perm)
2716
2717 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002718 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002719 lst = list(Perm)
2720 self.assertEqual(len(lst), len(Perm))
2721 self.assertEqual(len(Perm), 3, Perm)
2722 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2723 for i, n in enumerate('R W X'.split()):
2724 v = 1<<(2*i+1)
2725 e = Perm(v)
2726 self.assertEqual(e.value, v)
2727 self.assertEqual(type(e.value), int)
2728 self.assertEqual(e, v)
2729 self.assertEqual(e.name, n)
2730 self.assertIn(e, Perm)
2731 self.assertIs(type(e), Perm)
2732
2733 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002734 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002735 lst = list(Perm)
2736 self.assertEqual(len(lst), len(Perm))
2737 self.assertEqual(len(Perm), 3, Perm)
2738 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2739 for i, n in enumerate('R W X'.split()):
2740 v = 1<<(2*i+1)
2741 e = Perm(v)
2742 self.assertEqual(e.value, v)
2743 self.assertEqual(type(e.value), int)
2744 self.assertEqual(e, v)
2745 self.assertEqual(e.name, n)
2746 self.assertIn(e, Perm)
2747 self.assertIs(type(e), Perm)
2748
2749
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002750 def test_programatic_function_from_empty_list(self):
2751 Perm = enum.IntFlag('Perm', [])
2752 lst = list(Perm)
2753 self.assertEqual(len(lst), len(Perm))
2754 self.assertEqual(len(Perm), 0, Perm)
2755 Thing = enum.Enum('Thing', [])
2756 lst = list(Thing)
2757 self.assertEqual(len(lst), len(Thing))
2758 self.assertEqual(len(Thing), 0, Thing)
2759
2760
2761 def test_programatic_function_from_empty_tuple(self):
2762 Perm = enum.IntFlag('Perm', ())
2763 lst = list(Perm)
2764 self.assertEqual(len(lst), len(Perm))
2765 self.assertEqual(len(Perm), 0, Perm)
2766 Thing = enum.Enum('Thing', ())
2767 self.assertEqual(len(lst), len(Thing))
2768 self.assertEqual(len(Thing), 0, Thing)
2769
Rahul Jha94306522018-09-10 23:51:04 +05302770 def test_contains(self):
2771 Open = self.Open
2772 Color = self.Color
2773 self.assertTrue(Color.GREEN in Color)
2774 self.assertTrue(Open.RW in Open)
2775 self.assertFalse(Color.GREEN in Open)
2776 self.assertFalse(Open.RW in Color)
2777 with self.assertRaises(TypeError):
2778 'GREEN' in Color
2779 with self.assertRaises(TypeError):
2780 'RW' in Open
2781 with self.assertRaises(TypeError):
2782 2 in Color
2783 with self.assertRaises(TypeError):
2784 2 in Open
2785
2786 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002787 Perm = self.Perm
2788 R, W, X = Perm
2789 RW = R | W
2790 RX = R | X
2791 WX = W | X
2792 RWX = R | W | X
2793 self.assertTrue(R in RW)
2794 self.assertTrue(R in RX)
2795 self.assertTrue(R in RWX)
2796 self.assertTrue(W in RW)
2797 self.assertTrue(W in WX)
2798 self.assertTrue(W in RWX)
2799 self.assertTrue(X in RX)
2800 self.assertTrue(X in WX)
2801 self.assertTrue(X in RWX)
2802 self.assertFalse(R in WX)
2803 self.assertFalse(W in RX)
2804 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302805 with self.assertRaises(TypeError):
2806 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002807
Ethan Furman25d94bb2016-09-02 16:32:32 -07002808 def test_bool(self):
2809 Perm = self.Perm
2810 for f in Perm:
2811 self.assertTrue(f)
2812 Open = self.Open
2813 for f in Open:
2814 self.assertEqual(bool(f.value), bool(f))
2815
Ethan Furman5bdab642018-09-21 19:03:09 -07002816 def test_multiple_mixin(self):
2817 class AllMixin:
2818 @classproperty
2819 def ALL(cls):
2820 members = list(cls)
2821 all_value = None
2822 if members:
2823 all_value = members[0]
2824 for member in members[1:]:
2825 all_value |= member
2826 cls.ALL = all_value
2827 return all_value
2828 class StrMixin:
2829 def __str__(self):
2830 return self._name_.lower()
2831 class Color(AllMixin, IntFlag):
2832 RED = auto()
2833 GREEN = auto()
2834 BLUE = auto()
2835 self.assertEqual(Color.RED.value, 1)
2836 self.assertEqual(Color.GREEN.value, 2)
2837 self.assertEqual(Color.BLUE.value, 4)
2838 self.assertEqual(Color.ALL.value, 7)
2839 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2840 class Color(AllMixin, StrMixin, IntFlag):
2841 RED = auto()
2842 GREEN = auto()
2843 BLUE = auto()
2844 self.assertEqual(Color.RED.value, 1)
2845 self.assertEqual(Color.GREEN.value, 2)
2846 self.assertEqual(Color.BLUE.value, 4)
2847 self.assertEqual(Color.ALL.value, 7)
2848 self.assertEqual(str(Color.BLUE), 'blue')
2849 class Color(StrMixin, AllMixin, IntFlag):
2850 RED = auto()
2851 GREEN = auto()
2852 BLUE = auto()
2853 self.assertEqual(Color.RED.value, 1)
2854 self.assertEqual(Color.GREEN.value, 2)
2855 self.assertEqual(Color.BLUE.value, 4)
2856 self.assertEqual(Color.ALL.value, 7)
2857 self.assertEqual(str(Color.BLUE), 'blue')
2858
Hai Shie80697d2020-05-28 06:10:27 +08002859 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002860 def test_unique_composite(self):
2861 # override __eq__ to be identity only
2862 class TestFlag(IntFlag):
2863 one = auto()
2864 two = auto()
2865 three = auto()
2866 four = auto()
2867 five = auto()
2868 six = auto()
2869 seven = auto()
2870 eight = auto()
2871 def __eq__(self, other):
2872 return self is other
2873 def __hash__(self):
2874 return hash(self._value_)
2875 # have multiple threads competing to complete the composite members
2876 seen = set()
2877 failed = False
2878 def cycle_enum():
2879 nonlocal failed
2880 try:
2881 for i in range(256):
2882 seen.add(TestFlag(i))
2883 except Exception:
2884 failed = True
2885 threads = [
2886 threading.Thread(target=cycle_enum)
2887 for _ in range(8)
2888 ]
Hai Shie80697d2020-05-28 06:10:27 +08002889 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002890 pass
2891 # check that only 248 members were created
2892 self.assertFalse(
2893 failed,
2894 'at least one thread failed while creating composite members')
2895 self.assertEqual(256, len(seen), 'too many composite members created')
2896
2897
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002898class TestEmptyAndNonLatinStrings(unittest.TestCase):
2899
2900 def test_empty_string(self):
2901 with self.assertRaises(ValueError):
2902 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2903
2904 def test_non_latin_character_string(self):
2905 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2906 item = getattr(greek_abc, '\u03B1')
2907 self.assertEqual(item.value, 1)
2908
2909 def test_non_latin_number_string(self):
2910 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2911 item = getattr(hebrew_123, '\u05D0')
2912 self.assertEqual(item.value, 1)
2913
2914
Ethan Furmanf24bb352013-07-18 17:05:39 -07002915class TestUnique(unittest.TestCase):
2916
2917 def test_unique_clean(self):
2918 @unique
2919 class Clean(Enum):
2920 one = 1
2921 two = 'dos'
2922 tres = 4.0
2923 @unique
2924 class Cleaner(IntEnum):
2925 single = 1
2926 double = 2
2927 triple = 3
2928
2929 def test_unique_dirty(self):
2930 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2931 @unique
2932 class Dirty(Enum):
2933 one = 1
2934 two = 'dos'
2935 tres = 1
2936 with self.assertRaisesRegex(
2937 ValueError,
2938 'double.*single.*turkey.*triple',
2939 ):
2940 @unique
2941 class Dirtier(IntEnum):
2942 single = 1
2943 double = 1
2944 triple = 3
2945 turkey = 3
2946
Ethan Furman3803ad42016-05-01 10:03:53 -07002947 def test_unique_with_name(self):
2948 @unique
2949 class Silly(Enum):
2950 one = 1
2951 two = 'dos'
2952 name = 3
2953 @unique
2954 class Sillier(IntEnum):
2955 single = 1
2956 name = 2
2957 triple = 3
2958 value = 4
2959
Ethan Furmanf24bb352013-07-18 17:05:39 -07002960
Ethan Furman5bdab642018-09-21 19:03:09 -07002961
Ethan Furman3323da92015-04-11 09:39:59 -07002962expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002963Help on class Color in module %s:
2964
2965class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002966 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2967 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002968 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002969 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002970 | Method resolution order:
2971 | Color
2972 | enum.Enum
2973 | builtins.object
2974 |\x20\x20
2975 | Data and other attributes defined here:
2976 |\x20\x20
2977 | blue = <Color.blue: 3>
2978 |\x20\x20
2979 | green = <Color.green: 2>
2980 |\x20\x20
2981 | red = <Color.red: 1>
2982 |\x20\x20
2983 | ----------------------------------------------------------------------
2984 | Data descriptors inherited from enum.Enum:
2985 |\x20\x20
2986 | name
2987 | The name of the Enum member.
2988 |\x20\x20
2989 | value
2990 | The value of the Enum member.
2991 |\x20\x20
2992 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002993 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002994 |\x20\x20
2995 | __members__
2996 | Returns a mapping of member name->value.
2997 |\x20\x20\x20\x20\x20\x20
2998 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002999 | is a read-only view of the internal mapping."""
3000
3001expected_help_output_without_docs = """\
3002Help on class Color in module %s:
3003
3004class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003005 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3006 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003007 | Method resolution order:
3008 | Color
3009 | enum.Enum
3010 | builtins.object
3011 |\x20\x20
3012 | Data and other attributes defined here:
3013 |\x20\x20
3014 | blue = <Color.blue: 3>
3015 |\x20\x20
3016 | green = <Color.green: 2>
3017 |\x20\x20
3018 | red = <Color.red: 1>
3019 |\x20\x20
3020 | ----------------------------------------------------------------------
3021 | Data descriptors inherited from enum.Enum:
3022 |\x20\x20
3023 | name
3024 |\x20\x20
3025 | value
3026 |\x20\x20
3027 | ----------------------------------------------------------------------
3028 | Data descriptors inherited from enum.EnumMeta:
3029 |\x20\x20
3030 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003031
3032class TestStdLib(unittest.TestCase):
3033
Ethan Furman48a724f2015-04-11 23:23:06 -07003034 maxDiff = None
3035
Ethan Furman5875d742013-10-21 20:45:55 -07003036 class Color(Enum):
3037 red = 1
3038 green = 2
3039 blue = 3
3040
3041 def test_pydoc(self):
3042 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003043 if StrEnum.__doc__ is None:
3044 expected_text = expected_help_output_without_docs % __name__
3045 else:
3046 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003047 output = StringIO()
3048 helper = pydoc.Helper(output=output)
3049 helper(self.Color)
3050 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003051 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003052
3053 def test_inspect_getmembers(self):
3054 values = dict((
3055 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003056 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003057 ('__members__', self.Color.__members__),
3058 ('__module__', __name__),
3059 ('blue', self.Color.blue),
3060 ('green', self.Color.green),
3061 ('name', Enum.__dict__['name']),
3062 ('red', self.Color.red),
3063 ('value', Enum.__dict__['value']),
3064 ))
3065 result = dict(inspect.getmembers(self.Color))
3066 self.assertEqual(values.keys(), result.keys())
3067 failed = False
3068 for k in values.keys():
3069 if result[k] != values[k]:
3070 print()
3071 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3072 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3073 failed = True
3074 if failed:
3075 self.fail("result does not equal expected, see print above")
3076
3077 def test_inspect_classify_class_attrs(self):
3078 # indirectly test __objclass__
3079 from inspect import Attribute
3080 values = [
3081 Attribute(name='__class__', kind='data',
3082 defining_class=object, object=EnumMeta),
3083 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003084 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003085 Attribute(name='__members__', kind='property',
3086 defining_class=EnumMeta, object=EnumMeta.__members__),
3087 Attribute(name='__module__', kind='data',
3088 defining_class=self.Color, object=__name__),
3089 Attribute(name='blue', kind='data',
3090 defining_class=self.Color, object=self.Color.blue),
3091 Attribute(name='green', kind='data',
3092 defining_class=self.Color, object=self.Color.green),
3093 Attribute(name='red', kind='data',
3094 defining_class=self.Color, object=self.Color.red),
3095 Attribute(name='name', kind='data',
3096 defining_class=Enum, object=Enum.__dict__['name']),
3097 Attribute(name='value', kind='data',
3098 defining_class=Enum, object=Enum.__dict__['value']),
3099 ]
3100 values.sort(key=lambda item: item.name)
3101 result = list(inspect.classify_class_attrs(self.Color))
3102 result.sort(key=lambda item: item.name)
3103 failed = False
3104 for v, r in zip(values, result):
3105 if r != v:
3106 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3107 failed = True
3108 if failed:
3109 self.fail("result does not equal expected, see print above")
3110
Martin Panter19e69c52015-11-14 12:46:42 +00003111
3112class MiscTestCase(unittest.TestCase):
3113 def test__all__(self):
3114 support.check__all__(self, enum)
3115
3116
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003117# These are unordered here on purpose to ensure that declaration order
3118# makes no difference.
3119CONVERT_TEST_NAME_D = 5
3120CONVERT_TEST_NAME_C = 5
3121CONVERT_TEST_NAME_B = 5
3122CONVERT_TEST_NAME_A = 5 # This one should sort first.
3123CONVERT_TEST_NAME_E = 5
3124CONVERT_TEST_NAME_F = 5
3125
3126class TestIntEnumConvert(unittest.TestCase):
3127 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003128 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003129 'UnittestConvert',
3130 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003131 filter=lambda x: x.startswith('CONVERT_TEST_'))
3132 # We don't want the reverse lookup value to vary when there are
3133 # multiple possible names for a given value. It should always
3134 # report the first lexigraphical name in that case.
3135 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3136
3137 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003138 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003139 'UnittestConvert',
3140 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003141 filter=lambda x: x.startswith('CONVERT_TEST_'))
3142 # Ensure that test_type has all of the desired names and values.
3143 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3144 test_type.CONVERT_TEST_NAME_A)
3145 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3146 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3147 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3148 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3149 # Ensure that test_type only picked up names matching the filter.
3150 self.assertEqual([name for name in dir(test_type)
3151 if name[0:2] not in ('CO', '__')],
3152 [], msg='Names other than CONVERT_TEST_* found.')
3153
orlnub1230fb9fad2018-09-12 20:28:53 +03003154 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3155 '_convert was deprecated in 3.8')
3156 def test_convert_warn(self):
3157 with self.assertWarns(DeprecationWarning):
3158 enum.IntEnum._convert(
3159 'UnittestConvert',
3160 ('test.test_enum', '__main__')[__name__=='__main__'],
3161 filter=lambda x: x.startswith('CONVERT_TEST_'))
3162
3163 @unittest.skipUnless(sys.version_info >= (3, 9),
3164 '_convert was removed in 3.9')
3165 def test_convert_raise(self):
3166 with self.assertRaises(AttributeError):
3167 enum.IntEnum._convert(
3168 'UnittestConvert',
3169 ('test.test_enum', '__main__')[__name__=='__main__'],
3170 filter=lambda x: x.startswith('CONVERT_TEST_'))
3171
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003172
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003173if __name__ == '__main__':
3174 unittest.main()