blob: e7bad62406773174231c80c7e21aa78cbecfd16c [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
422
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700423 def test_enum_with_value_name(self):
424 class Huh(Enum):
425 name = 1
426 value = 2
427 self.assertEqual(
428 list(Huh),
429 [Huh.name, Huh.value],
430 )
431 self.assertIs(type(Huh.name), Huh)
432 self.assertEqual(Huh.name.name, 'name')
433 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700434
435 def test_format_enum(self):
436 Season = self.Season
437 self.assertEqual('{}'.format(Season.SPRING),
438 '{}'.format(str(Season.SPRING)))
439 self.assertEqual( '{:}'.format(Season.SPRING),
440 '{:}'.format(str(Season.SPRING)))
441 self.assertEqual('{:20}'.format(Season.SPRING),
442 '{:20}'.format(str(Season.SPRING)))
443 self.assertEqual('{:^20}'.format(Season.SPRING),
444 '{:^20}'.format(str(Season.SPRING)))
445 self.assertEqual('{:>20}'.format(Season.SPRING),
446 '{:>20}'.format(str(Season.SPRING)))
447 self.assertEqual('{:<20}'.format(Season.SPRING),
448 '{:<20}'.format(str(Season.SPRING)))
449
thatneat2f19e822019-07-04 11:28:37 -0700450 def test_str_override_enum(self):
451 class EnumWithStrOverrides(Enum):
452 one = auto()
453 two = auto()
454
455 def __str__(self):
456 return 'Str!'
457 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
458 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
459
460 def test_format_override_enum(self):
461 class EnumWithFormatOverride(Enum):
462 one = 1.0
463 two = 2.0
464 def __format__(self, spec):
465 return 'Format!!'
466 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
467 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
468
469 def test_str_and_format_override_enum(self):
470 class EnumWithStrFormatOverrides(Enum):
471 one = auto()
472 two = auto()
473 def __str__(self):
474 return 'Str!'
475 def __format__(self, spec):
476 return 'Format!'
477 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
478 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
479
480 def test_str_override_mixin(self):
481 class MixinEnumWithStrOverride(float, Enum):
482 one = 1.0
483 two = 2.0
484 def __str__(self):
485 return 'Overridden!'
486 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
487 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
488
489 def test_str_and_format_override_mixin(self):
490 class MixinWithStrFormatOverrides(float, Enum):
491 one = 1.0
492 two = 2.0
493 def __str__(self):
494 return 'Str!'
495 def __format__(self, spec):
496 return 'Format!'
497 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
498 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
499
500 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700501 class TestFloat(float, Enum):
502 one = 1.0
503 two = 2.0
504 def __format__(self, spec):
505 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700506 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700507 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
508
509 def assertFormatIsValue(self, spec, member):
510 self.assertEqual(spec.format(member), spec.format(member.value))
511
512 def test_format_enum_date(self):
513 Holiday = self.Holiday
514 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
515 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
516 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
517 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
518 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
519 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
520 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
521 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
522
523 def test_format_enum_float(self):
524 Konstants = self.Konstants
525 self.assertFormatIsValue('{}', Konstants.TAU)
526 self.assertFormatIsValue('{:}', Konstants.TAU)
527 self.assertFormatIsValue('{:20}', Konstants.TAU)
528 self.assertFormatIsValue('{:^20}', Konstants.TAU)
529 self.assertFormatIsValue('{:>20}', Konstants.TAU)
530 self.assertFormatIsValue('{:<20}', Konstants.TAU)
531 self.assertFormatIsValue('{:n}', Konstants.TAU)
532 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
533 self.assertFormatIsValue('{:f}', Konstants.TAU)
534
535 def test_format_enum_int(self):
536 Grades = self.Grades
537 self.assertFormatIsValue('{}', Grades.C)
538 self.assertFormatIsValue('{:}', Grades.C)
539 self.assertFormatIsValue('{:20}', Grades.C)
540 self.assertFormatIsValue('{:^20}', Grades.C)
541 self.assertFormatIsValue('{:>20}', Grades.C)
542 self.assertFormatIsValue('{:<20}', Grades.C)
543 self.assertFormatIsValue('{:+}', Grades.C)
544 self.assertFormatIsValue('{:08X}', Grades.C)
545 self.assertFormatIsValue('{:b}', Grades.C)
546
547 def test_format_enum_str(self):
548 Directional = self.Directional
549 self.assertFormatIsValue('{}', Directional.WEST)
550 self.assertFormatIsValue('{:}', Directional.WEST)
551 self.assertFormatIsValue('{:20}', Directional.WEST)
552 self.assertFormatIsValue('{:^20}', Directional.WEST)
553 self.assertFormatIsValue('{:>20}', Directional.WEST)
554 self.assertFormatIsValue('{:<20}', Directional.WEST)
555
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700556 def test_hash(self):
557 Season = self.Season
558 dates = {}
559 dates[Season.WINTER] = '1225'
560 dates[Season.SPRING] = '0315'
561 dates[Season.SUMMER] = '0704'
562 dates[Season.AUTUMN] = '1031'
563 self.assertEqual(dates[Season.AUTUMN], '1031')
564
565 def test_intenum_from_scratch(self):
566 class phy(int, Enum):
567 pi = 3
568 tau = 2 * pi
569 self.assertTrue(phy.pi < phy.tau)
570
571 def test_intenum_inherited(self):
572 class IntEnum(int, Enum):
573 pass
574 class phy(IntEnum):
575 pi = 3
576 tau = 2 * pi
577 self.assertTrue(phy.pi < phy.tau)
578
579 def test_floatenum_from_scratch(self):
580 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700581 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700582 tau = 2 * pi
583 self.assertTrue(phy.pi < phy.tau)
584
585 def test_floatenum_inherited(self):
586 class FloatEnum(float, Enum):
587 pass
588 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700589 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700590 tau = 2 * pi
591 self.assertTrue(phy.pi < phy.tau)
592
593 def test_strenum_from_scratch(self):
594 class phy(str, Enum):
595 pi = 'Pi'
596 tau = 'Tau'
597 self.assertTrue(phy.pi < phy.tau)
598
599 def test_strenum_inherited(self):
600 class StrEnum(str, Enum):
601 pass
602 class phy(StrEnum):
603 pi = 'Pi'
604 tau = 'Tau'
605 self.assertTrue(phy.pi < phy.tau)
606
607
608 def test_intenum(self):
609 class WeekDay(IntEnum):
610 SUNDAY = 1
611 MONDAY = 2
612 TUESDAY = 3
613 WEDNESDAY = 4
614 THURSDAY = 5
615 FRIDAY = 6
616 SATURDAY = 7
617
618 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
619 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
620
621 lst = list(WeekDay)
622 self.assertEqual(len(lst), len(WeekDay))
623 self.assertEqual(len(WeekDay), 7)
624 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
625 target = target.split()
626 for i, weekday in enumerate(target, 1):
627 e = WeekDay(i)
628 self.assertEqual(e, i)
629 self.assertEqual(int(e), i)
630 self.assertEqual(e.name, weekday)
631 self.assertIn(e, WeekDay)
632 self.assertEqual(lst.index(e)+1, i)
633 self.assertTrue(0 < e < 8)
634 self.assertIs(type(e), WeekDay)
635 self.assertIsInstance(e, int)
636 self.assertIsInstance(e, Enum)
637
638 def test_intenum_duplicates(self):
639 class WeekDay(IntEnum):
640 SUNDAY = 1
641 MONDAY = 2
642 TUESDAY = TEUSDAY = 3
643 WEDNESDAY = 4
644 THURSDAY = 5
645 FRIDAY = 6
646 SATURDAY = 7
647 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
648 self.assertEqual(WeekDay(3).name, 'TUESDAY')
649 self.assertEqual([k for k,v in WeekDay.__members__.items()
650 if v.name != k], ['TEUSDAY', ])
651
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300652 def test_intenum_from_bytes(self):
653 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
654 with self.assertRaises(ValueError):
655 IntStooges.from_bytes(b'\x00\x05', 'big')
656
657 def test_floatenum_fromhex(self):
658 h = float.hex(FloatStooges.MOE.value)
659 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
660 h = float.hex(FloatStooges.MOE.value + 0.01)
661 with self.assertRaises(ValueError):
662 FloatStooges.fromhex(h)
663
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700664 def test_pickle_enum(self):
665 if isinstance(Stooges, Exception):
666 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800667 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
668 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700669
670 def test_pickle_int(self):
671 if isinstance(IntStooges, Exception):
672 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800673 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
674 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700675
676 def test_pickle_float(self):
677 if isinstance(FloatStooges, Exception):
678 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800679 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
680 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700681
682 def test_pickle_enum_function(self):
683 if isinstance(Answer, Exception):
684 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800685 test_pickle_dump_load(self.assertIs, Answer.him)
686 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700687
688 def test_pickle_enum_function_with_module(self):
689 if isinstance(Question, Exception):
690 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800691 test_pickle_dump_load(self.assertIs, Question.who)
692 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700693
Ethan Furmanca1b7942014-02-08 11:36:27 -0800694 def test_enum_function_with_qualname(self):
695 if isinstance(Theory, Exception):
696 raise Theory
697 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
698
699 def test_class_nested_enum_and_pickle_protocol_four(self):
700 # would normally just have this directly in the class namespace
701 class NestedEnum(Enum):
702 twigs = 'common'
703 shiny = 'rare'
704
705 self.__class__.NestedEnum = NestedEnum
706 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300707 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800708
Ethan Furman24e837f2015-03-18 17:27:57 -0700709 def test_pickle_by_name(self):
710 class ReplaceGlobalInt(IntEnum):
711 ONE = 1
712 TWO = 2
713 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
714 for proto in range(HIGHEST_PROTOCOL):
715 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
716
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700717 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800718 BadPickle = Enum(
719 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700720 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800721 # now break BadPickle to test exception raising
722 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800723 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
724 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700725
726 def test_string_enum(self):
727 class SkillLevel(str, Enum):
728 master = 'what is the sound of one hand clapping?'
729 journeyman = 'why did the chicken cross the road?'
730 apprentice = 'knock, knock!'
731 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
732
733 def test_getattr_getitem(self):
734 class Period(Enum):
735 morning = 1
736 noon = 2
737 evening = 3
738 night = 4
739 self.assertIs(Period(2), Period.noon)
740 self.assertIs(getattr(Period, 'night'), Period.night)
741 self.assertIs(Period['morning'], Period.morning)
742
743 def test_getattr_dunder(self):
744 Season = self.Season
745 self.assertTrue(getattr(Season, '__eq__'))
746
747 def test_iteration_order(self):
748 class Season(Enum):
749 SUMMER = 2
750 WINTER = 4
751 AUTUMN = 3
752 SPRING = 1
753 self.assertEqual(
754 list(Season),
755 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
756 )
757
Ethan Furman2131a4a2013-09-14 18:11:24 -0700758 def test_reversed_iteration_order(self):
759 self.assertEqual(
760 list(reversed(self.Season)),
761 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
762 self.Season.SPRING]
763 )
764
Martin Pantereb995702016-07-28 01:11:04 +0000765 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700766 SummerMonth = Enum('SummerMonth', 'june july august')
767 lst = list(SummerMonth)
768 self.assertEqual(len(lst), len(SummerMonth))
769 self.assertEqual(len(SummerMonth), 3, SummerMonth)
770 self.assertEqual(
771 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
772 lst,
773 )
774 for i, month in enumerate('june july august'.split(), 1):
775 e = SummerMonth(i)
776 self.assertEqual(int(e.value), i)
777 self.assertNotEqual(e, i)
778 self.assertEqual(e.name, month)
779 self.assertIn(e, SummerMonth)
780 self.assertIs(type(e), SummerMonth)
781
Martin Pantereb995702016-07-28 01:11:04 +0000782 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700783 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
784 lst = list(SummerMonth)
785 self.assertEqual(len(lst), len(SummerMonth))
786 self.assertEqual(len(SummerMonth), 3, SummerMonth)
787 self.assertEqual(
788 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
789 lst,
790 )
791 for i, month in enumerate('june july august'.split(), 10):
792 e = SummerMonth(i)
793 self.assertEqual(int(e.value), i)
794 self.assertNotEqual(e, i)
795 self.assertEqual(e.name, month)
796 self.assertIn(e, SummerMonth)
797 self.assertIs(type(e), SummerMonth)
798
Martin Pantereb995702016-07-28 01:11:04 +0000799 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700800 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
801 lst = list(SummerMonth)
802 self.assertEqual(len(lst), len(SummerMonth))
803 self.assertEqual(len(SummerMonth), 3, SummerMonth)
804 self.assertEqual(
805 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
806 lst,
807 )
808 for i, month in enumerate('june july august'.split(), 1):
809 e = SummerMonth(i)
810 self.assertEqual(int(e.value), i)
811 self.assertNotEqual(e, i)
812 self.assertEqual(e.name, month)
813 self.assertIn(e, SummerMonth)
814 self.assertIs(type(e), SummerMonth)
815
Martin Pantereb995702016-07-28 01:11:04 +0000816 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700817 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
818 lst = list(SummerMonth)
819 self.assertEqual(len(lst), len(SummerMonth))
820 self.assertEqual(len(SummerMonth), 3, SummerMonth)
821 self.assertEqual(
822 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
823 lst,
824 )
825 for i, month in enumerate('june july august'.split(), 20):
826 e = SummerMonth(i)
827 self.assertEqual(int(e.value), i)
828 self.assertNotEqual(e, i)
829 self.assertEqual(e.name, month)
830 self.assertIn(e, SummerMonth)
831 self.assertIs(type(e), SummerMonth)
832
Martin Pantereb995702016-07-28 01:11:04 +0000833 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700834 SummerMonth = Enum(
835 'SummerMonth',
836 (('june', 1), ('july', 2), ('august', 3))
837 )
838 lst = list(SummerMonth)
839 self.assertEqual(len(lst), len(SummerMonth))
840 self.assertEqual(len(SummerMonth), 3, SummerMonth)
841 self.assertEqual(
842 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
843 lst,
844 )
845 for i, month in enumerate('june july august'.split(), 1):
846 e = SummerMonth(i)
847 self.assertEqual(int(e.value), i)
848 self.assertNotEqual(e, i)
849 self.assertEqual(e.name, month)
850 self.assertIn(e, SummerMonth)
851 self.assertIs(type(e), SummerMonth)
852
Martin Pantereb995702016-07-28 01:11:04 +0000853 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700854 SummerMonth = Enum(
855 'SummerMonth',
856 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
857 )
858 lst = list(SummerMonth)
859 self.assertEqual(len(lst), len(SummerMonth))
860 self.assertEqual(len(SummerMonth), 3, SummerMonth)
861 self.assertEqual(
862 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
863 lst,
864 )
865 for i, month in enumerate('june july august'.split(), 1):
866 e = SummerMonth(i)
867 self.assertEqual(int(e.value), i)
868 self.assertNotEqual(e, i)
869 self.assertEqual(e.name, month)
870 self.assertIn(e, SummerMonth)
871 self.assertIs(type(e), SummerMonth)
872
Martin Pantereb995702016-07-28 01:11:04 +0000873 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700874 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
875 lst = list(SummerMonth)
876 self.assertEqual(len(lst), len(SummerMonth))
877 self.assertEqual(len(SummerMonth), 3, SummerMonth)
878 self.assertEqual(
879 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
880 lst,
881 )
882 for i, month in enumerate('june july august'.split(), 1):
883 e = SummerMonth(i)
884 self.assertEqual(e, i)
885 self.assertEqual(e.name, month)
886 self.assertIn(e, SummerMonth)
887 self.assertIs(type(e), SummerMonth)
888
Martin Pantereb995702016-07-28 01:11:04 +0000889 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700890 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
891 lst = list(SummerMonth)
892 self.assertEqual(len(lst), len(SummerMonth))
893 self.assertEqual(len(SummerMonth), 3, SummerMonth)
894 self.assertEqual(
895 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
896 lst,
897 )
898 for i, month in enumerate('june july august'.split(), 30):
899 e = SummerMonth(i)
900 self.assertEqual(e, i)
901 self.assertEqual(e.name, month)
902 self.assertIn(e, SummerMonth)
903 self.assertIs(type(e), SummerMonth)
904
Martin Pantereb995702016-07-28 01:11:04 +0000905 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700906 SummerMonth = IntEnum('SummerMonth', 'june july august')
907 lst = list(SummerMonth)
908 self.assertEqual(len(lst), len(SummerMonth))
909 self.assertEqual(len(SummerMonth), 3, SummerMonth)
910 self.assertEqual(
911 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
912 lst,
913 )
914 for i, month in enumerate('june july august'.split(), 1):
915 e = SummerMonth(i)
916 self.assertEqual(e, i)
917 self.assertEqual(e.name, month)
918 self.assertIn(e, SummerMonth)
919 self.assertIs(type(e), SummerMonth)
920
Martin Pantereb995702016-07-28 01:11:04 +0000921 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700922 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
923 lst = list(SummerMonth)
924 self.assertEqual(len(lst), len(SummerMonth))
925 self.assertEqual(len(SummerMonth), 3, SummerMonth)
926 self.assertEqual(
927 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
928 lst,
929 )
930 for i, month in enumerate('june july august'.split(), 40):
931 e = SummerMonth(i)
932 self.assertEqual(e, i)
933 self.assertEqual(e.name, month)
934 self.assertIn(e, SummerMonth)
935 self.assertIs(type(e), SummerMonth)
936
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700937 def test_subclassing(self):
938 if isinstance(Name, Exception):
939 raise Name
940 self.assertEqual(Name.BDFL, 'Guido van Rossum')
941 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
942 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800943 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700944
945 def test_extending(self):
946 class Color(Enum):
947 red = 1
948 green = 2
949 blue = 3
950 with self.assertRaises(TypeError):
951 class MoreColor(Color):
952 cyan = 4
953 magenta = 5
954 yellow = 6
955
956 def test_exclude_methods(self):
957 class whatever(Enum):
958 this = 'that'
959 these = 'those'
960 def really(self):
961 return 'no, not %s' % self.value
962 self.assertIsNot(type(whatever.really), whatever)
963 self.assertEqual(whatever.this.really(), 'no, not that')
964
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700965 def test_wrong_inheritance_order(self):
966 with self.assertRaises(TypeError):
967 class Wrong(Enum, str):
968 NotHere = 'error before this point'
969
970 def test_intenum_transitivity(self):
971 class number(IntEnum):
972 one = 1
973 two = 2
974 three = 3
975 class numero(IntEnum):
976 uno = 1
977 dos = 2
978 tres = 3
979 self.assertEqual(number.one, numero.uno)
980 self.assertEqual(number.two, numero.dos)
981 self.assertEqual(number.three, numero.tres)
982
983 def test_wrong_enum_in_call(self):
984 class Monochrome(Enum):
985 black = 0
986 white = 1
987 class Gender(Enum):
988 male = 0
989 female = 1
990 self.assertRaises(ValueError, Monochrome, Gender.male)
991
992 def test_wrong_enum_in_mixed_call(self):
993 class Monochrome(IntEnum):
994 black = 0
995 white = 1
996 class Gender(Enum):
997 male = 0
998 female = 1
999 self.assertRaises(ValueError, Monochrome, Gender.male)
1000
1001 def test_mixed_enum_in_call_1(self):
1002 class Monochrome(IntEnum):
1003 black = 0
1004 white = 1
1005 class Gender(IntEnum):
1006 male = 0
1007 female = 1
1008 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1009
1010 def test_mixed_enum_in_call_2(self):
1011 class Monochrome(Enum):
1012 black = 0
1013 white = 1
1014 class Gender(IntEnum):
1015 male = 0
1016 female = 1
1017 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1018
1019 def test_flufl_enum(self):
1020 class Fluflnum(Enum):
1021 def __int__(self):
1022 return int(self.value)
1023 class MailManOptions(Fluflnum):
1024 option1 = 1
1025 option2 = 2
1026 option3 = 3
1027 self.assertEqual(int(MailManOptions.option1), 1)
1028
Ethan Furman5e5a8232013-08-04 08:42:23 -07001029 def test_introspection(self):
1030 class Number(IntEnum):
1031 one = 100
1032 two = 200
1033 self.assertIs(Number.one._member_type_, int)
1034 self.assertIs(Number._member_type_, int)
1035 class String(str, Enum):
1036 yarn = 'soft'
1037 rope = 'rough'
1038 wire = 'hard'
1039 self.assertIs(String.yarn._member_type_, str)
1040 self.assertIs(String._member_type_, str)
1041 class Plain(Enum):
1042 vanilla = 'white'
1043 one = 1
1044 self.assertIs(Plain.vanilla._member_type_, object)
1045 self.assertIs(Plain._member_type_, object)
1046
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001047 def test_no_such_enum_member(self):
1048 class Color(Enum):
1049 red = 1
1050 green = 2
1051 blue = 3
1052 with self.assertRaises(ValueError):
1053 Color(4)
1054 with self.assertRaises(KeyError):
1055 Color['chartreuse']
1056
1057 def test_new_repr(self):
1058 class Color(Enum):
1059 red = 1
1060 green = 2
1061 blue = 3
1062 def __repr__(self):
1063 return "don't you just love shades of %s?" % self.name
1064 self.assertEqual(
1065 repr(Color.blue),
1066 "don't you just love shades of blue?",
1067 )
1068
1069 def test_inherited_repr(self):
1070 class MyEnum(Enum):
1071 def __repr__(self):
1072 return "My name is %s." % self.name
1073 class MyIntEnum(int, MyEnum):
1074 this = 1
1075 that = 2
1076 theother = 3
1077 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1078
1079 def test_multiple_mixin_mro(self):
1080 class auto_enum(type(Enum)):
1081 def __new__(metacls, cls, bases, classdict):
1082 temp = type(classdict)()
1083 names = set(classdict._member_names)
1084 i = 0
1085 for k in classdict._member_names:
1086 v = classdict[k]
1087 if v is Ellipsis:
1088 v = i
1089 else:
1090 i = v
1091 i += 1
1092 temp[k] = v
1093 for k, v in classdict.items():
1094 if k not in names:
1095 temp[k] = v
1096 return super(auto_enum, metacls).__new__(
1097 metacls, cls, bases, temp)
1098
1099 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1100 pass
1101
1102 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1103 pass
1104
1105 class TestAutoNumber(AutoNumberedEnum):
1106 a = ...
1107 b = 3
1108 c = ...
1109
1110 class TestAutoInt(AutoIntEnum):
1111 a = ...
1112 b = 3
1113 c = ...
1114
1115 def test_subclasses_with_getnewargs(self):
1116 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001117 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001118 def __new__(cls, *args):
1119 _args = args
1120 name, *args = args
1121 if len(args) == 0:
1122 raise TypeError("name and value must be specified")
1123 self = int.__new__(cls, *args)
1124 self._intname = name
1125 self._args = _args
1126 return self
1127 def __getnewargs__(self):
1128 return self._args
1129 @property
1130 def __name__(self):
1131 return self._intname
1132 def __repr__(self):
1133 # repr() is updated to include the name and type info
1134 return "{}({!r}, {})".format(type(self).__name__,
1135 self.__name__,
1136 int.__repr__(self))
1137 def __str__(self):
1138 # str() is unchanged, even if it relies on the repr() fallback
1139 base = int
1140 base_str = base.__str__
1141 if base_str.__objclass__ is object:
1142 return base.__repr__(self)
1143 return base_str(self)
1144 # for simplicity, we only define one operator that
1145 # propagates expressions
1146 def __add__(self, other):
1147 temp = int(self) + int( other)
1148 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1149 return NamedInt(
1150 '({0} + {1})'.format(self.__name__, other.__name__),
1151 temp )
1152 else:
1153 return temp
1154
1155 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001156 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001157 x = ('the-x', 1)
1158 y = ('the-y', 2)
1159
Ethan Furman2aa27322013-07-19 19:35:56 -07001160
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001161 self.assertIs(NEI.__new__, Enum.__new__)
1162 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1163 globals()['NamedInt'] = NamedInt
1164 globals()['NEI'] = NEI
1165 NI5 = NamedInt('test', 5)
1166 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001167 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001168 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001169 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001170 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001171
Ethan Furmanca1b7942014-02-08 11:36:27 -08001172 def test_subclasses_with_getnewargs_ex(self):
1173 class NamedInt(int):
1174 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1175 def __new__(cls, *args):
1176 _args = args
1177 name, *args = args
1178 if len(args) == 0:
1179 raise TypeError("name and value must be specified")
1180 self = int.__new__(cls, *args)
1181 self._intname = name
1182 self._args = _args
1183 return self
1184 def __getnewargs_ex__(self):
1185 return self._args, {}
1186 @property
1187 def __name__(self):
1188 return self._intname
1189 def __repr__(self):
1190 # repr() is updated to include the name and type info
1191 return "{}({!r}, {})".format(type(self).__name__,
1192 self.__name__,
1193 int.__repr__(self))
1194 def __str__(self):
1195 # str() is unchanged, even if it relies on the repr() fallback
1196 base = int
1197 base_str = base.__str__
1198 if base_str.__objclass__ is object:
1199 return base.__repr__(self)
1200 return base_str(self)
1201 # for simplicity, we only define one operator that
1202 # propagates expressions
1203 def __add__(self, other):
1204 temp = int(self) + int( other)
1205 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1206 return NamedInt(
1207 '({0} + {1})'.format(self.__name__, other.__name__),
1208 temp )
1209 else:
1210 return temp
1211
1212 class NEI(NamedInt, Enum):
1213 __qualname__ = 'NEI' # needed for pickle protocol 4
1214 x = ('the-x', 1)
1215 y = ('the-y', 2)
1216
1217
1218 self.assertIs(NEI.__new__, Enum.__new__)
1219 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1220 globals()['NamedInt'] = NamedInt
1221 globals()['NEI'] = NEI
1222 NI5 = NamedInt('test', 5)
1223 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001224 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001225 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001226 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001227 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001228
1229 def test_subclasses_with_reduce(self):
1230 class NamedInt(int):
1231 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1232 def __new__(cls, *args):
1233 _args = args
1234 name, *args = args
1235 if len(args) == 0:
1236 raise TypeError("name and value must be specified")
1237 self = int.__new__(cls, *args)
1238 self._intname = name
1239 self._args = _args
1240 return self
1241 def __reduce__(self):
1242 return self.__class__, self._args
1243 @property
1244 def __name__(self):
1245 return self._intname
1246 def __repr__(self):
1247 # repr() is updated to include the name and type info
1248 return "{}({!r}, {})".format(type(self).__name__,
1249 self.__name__,
1250 int.__repr__(self))
1251 def __str__(self):
1252 # str() is unchanged, even if it relies on the repr() fallback
1253 base = int
1254 base_str = base.__str__
1255 if base_str.__objclass__ is object:
1256 return base.__repr__(self)
1257 return base_str(self)
1258 # for simplicity, we only define one operator that
1259 # propagates expressions
1260 def __add__(self, other):
1261 temp = int(self) + int( other)
1262 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1263 return NamedInt(
1264 '({0} + {1})'.format(self.__name__, other.__name__),
1265 temp )
1266 else:
1267 return temp
1268
1269 class NEI(NamedInt, Enum):
1270 __qualname__ = 'NEI' # needed for pickle protocol 4
1271 x = ('the-x', 1)
1272 y = ('the-y', 2)
1273
1274
1275 self.assertIs(NEI.__new__, Enum.__new__)
1276 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1277 globals()['NamedInt'] = NamedInt
1278 globals()['NEI'] = NEI
1279 NI5 = NamedInt('test', 5)
1280 self.assertEqual(NI5, 5)
1281 test_pickle_dump_load(self.assertEqual, NI5, 5)
1282 self.assertEqual(NEI.y.value, 2)
1283 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001284 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001285
1286 def test_subclasses_with_reduce_ex(self):
1287 class NamedInt(int):
1288 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1289 def __new__(cls, *args):
1290 _args = args
1291 name, *args = args
1292 if len(args) == 0:
1293 raise TypeError("name and value must be specified")
1294 self = int.__new__(cls, *args)
1295 self._intname = name
1296 self._args = _args
1297 return self
1298 def __reduce_ex__(self, proto):
1299 return self.__class__, self._args
1300 @property
1301 def __name__(self):
1302 return self._intname
1303 def __repr__(self):
1304 # repr() is updated to include the name and type info
1305 return "{}({!r}, {})".format(type(self).__name__,
1306 self.__name__,
1307 int.__repr__(self))
1308 def __str__(self):
1309 # str() is unchanged, even if it relies on the repr() fallback
1310 base = int
1311 base_str = base.__str__
1312 if base_str.__objclass__ is object:
1313 return base.__repr__(self)
1314 return base_str(self)
1315 # for simplicity, we only define one operator that
1316 # propagates expressions
1317 def __add__(self, other):
1318 temp = int(self) + int( other)
1319 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1320 return NamedInt(
1321 '({0} + {1})'.format(self.__name__, other.__name__),
1322 temp )
1323 else:
1324 return temp
1325
1326 class NEI(NamedInt, Enum):
1327 __qualname__ = 'NEI' # needed for pickle protocol 4
1328 x = ('the-x', 1)
1329 y = ('the-y', 2)
1330
1331
1332 self.assertIs(NEI.__new__, Enum.__new__)
1333 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1334 globals()['NamedInt'] = NamedInt
1335 globals()['NEI'] = NEI
1336 NI5 = NamedInt('test', 5)
1337 self.assertEqual(NI5, 5)
1338 test_pickle_dump_load(self.assertEqual, NI5, 5)
1339 self.assertEqual(NEI.y.value, 2)
1340 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001341 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001342
Ethan Furmandc870522014-02-18 12:37:12 -08001343 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001344 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001345 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001346 def __new__(cls, *args):
1347 _args = args
1348 name, *args = args
1349 if len(args) == 0:
1350 raise TypeError("name and value must be specified")
1351 self = int.__new__(cls, *args)
1352 self._intname = name
1353 self._args = _args
1354 return self
1355 @property
1356 def __name__(self):
1357 return self._intname
1358 def __repr__(self):
1359 # repr() is updated to include the name and type info
1360 return "{}({!r}, {})".format(type(self).__name__,
1361 self.__name__,
1362 int.__repr__(self))
1363 def __str__(self):
1364 # str() is unchanged, even if it relies on the repr() fallback
1365 base = int
1366 base_str = base.__str__
1367 if base_str.__objclass__ is object:
1368 return base.__repr__(self)
1369 return base_str(self)
1370 # for simplicity, we only define one operator that
1371 # propagates expressions
1372 def __add__(self, other):
1373 temp = int(self) + int( other)
1374 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1375 return NamedInt(
1376 '({0} + {1})'.format(self.__name__, other.__name__),
1377 temp )
1378 else:
1379 return temp
1380
1381 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001382 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001383 x = ('the-x', 1)
1384 y = ('the-y', 2)
1385
1386 self.assertIs(NEI.__new__, Enum.__new__)
1387 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1388 globals()['NamedInt'] = NamedInt
1389 globals()['NEI'] = NEI
1390 NI5 = NamedInt('test', 5)
1391 self.assertEqual(NI5, 5)
1392 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001393 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1394 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001395
Ethan Furmandc870522014-02-18 12:37:12 -08001396 def test_subclasses_without_direct_pickle_support_using_name(self):
1397 class NamedInt(int):
1398 __qualname__ = 'NamedInt'
1399 def __new__(cls, *args):
1400 _args = args
1401 name, *args = args
1402 if len(args) == 0:
1403 raise TypeError("name and value must be specified")
1404 self = int.__new__(cls, *args)
1405 self._intname = name
1406 self._args = _args
1407 return self
1408 @property
1409 def __name__(self):
1410 return self._intname
1411 def __repr__(self):
1412 # repr() is updated to include the name and type info
1413 return "{}({!r}, {})".format(type(self).__name__,
1414 self.__name__,
1415 int.__repr__(self))
1416 def __str__(self):
1417 # str() is unchanged, even if it relies on the repr() fallback
1418 base = int
1419 base_str = base.__str__
1420 if base_str.__objclass__ is object:
1421 return base.__repr__(self)
1422 return base_str(self)
1423 # for simplicity, we only define one operator that
1424 # propagates expressions
1425 def __add__(self, other):
1426 temp = int(self) + int( other)
1427 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1428 return NamedInt(
1429 '({0} + {1})'.format(self.__name__, other.__name__),
1430 temp )
1431 else:
1432 return temp
1433
1434 class NEI(NamedInt, Enum):
1435 __qualname__ = 'NEI'
1436 x = ('the-x', 1)
1437 y = ('the-y', 2)
1438 def __reduce_ex__(self, proto):
1439 return getattr, (self.__class__, self._name_)
1440
1441 self.assertIs(NEI.__new__, Enum.__new__)
1442 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1443 globals()['NamedInt'] = NamedInt
1444 globals()['NEI'] = NEI
1445 NI5 = NamedInt('test', 5)
1446 self.assertEqual(NI5, 5)
1447 self.assertEqual(NEI.y.value, 2)
1448 test_pickle_dump_load(self.assertIs, NEI.y)
1449 test_pickle_dump_load(self.assertIs, NEI)
1450
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001451 def test_tuple_subclass(self):
1452 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001453 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001454 first = (1, 'for the money')
1455 second = (2, 'for the show')
1456 third = (3, 'for the music')
1457 self.assertIs(type(SomeTuple.first), SomeTuple)
1458 self.assertIsInstance(SomeTuple.second, tuple)
1459 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1460 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001461 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001462
1463 def test_duplicate_values_give_unique_enum_items(self):
1464 class AutoNumber(Enum):
1465 first = ()
1466 second = ()
1467 third = ()
1468 def __new__(cls):
1469 value = len(cls.__members__) + 1
1470 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001471 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001472 return obj
1473 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001474 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001475 self.assertEqual(
1476 list(AutoNumber),
1477 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1478 )
1479 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001480 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001481 self.assertIs(AutoNumber(1), AutoNumber.first)
1482
1483 def test_inherited_new_from_enhanced_enum(self):
1484 class AutoNumber(Enum):
1485 def __new__(cls):
1486 value = len(cls.__members__) + 1
1487 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001488 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001489 return obj
1490 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001491 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001492 class Color(AutoNumber):
1493 red = ()
1494 green = ()
1495 blue = ()
1496 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1497 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1498
1499 def test_inherited_new_from_mixed_enum(self):
1500 class AutoNumber(IntEnum):
1501 def __new__(cls):
1502 value = len(cls.__members__) + 1
1503 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001504 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001505 return obj
1506 class Color(AutoNumber):
1507 red = ()
1508 green = ()
1509 blue = ()
1510 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1511 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1512
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001513 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001514 class OrdinaryEnum(Enum):
1515 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001516 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1517 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001518
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001519 def test_ordered_mixin(self):
1520 class OrderedEnum(Enum):
1521 def __ge__(self, other):
1522 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001523 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001524 return NotImplemented
1525 def __gt__(self, other):
1526 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001527 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001528 return NotImplemented
1529 def __le__(self, other):
1530 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001531 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001532 return NotImplemented
1533 def __lt__(self, other):
1534 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001535 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001536 return NotImplemented
1537 class Grade(OrderedEnum):
1538 A = 5
1539 B = 4
1540 C = 3
1541 D = 2
1542 F = 1
1543 self.assertGreater(Grade.A, Grade.B)
1544 self.assertLessEqual(Grade.F, Grade.C)
1545 self.assertLess(Grade.D, Grade.A)
1546 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001547 self.assertEqual(Grade.B, Grade.B)
1548 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001549
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001550 def test_extending2(self):
1551 class Shade(Enum):
1552 def shade(self):
1553 print(self.name)
1554 class Color(Shade):
1555 red = 1
1556 green = 2
1557 blue = 3
1558 with self.assertRaises(TypeError):
1559 class MoreColor(Color):
1560 cyan = 4
1561 magenta = 5
1562 yellow = 6
1563
1564 def test_extending3(self):
1565 class Shade(Enum):
1566 def shade(self):
1567 return self.name
1568 class Color(Shade):
1569 def hex(self):
1570 return '%s hexlified!' % self.value
1571 class MoreColor(Color):
1572 cyan = 4
1573 magenta = 5
1574 yellow = 6
1575 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1576
orlnub1230fb9fad2018-09-12 20:28:53 +03001577 def test_subclass_duplicate_name(self):
1578 class Base(Enum):
1579 def test(self):
1580 pass
1581 class Test(Base):
1582 test = 1
1583 self.assertIs(type(Test.test), Test)
1584
1585 def test_subclass_duplicate_name_dynamic(self):
1586 from types import DynamicClassAttribute
1587 class Base(Enum):
1588 @DynamicClassAttribute
1589 def test(self):
1590 return 'dynamic'
1591 class Test(Base):
1592 test = 1
1593 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001594
1595 def test_no_duplicates(self):
1596 class UniqueEnum(Enum):
1597 def __init__(self, *args):
1598 cls = self.__class__
1599 if any(self.value == e.value for e in cls):
1600 a = self.name
1601 e = cls(self.value).name
1602 raise ValueError(
1603 "aliases not allowed in UniqueEnum: %r --> %r"
1604 % (a, e)
1605 )
1606 class Color(UniqueEnum):
1607 red = 1
1608 green = 2
1609 blue = 3
1610 with self.assertRaises(ValueError):
1611 class Color(UniqueEnum):
1612 red = 1
1613 green = 2
1614 blue = 3
1615 grene = 2
1616
1617 def test_init(self):
1618 class Planet(Enum):
1619 MERCURY = (3.303e+23, 2.4397e6)
1620 VENUS = (4.869e+24, 6.0518e6)
1621 EARTH = (5.976e+24, 6.37814e6)
1622 MARS = (6.421e+23, 3.3972e6)
1623 JUPITER = (1.9e+27, 7.1492e7)
1624 SATURN = (5.688e+26, 6.0268e7)
1625 URANUS = (8.686e+25, 2.5559e7)
1626 NEPTUNE = (1.024e+26, 2.4746e7)
1627 def __init__(self, mass, radius):
1628 self.mass = mass # in kilograms
1629 self.radius = radius # in meters
1630 @property
1631 def surface_gravity(self):
1632 # universal gravitational constant (m3 kg-1 s-2)
1633 G = 6.67300E-11
1634 return G * self.mass / (self.radius * self.radius)
1635 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1636 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1637
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001638 def test_ignore(self):
1639 class Period(timedelta, Enum):
1640 '''
1641 different lengths of time
1642 '''
1643 def __new__(cls, value, period):
1644 obj = timedelta.__new__(cls, value)
1645 obj._value_ = value
1646 obj.period = period
1647 return obj
1648 _ignore_ = 'Period i'
1649 Period = vars()
1650 for i in range(13):
1651 Period['month_%d' % i] = i*30, 'month'
1652 for i in range(53):
1653 Period['week_%d' % i] = i*7, 'week'
1654 for i in range(32):
1655 Period['day_%d' % i] = i, 'day'
1656 OneDay = day_1
1657 OneWeek = week_1
1658 OneMonth = month_1
1659 self.assertFalse(hasattr(Period, '_ignore_'))
1660 self.assertFalse(hasattr(Period, 'Period'))
1661 self.assertFalse(hasattr(Period, 'i'))
1662 self.assertTrue(isinstance(Period.day_1, timedelta))
1663 self.assertTrue(Period.month_1 is Period.day_30)
1664 self.assertTrue(Period.week_4 is Period.day_28)
1665
Ethan Furman2aa27322013-07-19 19:35:56 -07001666 def test_nonhash_value(self):
1667 class AutoNumberInAList(Enum):
1668 def __new__(cls):
1669 value = [len(cls.__members__) + 1]
1670 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001671 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001672 return obj
1673 class ColorInAList(AutoNumberInAList):
1674 red = ()
1675 green = ()
1676 blue = ()
1677 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001678 for enum, value in zip(ColorInAList, range(3)):
1679 value += 1
1680 self.assertEqual(enum.value, [value])
1681 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001682
Ethan Furmanb41803e2013-07-25 13:50:45 -07001683 def test_conflicting_types_resolved_in_new(self):
1684 class LabelledIntEnum(int, Enum):
1685 def __new__(cls, *args):
1686 value, label = args
1687 obj = int.__new__(cls, value)
1688 obj.label = label
1689 obj._value_ = value
1690 return obj
1691
1692 class LabelledList(LabelledIntEnum):
1693 unprocessed = (1, "Unprocessed")
1694 payment_complete = (2, "Payment Complete")
1695
1696 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1697 self.assertEqual(LabelledList.unprocessed, 1)
1698 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001699
Ethan Furmanc16595e2016-09-10 23:36:59 -07001700 def test_auto_number(self):
1701 class Color(Enum):
1702 red = auto()
1703 blue = auto()
1704 green = auto()
1705
1706 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1707 self.assertEqual(Color.red.value, 1)
1708 self.assertEqual(Color.blue.value, 2)
1709 self.assertEqual(Color.green.value, 3)
1710
1711 def test_auto_name(self):
1712 class Color(Enum):
1713 def _generate_next_value_(name, start, count, last):
1714 return name
1715 red = auto()
1716 blue = auto()
1717 green = auto()
1718
1719 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1720 self.assertEqual(Color.red.value, 'red')
1721 self.assertEqual(Color.blue.value, 'blue')
1722 self.assertEqual(Color.green.value, 'green')
1723
1724 def test_auto_name_inherit(self):
1725 class AutoNameEnum(Enum):
1726 def _generate_next_value_(name, start, count, last):
1727 return name
1728 class Color(AutoNameEnum):
1729 red = auto()
1730 blue = auto()
1731 green = auto()
1732
1733 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1734 self.assertEqual(Color.red.value, 'red')
1735 self.assertEqual(Color.blue.value, 'blue')
1736 self.assertEqual(Color.green.value, 'green')
1737
1738 def test_auto_garbage(self):
1739 class Color(Enum):
1740 red = 'red'
1741 blue = auto()
1742 self.assertEqual(Color.blue.value, 1)
1743
1744 def test_auto_garbage_corrected(self):
1745 class Color(Enum):
1746 red = 'red'
1747 blue = 2
1748 green = auto()
1749
1750 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1751 self.assertEqual(Color.red.value, 'red')
1752 self.assertEqual(Color.blue.value, 2)
1753 self.assertEqual(Color.green.value, 3)
1754
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001755 def test_auto_order(self):
1756 with self.assertRaises(TypeError):
1757 class Color(Enum):
1758 red = auto()
1759 green = auto()
1760 blue = auto()
1761 def _generate_next_value_(name, start, count, last):
1762 return name
1763
1764
Ethan Furman3515dcc2016-09-18 13:15:41 -07001765 def test_duplicate_auto(self):
1766 class Dupes(Enum):
1767 first = primero = auto()
1768 second = auto()
1769 third = auto()
1770 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1771
Ethan Furman019f0a02018-09-12 11:43:34 -07001772 def test_missing(self):
1773 class Color(Enum):
1774 red = 1
1775 green = 2
1776 blue = 3
1777 @classmethod
1778 def _missing_(cls, item):
1779 if item == 'three':
1780 return cls.blue
1781 elif item == 'bad return':
1782 # trigger internal error
1783 return 5
1784 elif item == 'error out':
1785 raise ZeroDivisionError
1786 else:
1787 # trigger not found
1788 return None
1789 self.assertIs(Color('three'), Color.blue)
1790 self.assertRaises(ValueError, Color, 7)
1791 try:
1792 Color('bad return')
1793 except TypeError as exc:
1794 self.assertTrue(isinstance(exc.__context__, ValueError))
1795 else:
1796 raise Exception('Exception not raised.')
1797 try:
1798 Color('error out')
1799 except ZeroDivisionError as exc:
1800 self.assertTrue(isinstance(exc.__context__, ValueError))
1801 else:
1802 raise Exception('Exception not raised.')
1803
Ethan Furman5bdab642018-09-21 19:03:09 -07001804 def test_multiple_mixin(self):
1805 class MaxMixin:
1806 @classproperty
1807 def MAX(cls):
1808 max = len(cls)
1809 cls.MAX = max
1810 return max
1811 class StrMixin:
1812 def __str__(self):
1813 return self._name_.lower()
1814 class SomeEnum(Enum):
1815 def behavior(self):
1816 return 'booyah'
1817 class AnotherEnum(Enum):
1818 def behavior(self):
1819 return 'nuhuh!'
1820 def social(self):
1821 return "what's up?"
1822 class Color(MaxMixin, Enum):
1823 RED = auto()
1824 GREEN = auto()
1825 BLUE = auto()
1826 self.assertEqual(Color.RED.value, 1)
1827 self.assertEqual(Color.GREEN.value, 2)
1828 self.assertEqual(Color.BLUE.value, 3)
1829 self.assertEqual(Color.MAX, 3)
1830 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1831 class Color(MaxMixin, StrMixin, Enum):
1832 RED = auto()
1833 GREEN = auto()
1834 BLUE = auto()
1835 self.assertEqual(Color.RED.value, 1)
1836 self.assertEqual(Color.GREEN.value, 2)
1837 self.assertEqual(Color.BLUE.value, 3)
1838 self.assertEqual(Color.MAX, 3)
1839 self.assertEqual(str(Color.BLUE), 'blue')
1840 class Color(StrMixin, MaxMixin, Enum):
1841 RED = auto()
1842 GREEN = auto()
1843 BLUE = auto()
1844 self.assertEqual(Color.RED.value, 1)
1845 self.assertEqual(Color.GREEN.value, 2)
1846 self.assertEqual(Color.BLUE.value, 3)
1847 self.assertEqual(Color.MAX, 3)
1848 self.assertEqual(str(Color.BLUE), 'blue')
1849 class CoolColor(StrMixin, SomeEnum, Enum):
1850 RED = auto()
1851 GREEN = auto()
1852 BLUE = auto()
1853 self.assertEqual(CoolColor.RED.value, 1)
1854 self.assertEqual(CoolColor.GREEN.value, 2)
1855 self.assertEqual(CoolColor.BLUE.value, 3)
1856 self.assertEqual(str(CoolColor.BLUE), 'blue')
1857 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1858 class CoolerColor(StrMixin, AnotherEnum, Enum):
1859 RED = auto()
1860 GREEN = auto()
1861 BLUE = auto()
1862 self.assertEqual(CoolerColor.RED.value, 1)
1863 self.assertEqual(CoolerColor.GREEN.value, 2)
1864 self.assertEqual(CoolerColor.BLUE.value, 3)
1865 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1866 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1867 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1868 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1869 RED = auto()
1870 GREEN = auto()
1871 BLUE = auto()
1872 self.assertEqual(CoolestColor.RED.value, 1)
1873 self.assertEqual(CoolestColor.GREEN.value, 2)
1874 self.assertEqual(CoolestColor.BLUE.value, 3)
1875 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1876 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1877 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1878 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1879 RED = auto()
1880 GREEN = auto()
1881 BLUE = auto()
1882 self.assertEqual(ConfusedColor.RED.value, 1)
1883 self.assertEqual(ConfusedColor.GREEN.value, 2)
1884 self.assertEqual(ConfusedColor.BLUE.value, 3)
1885 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1886 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1887 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1888 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1889 RED = auto()
1890 GREEN = auto()
1891 BLUE = auto()
1892 self.assertEqual(ReformedColor.RED.value, 1)
1893 self.assertEqual(ReformedColor.GREEN.value, 2)
1894 self.assertEqual(ReformedColor.BLUE.value, 3)
1895 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1896 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1897 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1898 self.assertTrue(issubclass(ReformedColor, int))
1899
Ethan Furmancd453852018-10-05 23:29:36 -07001900 def test_multiple_inherited_mixin(self):
1901 class StrEnum(str, Enum):
1902 def __new__(cls, *args, **kwargs):
1903 for a in args:
1904 if not isinstance(a, str):
1905 raise TypeError("Enumeration '%s' (%s) is not"
1906 " a string" % (a, type(a).__name__))
1907 return str.__new__(cls, *args, **kwargs)
1908 @unique
1909 class Decision1(StrEnum):
1910 REVERT = "REVERT"
1911 REVERT_ALL = "REVERT_ALL"
1912 RETRY = "RETRY"
1913 class MyEnum(StrEnum):
1914 pass
1915 @unique
1916 class Decision2(MyEnum):
1917 REVERT = "REVERT"
1918 REVERT_ALL = "REVERT_ALL"
1919 RETRY = "RETRY"
1920
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001921 def test_empty_globals(self):
1922 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1923 # when using compile and exec because f_globals is empty
1924 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1925 code = compile(code, "<string>", "exec")
1926 global_ns = {}
1927 local_ls = {}
1928 exec(code, global_ns, local_ls)
1929
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001930
Ethan Furmane8e61272016-08-20 07:19:31 -07001931class TestOrder(unittest.TestCase):
1932
1933 def test_same_members(self):
1934 class Color(Enum):
1935 _order_ = 'red green blue'
1936 red = 1
1937 green = 2
1938 blue = 3
1939
1940 def test_same_members_with_aliases(self):
1941 class Color(Enum):
1942 _order_ = 'red green blue'
1943 red = 1
1944 green = 2
1945 blue = 3
1946 verde = green
1947
1948 def test_same_members_wrong_order(self):
1949 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1950 class Color(Enum):
1951 _order_ = 'red green blue'
1952 red = 1
1953 blue = 3
1954 green = 2
1955
1956 def test_order_has_extra_members(self):
1957 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1958 class Color(Enum):
1959 _order_ = 'red green blue purple'
1960 red = 1
1961 green = 2
1962 blue = 3
1963
1964 def test_order_has_extra_members_with_aliases(self):
1965 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1966 class Color(Enum):
1967 _order_ = 'red green blue purple'
1968 red = 1
1969 green = 2
1970 blue = 3
1971 verde = green
1972
1973 def test_enum_has_extra_members(self):
1974 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1975 class Color(Enum):
1976 _order_ = 'red green blue'
1977 red = 1
1978 green = 2
1979 blue = 3
1980 purple = 4
1981
1982 def test_enum_has_extra_members_with_aliases(self):
1983 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1984 class Color(Enum):
1985 _order_ = 'red green blue'
1986 red = 1
1987 green = 2
1988 blue = 3
1989 purple = 4
1990 verde = green
1991
1992
Ethan Furman65a5a472016-09-01 23:55:19 -07001993class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001994 """Tests of the Flags."""
1995
Ethan Furman65a5a472016-09-01 23:55:19 -07001996 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001997 R, W, X = 4, 2, 1
1998
Ethan Furman65a5a472016-09-01 23:55:19 -07001999 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002000 RO = 0
2001 WO = 1
2002 RW = 2
2003 AC = 3
2004 CE = 1<<19
2005
Rahul Jha94306522018-09-10 23:51:04 +05302006 class Color(Flag):
2007 BLACK = 0
2008 RED = 1
2009 GREEN = 2
2010 BLUE = 4
2011 PURPLE = RED|BLUE
2012
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002013 def test_str(self):
2014 Perm = self.Perm
2015 self.assertEqual(str(Perm.R), 'Perm.R')
2016 self.assertEqual(str(Perm.W), 'Perm.W')
2017 self.assertEqual(str(Perm.X), 'Perm.X')
2018 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2019 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2020 self.assertEqual(str(Perm(0)), 'Perm.0')
2021 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2022 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2023 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2024 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2025 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2026 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2027
2028 Open = self.Open
2029 self.assertEqual(str(Open.RO), 'Open.RO')
2030 self.assertEqual(str(Open.WO), 'Open.WO')
2031 self.assertEqual(str(Open.AC), 'Open.AC')
2032 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2033 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002034 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002035 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2036 self.assertEqual(str(~Open.AC), 'Open.CE')
2037 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2038 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2039
2040 def test_repr(self):
2041 Perm = self.Perm
2042 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2043 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2044 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2045 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2046 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002047 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002048 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2049 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2050 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2051 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002052 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002053 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2054
2055 Open = self.Open
2056 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2057 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2058 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2059 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2060 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002061 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002062 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2063 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2064 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2065 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2066
2067 def test_or(self):
2068 Perm = self.Perm
2069 for i in Perm:
2070 for j in Perm:
2071 self.assertEqual((i | j), Perm(i.value | j.value))
2072 self.assertEqual((i | j).value, i.value | j.value)
2073 self.assertIs(type(i | j), Perm)
2074 for i in Perm:
2075 self.assertIs(i | i, i)
2076 Open = self.Open
2077 self.assertIs(Open.RO | Open.CE, Open.CE)
2078
2079 def test_and(self):
2080 Perm = self.Perm
2081 RW = Perm.R | Perm.W
2082 RX = Perm.R | Perm.X
2083 WX = Perm.W | Perm.X
2084 RWX = Perm.R | Perm.W | Perm.X
2085 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2086 for i in values:
2087 for j in values:
2088 self.assertEqual((i & j).value, i.value & j.value)
2089 self.assertIs(type(i & j), Perm)
2090 for i in Perm:
2091 self.assertIs(i & i, i)
2092 self.assertIs(i & RWX, i)
2093 self.assertIs(RWX & i, i)
2094 Open = self.Open
2095 self.assertIs(Open.RO & Open.CE, Open.RO)
2096
2097 def test_xor(self):
2098 Perm = self.Perm
2099 for i in Perm:
2100 for j in Perm:
2101 self.assertEqual((i ^ j).value, i.value ^ j.value)
2102 self.assertIs(type(i ^ j), Perm)
2103 for i in Perm:
2104 self.assertIs(i ^ Perm(0), i)
2105 self.assertIs(Perm(0) ^ i, i)
2106 Open = self.Open
2107 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2108 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2109
2110 def test_invert(self):
2111 Perm = self.Perm
2112 RW = Perm.R | Perm.W
2113 RX = Perm.R | Perm.X
2114 WX = Perm.W | Perm.X
2115 RWX = Perm.R | Perm.W | Perm.X
2116 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2117 for i in values:
2118 self.assertIs(type(~i), Perm)
2119 self.assertEqual(~~i, i)
2120 for i in Perm:
2121 self.assertIs(~~i, i)
2122 Open = self.Open
2123 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2124 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2125
Ethan Furman25d94bb2016-09-02 16:32:32 -07002126 def test_bool(self):
2127 Perm = self.Perm
2128 for f in Perm:
2129 self.assertTrue(f)
2130 Open = self.Open
2131 for f in Open:
2132 self.assertEqual(bool(f.value), bool(f))
2133
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002134 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002135 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002136 lst = list(Perm)
2137 self.assertEqual(len(lst), len(Perm))
2138 self.assertEqual(len(Perm), 3, Perm)
2139 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2140 for i, n in enumerate('R W X'.split()):
2141 v = 1<<i
2142 e = Perm(v)
2143 self.assertEqual(e.value, v)
2144 self.assertEqual(type(e.value), int)
2145 self.assertEqual(e.name, n)
2146 self.assertIn(e, Perm)
2147 self.assertIs(type(e), Perm)
2148
2149 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002150 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002151 lst = list(Perm)
2152 self.assertEqual(len(lst), len(Perm))
2153 self.assertEqual(len(Perm), 3, Perm)
2154 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2155 for i, n in enumerate('R W X'.split()):
2156 v = 8<<i
2157 e = Perm(v)
2158 self.assertEqual(e.value, v)
2159 self.assertEqual(type(e.value), int)
2160 self.assertEqual(e.name, n)
2161 self.assertIn(e, Perm)
2162 self.assertIs(type(e), Perm)
2163
2164 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002165 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002166 lst = list(Perm)
2167 self.assertEqual(len(lst), len(Perm))
2168 self.assertEqual(len(Perm), 3, Perm)
2169 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2170 for i, n in enumerate('R W X'.split()):
2171 v = 1<<i
2172 e = Perm(v)
2173 self.assertEqual(e.value, v)
2174 self.assertEqual(type(e.value), int)
2175 self.assertEqual(e.name, n)
2176 self.assertIn(e, Perm)
2177 self.assertIs(type(e), Perm)
2178
2179 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002180 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002181 lst = list(Perm)
2182 self.assertEqual(len(lst), len(Perm))
2183 self.assertEqual(len(Perm), 3, Perm)
2184 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2185 for i, n in enumerate('R W X'.split()):
2186 v = 1<<(2*i+1)
2187 e = Perm(v)
2188 self.assertEqual(e.value, v)
2189 self.assertEqual(type(e.value), int)
2190 self.assertEqual(e.name, n)
2191 self.assertIn(e, Perm)
2192 self.assertIs(type(e), Perm)
2193
2194 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002195 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002196 lst = list(Perm)
2197 self.assertEqual(len(lst), len(Perm))
2198 self.assertEqual(len(Perm), 3, Perm)
2199 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2200 for i, n in enumerate('R W X'.split()):
2201 v = 1<<(2*i+1)
2202 e = Perm(v)
2203 self.assertEqual(e.value, v)
2204 self.assertEqual(type(e.value), int)
2205 self.assertEqual(e.name, n)
2206 self.assertIn(e, Perm)
2207 self.assertIs(type(e), Perm)
2208
Ethan Furman65a5a472016-09-01 23:55:19 -07002209 def test_pickle(self):
2210 if isinstance(FlagStooges, Exception):
2211 raise FlagStooges
2212 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2213 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002214
Rahul Jha94306522018-09-10 23:51:04 +05302215 def test_contains(self):
2216 Open = self.Open
2217 Color = self.Color
2218 self.assertFalse(Color.BLACK in Open)
2219 self.assertFalse(Open.RO in Color)
2220 with self.assertRaises(TypeError):
2221 'BLACK' in Color
2222 with self.assertRaises(TypeError):
2223 'RO' in Open
2224 with self.assertRaises(TypeError):
2225 1 in Color
2226 with self.assertRaises(TypeError):
2227 1 in Open
2228
2229 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002230 Perm = self.Perm
2231 R, W, X = Perm
2232 RW = R | W
2233 RX = R | X
2234 WX = W | X
2235 RWX = R | W | X
2236 self.assertTrue(R in RW)
2237 self.assertTrue(R in RX)
2238 self.assertTrue(R in RWX)
2239 self.assertTrue(W in RW)
2240 self.assertTrue(W in WX)
2241 self.assertTrue(W in RWX)
2242 self.assertTrue(X in RX)
2243 self.assertTrue(X in WX)
2244 self.assertTrue(X in RWX)
2245 self.assertFalse(R in WX)
2246 self.assertFalse(W in RX)
2247 self.assertFalse(X in RW)
2248
Ethan Furmanc16595e2016-09-10 23:36:59 -07002249 def test_auto_number(self):
2250 class Color(Flag):
2251 red = auto()
2252 blue = auto()
2253 green = auto()
2254
2255 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2256 self.assertEqual(Color.red.value, 1)
2257 self.assertEqual(Color.blue.value, 2)
2258 self.assertEqual(Color.green.value, 4)
2259
2260 def test_auto_number_garbage(self):
2261 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2262 class Color(Flag):
2263 red = 'not an int'
2264 blue = auto()
2265
Ethan Furman3515dcc2016-09-18 13:15:41 -07002266 def test_cascading_failure(self):
2267 class Bizarre(Flag):
2268 c = 3
2269 d = 4
2270 f = 6
2271 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002272 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2273 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2274 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2275 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2276 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2277 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2278 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002279
2280 def test_duplicate_auto(self):
2281 class Dupes(Enum):
2282 first = primero = auto()
2283 second = auto()
2284 third = auto()
2285 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2286
2287 def test_bizarre(self):
2288 class Bizarre(Flag):
2289 b = 3
2290 c = 4
2291 d = 6
2292 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2293
Ethan Furman5bdab642018-09-21 19:03:09 -07002294 def test_multiple_mixin(self):
2295 class AllMixin:
2296 @classproperty
2297 def ALL(cls):
2298 members = list(cls)
2299 all_value = None
2300 if members:
2301 all_value = members[0]
2302 for member in members[1:]:
2303 all_value |= member
2304 cls.ALL = all_value
2305 return all_value
2306 class StrMixin:
2307 def __str__(self):
2308 return self._name_.lower()
2309 class Color(AllMixin, Flag):
2310 RED = auto()
2311 GREEN = auto()
2312 BLUE = auto()
2313 self.assertEqual(Color.RED.value, 1)
2314 self.assertEqual(Color.GREEN.value, 2)
2315 self.assertEqual(Color.BLUE.value, 4)
2316 self.assertEqual(Color.ALL.value, 7)
2317 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2318 class Color(AllMixin, StrMixin, Flag):
2319 RED = auto()
2320 GREEN = auto()
2321 BLUE = auto()
2322 self.assertEqual(Color.RED.value, 1)
2323 self.assertEqual(Color.GREEN.value, 2)
2324 self.assertEqual(Color.BLUE.value, 4)
2325 self.assertEqual(Color.ALL.value, 7)
2326 self.assertEqual(str(Color.BLUE), 'blue')
2327 class Color(StrMixin, AllMixin, Flag):
2328 RED = auto()
2329 GREEN = auto()
2330 BLUE = auto()
2331 self.assertEqual(Color.RED.value, 1)
2332 self.assertEqual(Color.GREEN.value, 2)
2333 self.assertEqual(Color.BLUE.value, 4)
2334 self.assertEqual(Color.ALL.value, 7)
2335 self.assertEqual(str(Color.BLUE), 'blue')
2336
Hai Shie80697d2020-05-28 06:10:27 +08002337 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002338 def test_unique_composite(self):
2339 # override __eq__ to be identity only
2340 class TestFlag(Flag):
2341 one = auto()
2342 two = auto()
2343 three = auto()
2344 four = auto()
2345 five = auto()
2346 six = auto()
2347 seven = auto()
2348 eight = auto()
2349 def __eq__(self, other):
2350 return self is other
2351 def __hash__(self):
2352 return hash(self._value_)
2353 # have multiple threads competing to complete the composite members
2354 seen = set()
2355 failed = False
2356 def cycle_enum():
2357 nonlocal failed
2358 try:
2359 for i in range(256):
2360 seen.add(TestFlag(i))
2361 except Exception:
2362 failed = True
2363 threads = [
2364 threading.Thread(target=cycle_enum)
2365 for _ in range(8)
2366 ]
Hai Shie80697d2020-05-28 06:10:27 +08002367 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002368 pass
2369 # check that only 248 members were created
2370 self.assertFalse(
2371 failed,
2372 'at least one thread failed while creating composite members')
2373 self.assertEqual(256, len(seen), 'too many composite members created')
2374
Ethan Furmanc16595e2016-09-10 23:36:59 -07002375
Ethan Furman65a5a472016-09-01 23:55:19 -07002376class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002377 """Tests of the IntFlags."""
2378
Ethan Furman65a5a472016-09-01 23:55:19 -07002379 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002380 X = 1 << 0
2381 W = 1 << 1
2382 R = 1 << 2
2383
Ethan Furman65a5a472016-09-01 23:55:19 -07002384 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002385 RO = 0
2386 WO = 1
2387 RW = 2
2388 AC = 3
2389 CE = 1<<19
2390
Rahul Jha94306522018-09-10 23:51:04 +05302391 class Color(IntFlag):
2392 BLACK = 0
2393 RED = 1
2394 GREEN = 2
2395 BLUE = 4
2396 PURPLE = RED|BLUE
2397
Ethan Furman3515dcc2016-09-18 13:15:41 -07002398 def test_type(self):
2399 Perm = self.Perm
2400 Open = self.Open
2401 for f in Perm:
2402 self.assertTrue(isinstance(f, Perm))
2403 self.assertEqual(f, f.value)
2404 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2405 self.assertEqual(Perm.W | Perm.X, 3)
2406 for f in Open:
2407 self.assertTrue(isinstance(f, Open))
2408 self.assertEqual(f, f.value)
2409 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2410 self.assertEqual(Open.WO | Open.RW, 3)
2411
2412
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002413 def test_str(self):
2414 Perm = self.Perm
2415 self.assertEqual(str(Perm.R), 'Perm.R')
2416 self.assertEqual(str(Perm.W), 'Perm.W')
2417 self.assertEqual(str(Perm.X), 'Perm.X')
2418 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2419 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2420 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2421 self.assertEqual(str(Perm(0)), 'Perm.0')
2422 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002423 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2424 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2425 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2426 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002427 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002428 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2429 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2430 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002431
2432 Open = self.Open
2433 self.assertEqual(str(Open.RO), 'Open.RO')
2434 self.assertEqual(str(Open.WO), 'Open.WO')
2435 self.assertEqual(str(Open.AC), 'Open.AC')
2436 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2437 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2438 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002439 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2440 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2441 self.assertEqual(str(~Open.AC), 'Open.CE')
2442 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2443 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2444 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002445
2446 def test_repr(self):
2447 Perm = self.Perm
2448 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2449 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2450 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2451 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2452 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2453 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002454 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2455 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002456 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2457 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2458 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2459 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002460 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002461 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2462 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2463 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002464
2465 Open = self.Open
2466 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2467 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2468 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2469 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2470 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002471 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002472 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2473 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2474 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2475 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2476 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2477 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002478
2479 def test_or(self):
2480 Perm = self.Perm
2481 for i in Perm:
2482 for j in Perm:
2483 self.assertEqual(i | j, i.value | j.value)
2484 self.assertEqual((i | j).value, i.value | j.value)
2485 self.assertIs(type(i | j), Perm)
2486 for j in range(8):
2487 self.assertEqual(i | j, i.value | j)
2488 self.assertEqual((i | j).value, i.value | j)
2489 self.assertIs(type(i | j), Perm)
2490 self.assertEqual(j | i, j | i.value)
2491 self.assertEqual((j | i).value, j | i.value)
2492 self.assertIs(type(j | i), Perm)
2493 for i in Perm:
2494 self.assertIs(i | i, i)
2495 self.assertIs(i | 0, i)
2496 self.assertIs(0 | i, i)
2497 Open = self.Open
2498 self.assertIs(Open.RO | Open.CE, Open.CE)
2499
2500 def test_and(self):
2501 Perm = self.Perm
2502 RW = Perm.R | Perm.W
2503 RX = Perm.R | Perm.X
2504 WX = Perm.W | Perm.X
2505 RWX = Perm.R | Perm.W | Perm.X
2506 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2507 for i in values:
2508 for j in values:
2509 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2510 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2511 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2512 for j in range(8):
2513 self.assertEqual(i & j, i.value & j)
2514 self.assertEqual((i & j).value, i.value & j)
2515 self.assertIs(type(i & j), Perm)
2516 self.assertEqual(j & i, j & i.value)
2517 self.assertEqual((j & i).value, j & i.value)
2518 self.assertIs(type(j & i), Perm)
2519 for i in Perm:
2520 self.assertIs(i & i, i)
2521 self.assertIs(i & 7, i)
2522 self.assertIs(7 & i, i)
2523 Open = self.Open
2524 self.assertIs(Open.RO & Open.CE, Open.RO)
2525
2526 def test_xor(self):
2527 Perm = self.Perm
2528 for i in Perm:
2529 for j in Perm:
2530 self.assertEqual(i ^ j, i.value ^ j.value)
2531 self.assertEqual((i ^ j).value, i.value ^ j.value)
2532 self.assertIs(type(i ^ j), Perm)
2533 for j in range(8):
2534 self.assertEqual(i ^ j, i.value ^ j)
2535 self.assertEqual((i ^ j).value, i.value ^ j)
2536 self.assertIs(type(i ^ j), Perm)
2537 self.assertEqual(j ^ i, j ^ i.value)
2538 self.assertEqual((j ^ i).value, j ^ i.value)
2539 self.assertIs(type(j ^ i), Perm)
2540 for i in Perm:
2541 self.assertIs(i ^ 0, i)
2542 self.assertIs(0 ^ i, i)
2543 Open = self.Open
2544 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2545 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2546
2547 def test_invert(self):
2548 Perm = self.Perm
2549 RW = Perm.R | Perm.W
2550 RX = Perm.R | Perm.X
2551 WX = Perm.W | Perm.X
2552 RWX = Perm.R | Perm.W | Perm.X
2553 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2554 for i in values:
2555 self.assertEqual(~i, ~i.value)
2556 self.assertEqual((~i).value, ~i.value)
2557 self.assertIs(type(~i), Perm)
2558 self.assertEqual(~~i, i)
2559 for i in Perm:
2560 self.assertIs(~~i, i)
2561 Open = self.Open
2562 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2563 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2564
2565 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002566 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002567 lst = list(Perm)
2568 self.assertEqual(len(lst), len(Perm))
2569 self.assertEqual(len(Perm), 3, Perm)
2570 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2571 for i, n in enumerate('R W X'.split()):
2572 v = 1<<i
2573 e = Perm(v)
2574 self.assertEqual(e.value, v)
2575 self.assertEqual(type(e.value), int)
2576 self.assertEqual(e, v)
2577 self.assertEqual(e.name, n)
2578 self.assertIn(e, Perm)
2579 self.assertIs(type(e), Perm)
2580
2581 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002582 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002583 lst = list(Perm)
2584 self.assertEqual(len(lst), len(Perm))
2585 self.assertEqual(len(Perm), 3, Perm)
2586 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2587 for i, n in enumerate('R W X'.split()):
2588 v = 8<<i
2589 e = Perm(v)
2590 self.assertEqual(e.value, v)
2591 self.assertEqual(type(e.value), int)
2592 self.assertEqual(e, v)
2593 self.assertEqual(e.name, n)
2594 self.assertIn(e, Perm)
2595 self.assertIs(type(e), Perm)
2596
2597 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002598 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002599 lst = list(Perm)
2600 self.assertEqual(len(lst), len(Perm))
2601 self.assertEqual(len(Perm), 3, Perm)
2602 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2603 for i, n in enumerate('R W X'.split()):
2604 v = 1<<i
2605 e = Perm(v)
2606 self.assertEqual(e.value, v)
2607 self.assertEqual(type(e.value), int)
2608 self.assertEqual(e, v)
2609 self.assertEqual(e.name, n)
2610 self.assertIn(e, Perm)
2611 self.assertIs(type(e), Perm)
2612
2613 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002614 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002615 lst = list(Perm)
2616 self.assertEqual(len(lst), len(Perm))
2617 self.assertEqual(len(Perm), 3, Perm)
2618 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2619 for i, n in enumerate('R W X'.split()):
2620 v = 1<<(2*i+1)
2621 e = Perm(v)
2622 self.assertEqual(e.value, v)
2623 self.assertEqual(type(e.value), int)
2624 self.assertEqual(e, v)
2625 self.assertEqual(e.name, n)
2626 self.assertIn(e, Perm)
2627 self.assertIs(type(e), Perm)
2628
2629 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002630 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002631 lst = list(Perm)
2632 self.assertEqual(len(lst), len(Perm))
2633 self.assertEqual(len(Perm), 3, Perm)
2634 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2635 for i, n in enumerate('R W X'.split()):
2636 v = 1<<(2*i+1)
2637 e = Perm(v)
2638 self.assertEqual(e.value, v)
2639 self.assertEqual(type(e.value), int)
2640 self.assertEqual(e, v)
2641 self.assertEqual(e.name, n)
2642 self.assertIn(e, Perm)
2643 self.assertIs(type(e), Perm)
2644
2645
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002646 def test_programatic_function_from_empty_list(self):
2647 Perm = enum.IntFlag('Perm', [])
2648 lst = list(Perm)
2649 self.assertEqual(len(lst), len(Perm))
2650 self.assertEqual(len(Perm), 0, Perm)
2651 Thing = enum.Enum('Thing', [])
2652 lst = list(Thing)
2653 self.assertEqual(len(lst), len(Thing))
2654 self.assertEqual(len(Thing), 0, Thing)
2655
2656
2657 def test_programatic_function_from_empty_tuple(self):
2658 Perm = enum.IntFlag('Perm', ())
2659 lst = list(Perm)
2660 self.assertEqual(len(lst), len(Perm))
2661 self.assertEqual(len(Perm), 0, Perm)
2662 Thing = enum.Enum('Thing', ())
2663 self.assertEqual(len(lst), len(Thing))
2664 self.assertEqual(len(Thing), 0, Thing)
2665
Rahul Jha94306522018-09-10 23:51:04 +05302666 def test_contains(self):
2667 Open = self.Open
2668 Color = self.Color
2669 self.assertTrue(Color.GREEN in Color)
2670 self.assertTrue(Open.RW in Open)
2671 self.assertFalse(Color.GREEN in Open)
2672 self.assertFalse(Open.RW in Color)
2673 with self.assertRaises(TypeError):
2674 'GREEN' in Color
2675 with self.assertRaises(TypeError):
2676 'RW' in Open
2677 with self.assertRaises(TypeError):
2678 2 in Color
2679 with self.assertRaises(TypeError):
2680 2 in Open
2681
2682 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002683 Perm = self.Perm
2684 R, W, X = Perm
2685 RW = R | W
2686 RX = R | X
2687 WX = W | X
2688 RWX = R | W | X
2689 self.assertTrue(R in RW)
2690 self.assertTrue(R in RX)
2691 self.assertTrue(R in RWX)
2692 self.assertTrue(W in RW)
2693 self.assertTrue(W in WX)
2694 self.assertTrue(W in RWX)
2695 self.assertTrue(X in RX)
2696 self.assertTrue(X in WX)
2697 self.assertTrue(X in RWX)
2698 self.assertFalse(R in WX)
2699 self.assertFalse(W in RX)
2700 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302701 with self.assertRaises(TypeError):
2702 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002703
Ethan Furman25d94bb2016-09-02 16:32:32 -07002704 def test_bool(self):
2705 Perm = self.Perm
2706 for f in Perm:
2707 self.assertTrue(f)
2708 Open = self.Open
2709 for f in Open:
2710 self.assertEqual(bool(f.value), bool(f))
2711
Ethan Furman5bdab642018-09-21 19:03:09 -07002712 def test_multiple_mixin(self):
2713 class AllMixin:
2714 @classproperty
2715 def ALL(cls):
2716 members = list(cls)
2717 all_value = None
2718 if members:
2719 all_value = members[0]
2720 for member in members[1:]:
2721 all_value |= member
2722 cls.ALL = all_value
2723 return all_value
2724 class StrMixin:
2725 def __str__(self):
2726 return self._name_.lower()
2727 class Color(AllMixin, IntFlag):
2728 RED = auto()
2729 GREEN = auto()
2730 BLUE = auto()
2731 self.assertEqual(Color.RED.value, 1)
2732 self.assertEqual(Color.GREEN.value, 2)
2733 self.assertEqual(Color.BLUE.value, 4)
2734 self.assertEqual(Color.ALL.value, 7)
2735 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2736 class Color(AllMixin, StrMixin, IntFlag):
2737 RED = auto()
2738 GREEN = auto()
2739 BLUE = auto()
2740 self.assertEqual(Color.RED.value, 1)
2741 self.assertEqual(Color.GREEN.value, 2)
2742 self.assertEqual(Color.BLUE.value, 4)
2743 self.assertEqual(Color.ALL.value, 7)
2744 self.assertEqual(str(Color.BLUE), 'blue')
2745 class Color(StrMixin, AllMixin, IntFlag):
2746 RED = auto()
2747 GREEN = auto()
2748 BLUE = auto()
2749 self.assertEqual(Color.RED.value, 1)
2750 self.assertEqual(Color.GREEN.value, 2)
2751 self.assertEqual(Color.BLUE.value, 4)
2752 self.assertEqual(Color.ALL.value, 7)
2753 self.assertEqual(str(Color.BLUE), 'blue')
2754
Hai Shie80697d2020-05-28 06:10:27 +08002755 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002756 def test_unique_composite(self):
2757 # override __eq__ to be identity only
2758 class TestFlag(IntFlag):
2759 one = auto()
2760 two = auto()
2761 three = auto()
2762 four = auto()
2763 five = auto()
2764 six = auto()
2765 seven = auto()
2766 eight = auto()
2767 def __eq__(self, other):
2768 return self is other
2769 def __hash__(self):
2770 return hash(self._value_)
2771 # have multiple threads competing to complete the composite members
2772 seen = set()
2773 failed = False
2774 def cycle_enum():
2775 nonlocal failed
2776 try:
2777 for i in range(256):
2778 seen.add(TestFlag(i))
2779 except Exception:
2780 failed = True
2781 threads = [
2782 threading.Thread(target=cycle_enum)
2783 for _ in range(8)
2784 ]
Hai Shie80697d2020-05-28 06:10:27 +08002785 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002786 pass
2787 # check that only 248 members were created
2788 self.assertFalse(
2789 failed,
2790 'at least one thread failed while creating composite members')
2791 self.assertEqual(256, len(seen), 'too many composite members created')
2792
2793
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002794class TestEmptyAndNonLatinStrings(unittest.TestCase):
2795
2796 def test_empty_string(self):
2797 with self.assertRaises(ValueError):
2798 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2799
2800 def test_non_latin_character_string(self):
2801 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2802 item = getattr(greek_abc, '\u03B1')
2803 self.assertEqual(item.value, 1)
2804
2805 def test_non_latin_number_string(self):
2806 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2807 item = getattr(hebrew_123, '\u05D0')
2808 self.assertEqual(item.value, 1)
2809
2810
Ethan Furmanf24bb352013-07-18 17:05:39 -07002811class TestUnique(unittest.TestCase):
2812
2813 def test_unique_clean(self):
2814 @unique
2815 class Clean(Enum):
2816 one = 1
2817 two = 'dos'
2818 tres = 4.0
2819 @unique
2820 class Cleaner(IntEnum):
2821 single = 1
2822 double = 2
2823 triple = 3
2824
2825 def test_unique_dirty(self):
2826 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2827 @unique
2828 class Dirty(Enum):
2829 one = 1
2830 two = 'dos'
2831 tres = 1
2832 with self.assertRaisesRegex(
2833 ValueError,
2834 'double.*single.*turkey.*triple',
2835 ):
2836 @unique
2837 class Dirtier(IntEnum):
2838 single = 1
2839 double = 1
2840 triple = 3
2841 turkey = 3
2842
Ethan Furman3803ad42016-05-01 10:03:53 -07002843 def test_unique_with_name(self):
2844 @unique
2845 class Silly(Enum):
2846 one = 1
2847 two = 'dos'
2848 name = 3
2849 @unique
2850 class Sillier(IntEnum):
2851 single = 1
2852 name = 2
2853 triple = 3
2854 value = 4
2855
Ethan Furmanf24bb352013-07-18 17:05:39 -07002856
Ethan Furman5bdab642018-09-21 19:03:09 -07002857
Ethan Furman3323da92015-04-11 09:39:59 -07002858expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002859Help on class Color in module %s:
2860
2861class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002862 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2863 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002864 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002865 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002866 | Method resolution order:
2867 | Color
2868 | enum.Enum
2869 | builtins.object
2870 |\x20\x20
2871 | Data and other attributes defined here:
2872 |\x20\x20
2873 | blue = <Color.blue: 3>
2874 |\x20\x20
2875 | green = <Color.green: 2>
2876 |\x20\x20
2877 | red = <Color.red: 1>
2878 |\x20\x20
2879 | ----------------------------------------------------------------------
2880 | Data descriptors inherited from enum.Enum:
2881 |\x20\x20
2882 | name
2883 | The name of the Enum member.
2884 |\x20\x20
2885 | value
2886 | The value of the Enum member.
2887 |\x20\x20
2888 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002889 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002890 |\x20\x20
2891 | __members__
2892 | Returns a mapping of member name->value.
2893 |\x20\x20\x20\x20\x20\x20
2894 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002895 | is a read-only view of the internal mapping."""
2896
2897expected_help_output_without_docs = """\
2898Help on class Color in module %s:
2899
2900class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002901 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2902 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002903 | Method resolution order:
2904 | Color
2905 | enum.Enum
2906 | builtins.object
2907 |\x20\x20
2908 | Data and other attributes defined here:
2909 |\x20\x20
2910 | blue = <Color.blue: 3>
2911 |\x20\x20
2912 | green = <Color.green: 2>
2913 |\x20\x20
2914 | red = <Color.red: 1>
2915 |\x20\x20
2916 | ----------------------------------------------------------------------
2917 | Data descriptors inherited from enum.Enum:
2918 |\x20\x20
2919 | name
2920 |\x20\x20
2921 | value
2922 |\x20\x20
2923 | ----------------------------------------------------------------------
2924 | Data descriptors inherited from enum.EnumMeta:
2925 |\x20\x20
2926 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002927
2928class TestStdLib(unittest.TestCase):
2929
Ethan Furman48a724f2015-04-11 23:23:06 -07002930 maxDiff = None
2931
Ethan Furman5875d742013-10-21 20:45:55 -07002932 class Color(Enum):
2933 red = 1
2934 green = 2
2935 blue = 3
2936
2937 def test_pydoc(self):
2938 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002939 if StrEnum.__doc__ is None:
2940 expected_text = expected_help_output_without_docs % __name__
2941 else:
2942 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002943 output = StringIO()
2944 helper = pydoc.Helper(output=output)
2945 helper(self.Color)
2946 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002947 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002948
2949 def test_inspect_getmembers(self):
2950 values = dict((
2951 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002952 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002953 ('__members__', self.Color.__members__),
2954 ('__module__', __name__),
2955 ('blue', self.Color.blue),
2956 ('green', self.Color.green),
2957 ('name', Enum.__dict__['name']),
2958 ('red', self.Color.red),
2959 ('value', Enum.__dict__['value']),
2960 ))
2961 result = dict(inspect.getmembers(self.Color))
2962 self.assertEqual(values.keys(), result.keys())
2963 failed = False
2964 for k in values.keys():
2965 if result[k] != values[k]:
2966 print()
2967 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2968 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2969 failed = True
2970 if failed:
2971 self.fail("result does not equal expected, see print above")
2972
2973 def test_inspect_classify_class_attrs(self):
2974 # indirectly test __objclass__
2975 from inspect import Attribute
2976 values = [
2977 Attribute(name='__class__', kind='data',
2978 defining_class=object, object=EnumMeta),
2979 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002980 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002981 Attribute(name='__members__', kind='property',
2982 defining_class=EnumMeta, object=EnumMeta.__members__),
2983 Attribute(name='__module__', kind='data',
2984 defining_class=self.Color, object=__name__),
2985 Attribute(name='blue', kind='data',
2986 defining_class=self.Color, object=self.Color.blue),
2987 Attribute(name='green', kind='data',
2988 defining_class=self.Color, object=self.Color.green),
2989 Attribute(name='red', kind='data',
2990 defining_class=self.Color, object=self.Color.red),
2991 Attribute(name='name', kind='data',
2992 defining_class=Enum, object=Enum.__dict__['name']),
2993 Attribute(name='value', kind='data',
2994 defining_class=Enum, object=Enum.__dict__['value']),
2995 ]
2996 values.sort(key=lambda item: item.name)
2997 result = list(inspect.classify_class_attrs(self.Color))
2998 result.sort(key=lambda item: item.name)
2999 failed = False
3000 for v, r in zip(values, result):
3001 if r != v:
3002 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3003 failed = True
3004 if failed:
3005 self.fail("result does not equal expected, see print above")
3006
Martin Panter19e69c52015-11-14 12:46:42 +00003007
3008class MiscTestCase(unittest.TestCase):
3009 def test__all__(self):
3010 support.check__all__(self, enum)
3011
3012
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003013# These are unordered here on purpose to ensure that declaration order
3014# makes no difference.
3015CONVERT_TEST_NAME_D = 5
3016CONVERT_TEST_NAME_C = 5
3017CONVERT_TEST_NAME_B = 5
3018CONVERT_TEST_NAME_A = 5 # This one should sort first.
3019CONVERT_TEST_NAME_E = 5
3020CONVERT_TEST_NAME_F = 5
3021
3022class TestIntEnumConvert(unittest.TestCase):
3023 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003024 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003025 'UnittestConvert',
3026 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003027 filter=lambda x: x.startswith('CONVERT_TEST_'))
3028 # We don't want the reverse lookup value to vary when there are
3029 # multiple possible names for a given value. It should always
3030 # report the first lexigraphical name in that case.
3031 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3032
3033 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003034 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003035 'UnittestConvert',
3036 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003037 filter=lambda x: x.startswith('CONVERT_TEST_'))
3038 # Ensure that test_type has all of the desired names and values.
3039 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3040 test_type.CONVERT_TEST_NAME_A)
3041 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3042 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3043 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3044 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3045 # Ensure that test_type only picked up names matching the filter.
3046 self.assertEqual([name for name in dir(test_type)
3047 if name[0:2] not in ('CO', '__')],
3048 [], msg='Names other than CONVERT_TEST_* found.')
3049
orlnub1230fb9fad2018-09-12 20:28:53 +03003050 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3051 '_convert was deprecated in 3.8')
3052 def test_convert_warn(self):
3053 with self.assertWarns(DeprecationWarning):
3054 enum.IntEnum._convert(
3055 'UnittestConvert',
3056 ('test.test_enum', '__main__')[__name__=='__main__'],
3057 filter=lambda x: x.startswith('CONVERT_TEST_'))
3058
3059 @unittest.skipUnless(sys.version_info >= (3, 9),
3060 '_convert was removed in 3.9')
3061 def test_convert_raise(self):
3062 with self.assertRaises(AttributeError):
3063 enum.IntEnum._convert(
3064 'UnittestConvert',
3065 ('test.test_enum', '__main__')[__name__=='__main__'],
3066 filter=lambda x: x.startswith('CONVERT_TEST_'))
3067
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003068
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003069if __name__ == '__main__':
3070 unittest.main()