blob: b18f3b38a6619f68b906c9b849bbdfbb8bb820b0 [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):
423 with self.assertRaisesRegex(ValueError, '_sunder_ names, such as '
424 '"_bad_", are reserved'):
425 class Bad(Enum):
426 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700427
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700428 def test_enum_with_value_name(self):
429 class Huh(Enum):
430 name = 1
431 value = 2
432 self.assertEqual(
433 list(Huh),
434 [Huh.name, Huh.value],
435 )
436 self.assertIs(type(Huh.name), Huh)
437 self.assertEqual(Huh.name.name, 'name')
438 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700439
440 def test_format_enum(self):
441 Season = self.Season
442 self.assertEqual('{}'.format(Season.SPRING),
443 '{}'.format(str(Season.SPRING)))
444 self.assertEqual( '{:}'.format(Season.SPRING),
445 '{:}'.format(str(Season.SPRING)))
446 self.assertEqual('{:20}'.format(Season.SPRING),
447 '{:20}'.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
thatneat2f19e822019-07-04 11:28:37 -0700455 def test_str_override_enum(self):
456 class EnumWithStrOverrides(Enum):
457 one = auto()
458 two = auto()
459
460 def __str__(self):
461 return 'Str!'
462 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
463 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
464
465 def test_format_override_enum(self):
466 class EnumWithFormatOverride(Enum):
467 one = 1.0
468 two = 2.0
469 def __format__(self, spec):
470 return 'Format!!'
471 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
472 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
473
474 def test_str_and_format_override_enum(self):
475 class EnumWithStrFormatOverrides(Enum):
476 one = auto()
477 two = auto()
478 def __str__(self):
479 return 'Str!'
480 def __format__(self, spec):
481 return 'Format!'
482 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
483 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
484
485 def test_str_override_mixin(self):
486 class MixinEnumWithStrOverride(float, Enum):
487 one = 1.0
488 two = 2.0
489 def __str__(self):
490 return 'Overridden!'
491 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
492 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
493
494 def test_str_and_format_override_mixin(self):
495 class MixinWithStrFormatOverrides(float, Enum):
496 one = 1.0
497 two = 2.0
498 def __str__(self):
499 return 'Str!'
500 def __format__(self, spec):
501 return 'Format!'
502 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
503 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
504
505 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700506 class TestFloat(float, Enum):
507 one = 1.0
508 two = 2.0
509 def __format__(self, spec):
510 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700511 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700512 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
513
514 def assertFormatIsValue(self, spec, member):
515 self.assertEqual(spec.format(member), spec.format(member.value))
516
517 def test_format_enum_date(self):
518 Holiday = self.Holiday
519 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
520 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
521 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
522 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
523 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
524 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
525 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
526 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
527
528 def test_format_enum_float(self):
529 Konstants = self.Konstants
530 self.assertFormatIsValue('{}', Konstants.TAU)
531 self.assertFormatIsValue('{:}', Konstants.TAU)
532 self.assertFormatIsValue('{:20}', Konstants.TAU)
533 self.assertFormatIsValue('{:^20}', Konstants.TAU)
534 self.assertFormatIsValue('{:>20}', Konstants.TAU)
535 self.assertFormatIsValue('{:<20}', Konstants.TAU)
536 self.assertFormatIsValue('{:n}', Konstants.TAU)
537 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
538 self.assertFormatIsValue('{:f}', Konstants.TAU)
539
540 def test_format_enum_int(self):
541 Grades = self.Grades
542 self.assertFormatIsValue('{}', Grades.C)
543 self.assertFormatIsValue('{:}', Grades.C)
544 self.assertFormatIsValue('{:20}', Grades.C)
545 self.assertFormatIsValue('{:^20}', Grades.C)
546 self.assertFormatIsValue('{:>20}', Grades.C)
547 self.assertFormatIsValue('{:<20}', Grades.C)
548 self.assertFormatIsValue('{:+}', Grades.C)
549 self.assertFormatIsValue('{:08X}', Grades.C)
550 self.assertFormatIsValue('{:b}', Grades.C)
551
552 def test_format_enum_str(self):
553 Directional = self.Directional
554 self.assertFormatIsValue('{}', Directional.WEST)
555 self.assertFormatIsValue('{:}', Directional.WEST)
556 self.assertFormatIsValue('{:20}', Directional.WEST)
557 self.assertFormatIsValue('{:^20}', Directional.WEST)
558 self.assertFormatIsValue('{:>20}', Directional.WEST)
559 self.assertFormatIsValue('{:<20}', Directional.WEST)
560
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700561 def test_hash(self):
562 Season = self.Season
563 dates = {}
564 dates[Season.WINTER] = '1225'
565 dates[Season.SPRING] = '0315'
566 dates[Season.SUMMER] = '0704'
567 dates[Season.AUTUMN] = '1031'
568 self.assertEqual(dates[Season.AUTUMN], '1031')
569
570 def test_intenum_from_scratch(self):
571 class phy(int, Enum):
572 pi = 3
573 tau = 2 * pi
574 self.assertTrue(phy.pi < phy.tau)
575
576 def test_intenum_inherited(self):
577 class IntEnum(int, Enum):
578 pass
579 class phy(IntEnum):
580 pi = 3
581 tau = 2 * pi
582 self.assertTrue(phy.pi < phy.tau)
583
584 def test_floatenum_from_scratch(self):
585 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700586 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700587 tau = 2 * pi
588 self.assertTrue(phy.pi < phy.tau)
589
590 def test_floatenum_inherited(self):
591 class FloatEnum(float, Enum):
592 pass
593 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700594 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700595 tau = 2 * pi
596 self.assertTrue(phy.pi < phy.tau)
597
598 def test_strenum_from_scratch(self):
599 class phy(str, Enum):
600 pi = 'Pi'
601 tau = 'Tau'
602 self.assertTrue(phy.pi < phy.tau)
603
604 def test_strenum_inherited(self):
605 class StrEnum(str, Enum):
606 pass
607 class phy(StrEnum):
608 pi = 'Pi'
609 tau = 'Tau'
610 self.assertTrue(phy.pi < phy.tau)
611
612
613 def test_intenum(self):
614 class WeekDay(IntEnum):
615 SUNDAY = 1
616 MONDAY = 2
617 TUESDAY = 3
618 WEDNESDAY = 4
619 THURSDAY = 5
620 FRIDAY = 6
621 SATURDAY = 7
622
623 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
624 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
625
626 lst = list(WeekDay)
627 self.assertEqual(len(lst), len(WeekDay))
628 self.assertEqual(len(WeekDay), 7)
629 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
630 target = target.split()
631 for i, weekday in enumerate(target, 1):
632 e = WeekDay(i)
633 self.assertEqual(e, i)
634 self.assertEqual(int(e), i)
635 self.assertEqual(e.name, weekday)
636 self.assertIn(e, WeekDay)
637 self.assertEqual(lst.index(e)+1, i)
638 self.assertTrue(0 < e < 8)
639 self.assertIs(type(e), WeekDay)
640 self.assertIsInstance(e, int)
641 self.assertIsInstance(e, Enum)
642
643 def test_intenum_duplicates(self):
644 class WeekDay(IntEnum):
645 SUNDAY = 1
646 MONDAY = 2
647 TUESDAY = TEUSDAY = 3
648 WEDNESDAY = 4
649 THURSDAY = 5
650 FRIDAY = 6
651 SATURDAY = 7
652 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
653 self.assertEqual(WeekDay(3).name, 'TUESDAY')
654 self.assertEqual([k for k,v in WeekDay.__members__.items()
655 if v.name != k], ['TEUSDAY', ])
656
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300657 def test_intenum_from_bytes(self):
658 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
659 with self.assertRaises(ValueError):
660 IntStooges.from_bytes(b'\x00\x05', 'big')
661
662 def test_floatenum_fromhex(self):
663 h = float.hex(FloatStooges.MOE.value)
664 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
665 h = float.hex(FloatStooges.MOE.value + 0.01)
666 with self.assertRaises(ValueError):
667 FloatStooges.fromhex(h)
668
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700669 def test_pickle_enum(self):
670 if isinstance(Stooges, Exception):
671 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800672 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
673 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700674
675 def test_pickle_int(self):
676 if isinstance(IntStooges, Exception):
677 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800678 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
679 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700680
681 def test_pickle_float(self):
682 if isinstance(FloatStooges, Exception):
683 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800684 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
685 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700686
687 def test_pickle_enum_function(self):
688 if isinstance(Answer, Exception):
689 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800690 test_pickle_dump_load(self.assertIs, Answer.him)
691 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700692
693 def test_pickle_enum_function_with_module(self):
694 if isinstance(Question, Exception):
695 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800696 test_pickle_dump_load(self.assertIs, Question.who)
697 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700698
Ethan Furmanca1b7942014-02-08 11:36:27 -0800699 def test_enum_function_with_qualname(self):
700 if isinstance(Theory, Exception):
701 raise Theory
702 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
703
704 def test_class_nested_enum_and_pickle_protocol_four(self):
705 # would normally just have this directly in the class namespace
706 class NestedEnum(Enum):
707 twigs = 'common'
708 shiny = 'rare'
709
710 self.__class__.NestedEnum = NestedEnum
711 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300712 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800713
Ethan Furman24e837f2015-03-18 17:27:57 -0700714 def test_pickle_by_name(self):
715 class ReplaceGlobalInt(IntEnum):
716 ONE = 1
717 TWO = 2
718 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
719 for proto in range(HIGHEST_PROTOCOL):
720 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
721
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700722 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800723 BadPickle = Enum(
724 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700725 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800726 # now break BadPickle to test exception raising
727 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800728 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
729 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700730
731 def test_string_enum(self):
732 class SkillLevel(str, Enum):
733 master = 'what is the sound of one hand clapping?'
734 journeyman = 'why did the chicken cross the road?'
735 apprentice = 'knock, knock!'
736 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
737
738 def test_getattr_getitem(self):
739 class Period(Enum):
740 morning = 1
741 noon = 2
742 evening = 3
743 night = 4
744 self.assertIs(Period(2), Period.noon)
745 self.assertIs(getattr(Period, 'night'), Period.night)
746 self.assertIs(Period['morning'], Period.morning)
747
748 def test_getattr_dunder(self):
749 Season = self.Season
750 self.assertTrue(getattr(Season, '__eq__'))
751
752 def test_iteration_order(self):
753 class Season(Enum):
754 SUMMER = 2
755 WINTER = 4
756 AUTUMN = 3
757 SPRING = 1
758 self.assertEqual(
759 list(Season),
760 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
761 )
762
Ethan Furman2131a4a2013-09-14 18:11:24 -0700763 def test_reversed_iteration_order(self):
764 self.assertEqual(
765 list(reversed(self.Season)),
766 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
767 self.Season.SPRING]
768 )
769
Martin Pantereb995702016-07-28 01:11:04 +0000770 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700771 SummerMonth = Enum('SummerMonth', 'june july august')
772 lst = list(SummerMonth)
773 self.assertEqual(len(lst), len(SummerMonth))
774 self.assertEqual(len(SummerMonth), 3, SummerMonth)
775 self.assertEqual(
776 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
777 lst,
778 )
779 for i, month in enumerate('june july august'.split(), 1):
780 e = SummerMonth(i)
781 self.assertEqual(int(e.value), i)
782 self.assertNotEqual(e, i)
783 self.assertEqual(e.name, month)
784 self.assertIn(e, SummerMonth)
785 self.assertIs(type(e), SummerMonth)
786
Martin Pantereb995702016-07-28 01:11:04 +0000787 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700788 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
789 lst = list(SummerMonth)
790 self.assertEqual(len(lst), len(SummerMonth))
791 self.assertEqual(len(SummerMonth), 3, SummerMonth)
792 self.assertEqual(
793 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
794 lst,
795 )
796 for i, month in enumerate('june july august'.split(), 10):
797 e = SummerMonth(i)
798 self.assertEqual(int(e.value), i)
799 self.assertNotEqual(e, i)
800 self.assertEqual(e.name, month)
801 self.assertIn(e, SummerMonth)
802 self.assertIs(type(e), SummerMonth)
803
Martin Pantereb995702016-07-28 01:11:04 +0000804 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700805 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
806 lst = list(SummerMonth)
807 self.assertEqual(len(lst), len(SummerMonth))
808 self.assertEqual(len(SummerMonth), 3, SummerMonth)
809 self.assertEqual(
810 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
811 lst,
812 )
813 for i, month in enumerate('june july august'.split(), 1):
814 e = SummerMonth(i)
815 self.assertEqual(int(e.value), i)
816 self.assertNotEqual(e, i)
817 self.assertEqual(e.name, month)
818 self.assertIn(e, SummerMonth)
819 self.assertIs(type(e), SummerMonth)
820
Martin Pantereb995702016-07-28 01:11:04 +0000821 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700822 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
823 lst = list(SummerMonth)
824 self.assertEqual(len(lst), len(SummerMonth))
825 self.assertEqual(len(SummerMonth), 3, SummerMonth)
826 self.assertEqual(
827 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
828 lst,
829 )
830 for i, month in enumerate('june july august'.split(), 20):
831 e = SummerMonth(i)
832 self.assertEqual(int(e.value), i)
833 self.assertNotEqual(e, i)
834 self.assertEqual(e.name, month)
835 self.assertIn(e, SummerMonth)
836 self.assertIs(type(e), SummerMonth)
837
Martin Pantereb995702016-07-28 01:11:04 +0000838 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700839 SummerMonth = Enum(
840 'SummerMonth',
841 (('june', 1), ('july', 2), ('august', 3))
842 )
843 lst = list(SummerMonth)
844 self.assertEqual(len(lst), len(SummerMonth))
845 self.assertEqual(len(SummerMonth), 3, SummerMonth)
846 self.assertEqual(
847 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
848 lst,
849 )
850 for i, month in enumerate('june july august'.split(), 1):
851 e = SummerMonth(i)
852 self.assertEqual(int(e.value), i)
853 self.assertNotEqual(e, i)
854 self.assertEqual(e.name, month)
855 self.assertIn(e, SummerMonth)
856 self.assertIs(type(e), SummerMonth)
857
Martin Pantereb995702016-07-28 01:11:04 +0000858 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700859 SummerMonth = Enum(
860 'SummerMonth',
861 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
862 )
863 lst = list(SummerMonth)
864 self.assertEqual(len(lst), len(SummerMonth))
865 self.assertEqual(len(SummerMonth), 3, SummerMonth)
866 self.assertEqual(
867 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
868 lst,
869 )
870 for i, month in enumerate('june july august'.split(), 1):
871 e = SummerMonth(i)
872 self.assertEqual(int(e.value), i)
873 self.assertNotEqual(e, i)
874 self.assertEqual(e.name, month)
875 self.assertIn(e, SummerMonth)
876 self.assertIs(type(e), SummerMonth)
877
Martin Pantereb995702016-07-28 01:11:04 +0000878 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700879 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
880 lst = list(SummerMonth)
881 self.assertEqual(len(lst), len(SummerMonth))
882 self.assertEqual(len(SummerMonth), 3, SummerMonth)
883 self.assertEqual(
884 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
885 lst,
886 )
887 for i, month in enumerate('june july august'.split(), 1):
888 e = SummerMonth(i)
889 self.assertEqual(e, i)
890 self.assertEqual(e.name, month)
891 self.assertIn(e, SummerMonth)
892 self.assertIs(type(e), SummerMonth)
893
Martin Pantereb995702016-07-28 01:11:04 +0000894 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700895 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
896 lst = list(SummerMonth)
897 self.assertEqual(len(lst), len(SummerMonth))
898 self.assertEqual(len(SummerMonth), 3, SummerMonth)
899 self.assertEqual(
900 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
901 lst,
902 )
903 for i, month in enumerate('june july august'.split(), 30):
904 e = SummerMonth(i)
905 self.assertEqual(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_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700911 SummerMonth = IntEnum('SummerMonth', 'june july august')
912 lst = list(SummerMonth)
913 self.assertEqual(len(lst), len(SummerMonth))
914 self.assertEqual(len(SummerMonth), 3, SummerMonth)
915 self.assertEqual(
916 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
917 lst,
918 )
919 for i, month in enumerate('june july august'.split(), 1):
920 e = SummerMonth(i)
921 self.assertEqual(e, i)
922 self.assertEqual(e.name, month)
923 self.assertIn(e, SummerMonth)
924 self.assertIs(type(e), SummerMonth)
925
Martin Pantereb995702016-07-28 01:11:04 +0000926 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700927 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
928 lst = list(SummerMonth)
929 self.assertEqual(len(lst), len(SummerMonth))
930 self.assertEqual(len(SummerMonth), 3, SummerMonth)
931 self.assertEqual(
932 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
933 lst,
934 )
935 for i, month in enumerate('june july august'.split(), 40):
936 e = SummerMonth(i)
937 self.assertEqual(e, i)
938 self.assertEqual(e.name, month)
939 self.assertIn(e, SummerMonth)
940 self.assertIs(type(e), SummerMonth)
941
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700942 def test_subclassing(self):
943 if isinstance(Name, Exception):
944 raise Name
945 self.assertEqual(Name.BDFL, 'Guido van Rossum')
946 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
947 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800948 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700949
950 def test_extending(self):
951 class Color(Enum):
952 red = 1
953 green = 2
954 blue = 3
955 with self.assertRaises(TypeError):
956 class MoreColor(Color):
957 cyan = 4
958 magenta = 5
959 yellow = 6
960
961 def test_exclude_methods(self):
962 class whatever(Enum):
963 this = 'that'
964 these = 'those'
965 def really(self):
966 return 'no, not %s' % self.value
967 self.assertIsNot(type(whatever.really), whatever)
968 self.assertEqual(whatever.this.really(), 'no, not that')
969
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700970 def test_wrong_inheritance_order(self):
971 with self.assertRaises(TypeError):
972 class Wrong(Enum, str):
973 NotHere = 'error before this point'
974
975 def test_intenum_transitivity(self):
976 class number(IntEnum):
977 one = 1
978 two = 2
979 three = 3
980 class numero(IntEnum):
981 uno = 1
982 dos = 2
983 tres = 3
984 self.assertEqual(number.one, numero.uno)
985 self.assertEqual(number.two, numero.dos)
986 self.assertEqual(number.three, numero.tres)
987
988 def test_wrong_enum_in_call(self):
989 class Monochrome(Enum):
990 black = 0
991 white = 1
992 class Gender(Enum):
993 male = 0
994 female = 1
995 self.assertRaises(ValueError, Monochrome, Gender.male)
996
997 def test_wrong_enum_in_mixed_call(self):
998 class Monochrome(IntEnum):
999 black = 0
1000 white = 1
1001 class Gender(Enum):
1002 male = 0
1003 female = 1
1004 self.assertRaises(ValueError, Monochrome, Gender.male)
1005
1006 def test_mixed_enum_in_call_1(self):
1007 class Monochrome(IntEnum):
1008 black = 0
1009 white = 1
1010 class Gender(IntEnum):
1011 male = 0
1012 female = 1
1013 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1014
1015 def test_mixed_enum_in_call_2(self):
1016 class Monochrome(Enum):
1017 black = 0
1018 white = 1
1019 class Gender(IntEnum):
1020 male = 0
1021 female = 1
1022 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1023
1024 def test_flufl_enum(self):
1025 class Fluflnum(Enum):
1026 def __int__(self):
1027 return int(self.value)
1028 class MailManOptions(Fluflnum):
1029 option1 = 1
1030 option2 = 2
1031 option3 = 3
1032 self.assertEqual(int(MailManOptions.option1), 1)
1033
Ethan Furman5e5a8232013-08-04 08:42:23 -07001034 def test_introspection(self):
1035 class Number(IntEnum):
1036 one = 100
1037 two = 200
1038 self.assertIs(Number.one._member_type_, int)
1039 self.assertIs(Number._member_type_, int)
1040 class String(str, Enum):
1041 yarn = 'soft'
1042 rope = 'rough'
1043 wire = 'hard'
1044 self.assertIs(String.yarn._member_type_, str)
1045 self.assertIs(String._member_type_, str)
1046 class Plain(Enum):
1047 vanilla = 'white'
1048 one = 1
1049 self.assertIs(Plain.vanilla._member_type_, object)
1050 self.assertIs(Plain._member_type_, object)
1051
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001052 def test_no_such_enum_member(self):
1053 class Color(Enum):
1054 red = 1
1055 green = 2
1056 blue = 3
1057 with self.assertRaises(ValueError):
1058 Color(4)
1059 with self.assertRaises(KeyError):
1060 Color['chartreuse']
1061
1062 def test_new_repr(self):
1063 class Color(Enum):
1064 red = 1
1065 green = 2
1066 blue = 3
1067 def __repr__(self):
1068 return "don't you just love shades of %s?" % self.name
1069 self.assertEqual(
1070 repr(Color.blue),
1071 "don't you just love shades of blue?",
1072 )
1073
1074 def test_inherited_repr(self):
1075 class MyEnum(Enum):
1076 def __repr__(self):
1077 return "My name is %s." % self.name
1078 class MyIntEnum(int, MyEnum):
1079 this = 1
1080 that = 2
1081 theother = 3
1082 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1083
1084 def test_multiple_mixin_mro(self):
1085 class auto_enum(type(Enum)):
1086 def __new__(metacls, cls, bases, classdict):
1087 temp = type(classdict)()
1088 names = set(classdict._member_names)
1089 i = 0
1090 for k in classdict._member_names:
1091 v = classdict[k]
1092 if v is Ellipsis:
1093 v = i
1094 else:
1095 i = v
1096 i += 1
1097 temp[k] = v
1098 for k, v in classdict.items():
1099 if k not in names:
1100 temp[k] = v
1101 return super(auto_enum, metacls).__new__(
1102 metacls, cls, bases, temp)
1103
1104 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1105 pass
1106
1107 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1108 pass
1109
1110 class TestAutoNumber(AutoNumberedEnum):
1111 a = ...
1112 b = 3
1113 c = ...
1114
1115 class TestAutoInt(AutoIntEnum):
1116 a = ...
1117 b = 3
1118 c = ...
1119
1120 def test_subclasses_with_getnewargs(self):
1121 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001122 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001123 def __new__(cls, *args):
1124 _args = args
1125 name, *args = args
1126 if len(args) == 0:
1127 raise TypeError("name and value must be specified")
1128 self = int.__new__(cls, *args)
1129 self._intname = name
1130 self._args = _args
1131 return self
1132 def __getnewargs__(self):
1133 return self._args
1134 @property
1135 def __name__(self):
1136 return self._intname
1137 def __repr__(self):
1138 # repr() is updated to include the name and type info
1139 return "{}({!r}, {})".format(type(self).__name__,
1140 self.__name__,
1141 int.__repr__(self))
1142 def __str__(self):
1143 # str() is unchanged, even if it relies on the repr() fallback
1144 base = int
1145 base_str = base.__str__
1146 if base_str.__objclass__ is object:
1147 return base.__repr__(self)
1148 return base_str(self)
1149 # for simplicity, we only define one operator that
1150 # propagates expressions
1151 def __add__(self, other):
1152 temp = int(self) + int( other)
1153 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1154 return NamedInt(
1155 '({0} + {1})'.format(self.__name__, other.__name__),
1156 temp )
1157 else:
1158 return temp
1159
1160 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001161 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001162 x = ('the-x', 1)
1163 y = ('the-y', 2)
1164
Ethan Furman2aa27322013-07-19 19:35:56 -07001165
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001166 self.assertIs(NEI.__new__, Enum.__new__)
1167 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1168 globals()['NamedInt'] = NamedInt
1169 globals()['NEI'] = NEI
1170 NI5 = NamedInt('test', 5)
1171 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001172 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001173 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001174 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001175 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001176
Ethan Furmanca1b7942014-02-08 11:36:27 -08001177 def test_subclasses_with_getnewargs_ex(self):
1178 class NamedInt(int):
1179 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1180 def __new__(cls, *args):
1181 _args = args
1182 name, *args = args
1183 if len(args) == 0:
1184 raise TypeError("name and value must be specified")
1185 self = int.__new__(cls, *args)
1186 self._intname = name
1187 self._args = _args
1188 return self
1189 def __getnewargs_ex__(self):
1190 return self._args, {}
1191 @property
1192 def __name__(self):
1193 return self._intname
1194 def __repr__(self):
1195 # repr() is updated to include the name and type info
1196 return "{}({!r}, {})".format(type(self).__name__,
1197 self.__name__,
1198 int.__repr__(self))
1199 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__),
1213 temp )
1214 else:
1215 return temp
1216
1217 class NEI(NamedInt, Enum):
1218 __qualname__ = 'NEI' # needed for pickle protocol 4
1219 x = ('the-x', 1)
1220 y = ('the-y', 2)
1221
1222
1223 self.assertIs(NEI.__new__, Enum.__new__)
1224 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1225 globals()['NamedInt'] = NamedInt
1226 globals()['NEI'] = NEI
1227 NI5 = NamedInt('test', 5)
1228 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001229 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001230 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001231 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001232 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001233
1234 def test_subclasses_with_reduce(self):
1235 class NamedInt(int):
1236 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1237 def __new__(cls, *args):
1238 _args = args
1239 name, *args = args
1240 if len(args) == 0:
1241 raise TypeError("name and value must be specified")
1242 self = int.__new__(cls, *args)
1243 self._intname = name
1244 self._args = _args
1245 return self
1246 def __reduce__(self):
1247 return self.__class__, self._args
1248 @property
1249 def __name__(self):
1250 return self._intname
1251 def __repr__(self):
1252 # repr() is updated to include the name and type info
1253 return "{}({!r}, {})".format(type(self).__name__,
1254 self.__name__,
1255 int.__repr__(self))
1256 def __str__(self):
1257 # str() is unchanged, even if it relies on the repr() fallback
1258 base = int
1259 base_str = base.__str__
1260 if base_str.__objclass__ is object:
1261 return base.__repr__(self)
1262 return base_str(self)
1263 # for simplicity, we only define one operator that
1264 # propagates expressions
1265 def __add__(self, other):
1266 temp = int(self) + int( other)
1267 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1268 return NamedInt(
1269 '({0} + {1})'.format(self.__name__, other.__name__),
1270 temp )
1271 else:
1272 return temp
1273
1274 class NEI(NamedInt, Enum):
1275 __qualname__ = 'NEI' # needed for pickle protocol 4
1276 x = ('the-x', 1)
1277 y = ('the-y', 2)
1278
1279
1280 self.assertIs(NEI.__new__, Enum.__new__)
1281 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1282 globals()['NamedInt'] = NamedInt
1283 globals()['NEI'] = NEI
1284 NI5 = NamedInt('test', 5)
1285 self.assertEqual(NI5, 5)
1286 test_pickle_dump_load(self.assertEqual, NI5, 5)
1287 self.assertEqual(NEI.y.value, 2)
1288 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001289 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001290
1291 def test_subclasses_with_reduce_ex(self):
1292 class NamedInt(int):
1293 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1294 def __new__(cls, *args):
1295 _args = args
1296 name, *args = args
1297 if len(args) == 0:
1298 raise TypeError("name and value must be specified")
1299 self = int.__new__(cls, *args)
1300 self._intname = name
1301 self._args = _args
1302 return self
1303 def __reduce_ex__(self, proto):
1304 return self.__class__, self._args
1305 @property
1306 def __name__(self):
1307 return self._intname
1308 def __repr__(self):
1309 # repr() is updated to include the name and type info
1310 return "{}({!r}, {})".format(type(self).__name__,
1311 self.__name__,
1312 int.__repr__(self))
1313 def __str__(self):
1314 # str() is unchanged, even if it relies on the repr() fallback
1315 base = int
1316 base_str = base.__str__
1317 if base_str.__objclass__ is object:
1318 return base.__repr__(self)
1319 return base_str(self)
1320 # for simplicity, we only define one operator that
1321 # propagates expressions
1322 def __add__(self, other):
1323 temp = int(self) + int( other)
1324 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1325 return NamedInt(
1326 '({0} + {1})'.format(self.__name__, other.__name__),
1327 temp )
1328 else:
1329 return temp
1330
1331 class NEI(NamedInt, Enum):
1332 __qualname__ = 'NEI' # needed for pickle protocol 4
1333 x = ('the-x', 1)
1334 y = ('the-y', 2)
1335
1336
1337 self.assertIs(NEI.__new__, Enum.__new__)
1338 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1339 globals()['NamedInt'] = NamedInt
1340 globals()['NEI'] = NEI
1341 NI5 = NamedInt('test', 5)
1342 self.assertEqual(NI5, 5)
1343 test_pickle_dump_load(self.assertEqual, NI5, 5)
1344 self.assertEqual(NEI.y.value, 2)
1345 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001346 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001347
Ethan Furmandc870522014-02-18 12:37:12 -08001348 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001349 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001350 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001351 def __new__(cls, *args):
1352 _args = args
1353 name, *args = args
1354 if len(args) == 0:
1355 raise TypeError("name and value must be specified")
1356 self = int.__new__(cls, *args)
1357 self._intname = name
1358 self._args = _args
1359 return self
1360 @property
1361 def __name__(self):
1362 return self._intname
1363 def __repr__(self):
1364 # repr() is updated to include the name and type info
1365 return "{}({!r}, {})".format(type(self).__name__,
1366 self.__name__,
1367 int.__repr__(self))
1368 def __str__(self):
1369 # str() is unchanged, even if it relies on the repr() fallback
1370 base = int
1371 base_str = base.__str__
1372 if base_str.__objclass__ is object:
1373 return base.__repr__(self)
1374 return base_str(self)
1375 # for simplicity, we only define one operator that
1376 # propagates expressions
1377 def __add__(self, other):
1378 temp = int(self) + int( other)
1379 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1380 return NamedInt(
1381 '({0} + {1})'.format(self.__name__, other.__name__),
1382 temp )
1383 else:
1384 return temp
1385
1386 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001387 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001388 x = ('the-x', 1)
1389 y = ('the-y', 2)
1390
1391 self.assertIs(NEI.__new__, Enum.__new__)
1392 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1393 globals()['NamedInt'] = NamedInt
1394 globals()['NEI'] = NEI
1395 NI5 = NamedInt('test', 5)
1396 self.assertEqual(NI5, 5)
1397 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001398 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1399 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001400
Ethan Furmandc870522014-02-18 12:37:12 -08001401 def test_subclasses_without_direct_pickle_support_using_name(self):
1402 class NamedInt(int):
1403 __qualname__ = 'NamedInt'
1404 def __new__(cls, *args):
1405 _args = args
1406 name, *args = args
1407 if len(args) == 0:
1408 raise TypeError("name and value must be specified")
1409 self = int.__new__(cls, *args)
1410 self._intname = name
1411 self._args = _args
1412 return self
1413 @property
1414 def __name__(self):
1415 return self._intname
1416 def __repr__(self):
1417 # repr() is updated to include the name and type info
1418 return "{}({!r}, {})".format(type(self).__name__,
1419 self.__name__,
1420 int.__repr__(self))
1421 def __str__(self):
1422 # str() is unchanged, even if it relies on the repr() fallback
1423 base = int
1424 base_str = base.__str__
1425 if base_str.__objclass__ is object:
1426 return base.__repr__(self)
1427 return base_str(self)
1428 # for simplicity, we only define one operator that
1429 # propagates expressions
1430 def __add__(self, other):
1431 temp = int(self) + int( other)
1432 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1433 return NamedInt(
1434 '({0} + {1})'.format(self.__name__, other.__name__),
1435 temp )
1436 else:
1437 return temp
1438
1439 class NEI(NamedInt, Enum):
1440 __qualname__ = 'NEI'
1441 x = ('the-x', 1)
1442 y = ('the-y', 2)
1443 def __reduce_ex__(self, proto):
1444 return getattr, (self.__class__, self._name_)
1445
1446 self.assertIs(NEI.__new__, Enum.__new__)
1447 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1448 globals()['NamedInt'] = NamedInt
1449 globals()['NEI'] = NEI
1450 NI5 = NamedInt('test', 5)
1451 self.assertEqual(NI5, 5)
1452 self.assertEqual(NEI.y.value, 2)
1453 test_pickle_dump_load(self.assertIs, NEI.y)
1454 test_pickle_dump_load(self.assertIs, NEI)
1455
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 def test_tuple_subclass(self):
1457 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001458 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001459 first = (1, 'for the money')
1460 second = (2, 'for the show')
1461 third = (3, 'for the music')
1462 self.assertIs(type(SomeTuple.first), SomeTuple)
1463 self.assertIsInstance(SomeTuple.second, tuple)
1464 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1465 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001466 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001467
1468 def test_duplicate_values_give_unique_enum_items(self):
1469 class AutoNumber(Enum):
1470 first = ()
1471 second = ()
1472 third = ()
1473 def __new__(cls):
1474 value = len(cls.__members__) + 1
1475 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001476 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477 return obj
1478 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001479 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001480 self.assertEqual(
1481 list(AutoNumber),
1482 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1483 )
1484 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001485 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001486 self.assertIs(AutoNumber(1), AutoNumber.first)
1487
1488 def test_inherited_new_from_enhanced_enum(self):
1489 class AutoNumber(Enum):
1490 def __new__(cls):
1491 value = len(cls.__members__) + 1
1492 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001493 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001494 return obj
1495 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001496 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001497 class Color(AutoNumber):
1498 red = ()
1499 green = ()
1500 blue = ()
1501 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1502 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1503
1504 def test_inherited_new_from_mixed_enum(self):
1505 class AutoNumber(IntEnum):
1506 def __new__(cls):
1507 value = len(cls.__members__) + 1
1508 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001509 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001510 return obj
1511 class Color(AutoNumber):
1512 red = ()
1513 green = ()
1514 blue = ()
1515 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1516 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1517
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001518 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001519 class OrdinaryEnum(Enum):
1520 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001521 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1522 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001523
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001524 def test_ordered_mixin(self):
1525 class OrderedEnum(Enum):
1526 def __ge__(self, other):
1527 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001528 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001529 return NotImplemented
1530 def __gt__(self, other):
1531 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001532 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001533 return NotImplemented
1534 def __le__(self, other):
1535 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001536 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001537 return NotImplemented
1538 def __lt__(self, other):
1539 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001540 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001541 return NotImplemented
1542 class Grade(OrderedEnum):
1543 A = 5
1544 B = 4
1545 C = 3
1546 D = 2
1547 F = 1
1548 self.assertGreater(Grade.A, Grade.B)
1549 self.assertLessEqual(Grade.F, Grade.C)
1550 self.assertLess(Grade.D, Grade.A)
1551 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001552 self.assertEqual(Grade.B, Grade.B)
1553 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001554
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001555 def test_extending2(self):
1556 class Shade(Enum):
1557 def shade(self):
1558 print(self.name)
1559 class Color(Shade):
1560 red = 1
1561 green = 2
1562 blue = 3
1563 with self.assertRaises(TypeError):
1564 class MoreColor(Color):
1565 cyan = 4
1566 magenta = 5
1567 yellow = 6
1568
1569 def test_extending3(self):
1570 class Shade(Enum):
1571 def shade(self):
1572 return self.name
1573 class Color(Shade):
1574 def hex(self):
1575 return '%s hexlified!' % self.value
1576 class MoreColor(Color):
1577 cyan = 4
1578 magenta = 5
1579 yellow = 6
1580 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1581
orlnub1230fb9fad2018-09-12 20:28:53 +03001582 def test_subclass_duplicate_name(self):
1583 class Base(Enum):
1584 def test(self):
1585 pass
1586 class Test(Base):
1587 test = 1
1588 self.assertIs(type(Test.test), Test)
1589
1590 def test_subclass_duplicate_name_dynamic(self):
1591 from types import DynamicClassAttribute
1592 class Base(Enum):
1593 @DynamicClassAttribute
1594 def test(self):
1595 return 'dynamic'
1596 class Test(Base):
1597 test = 1
1598 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001599
1600 def test_no_duplicates(self):
1601 class UniqueEnum(Enum):
1602 def __init__(self, *args):
1603 cls = self.__class__
1604 if any(self.value == e.value for e in cls):
1605 a = self.name
1606 e = cls(self.value).name
1607 raise ValueError(
1608 "aliases not allowed in UniqueEnum: %r --> %r"
1609 % (a, e)
1610 )
1611 class Color(UniqueEnum):
1612 red = 1
1613 green = 2
1614 blue = 3
1615 with self.assertRaises(ValueError):
1616 class Color(UniqueEnum):
1617 red = 1
1618 green = 2
1619 blue = 3
1620 grene = 2
1621
1622 def test_init(self):
1623 class Planet(Enum):
1624 MERCURY = (3.303e+23, 2.4397e6)
1625 VENUS = (4.869e+24, 6.0518e6)
1626 EARTH = (5.976e+24, 6.37814e6)
1627 MARS = (6.421e+23, 3.3972e6)
1628 JUPITER = (1.9e+27, 7.1492e7)
1629 SATURN = (5.688e+26, 6.0268e7)
1630 URANUS = (8.686e+25, 2.5559e7)
1631 NEPTUNE = (1.024e+26, 2.4746e7)
1632 def __init__(self, mass, radius):
1633 self.mass = mass # in kilograms
1634 self.radius = radius # in meters
1635 @property
1636 def surface_gravity(self):
1637 # universal gravitational constant (m3 kg-1 s-2)
1638 G = 6.67300E-11
1639 return G * self.mass / (self.radius * self.radius)
1640 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1641 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1642
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001643 def test_ignore(self):
1644 class Period(timedelta, Enum):
1645 '''
1646 different lengths of time
1647 '''
1648 def __new__(cls, value, period):
1649 obj = timedelta.__new__(cls, value)
1650 obj._value_ = value
1651 obj.period = period
1652 return obj
1653 _ignore_ = 'Period i'
1654 Period = vars()
1655 for i in range(13):
1656 Period['month_%d' % i] = i*30, 'month'
1657 for i in range(53):
1658 Period['week_%d' % i] = i*7, 'week'
1659 for i in range(32):
1660 Period['day_%d' % i] = i, 'day'
1661 OneDay = day_1
1662 OneWeek = week_1
1663 OneMonth = month_1
1664 self.assertFalse(hasattr(Period, '_ignore_'))
1665 self.assertFalse(hasattr(Period, 'Period'))
1666 self.assertFalse(hasattr(Period, 'i'))
1667 self.assertTrue(isinstance(Period.day_1, timedelta))
1668 self.assertTrue(Period.month_1 is Period.day_30)
1669 self.assertTrue(Period.week_4 is Period.day_28)
1670
Ethan Furman2aa27322013-07-19 19:35:56 -07001671 def test_nonhash_value(self):
1672 class AutoNumberInAList(Enum):
1673 def __new__(cls):
1674 value = [len(cls.__members__) + 1]
1675 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001676 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001677 return obj
1678 class ColorInAList(AutoNumberInAList):
1679 red = ()
1680 green = ()
1681 blue = ()
1682 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001683 for enum, value in zip(ColorInAList, range(3)):
1684 value += 1
1685 self.assertEqual(enum.value, [value])
1686 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001687
Ethan Furmanb41803e2013-07-25 13:50:45 -07001688 def test_conflicting_types_resolved_in_new(self):
1689 class LabelledIntEnum(int, Enum):
1690 def __new__(cls, *args):
1691 value, label = args
1692 obj = int.__new__(cls, value)
1693 obj.label = label
1694 obj._value_ = value
1695 return obj
1696
1697 class LabelledList(LabelledIntEnum):
1698 unprocessed = (1, "Unprocessed")
1699 payment_complete = (2, "Payment Complete")
1700
1701 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1702 self.assertEqual(LabelledList.unprocessed, 1)
1703 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001704
Ethan Furmanc16595e2016-09-10 23:36:59 -07001705 def test_auto_number(self):
1706 class Color(Enum):
1707 red = auto()
1708 blue = auto()
1709 green = auto()
1710
1711 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1712 self.assertEqual(Color.red.value, 1)
1713 self.assertEqual(Color.blue.value, 2)
1714 self.assertEqual(Color.green.value, 3)
1715
1716 def test_auto_name(self):
1717 class Color(Enum):
1718 def _generate_next_value_(name, start, count, last):
1719 return name
1720 red = auto()
1721 blue = auto()
1722 green = auto()
1723
1724 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1725 self.assertEqual(Color.red.value, 'red')
1726 self.assertEqual(Color.blue.value, 'blue')
1727 self.assertEqual(Color.green.value, 'green')
1728
1729 def test_auto_name_inherit(self):
1730 class AutoNameEnum(Enum):
1731 def _generate_next_value_(name, start, count, last):
1732 return name
1733 class Color(AutoNameEnum):
1734 red = auto()
1735 blue = auto()
1736 green = auto()
1737
1738 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1739 self.assertEqual(Color.red.value, 'red')
1740 self.assertEqual(Color.blue.value, 'blue')
1741 self.assertEqual(Color.green.value, 'green')
1742
1743 def test_auto_garbage(self):
1744 class Color(Enum):
1745 red = 'red'
1746 blue = auto()
1747 self.assertEqual(Color.blue.value, 1)
1748
1749 def test_auto_garbage_corrected(self):
1750 class Color(Enum):
1751 red = 'red'
1752 blue = 2
1753 green = auto()
1754
1755 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1756 self.assertEqual(Color.red.value, 'red')
1757 self.assertEqual(Color.blue.value, 2)
1758 self.assertEqual(Color.green.value, 3)
1759
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001760 def test_auto_order(self):
1761 with self.assertRaises(TypeError):
1762 class Color(Enum):
1763 red = auto()
1764 green = auto()
1765 blue = auto()
1766 def _generate_next_value_(name, start, count, last):
1767 return name
1768
1769
Ethan Furman3515dcc2016-09-18 13:15:41 -07001770 def test_duplicate_auto(self):
1771 class Dupes(Enum):
1772 first = primero = auto()
1773 second = auto()
1774 third = auto()
1775 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1776
Ethan Furman019f0a02018-09-12 11:43:34 -07001777 def test_missing(self):
1778 class Color(Enum):
1779 red = 1
1780 green = 2
1781 blue = 3
1782 @classmethod
1783 def _missing_(cls, item):
1784 if item == 'three':
1785 return cls.blue
1786 elif item == 'bad return':
1787 # trigger internal error
1788 return 5
1789 elif item == 'error out':
1790 raise ZeroDivisionError
1791 else:
1792 # trigger not found
1793 return None
1794 self.assertIs(Color('three'), Color.blue)
1795 self.assertRaises(ValueError, Color, 7)
1796 try:
1797 Color('bad return')
1798 except TypeError as exc:
1799 self.assertTrue(isinstance(exc.__context__, ValueError))
1800 else:
1801 raise Exception('Exception not raised.')
1802 try:
1803 Color('error out')
1804 except ZeroDivisionError as exc:
1805 self.assertTrue(isinstance(exc.__context__, ValueError))
1806 else:
1807 raise Exception('Exception not raised.')
1808
Ethan Furman5bdab642018-09-21 19:03:09 -07001809 def test_multiple_mixin(self):
1810 class MaxMixin:
1811 @classproperty
1812 def MAX(cls):
1813 max = len(cls)
1814 cls.MAX = max
1815 return max
1816 class StrMixin:
1817 def __str__(self):
1818 return self._name_.lower()
1819 class SomeEnum(Enum):
1820 def behavior(self):
1821 return 'booyah'
1822 class AnotherEnum(Enum):
1823 def behavior(self):
1824 return 'nuhuh!'
1825 def social(self):
1826 return "what's up?"
1827 class Color(MaxMixin, Enum):
1828 RED = auto()
1829 GREEN = auto()
1830 BLUE = auto()
1831 self.assertEqual(Color.RED.value, 1)
1832 self.assertEqual(Color.GREEN.value, 2)
1833 self.assertEqual(Color.BLUE.value, 3)
1834 self.assertEqual(Color.MAX, 3)
1835 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1836 class Color(MaxMixin, StrMixin, Enum):
1837 RED = auto()
1838 GREEN = auto()
1839 BLUE = auto()
1840 self.assertEqual(Color.RED.value, 1)
1841 self.assertEqual(Color.GREEN.value, 2)
1842 self.assertEqual(Color.BLUE.value, 3)
1843 self.assertEqual(Color.MAX, 3)
1844 self.assertEqual(str(Color.BLUE), 'blue')
1845 class Color(StrMixin, MaxMixin, Enum):
1846 RED = auto()
1847 GREEN = auto()
1848 BLUE = auto()
1849 self.assertEqual(Color.RED.value, 1)
1850 self.assertEqual(Color.GREEN.value, 2)
1851 self.assertEqual(Color.BLUE.value, 3)
1852 self.assertEqual(Color.MAX, 3)
1853 self.assertEqual(str(Color.BLUE), 'blue')
1854 class CoolColor(StrMixin, SomeEnum, Enum):
1855 RED = auto()
1856 GREEN = auto()
1857 BLUE = auto()
1858 self.assertEqual(CoolColor.RED.value, 1)
1859 self.assertEqual(CoolColor.GREEN.value, 2)
1860 self.assertEqual(CoolColor.BLUE.value, 3)
1861 self.assertEqual(str(CoolColor.BLUE), 'blue')
1862 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1863 class CoolerColor(StrMixin, AnotherEnum, Enum):
1864 RED = auto()
1865 GREEN = auto()
1866 BLUE = auto()
1867 self.assertEqual(CoolerColor.RED.value, 1)
1868 self.assertEqual(CoolerColor.GREEN.value, 2)
1869 self.assertEqual(CoolerColor.BLUE.value, 3)
1870 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1871 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1872 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1873 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1874 RED = auto()
1875 GREEN = auto()
1876 BLUE = auto()
1877 self.assertEqual(CoolestColor.RED.value, 1)
1878 self.assertEqual(CoolestColor.GREEN.value, 2)
1879 self.assertEqual(CoolestColor.BLUE.value, 3)
1880 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1881 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1882 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1883 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1884 RED = auto()
1885 GREEN = auto()
1886 BLUE = auto()
1887 self.assertEqual(ConfusedColor.RED.value, 1)
1888 self.assertEqual(ConfusedColor.GREEN.value, 2)
1889 self.assertEqual(ConfusedColor.BLUE.value, 3)
1890 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1891 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1892 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1893 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1894 RED = auto()
1895 GREEN = auto()
1896 BLUE = auto()
1897 self.assertEqual(ReformedColor.RED.value, 1)
1898 self.assertEqual(ReformedColor.GREEN.value, 2)
1899 self.assertEqual(ReformedColor.BLUE.value, 3)
1900 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1901 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1902 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1903 self.assertTrue(issubclass(ReformedColor, int))
1904
Ethan Furmancd453852018-10-05 23:29:36 -07001905 def test_multiple_inherited_mixin(self):
1906 class StrEnum(str, Enum):
1907 def __new__(cls, *args, **kwargs):
1908 for a in args:
1909 if not isinstance(a, str):
1910 raise TypeError("Enumeration '%s' (%s) is not"
1911 " a string" % (a, type(a).__name__))
1912 return str.__new__(cls, *args, **kwargs)
1913 @unique
1914 class Decision1(StrEnum):
1915 REVERT = "REVERT"
1916 REVERT_ALL = "REVERT_ALL"
1917 RETRY = "RETRY"
1918 class MyEnum(StrEnum):
1919 pass
1920 @unique
1921 class Decision2(MyEnum):
1922 REVERT = "REVERT"
1923 REVERT_ALL = "REVERT_ALL"
1924 RETRY = "RETRY"
1925
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001926 def test_empty_globals(self):
1927 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1928 # when using compile and exec because f_globals is empty
1929 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1930 code = compile(code, "<string>", "exec")
1931 global_ns = {}
1932 local_ls = {}
1933 exec(code, global_ns, local_ls)
1934
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001935
Ethan Furmane8e61272016-08-20 07:19:31 -07001936class TestOrder(unittest.TestCase):
1937
1938 def test_same_members(self):
1939 class Color(Enum):
1940 _order_ = 'red green blue'
1941 red = 1
1942 green = 2
1943 blue = 3
1944
1945 def test_same_members_with_aliases(self):
1946 class Color(Enum):
1947 _order_ = 'red green blue'
1948 red = 1
1949 green = 2
1950 blue = 3
1951 verde = green
1952
1953 def test_same_members_wrong_order(self):
1954 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1955 class Color(Enum):
1956 _order_ = 'red green blue'
1957 red = 1
1958 blue = 3
1959 green = 2
1960
1961 def test_order_has_extra_members(self):
1962 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1963 class Color(Enum):
1964 _order_ = 'red green blue purple'
1965 red = 1
1966 green = 2
1967 blue = 3
1968
1969 def test_order_has_extra_members_with_aliases(self):
1970 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1971 class Color(Enum):
1972 _order_ = 'red green blue purple'
1973 red = 1
1974 green = 2
1975 blue = 3
1976 verde = green
1977
1978 def test_enum_has_extra_members(self):
1979 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1980 class Color(Enum):
1981 _order_ = 'red green blue'
1982 red = 1
1983 green = 2
1984 blue = 3
1985 purple = 4
1986
1987 def test_enum_has_extra_members_with_aliases(self):
1988 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1989 class Color(Enum):
1990 _order_ = 'red green blue'
1991 red = 1
1992 green = 2
1993 blue = 3
1994 purple = 4
1995 verde = green
1996
1997
Ethan Furman65a5a472016-09-01 23:55:19 -07001998class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001999 """Tests of the Flags."""
2000
Ethan Furman65a5a472016-09-01 23:55:19 -07002001 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002002 R, W, X = 4, 2, 1
2003
Ethan Furman65a5a472016-09-01 23:55:19 -07002004 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002005 RO = 0
2006 WO = 1
2007 RW = 2
2008 AC = 3
2009 CE = 1<<19
2010
Rahul Jha94306522018-09-10 23:51:04 +05302011 class Color(Flag):
2012 BLACK = 0
2013 RED = 1
2014 GREEN = 2
2015 BLUE = 4
2016 PURPLE = RED|BLUE
2017
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002018 def test_str(self):
2019 Perm = self.Perm
2020 self.assertEqual(str(Perm.R), 'Perm.R')
2021 self.assertEqual(str(Perm.W), 'Perm.W')
2022 self.assertEqual(str(Perm.X), 'Perm.X')
2023 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2024 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2025 self.assertEqual(str(Perm(0)), 'Perm.0')
2026 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2027 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2028 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2029 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2030 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2031 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2032
2033 Open = self.Open
2034 self.assertEqual(str(Open.RO), 'Open.RO')
2035 self.assertEqual(str(Open.WO), 'Open.WO')
2036 self.assertEqual(str(Open.AC), 'Open.AC')
2037 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2038 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002039 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002040 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2041 self.assertEqual(str(~Open.AC), 'Open.CE')
2042 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2043 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2044
2045 def test_repr(self):
2046 Perm = self.Perm
2047 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2048 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2049 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2050 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2051 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002052 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002053 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2054 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2055 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2056 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002057 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002058 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2059
2060 Open = self.Open
2061 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2062 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2063 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2064 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2065 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002066 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002067 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2068 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2069 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2070 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2071
2072 def test_or(self):
2073 Perm = self.Perm
2074 for i in Perm:
2075 for j in Perm:
2076 self.assertEqual((i | j), Perm(i.value | j.value))
2077 self.assertEqual((i | j).value, i.value | j.value)
2078 self.assertIs(type(i | j), Perm)
2079 for i in Perm:
2080 self.assertIs(i | i, i)
2081 Open = self.Open
2082 self.assertIs(Open.RO | Open.CE, Open.CE)
2083
2084 def test_and(self):
2085 Perm = self.Perm
2086 RW = Perm.R | Perm.W
2087 RX = Perm.R | Perm.X
2088 WX = Perm.W | Perm.X
2089 RWX = Perm.R | Perm.W | Perm.X
2090 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2091 for i in values:
2092 for j in values:
2093 self.assertEqual((i & j).value, i.value & j.value)
2094 self.assertIs(type(i & j), Perm)
2095 for i in Perm:
2096 self.assertIs(i & i, i)
2097 self.assertIs(i & RWX, i)
2098 self.assertIs(RWX & i, i)
2099 Open = self.Open
2100 self.assertIs(Open.RO & Open.CE, Open.RO)
2101
2102 def test_xor(self):
2103 Perm = self.Perm
2104 for i in Perm:
2105 for j in Perm:
2106 self.assertEqual((i ^ j).value, i.value ^ j.value)
2107 self.assertIs(type(i ^ j), Perm)
2108 for i in Perm:
2109 self.assertIs(i ^ Perm(0), i)
2110 self.assertIs(Perm(0) ^ i, i)
2111 Open = self.Open
2112 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2113 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2114
2115 def test_invert(self):
2116 Perm = self.Perm
2117 RW = Perm.R | Perm.W
2118 RX = Perm.R | Perm.X
2119 WX = Perm.W | Perm.X
2120 RWX = Perm.R | Perm.W | Perm.X
2121 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2122 for i in values:
2123 self.assertIs(type(~i), Perm)
2124 self.assertEqual(~~i, i)
2125 for i in Perm:
2126 self.assertIs(~~i, i)
2127 Open = self.Open
2128 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2129 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2130
Ethan Furman25d94bb2016-09-02 16:32:32 -07002131 def test_bool(self):
2132 Perm = self.Perm
2133 for f in Perm:
2134 self.assertTrue(f)
2135 Open = self.Open
2136 for f in Open:
2137 self.assertEqual(bool(f.value), bool(f))
2138
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002139 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002140 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002141 lst = list(Perm)
2142 self.assertEqual(len(lst), len(Perm))
2143 self.assertEqual(len(Perm), 3, Perm)
2144 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2145 for i, n in enumerate('R W X'.split()):
2146 v = 1<<i
2147 e = Perm(v)
2148 self.assertEqual(e.value, v)
2149 self.assertEqual(type(e.value), int)
2150 self.assertEqual(e.name, n)
2151 self.assertIn(e, Perm)
2152 self.assertIs(type(e), Perm)
2153
2154 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002155 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002156 lst = list(Perm)
2157 self.assertEqual(len(lst), len(Perm))
2158 self.assertEqual(len(Perm), 3, Perm)
2159 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2160 for i, n in enumerate('R W X'.split()):
2161 v = 8<<i
2162 e = Perm(v)
2163 self.assertEqual(e.value, v)
2164 self.assertEqual(type(e.value), int)
2165 self.assertEqual(e.name, n)
2166 self.assertIn(e, Perm)
2167 self.assertIs(type(e), Perm)
2168
2169 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002170 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002171 lst = list(Perm)
2172 self.assertEqual(len(lst), len(Perm))
2173 self.assertEqual(len(Perm), 3, Perm)
2174 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2175 for i, n in enumerate('R W X'.split()):
2176 v = 1<<i
2177 e = Perm(v)
2178 self.assertEqual(e.value, v)
2179 self.assertEqual(type(e.value), int)
2180 self.assertEqual(e.name, n)
2181 self.assertIn(e, Perm)
2182 self.assertIs(type(e), Perm)
2183
2184 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002185 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002186 lst = list(Perm)
2187 self.assertEqual(len(lst), len(Perm))
2188 self.assertEqual(len(Perm), 3, Perm)
2189 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2190 for i, n in enumerate('R W X'.split()):
2191 v = 1<<(2*i+1)
2192 e = Perm(v)
2193 self.assertEqual(e.value, v)
2194 self.assertEqual(type(e.value), int)
2195 self.assertEqual(e.name, n)
2196 self.assertIn(e, Perm)
2197 self.assertIs(type(e), Perm)
2198
2199 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002200 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002201 lst = list(Perm)
2202 self.assertEqual(len(lst), len(Perm))
2203 self.assertEqual(len(Perm), 3, Perm)
2204 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2205 for i, n in enumerate('R W X'.split()):
2206 v = 1<<(2*i+1)
2207 e = Perm(v)
2208 self.assertEqual(e.value, v)
2209 self.assertEqual(type(e.value), int)
2210 self.assertEqual(e.name, n)
2211 self.assertIn(e, Perm)
2212 self.assertIs(type(e), Perm)
2213
Ethan Furman65a5a472016-09-01 23:55:19 -07002214 def test_pickle(self):
2215 if isinstance(FlagStooges, Exception):
2216 raise FlagStooges
2217 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2218 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002219
Rahul Jha94306522018-09-10 23:51:04 +05302220 def test_contains(self):
2221 Open = self.Open
2222 Color = self.Color
2223 self.assertFalse(Color.BLACK in Open)
2224 self.assertFalse(Open.RO in Color)
2225 with self.assertRaises(TypeError):
2226 'BLACK' in Color
2227 with self.assertRaises(TypeError):
2228 'RO' in Open
2229 with self.assertRaises(TypeError):
2230 1 in Color
2231 with self.assertRaises(TypeError):
2232 1 in Open
2233
2234 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002235 Perm = self.Perm
2236 R, W, X = Perm
2237 RW = R | W
2238 RX = R | X
2239 WX = W | X
2240 RWX = R | W | X
2241 self.assertTrue(R in RW)
2242 self.assertTrue(R in RX)
2243 self.assertTrue(R in RWX)
2244 self.assertTrue(W in RW)
2245 self.assertTrue(W in WX)
2246 self.assertTrue(W in RWX)
2247 self.assertTrue(X in RX)
2248 self.assertTrue(X in WX)
2249 self.assertTrue(X in RWX)
2250 self.assertFalse(R in WX)
2251 self.assertFalse(W in RX)
2252 self.assertFalse(X in RW)
2253
Ethan Furmanc16595e2016-09-10 23:36:59 -07002254 def test_auto_number(self):
2255 class Color(Flag):
2256 red = auto()
2257 blue = auto()
2258 green = auto()
2259
2260 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2261 self.assertEqual(Color.red.value, 1)
2262 self.assertEqual(Color.blue.value, 2)
2263 self.assertEqual(Color.green.value, 4)
2264
2265 def test_auto_number_garbage(self):
2266 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2267 class Color(Flag):
2268 red = 'not an int'
2269 blue = auto()
2270
Ethan Furman3515dcc2016-09-18 13:15:41 -07002271 def test_cascading_failure(self):
2272 class Bizarre(Flag):
2273 c = 3
2274 d = 4
2275 f = 6
2276 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002277 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2278 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2279 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2280 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2281 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2282 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2283 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002284
2285 def test_duplicate_auto(self):
2286 class Dupes(Enum):
2287 first = primero = auto()
2288 second = auto()
2289 third = auto()
2290 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2291
2292 def test_bizarre(self):
2293 class Bizarre(Flag):
2294 b = 3
2295 c = 4
2296 d = 6
2297 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2298
Ethan Furman5bdab642018-09-21 19:03:09 -07002299 def test_multiple_mixin(self):
2300 class AllMixin:
2301 @classproperty
2302 def ALL(cls):
2303 members = list(cls)
2304 all_value = None
2305 if members:
2306 all_value = members[0]
2307 for member in members[1:]:
2308 all_value |= member
2309 cls.ALL = all_value
2310 return all_value
2311 class StrMixin:
2312 def __str__(self):
2313 return self._name_.lower()
2314 class Color(AllMixin, Flag):
2315 RED = auto()
2316 GREEN = auto()
2317 BLUE = auto()
2318 self.assertEqual(Color.RED.value, 1)
2319 self.assertEqual(Color.GREEN.value, 2)
2320 self.assertEqual(Color.BLUE.value, 4)
2321 self.assertEqual(Color.ALL.value, 7)
2322 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2323 class Color(AllMixin, StrMixin, Flag):
2324 RED = auto()
2325 GREEN = auto()
2326 BLUE = auto()
2327 self.assertEqual(Color.RED.value, 1)
2328 self.assertEqual(Color.GREEN.value, 2)
2329 self.assertEqual(Color.BLUE.value, 4)
2330 self.assertEqual(Color.ALL.value, 7)
2331 self.assertEqual(str(Color.BLUE), 'blue')
2332 class Color(StrMixin, AllMixin, Flag):
2333 RED = auto()
2334 GREEN = auto()
2335 BLUE = auto()
2336 self.assertEqual(Color.RED.value, 1)
2337 self.assertEqual(Color.GREEN.value, 2)
2338 self.assertEqual(Color.BLUE.value, 4)
2339 self.assertEqual(Color.ALL.value, 7)
2340 self.assertEqual(str(Color.BLUE), 'blue')
2341
Hai Shie80697d2020-05-28 06:10:27 +08002342 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002343 def test_unique_composite(self):
2344 # override __eq__ to be identity only
2345 class TestFlag(Flag):
2346 one = auto()
2347 two = auto()
2348 three = auto()
2349 four = auto()
2350 five = auto()
2351 six = auto()
2352 seven = auto()
2353 eight = auto()
2354 def __eq__(self, other):
2355 return self is other
2356 def __hash__(self):
2357 return hash(self._value_)
2358 # have multiple threads competing to complete the composite members
2359 seen = set()
2360 failed = False
2361 def cycle_enum():
2362 nonlocal failed
2363 try:
2364 for i in range(256):
2365 seen.add(TestFlag(i))
2366 except Exception:
2367 failed = True
2368 threads = [
2369 threading.Thread(target=cycle_enum)
2370 for _ in range(8)
2371 ]
Hai Shie80697d2020-05-28 06:10:27 +08002372 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002373 pass
2374 # check that only 248 members were created
2375 self.assertFalse(
2376 failed,
2377 'at least one thread failed while creating composite members')
2378 self.assertEqual(256, len(seen), 'too many composite members created')
2379
Ethan Furmanc16595e2016-09-10 23:36:59 -07002380
Ethan Furman65a5a472016-09-01 23:55:19 -07002381class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002382 """Tests of the IntFlags."""
2383
Ethan Furman65a5a472016-09-01 23:55:19 -07002384 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002385 X = 1 << 0
2386 W = 1 << 1
2387 R = 1 << 2
2388
Ethan Furman65a5a472016-09-01 23:55:19 -07002389 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002390 RO = 0
2391 WO = 1
2392 RW = 2
2393 AC = 3
2394 CE = 1<<19
2395
Rahul Jha94306522018-09-10 23:51:04 +05302396 class Color(IntFlag):
2397 BLACK = 0
2398 RED = 1
2399 GREEN = 2
2400 BLUE = 4
2401 PURPLE = RED|BLUE
2402
Ethan Furman3515dcc2016-09-18 13:15:41 -07002403 def test_type(self):
2404 Perm = self.Perm
2405 Open = self.Open
2406 for f in Perm:
2407 self.assertTrue(isinstance(f, Perm))
2408 self.assertEqual(f, f.value)
2409 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2410 self.assertEqual(Perm.W | Perm.X, 3)
2411 for f in Open:
2412 self.assertTrue(isinstance(f, Open))
2413 self.assertEqual(f, f.value)
2414 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2415 self.assertEqual(Open.WO | Open.RW, 3)
2416
2417
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002418 def test_str(self):
2419 Perm = self.Perm
2420 self.assertEqual(str(Perm.R), 'Perm.R')
2421 self.assertEqual(str(Perm.W), 'Perm.W')
2422 self.assertEqual(str(Perm.X), 'Perm.X')
2423 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2424 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2425 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2426 self.assertEqual(str(Perm(0)), 'Perm.0')
2427 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002428 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2429 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2430 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2431 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002432 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002433 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2434 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2435 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002436
2437 Open = self.Open
2438 self.assertEqual(str(Open.RO), 'Open.RO')
2439 self.assertEqual(str(Open.WO), 'Open.WO')
2440 self.assertEqual(str(Open.AC), 'Open.AC')
2441 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2442 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2443 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002444 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2445 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2446 self.assertEqual(str(~Open.AC), 'Open.CE')
2447 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2448 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2449 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002450
2451 def test_repr(self):
2452 Perm = self.Perm
2453 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2454 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2455 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2456 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2457 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2458 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002459 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2460 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002461 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2462 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2463 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2464 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002465 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002466 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2467 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2468 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002469
2470 Open = self.Open
2471 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2472 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2473 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2474 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2475 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002476 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002477 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2478 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2479 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2480 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2481 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2482 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002483
2484 def test_or(self):
2485 Perm = self.Perm
2486 for i in Perm:
2487 for j in Perm:
2488 self.assertEqual(i | j, i.value | j.value)
2489 self.assertEqual((i | j).value, i.value | j.value)
2490 self.assertIs(type(i | j), Perm)
2491 for j in range(8):
2492 self.assertEqual(i | j, i.value | j)
2493 self.assertEqual((i | j).value, i.value | j)
2494 self.assertIs(type(i | j), Perm)
2495 self.assertEqual(j | i, j | i.value)
2496 self.assertEqual((j | i).value, j | i.value)
2497 self.assertIs(type(j | i), Perm)
2498 for i in Perm:
2499 self.assertIs(i | i, i)
2500 self.assertIs(i | 0, i)
2501 self.assertIs(0 | i, i)
2502 Open = self.Open
2503 self.assertIs(Open.RO | Open.CE, Open.CE)
2504
2505 def test_and(self):
2506 Perm = self.Perm
2507 RW = Perm.R | Perm.W
2508 RX = Perm.R | Perm.X
2509 WX = Perm.W | Perm.X
2510 RWX = Perm.R | Perm.W | Perm.X
2511 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2512 for i in values:
2513 for j in values:
2514 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2515 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2516 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2517 for j in range(8):
2518 self.assertEqual(i & j, i.value & j)
2519 self.assertEqual((i & j).value, i.value & j)
2520 self.assertIs(type(i & j), Perm)
2521 self.assertEqual(j & i, j & i.value)
2522 self.assertEqual((j & i).value, j & i.value)
2523 self.assertIs(type(j & i), Perm)
2524 for i in Perm:
2525 self.assertIs(i & i, i)
2526 self.assertIs(i & 7, i)
2527 self.assertIs(7 & i, i)
2528 Open = self.Open
2529 self.assertIs(Open.RO & Open.CE, Open.RO)
2530
2531 def test_xor(self):
2532 Perm = self.Perm
2533 for i in Perm:
2534 for j in Perm:
2535 self.assertEqual(i ^ j, i.value ^ j.value)
2536 self.assertEqual((i ^ j).value, i.value ^ j.value)
2537 self.assertIs(type(i ^ j), Perm)
2538 for j in range(8):
2539 self.assertEqual(i ^ j, i.value ^ j)
2540 self.assertEqual((i ^ j).value, i.value ^ j)
2541 self.assertIs(type(i ^ j), Perm)
2542 self.assertEqual(j ^ i, j ^ i.value)
2543 self.assertEqual((j ^ i).value, j ^ i.value)
2544 self.assertIs(type(j ^ i), Perm)
2545 for i in Perm:
2546 self.assertIs(i ^ 0, i)
2547 self.assertIs(0 ^ i, i)
2548 Open = self.Open
2549 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2550 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2551
2552 def test_invert(self):
2553 Perm = self.Perm
2554 RW = Perm.R | Perm.W
2555 RX = Perm.R | Perm.X
2556 WX = Perm.W | Perm.X
2557 RWX = Perm.R | Perm.W | Perm.X
2558 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2559 for i in values:
2560 self.assertEqual(~i, ~i.value)
2561 self.assertEqual((~i).value, ~i.value)
2562 self.assertIs(type(~i), Perm)
2563 self.assertEqual(~~i, i)
2564 for i in Perm:
2565 self.assertIs(~~i, i)
2566 Open = self.Open
2567 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2568 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2569
2570 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002571 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002572 lst = list(Perm)
2573 self.assertEqual(len(lst), len(Perm))
2574 self.assertEqual(len(Perm), 3, Perm)
2575 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2576 for i, n in enumerate('R W X'.split()):
2577 v = 1<<i
2578 e = Perm(v)
2579 self.assertEqual(e.value, v)
2580 self.assertEqual(type(e.value), int)
2581 self.assertEqual(e, v)
2582 self.assertEqual(e.name, n)
2583 self.assertIn(e, Perm)
2584 self.assertIs(type(e), Perm)
2585
2586 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002587 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002588 lst = list(Perm)
2589 self.assertEqual(len(lst), len(Perm))
2590 self.assertEqual(len(Perm), 3, Perm)
2591 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2592 for i, n in enumerate('R W X'.split()):
2593 v = 8<<i
2594 e = Perm(v)
2595 self.assertEqual(e.value, v)
2596 self.assertEqual(type(e.value), int)
2597 self.assertEqual(e, v)
2598 self.assertEqual(e.name, n)
2599 self.assertIn(e, Perm)
2600 self.assertIs(type(e), Perm)
2601
2602 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002603 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002604 lst = list(Perm)
2605 self.assertEqual(len(lst), len(Perm))
2606 self.assertEqual(len(Perm), 3, Perm)
2607 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2608 for i, n in enumerate('R W X'.split()):
2609 v = 1<<i
2610 e = Perm(v)
2611 self.assertEqual(e.value, v)
2612 self.assertEqual(type(e.value), int)
2613 self.assertEqual(e, v)
2614 self.assertEqual(e.name, n)
2615 self.assertIn(e, Perm)
2616 self.assertIs(type(e), Perm)
2617
2618 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002619 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002620 lst = list(Perm)
2621 self.assertEqual(len(lst), len(Perm))
2622 self.assertEqual(len(Perm), 3, Perm)
2623 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2624 for i, n in enumerate('R W X'.split()):
2625 v = 1<<(2*i+1)
2626 e = Perm(v)
2627 self.assertEqual(e.value, v)
2628 self.assertEqual(type(e.value), int)
2629 self.assertEqual(e, v)
2630 self.assertEqual(e.name, n)
2631 self.assertIn(e, Perm)
2632 self.assertIs(type(e), Perm)
2633
2634 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002635 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002636 lst = list(Perm)
2637 self.assertEqual(len(lst), len(Perm))
2638 self.assertEqual(len(Perm), 3, Perm)
2639 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2640 for i, n in enumerate('R W X'.split()):
2641 v = 1<<(2*i+1)
2642 e = Perm(v)
2643 self.assertEqual(e.value, v)
2644 self.assertEqual(type(e.value), int)
2645 self.assertEqual(e, v)
2646 self.assertEqual(e.name, n)
2647 self.assertIn(e, Perm)
2648 self.assertIs(type(e), Perm)
2649
2650
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002651 def test_programatic_function_from_empty_list(self):
2652 Perm = enum.IntFlag('Perm', [])
2653 lst = list(Perm)
2654 self.assertEqual(len(lst), len(Perm))
2655 self.assertEqual(len(Perm), 0, Perm)
2656 Thing = enum.Enum('Thing', [])
2657 lst = list(Thing)
2658 self.assertEqual(len(lst), len(Thing))
2659 self.assertEqual(len(Thing), 0, Thing)
2660
2661
2662 def test_programatic_function_from_empty_tuple(self):
2663 Perm = enum.IntFlag('Perm', ())
2664 lst = list(Perm)
2665 self.assertEqual(len(lst), len(Perm))
2666 self.assertEqual(len(Perm), 0, Perm)
2667 Thing = enum.Enum('Thing', ())
2668 self.assertEqual(len(lst), len(Thing))
2669 self.assertEqual(len(Thing), 0, Thing)
2670
Rahul Jha94306522018-09-10 23:51:04 +05302671 def test_contains(self):
2672 Open = self.Open
2673 Color = self.Color
2674 self.assertTrue(Color.GREEN in Color)
2675 self.assertTrue(Open.RW in Open)
2676 self.assertFalse(Color.GREEN in Open)
2677 self.assertFalse(Open.RW in Color)
2678 with self.assertRaises(TypeError):
2679 'GREEN' in Color
2680 with self.assertRaises(TypeError):
2681 'RW' in Open
2682 with self.assertRaises(TypeError):
2683 2 in Color
2684 with self.assertRaises(TypeError):
2685 2 in Open
2686
2687 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002688 Perm = self.Perm
2689 R, W, X = Perm
2690 RW = R | W
2691 RX = R | X
2692 WX = W | X
2693 RWX = R | W | X
2694 self.assertTrue(R in RW)
2695 self.assertTrue(R in RX)
2696 self.assertTrue(R in RWX)
2697 self.assertTrue(W in RW)
2698 self.assertTrue(W in WX)
2699 self.assertTrue(W in RWX)
2700 self.assertTrue(X in RX)
2701 self.assertTrue(X in WX)
2702 self.assertTrue(X in RWX)
2703 self.assertFalse(R in WX)
2704 self.assertFalse(W in RX)
2705 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302706 with self.assertRaises(TypeError):
2707 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002708
Ethan Furman25d94bb2016-09-02 16:32:32 -07002709 def test_bool(self):
2710 Perm = self.Perm
2711 for f in Perm:
2712 self.assertTrue(f)
2713 Open = self.Open
2714 for f in Open:
2715 self.assertEqual(bool(f.value), bool(f))
2716
Ethan Furman5bdab642018-09-21 19:03:09 -07002717 def test_multiple_mixin(self):
2718 class AllMixin:
2719 @classproperty
2720 def ALL(cls):
2721 members = list(cls)
2722 all_value = None
2723 if members:
2724 all_value = members[0]
2725 for member in members[1:]:
2726 all_value |= member
2727 cls.ALL = all_value
2728 return all_value
2729 class StrMixin:
2730 def __str__(self):
2731 return self._name_.lower()
2732 class Color(AllMixin, IntFlag):
2733 RED = auto()
2734 GREEN = auto()
2735 BLUE = auto()
2736 self.assertEqual(Color.RED.value, 1)
2737 self.assertEqual(Color.GREEN.value, 2)
2738 self.assertEqual(Color.BLUE.value, 4)
2739 self.assertEqual(Color.ALL.value, 7)
2740 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2741 class Color(AllMixin, StrMixin, IntFlag):
2742 RED = auto()
2743 GREEN = auto()
2744 BLUE = auto()
2745 self.assertEqual(Color.RED.value, 1)
2746 self.assertEqual(Color.GREEN.value, 2)
2747 self.assertEqual(Color.BLUE.value, 4)
2748 self.assertEqual(Color.ALL.value, 7)
2749 self.assertEqual(str(Color.BLUE), 'blue')
2750 class Color(StrMixin, AllMixin, IntFlag):
2751 RED = auto()
2752 GREEN = auto()
2753 BLUE = auto()
2754 self.assertEqual(Color.RED.value, 1)
2755 self.assertEqual(Color.GREEN.value, 2)
2756 self.assertEqual(Color.BLUE.value, 4)
2757 self.assertEqual(Color.ALL.value, 7)
2758 self.assertEqual(str(Color.BLUE), 'blue')
2759
Hai Shie80697d2020-05-28 06:10:27 +08002760 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002761 def test_unique_composite(self):
2762 # override __eq__ to be identity only
2763 class TestFlag(IntFlag):
2764 one = auto()
2765 two = auto()
2766 three = auto()
2767 four = auto()
2768 five = auto()
2769 six = auto()
2770 seven = auto()
2771 eight = auto()
2772 def __eq__(self, other):
2773 return self is other
2774 def __hash__(self):
2775 return hash(self._value_)
2776 # have multiple threads competing to complete the composite members
2777 seen = set()
2778 failed = False
2779 def cycle_enum():
2780 nonlocal failed
2781 try:
2782 for i in range(256):
2783 seen.add(TestFlag(i))
2784 except Exception:
2785 failed = True
2786 threads = [
2787 threading.Thread(target=cycle_enum)
2788 for _ in range(8)
2789 ]
Hai Shie80697d2020-05-28 06:10:27 +08002790 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002791 pass
2792 # check that only 248 members were created
2793 self.assertFalse(
2794 failed,
2795 'at least one thread failed while creating composite members')
2796 self.assertEqual(256, len(seen), 'too many composite members created')
2797
2798
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002799class TestEmptyAndNonLatinStrings(unittest.TestCase):
2800
2801 def test_empty_string(self):
2802 with self.assertRaises(ValueError):
2803 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2804
2805 def test_non_latin_character_string(self):
2806 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2807 item = getattr(greek_abc, '\u03B1')
2808 self.assertEqual(item.value, 1)
2809
2810 def test_non_latin_number_string(self):
2811 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2812 item = getattr(hebrew_123, '\u05D0')
2813 self.assertEqual(item.value, 1)
2814
2815
Ethan Furmanf24bb352013-07-18 17:05:39 -07002816class TestUnique(unittest.TestCase):
2817
2818 def test_unique_clean(self):
2819 @unique
2820 class Clean(Enum):
2821 one = 1
2822 two = 'dos'
2823 tres = 4.0
2824 @unique
2825 class Cleaner(IntEnum):
2826 single = 1
2827 double = 2
2828 triple = 3
2829
2830 def test_unique_dirty(self):
2831 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2832 @unique
2833 class Dirty(Enum):
2834 one = 1
2835 two = 'dos'
2836 tres = 1
2837 with self.assertRaisesRegex(
2838 ValueError,
2839 'double.*single.*turkey.*triple',
2840 ):
2841 @unique
2842 class Dirtier(IntEnum):
2843 single = 1
2844 double = 1
2845 triple = 3
2846 turkey = 3
2847
Ethan Furman3803ad42016-05-01 10:03:53 -07002848 def test_unique_with_name(self):
2849 @unique
2850 class Silly(Enum):
2851 one = 1
2852 two = 'dos'
2853 name = 3
2854 @unique
2855 class Sillier(IntEnum):
2856 single = 1
2857 name = 2
2858 triple = 3
2859 value = 4
2860
Ethan Furmanf24bb352013-07-18 17:05:39 -07002861
Ethan Furman5bdab642018-09-21 19:03:09 -07002862
Ethan Furman3323da92015-04-11 09:39:59 -07002863expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002864Help on class Color in module %s:
2865
2866class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002867 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2868 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002869 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002870 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002871 | Method resolution order:
2872 | Color
2873 | enum.Enum
2874 | builtins.object
2875 |\x20\x20
2876 | Data and other attributes defined here:
2877 |\x20\x20
2878 | blue = <Color.blue: 3>
2879 |\x20\x20
2880 | green = <Color.green: 2>
2881 |\x20\x20
2882 | red = <Color.red: 1>
2883 |\x20\x20
2884 | ----------------------------------------------------------------------
2885 | Data descriptors inherited from enum.Enum:
2886 |\x20\x20
2887 | name
2888 | The name of the Enum member.
2889 |\x20\x20
2890 | value
2891 | The value of the Enum member.
2892 |\x20\x20
2893 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002894 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002895 |\x20\x20
2896 | __members__
2897 | Returns a mapping of member name->value.
2898 |\x20\x20\x20\x20\x20\x20
2899 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002900 | is a read-only view of the internal mapping."""
2901
2902expected_help_output_without_docs = """\
2903Help on class Color in module %s:
2904
2905class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002906 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2907 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002908 | Method resolution order:
2909 | Color
2910 | enum.Enum
2911 | builtins.object
2912 |\x20\x20
2913 | Data and other attributes defined here:
2914 |\x20\x20
2915 | blue = <Color.blue: 3>
2916 |\x20\x20
2917 | green = <Color.green: 2>
2918 |\x20\x20
2919 | red = <Color.red: 1>
2920 |\x20\x20
2921 | ----------------------------------------------------------------------
2922 | Data descriptors inherited from enum.Enum:
2923 |\x20\x20
2924 | name
2925 |\x20\x20
2926 | value
2927 |\x20\x20
2928 | ----------------------------------------------------------------------
2929 | Data descriptors inherited from enum.EnumMeta:
2930 |\x20\x20
2931 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002932
2933class TestStdLib(unittest.TestCase):
2934
Ethan Furman48a724f2015-04-11 23:23:06 -07002935 maxDiff = None
2936
Ethan Furman5875d742013-10-21 20:45:55 -07002937 class Color(Enum):
2938 red = 1
2939 green = 2
2940 blue = 3
2941
2942 def test_pydoc(self):
2943 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002944 if StrEnum.__doc__ is None:
2945 expected_text = expected_help_output_without_docs % __name__
2946 else:
2947 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002948 output = StringIO()
2949 helper = pydoc.Helper(output=output)
2950 helper(self.Color)
2951 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002952 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002953
2954 def test_inspect_getmembers(self):
2955 values = dict((
2956 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002957 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002958 ('__members__', self.Color.__members__),
2959 ('__module__', __name__),
2960 ('blue', self.Color.blue),
2961 ('green', self.Color.green),
2962 ('name', Enum.__dict__['name']),
2963 ('red', self.Color.red),
2964 ('value', Enum.__dict__['value']),
2965 ))
2966 result = dict(inspect.getmembers(self.Color))
2967 self.assertEqual(values.keys(), result.keys())
2968 failed = False
2969 for k in values.keys():
2970 if result[k] != values[k]:
2971 print()
2972 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2973 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2974 failed = True
2975 if failed:
2976 self.fail("result does not equal expected, see print above")
2977
2978 def test_inspect_classify_class_attrs(self):
2979 # indirectly test __objclass__
2980 from inspect import Attribute
2981 values = [
2982 Attribute(name='__class__', kind='data',
2983 defining_class=object, object=EnumMeta),
2984 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002985 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002986 Attribute(name='__members__', kind='property',
2987 defining_class=EnumMeta, object=EnumMeta.__members__),
2988 Attribute(name='__module__', kind='data',
2989 defining_class=self.Color, object=__name__),
2990 Attribute(name='blue', kind='data',
2991 defining_class=self.Color, object=self.Color.blue),
2992 Attribute(name='green', kind='data',
2993 defining_class=self.Color, object=self.Color.green),
2994 Attribute(name='red', kind='data',
2995 defining_class=self.Color, object=self.Color.red),
2996 Attribute(name='name', kind='data',
2997 defining_class=Enum, object=Enum.__dict__['name']),
2998 Attribute(name='value', kind='data',
2999 defining_class=Enum, object=Enum.__dict__['value']),
3000 ]
3001 values.sort(key=lambda item: item.name)
3002 result = list(inspect.classify_class_attrs(self.Color))
3003 result.sort(key=lambda item: item.name)
3004 failed = False
3005 for v, r in zip(values, result):
3006 if r != v:
3007 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3008 failed = True
3009 if failed:
3010 self.fail("result does not equal expected, see print above")
3011
Martin Panter19e69c52015-11-14 12:46:42 +00003012
3013class MiscTestCase(unittest.TestCase):
3014 def test__all__(self):
3015 support.check__all__(self, enum)
3016
3017
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003018# These are unordered here on purpose to ensure that declaration order
3019# makes no difference.
3020CONVERT_TEST_NAME_D = 5
3021CONVERT_TEST_NAME_C = 5
3022CONVERT_TEST_NAME_B = 5
3023CONVERT_TEST_NAME_A = 5 # This one should sort first.
3024CONVERT_TEST_NAME_E = 5
3025CONVERT_TEST_NAME_F = 5
3026
3027class TestIntEnumConvert(unittest.TestCase):
3028 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003029 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003030 'UnittestConvert',
3031 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003032 filter=lambda x: x.startswith('CONVERT_TEST_'))
3033 # We don't want the reverse lookup value to vary when there are
3034 # multiple possible names for a given value. It should always
3035 # report the first lexigraphical name in that case.
3036 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3037
3038 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003039 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003040 'UnittestConvert',
3041 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003042 filter=lambda x: x.startswith('CONVERT_TEST_'))
3043 # Ensure that test_type has all of the desired names and values.
3044 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3045 test_type.CONVERT_TEST_NAME_A)
3046 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3047 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3048 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3049 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3050 # Ensure that test_type only picked up names matching the filter.
3051 self.assertEqual([name for name in dir(test_type)
3052 if name[0:2] not in ('CO', '__')],
3053 [], msg='Names other than CONVERT_TEST_* found.')
3054
orlnub1230fb9fad2018-09-12 20:28:53 +03003055 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3056 '_convert was deprecated in 3.8')
3057 def test_convert_warn(self):
3058 with self.assertWarns(DeprecationWarning):
3059 enum.IntEnum._convert(
3060 'UnittestConvert',
3061 ('test.test_enum', '__main__')[__name__=='__main__'],
3062 filter=lambda x: x.startswith('CONVERT_TEST_'))
3063
3064 @unittest.skipUnless(sys.version_info >= (3, 9),
3065 '_convert was removed in 3.9')
3066 def test_convert_raise(self):
3067 with self.assertRaises(AttributeError):
3068 enum.IntEnum._convert(
3069 'UnittestConvert',
3070 ('test.test_enum', '__main__')[__name__=='__main__'],
3071 filter=lambda x: x.startswith('CONVERT_TEST_'))
3072
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003073
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003074if __name__ == '__main__':
3075 unittest.main()