blob: 138f572906a478465871cc335047adb6f5a7c3bb [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07008from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000011from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030012from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080013from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080014from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080015
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016
17# for pickle tests
18try:
19 class Stooges(Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23except Exception as exc:
24 Stooges = exc
25
26try:
27 class IntStooges(int, Enum):
28 LARRY = 1
29 CURLY = 2
30 MOE = 3
31except Exception as exc:
32 IntStooges = exc
33
34try:
35 class FloatStooges(float, Enum):
36 LARRY = 1.39
37 CURLY = 2.72
38 MOE = 3.142596
39except Exception as exc:
40 FloatStooges = exc
41
Ethan Furman65a5a472016-09-01 23:55:19 -070042try:
43 class FlagStooges(Flag):
44 LARRY = 1
45 CURLY = 2
46 MOE = 3
47except Exception as exc:
48 FlagStooges = exc
49
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050# for pickle test and subclass tests
51try:
52 class StrEnum(str, Enum):
53 'accepts only string values'
54 class Name(StrEnum):
55 BDFL = 'Guido van Rossum'
56 FLUFL = 'Barry Warsaw'
57except Exception as exc:
58 Name = exc
59
60try:
61 Question = Enum('Question', 'who what when where why', module=__name__)
62except Exception as exc:
63 Question = exc
64
65try:
66 Answer = Enum('Answer', 'him this then there because')
67except Exception as exc:
68 Answer = exc
69
Ethan Furmanca1b7942014-02-08 11:36:27 -080070try:
71 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
72except Exception as exc:
73 Theory = exc
74
Ethan Furman6b3d64a2013-06-14 16:55:46 -070075# for doctests
76try:
77 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080078 TOMATO = 1
79 BANANA = 2
80 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081except Exception:
82 pass
83
Serhiy Storchakae50e7802015-03-31 16:56:49 +030084def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080085 if target is None:
86 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030087 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080088 assertion(loads(dumps(source, protocol=protocol)), target)
89
Serhiy Storchakae50e7802015-03-31 16:56:49 +030090def test_pickle_exception(assertion, exception, obj):
91 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080092 with assertion(exception):
93 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070094
95class TestHelpers(unittest.TestCase):
96 # _is_descriptor, _is_sunder, _is_dunder
97
98 def test_is_descriptor(self):
99 class foo:
100 pass
101 for attr in ('__get__','__set__','__delete__'):
102 obj = foo()
103 self.assertFalse(enum._is_descriptor(obj))
104 setattr(obj, attr, 1)
105 self.assertTrue(enum._is_descriptor(obj))
106
107 def test_is_sunder(self):
108 for s in ('_a_', '_aa_'):
109 self.assertTrue(enum._is_sunder(s))
110
111 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
112 '__', '___', '____', '_____',):
113 self.assertFalse(enum._is_sunder(s))
114
115 def test_is_dunder(self):
116 for s in ('__a__', '__aa__'):
117 self.assertTrue(enum._is_dunder(s))
118 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
119 '__', '___', '____', '_____',):
120 self.assertFalse(enum._is_dunder(s))
121
Ethan Furman5bdab642018-09-21 19:03:09 -0700122# for subclassing tests
123
124class classproperty:
125
126 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
127 self.fget = fget
128 self.fset = fset
129 self.fdel = fdel
130 if doc is None and fget is not None:
131 doc = fget.__doc__
132 self.__doc__ = doc
133
134 def __get__(self, instance, ownerclass):
135 return self.fget(ownerclass)
136
137
Ethan Furmanc16595e2016-09-10 23:36:59 -0700138# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700139
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700140class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800141
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700142 def setUp(self):
143 class Season(Enum):
144 SPRING = 1
145 SUMMER = 2
146 AUTUMN = 3
147 WINTER = 4
148 self.Season = Season
149
Ethan Furmanec15a822013-08-31 19:17:41 -0700150 class Konstants(float, Enum):
151 E = 2.7182818
152 PI = 3.1415926
153 TAU = 2 * PI
154 self.Konstants = Konstants
155
156 class Grades(IntEnum):
157 A = 5
158 B = 4
159 C = 3
160 D = 2
161 F = 0
162 self.Grades = Grades
163
164 class Directional(str, Enum):
165 EAST = 'east'
166 WEST = 'west'
167 NORTH = 'north'
168 SOUTH = 'south'
169 self.Directional = Directional
170
171 from datetime import date
172 class Holiday(date, Enum):
173 NEW_YEAR = 2013, 1, 1
174 IDES_OF_MARCH = 2013, 3, 15
175 self.Holiday = Holiday
176
Ethan Furman388a3922013-08-12 06:51:41 -0700177 def test_dir_on_class(self):
178 Season = self.Season
179 self.assertEqual(
180 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700181 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700182 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
183 )
184
185 def test_dir_on_item(self):
186 Season = self.Season
187 self.assertEqual(
188 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700189 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700190 )
191
Ethan Furmanc850f342013-09-15 16:59:35 -0700192 def test_dir_with_added_behavior(self):
193 class Test(Enum):
194 this = 'that'
195 these = 'those'
196 def wowser(self):
197 return ("Wowser! I'm %s!" % self.name)
198 self.assertEqual(
199 set(dir(Test)),
200 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
201 )
202 self.assertEqual(
203 set(dir(Test.this)),
204 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
205 )
206
Ethan Furman0ae550b2014-10-14 08:58:32 -0700207 def test_dir_on_sub_with_behavior_on_super(self):
208 # see issue22506
209 class SuperEnum(Enum):
210 def invisible(self):
211 return "did you see me?"
212 class SubEnum(SuperEnum):
213 sample = 5
214 self.assertEqual(
215 set(dir(SubEnum.sample)),
216 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
217 )
218
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219 def test_enum_in_enum_out(self):
220 Season = self.Season
221 self.assertIs(Season(Season.WINTER), Season.WINTER)
222
223 def test_enum_value(self):
224 Season = self.Season
225 self.assertEqual(Season.SPRING.value, 1)
226
227 def test_intenum_value(self):
228 self.assertEqual(IntStooges.CURLY.value, 2)
229
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700230 def test_enum(self):
231 Season = self.Season
232 lst = list(Season)
233 self.assertEqual(len(lst), len(Season))
234 self.assertEqual(len(Season), 4, Season)
235 self.assertEqual(
236 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
237
238 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
239 e = Season(i)
240 self.assertEqual(e, getattr(Season, season))
241 self.assertEqual(e.value, i)
242 self.assertNotEqual(e, i)
243 self.assertEqual(e.name, season)
244 self.assertIn(e, Season)
245 self.assertIs(type(e), Season)
246 self.assertIsInstance(e, Season)
247 self.assertEqual(str(e), 'Season.' + season)
248 self.assertEqual(
249 repr(e),
250 '<Season.{0}: {1}>'.format(season, i),
251 )
252
253 def test_value_name(self):
254 Season = self.Season
255 self.assertEqual(Season.SPRING.name, 'SPRING')
256 self.assertEqual(Season.SPRING.value, 1)
257 with self.assertRaises(AttributeError):
258 Season.SPRING.name = 'invierno'
259 with self.assertRaises(AttributeError):
260 Season.SPRING.value = 2
261
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700262 def test_changing_member(self):
263 Season = self.Season
264 with self.assertRaises(AttributeError):
265 Season.WINTER = 'really cold'
266
Ethan Furman64a99722013-09-22 16:18:19 -0700267 def test_attribute_deletion(self):
268 class Season(Enum):
269 SPRING = 1
270 SUMMER = 2
271 AUTUMN = 3
272 WINTER = 4
273
274 def spam(cls):
275 pass
276
277 self.assertTrue(hasattr(Season, 'spam'))
278 del Season.spam
279 self.assertFalse(hasattr(Season, 'spam'))
280
281 with self.assertRaises(AttributeError):
282 del Season.SPRING
283 with self.assertRaises(AttributeError):
284 del Season.DRY
285 with self.assertRaises(AttributeError):
286 del Season.SPRING.name
287
Ethan Furman5de67b12016-04-13 23:52:09 -0700288 def test_bool_of_class(self):
289 class Empty(Enum):
290 pass
291 self.assertTrue(bool(Empty))
292
293 def test_bool_of_member(self):
294 class Count(Enum):
295 zero = 0
296 one = 1
297 two = 2
298 for member in Count:
299 self.assertTrue(bool(member))
300
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700301 def test_invalid_names(self):
302 with self.assertRaises(ValueError):
303 class Wrong(Enum):
304 mro = 9
305 with self.assertRaises(ValueError):
306 class Wrong(Enum):
307 _create_= 11
308 with self.assertRaises(ValueError):
309 class Wrong(Enum):
310 _get_mixins_ = 9
311 with self.assertRaises(ValueError):
312 class Wrong(Enum):
313 _find_new_ = 1
314 with self.assertRaises(ValueError):
315 class Wrong(Enum):
316 _any_name_ = 9
317
Ethan Furman6db1fd52015-09-17 21:49:12 -0700318 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800319 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700320 class Logic(Enum):
321 true = True
322 false = False
323 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800324 self.assertTrue(Logic.false)
325 # unless overridden
326 class RealLogic(Enum):
327 true = True
328 false = False
329 def __bool__(self):
330 return bool(self._value_)
331 self.assertTrue(RealLogic.true)
332 self.assertFalse(RealLogic.false)
333 # mixed Enums depend on mixed-in type
334 class IntLogic(int, Enum):
335 true = 1
336 false = 0
337 self.assertTrue(IntLogic.true)
338 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700339
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700340 def test_contains(self):
341 Season = self.Season
342 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530343 with self.assertRaises(TypeError):
344 3 in Season
345 with self.assertRaises(TypeError):
346 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347
348 val = Season(3)
349 self.assertIn(val, Season)
350
351 class OtherEnum(Enum):
352 one = 1; two = 2
353 self.assertNotIn(OtherEnum.two, Season)
354
355 def test_comparisons(self):
356 Season = self.Season
357 with self.assertRaises(TypeError):
358 Season.SPRING < Season.WINTER
359 with self.assertRaises(TypeError):
360 Season.SPRING > 4
361
362 self.assertNotEqual(Season.SPRING, 1)
363
364 class Part(Enum):
365 SPRING = 1
366 CLIP = 2
367 BARREL = 3
368
369 self.assertNotEqual(Season.SPRING, Part.SPRING)
370 with self.assertRaises(TypeError):
371 Season.SPRING < Part.CLIP
372
373 def test_enum_duplicates(self):
374 class Season(Enum):
375 SPRING = 1
376 SUMMER = 2
377 AUTUMN = FALL = 3
378 WINTER = 4
379 ANOTHER_SPRING = 1
380 lst = list(Season)
381 self.assertEqual(
382 lst,
383 [Season.SPRING, Season.SUMMER,
384 Season.AUTUMN, Season.WINTER,
385 ])
386 self.assertIs(Season.FALL, Season.AUTUMN)
387 self.assertEqual(Season.FALL.value, 3)
388 self.assertEqual(Season.AUTUMN.value, 3)
389 self.assertIs(Season(3), Season.AUTUMN)
390 self.assertIs(Season(1), Season.SPRING)
391 self.assertEqual(Season.FALL.name, 'AUTUMN')
392 self.assertEqual(
393 [k for k,v in Season.__members__.items() if v.name != k],
394 ['FALL', 'ANOTHER_SPRING'],
395 )
396
Ethan Furman101e0742013-09-15 12:34:36 -0700397 def test_duplicate_name(self):
398 with self.assertRaises(TypeError):
399 class Color(Enum):
400 red = 1
401 green = 2
402 blue = 3
403 red = 4
404
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 def red(self):
411 return 'red'
412
413 with self.assertRaises(TypeError):
414 class Color(Enum):
415 @property
416 def red(self):
417 return 'redder'
418 red = 1
419 green = 2
420 blue = 3
421
Zackery Spytz2ec67522020-09-13 14:27:51 -0600422 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700423 with self.assertRaisesRegex(
424 ValueError,
425 '_sunder_ names, such as "_bad_", are reserved',
426 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600427 class Bad(Enum):
428 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700429
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700430 def test_enum_with_value_name(self):
431 class Huh(Enum):
432 name = 1
433 value = 2
434 self.assertEqual(
435 list(Huh),
436 [Huh.name, Huh.value],
437 )
438 self.assertIs(type(Huh.name), Huh)
439 self.assertEqual(Huh.name.name, 'name')
440 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700441
442 def test_format_enum(self):
443 Season = self.Season
444 self.assertEqual('{}'.format(Season.SPRING),
445 '{}'.format(str(Season.SPRING)))
446 self.assertEqual( '{:}'.format(Season.SPRING),
447 '{:}'.format(str(Season.SPRING)))
448 self.assertEqual('{:20}'.format(Season.SPRING),
449 '{:20}'.format(str(Season.SPRING)))
450 self.assertEqual('{:^20}'.format(Season.SPRING),
451 '{:^20}'.format(str(Season.SPRING)))
452 self.assertEqual('{:>20}'.format(Season.SPRING),
453 '{:>20}'.format(str(Season.SPRING)))
454 self.assertEqual('{:<20}'.format(Season.SPRING),
455 '{:<20}'.format(str(Season.SPRING)))
456
thatneat2f19e822019-07-04 11:28:37 -0700457 def test_str_override_enum(self):
458 class EnumWithStrOverrides(Enum):
459 one = auto()
460 two = auto()
461
462 def __str__(self):
463 return 'Str!'
464 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
465 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
466
467 def test_format_override_enum(self):
468 class EnumWithFormatOverride(Enum):
469 one = 1.0
470 two = 2.0
471 def __format__(self, spec):
472 return 'Format!!'
473 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
474 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
475
476 def test_str_and_format_override_enum(self):
477 class EnumWithStrFormatOverrides(Enum):
478 one = auto()
479 two = auto()
480 def __str__(self):
481 return 'Str!'
482 def __format__(self, spec):
483 return 'Format!'
484 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
485 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
486
487 def test_str_override_mixin(self):
488 class MixinEnumWithStrOverride(float, Enum):
489 one = 1.0
490 two = 2.0
491 def __str__(self):
492 return 'Overridden!'
493 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
494 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
495
496 def test_str_and_format_override_mixin(self):
497 class MixinWithStrFormatOverrides(float, Enum):
498 one = 1.0
499 two = 2.0
500 def __str__(self):
501 return 'Str!'
502 def __format__(self, spec):
503 return 'Format!'
504 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
505 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
506
507 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700508 class TestFloat(float, Enum):
509 one = 1.0
510 two = 2.0
511 def __format__(self, spec):
512 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700513 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700514 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
515
516 def assertFormatIsValue(self, spec, member):
517 self.assertEqual(spec.format(member), spec.format(member.value))
518
519 def test_format_enum_date(self):
520 Holiday = self.Holiday
521 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
522 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
523 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
524 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
525 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
526 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
527 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
528 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
529
530 def test_format_enum_float(self):
531 Konstants = self.Konstants
532 self.assertFormatIsValue('{}', Konstants.TAU)
533 self.assertFormatIsValue('{:}', Konstants.TAU)
534 self.assertFormatIsValue('{:20}', Konstants.TAU)
535 self.assertFormatIsValue('{:^20}', Konstants.TAU)
536 self.assertFormatIsValue('{:>20}', Konstants.TAU)
537 self.assertFormatIsValue('{:<20}', Konstants.TAU)
538 self.assertFormatIsValue('{:n}', Konstants.TAU)
539 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
540 self.assertFormatIsValue('{:f}', Konstants.TAU)
541
542 def test_format_enum_int(self):
543 Grades = self.Grades
544 self.assertFormatIsValue('{}', Grades.C)
545 self.assertFormatIsValue('{:}', Grades.C)
546 self.assertFormatIsValue('{:20}', Grades.C)
547 self.assertFormatIsValue('{:^20}', Grades.C)
548 self.assertFormatIsValue('{:>20}', Grades.C)
549 self.assertFormatIsValue('{:<20}', Grades.C)
550 self.assertFormatIsValue('{:+}', Grades.C)
551 self.assertFormatIsValue('{:08X}', Grades.C)
552 self.assertFormatIsValue('{:b}', Grades.C)
553
554 def test_format_enum_str(self):
555 Directional = self.Directional
556 self.assertFormatIsValue('{}', Directional.WEST)
557 self.assertFormatIsValue('{:}', Directional.WEST)
558 self.assertFormatIsValue('{:20}', Directional.WEST)
559 self.assertFormatIsValue('{:^20}', Directional.WEST)
560 self.assertFormatIsValue('{:>20}', Directional.WEST)
561 self.assertFormatIsValue('{:<20}', Directional.WEST)
562
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700563 def test_hash(self):
564 Season = self.Season
565 dates = {}
566 dates[Season.WINTER] = '1225'
567 dates[Season.SPRING] = '0315'
568 dates[Season.SUMMER] = '0704'
569 dates[Season.AUTUMN] = '1031'
570 self.assertEqual(dates[Season.AUTUMN], '1031')
571
572 def test_intenum_from_scratch(self):
573 class phy(int, Enum):
574 pi = 3
575 tau = 2 * pi
576 self.assertTrue(phy.pi < phy.tau)
577
578 def test_intenum_inherited(self):
579 class IntEnum(int, Enum):
580 pass
581 class phy(IntEnum):
582 pi = 3
583 tau = 2 * pi
584 self.assertTrue(phy.pi < phy.tau)
585
586 def test_floatenum_from_scratch(self):
587 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700588 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700589 tau = 2 * pi
590 self.assertTrue(phy.pi < phy.tau)
591
592 def test_floatenum_inherited(self):
593 class FloatEnum(float, Enum):
594 pass
595 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700596 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700597 tau = 2 * pi
598 self.assertTrue(phy.pi < phy.tau)
599
600 def test_strenum_from_scratch(self):
601 class phy(str, Enum):
602 pi = 'Pi'
603 tau = 'Tau'
604 self.assertTrue(phy.pi < phy.tau)
605
606 def test_strenum_inherited(self):
607 class StrEnum(str, Enum):
608 pass
609 class phy(StrEnum):
610 pi = 'Pi'
611 tau = 'Tau'
612 self.assertTrue(phy.pi < phy.tau)
613
614
615 def test_intenum(self):
616 class WeekDay(IntEnum):
617 SUNDAY = 1
618 MONDAY = 2
619 TUESDAY = 3
620 WEDNESDAY = 4
621 THURSDAY = 5
622 FRIDAY = 6
623 SATURDAY = 7
624
625 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
626 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
627
628 lst = list(WeekDay)
629 self.assertEqual(len(lst), len(WeekDay))
630 self.assertEqual(len(WeekDay), 7)
631 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
632 target = target.split()
633 for i, weekday in enumerate(target, 1):
634 e = WeekDay(i)
635 self.assertEqual(e, i)
636 self.assertEqual(int(e), i)
637 self.assertEqual(e.name, weekday)
638 self.assertIn(e, WeekDay)
639 self.assertEqual(lst.index(e)+1, i)
640 self.assertTrue(0 < e < 8)
641 self.assertIs(type(e), WeekDay)
642 self.assertIsInstance(e, int)
643 self.assertIsInstance(e, Enum)
644
645 def test_intenum_duplicates(self):
646 class WeekDay(IntEnum):
647 SUNDAY = 1
648 MONDAY = 2
649 TUESDAY = TEUSDAY = 3
650 WEDNESDAY = 4
651 THURSDAY = 5
652 FRIDAY = 6
653 SATURDAY = 7
654 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
655 self.assertEqual(WeekDay(3).name, 'TUESDAY')
656 self.assertEqual([k for k,v in WeekDay.__members__.items()
657 if v.name != k], ['TEUSDAY', ])
658
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300659 def test_intenum_from_bytes(self):
660 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
661 with self.assertRaises(ValueError):
662 IntStooges.from_bytes(b'\x00\x05', 'big')
663
664 def test_floatenum_fromhex(self):
665 h = float.hex(FloatStooges.MOE.value)
666 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
667 h = float.hex(FloatStooges.MOE.value + 0.01)
668 with self.assertRaises(ValueError):
669 FloatStooges.fromhex(h)
670
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700671 def test_pickle_enum(self):
672 if isinstance(Stooges, Exception):
673 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800674 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
675 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700676
677 def test_pickle_int(self):
678 if isinstance(IntStooges, Exception):
679 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800680 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
681 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700682
683 def test_pickle_float(self):
684 if isinstance(FloatStooges, Exception):
685 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800686 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
687 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700688
689 def test_pickle_enum_function(self):
690 if isinstance(Answer, Exception):
691 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800692 test_pickle_dump_load(self.assertIs, Answer.him)
693 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700694
695 def test_pickle_enum_function_with_module(self):
696 if isinstance(Question, Exception):
697 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800698 test_pickle_dump_load(self.assertIs, Question.who)
699 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700700
Ethan Furmanca1b7942014-02-08 11:36:27 -0800701 def test_enum_function_with_qualname(self):
702 if isinstance(Theory, Exception):
703 raise Theory
704 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
705
706 def test_class_nested_enum_and_pickle_protocol_four(self):
707 # would normally just have this directly in the class namespace
708 class NestedEnum(Enum):
709 twigs = 'common'
710 shiny = 'rare'
711
712 self.__class__.NestedEnum = NestedEnum
713 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300714 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800715
Ethan Furman24e837f2015-03-18 17:27:57 -0700716 def test_pickle_by_name(self):
717 class ReplaceGlobalInt(IntEnum):
718 ONE = 1
719 TWO = 2
720 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
721 for proto in range(HIGHEST_PROTOCOL):
722 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
723
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700724 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800725 BadPickle = Enum(
726 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700727 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800728 # now break BadPickle to test exception raising
729 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800730 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
731 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700732
733 def test_string_enum(self):
734 class SkillLevel(str, Enum):
735 master = 'what is the sound of one hand clapping?'
736 journeyman = 'why did the chicken cross the road?'
737 apprentice = 'knock, knock!'
738 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
739
740 def test_getattr_getitem(self):
741 class Period(Enum):
742 morning = 1
743 noon = 2
744 evening = 3
745 night = 4
746 self.assertIs(Period(2), Period.noon)
747 self.assertIs(getattr(Period, 'night'), Period.night)
748 self.assertIs(Period['morning'], Period.morning)
749
750 def test_getattr_dunder(self):
751 Season = self.Season
752 self.assertTrue(getattr(Season, '__eq__'))
753
754 def test_iteration_order(self):
755 class Season(Enum):
756 SUMMER = 2
757 WINTER = 4
758 AUTUMN = 3
759 SPRING = 1
760 self.assertEqual(
761 list(Season),
762 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
763 )
764
Ethan Furman2131a4a2013-09-14 18:11:24 -0700765 def test_reversed_iteration_order(self):
766 self.assertEqual(
767 list(reversed(self.Season)),
768 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
769 self.Season.SPRING]
770 )
771
Martin Pantereb995702016-07-28 01:11:04 +0000772 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700773 SummerMonth = Enum('SummerMonth', 'june july august')
774 lst = list(SummerMonth)
775 self.assertEqual(len(lst), len(SummerMonth))
776 self.assertEqual(len(SummerMonth), 3, SummerMonth)
777 self.assertEqual(
778 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
779 lst,
780 )
781 for i, month in enumerate('june july august'.split(), 1):
782 e = SummerMonth(i)
783 self.assertEqual(int(e.value), i)
784 self.assertNotEqual(e, i)
785 self.assertEqual(e.name, month)
786 self.assertIn(e, SummerMonth)
787 self.assertIs(type(e), SummerMonth)
788
Martin Pantereb995702016-07-28 01:11:04 +0000789 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700790 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
791 lst = list(SummerMonth)
792 self.assertEqual(len(lst), len(SummerMonth))
793 self.assertEqual(len(SummerMonth), 3, SummerMonth)
794 self.assertEqual(
795 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
796 lst,
797 )
798 for i, month in enumerate('june july august'.split(), 10):
799 e = SummerMonth(i)
800 self.assertEqual(int(e.value), i)
801 self.assertNotEqual(e, i)
802 self.assertEqual(e.name, month)
803 self.assertIn(e, SummerMonth)
804 self.assertIs(type(e), SummerMonth)
805
Martin Pantereb995702016-07-28 01:11:04 +0000806 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700807 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
808 lst = list(SummerMonth)
809 self.assertEqual(len(lst), len(SummerMonth))
810 self.assertEqual(len(SummerMonth), 3, SummerMonth)
811 self.assertEqual(
812 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
813 lst,
814 )
815 for i, month in enumerate('june july august'.split(), 1):
816 e = SummerMonth(i)
817 self.assertEqual(int(e.value), i)
818 self.assertNotEqual(e, i)
819 self.assertEqual(e.name, month)
820 self.assertIn(e, SummerMonth)
821 self.assertIs(type(e), SummerMonth)
822
Martin Pantereb995702016-07-28 01:11:04 +0000823 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700824 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
825 lst = list(SummerMonth)
826 self.assertEqual(len(lst), len(SummerMonth))
827 self.assertEqual(len(SummerMonth), 3, SummerMonth)
828 self.assertEqual(
829 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
830 lst,
831 )
832 for i, month in enumerate('june july august'.split(), 20):
833 e = SummerMonth(i)
834 self.assertEqual(int(e.value), i)
835 self.assertNotEqual(e, i)
836 self.assertEqual(e.name, month)
837 self.assertIn(e, SummerMonth)
838 self.assertIs(type(e), SummerMonth)
839
Martin Pantereb995702016-07-28 01:11:04 +0000840 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700841 SummerMonth = Enum(
842 'SummerMonth',
843 (('june', 1), ('july', 2), ('august', 3))
844 )
845 lst = list(SummerMonth)
846 self.assertEqual(len(lst), len(SummerMonth))
847 self.assertEqual(len(SummerMonth), 3, SummerMonth)
848 self.assertEqual(
849 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
850 lst,
851 )
852 for i, month in enumerate('june july august'.split(), 1):
853 e = SummerMonth(i)
854 self.assertEqual(int(e.value), i)
855 self.assertNotEqual(e, i)
856 self.assertEqual(e.name, month)
857 self.assertIn(e, SummerMonth)
858 self.assertIs(type(e), SummerMonth)
859
Martin Pantereb995702016-07-28 01:11:04 +0000860 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700861 SummerMonth = Enum(
862 'SummerMonth',
863 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
864 )
865 lst = list(SummerMonth)
866 self.assertEqual(len(lst), len(SummerMonth))
867 self.assertEqual(len(SummerMonth), 3, SummerMonth)
868 self.assertEqual(
869 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
870 lst,
871 )
872 for i, month in enumerate('june july august'.split(), 1):
873 e = SummerMonth(i)
874 self.assertEqual(int(e.value), i)
875 self.assertNotEqual(e, i)
876 self.assertEqual(e.name, month)
877 self.assertIn(e, SummerMonth)
878 self.assertIs(type(e), SummerMonth)
879
Martin Pantereb995702016-07-28 01:11:04 +0000880 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700881 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
882 lst = list(SummerMonth)
883 self.assertEqual(len(lst), len(SummerMonth))
884 self.assertEqual(len(SummerMonth), 3, SummerMonth)
885 self.assertEqual(
886 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
887 lst,
888 )
889 for i, month in enumerate('june july august'.split(), 1):
890 e = SummerMonth(i)
891 self.assertEqual(e, i)
892 self.assertEqual(e.name, month)
893 self.assertIn(e, SummerMonth)
894 self.assertIs(type(e), SummerMonth)
895
Martin Pantereb995702016-07-28 01:11:04 +0000896 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700897 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
898 lst = list(SummerMonth)
899 self.assertEqual(len(lst), len(SummerMonth))
900 self.assertEqual(len(SummerMonth), 3, SummerMonth)
901 self.assertEqual(
902 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
903 lst,
904 )
905 for i, month in enumerate('june july august'.split(), 30):
906 e = SummerMonth(i)
907 self.assertEqual(e, i)
908 self.assertEqual(e.name, month)
909 self.assertIn(e, SummerMonth)
910 self.assertIs(type(e), SummerMonth)
911
Martin Pantereb995702016-07-28 01:11:04 +0000912 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700913 SummerMonth = IntEnum('SummerMonth', 'june july august')
914 lst = list(SummerMonth)
915 self.assertEqual(len(lst), len(SummerMonth))
916 self.assertEqual(len(SummerMonth), 3, SummerMonth)
917 self.assertEqual(
918 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
919 lst,
920 )
921 for i, month in enumerate('june july august'.split(), 1):
922 e = SummerMonth(i)
923 self.assertEqual(e, i)
924 self.assertEqual(e.name, month)
925 self.assertIn(e, SummerMonth)
926 self.assertIs(type(e), SummerMonth)
927
Martin Pantereb995702016-07-28 01:11:04 +0000928 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700929 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
930 lst = list(SummerMonth)
931 self.assertEqual(len(lst), len(SummerMonth))
932 self.assertEqual(len(SummerMonth), 3, SummerMonth)
933 self.assertEqual(
934 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
935 lst,
936 )
937 for i, month in enumerate('june july august'.split(), 40):
938 e = SummerMonth(i)
939 self.assertEqual(e, i)
940 self.assertEqual(e.name, month)
941 self.assertIn(e, SummerMonth)
942 self.assertIs(type(e), SummerMonth)
943
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700944 def test_subclassing(self):
945 if isinstance(Name, Exception):
946 raise Name
947 self.assertEqual(Name.BDFL, 'Guido van Rossum')
948 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
949 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800950 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700951
952 def test_extending(self):
953 class Color(Enum):
954 red = 1
955 green = 2
956 blue = 3
957 with self.assertRaises(TypeError):
958 class MoreColor(Color):
959 cyan = 4
960 magenta = 5
961 yellow = 6
962
963 def test_exclude_methods(self):
964 class whatever(Enum):
965 this = 'that'
966 these = 'those'
967 def really(self):
968 return 'no, not %s' % self.value
969 self.assertIsNot(type(whatever.really), whatever)
970 self.assertEqual(whatever.this.really(), 'no, not that')
971
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700972 def test_wrong_inheritance_order(self):
973 with self.assertRaises(TypeError):
974 class Wrong(Enum, str):
975 NotHere = 'error before this point'
976
977 def test_intenum_transitivity(self):
978 class number(IntEnum):
979 one = 1
980 two = 2
981 three = 3
982 class numero(IntEnum):
983 uno = 1
984 dos = 2
985 tres = 3
986 self.assertEqual(number.one, numero.uno)
987 self.assertEqual(number.two, numero.dos)
988 self.assertEqual(number.three, numero.tres)
989
990 def test_wrong_enum_in_call(self):
991 class Monochrome(Enum):
992 black = 0
993 white = 1
994 class Gender(Enum):
995 male = 0
996 female = 1
997 self.assertRaises(ValueError, Monochrome, Gender.male)
998
999 def test_wrong_enum_in_mixed_call(self):
1000 class Monochrome(IntEnum):
1001 black = 0
1002 white = 1
1003 class Gender(Enum):
1004 male = 0
1005 female = 1
1006 self.assertRaises(ValueError, Monochrome, Gender.male)
1007
1008 def test_mixed_enum_in_call_1(self):
1009 class Monochrome(IntEnum):
1010 black = 0
1011 white = 1
1012 class Gender(IntEnum):
1013 male = 0
1014 female = 1
1015 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1016
1017 def test_mixed_enum_in_call_2(self):
1018 class Monochrome(Enum):
1019 black = 0
1020 white = 1
1021 class Gender(IntEnum):
1022 male = 0
1023 female = 1
1024 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1025
1026 def test_flufl_enum(self):
1027 class Fluflnum(Enum):
1028 def __int__(self):
1029 return int(self.value)
1030 class MailManOptions(Fluflnum):
1031 option1 = 1
1032 option2 = 2
1033 option3 = 3
1034 self.assertEqual(int(MailManOptions.option1), 1)
1035
Ethan Furman5e5a8232013-08-04 08:42:23 -07001036 def test_introspection(self):
1037 class Number(IntEnum):
1038 one = 100
1039 two = 200
1040 self.assertIs(Number.one._member_type_, int)
1041 self.assertIs(Number._member_type_, int)
1042 class String(str, Enum):
1043 yarn = 'soft'
1044 rope = 'rough'
1045 wire = 'hard'
1046 self.assertIs(String.yarn._member_type_, str)
1047 self.assertIs(String._member_type_, str)
1048 class Plain(Enum):
1049 vanilla = 'white'
1050 one = 1
1051 self.assertIs(Plain.vanilla._member_type_, object)
1052 self.assertIs(Plain._member_type_, object)
1053
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001054 def test_no_such_enum_member(self):
1055 class Color(Enum):
1056 red = 1
1057 green = 2
1058 blue = 3
1059 with self.assertRaises(ValueError):
1060 Color(4)
1061 with self.assertRaises(KeyError):
1062 Color['chartreuse']
1063
1064 def test_new_repr(self):
1065 class Color(Enum):
1066 red = 1
1067 green = 2
1068 blue = 3
1069 def __repr__(self):
1070 return "don't you just love shades of %s?" % self.name
1071 self.assertEqual(
1072 repr(Color.blue),
1073 "don't you just love shades of blue?",
1074 )
1075
1076 def test_inherited_repr(self):
1077 class MyEnum(Enum):
1078 def __repr__(self):
1079 return "My name is %s." % self.name
1080 class MyIntEnum(int, MyEnum):
1081 this = 1
1082 that = 2
1083 theother = 3
1084 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1085
1086 def test_multiple_mixin_mro(self):
1087 class auto_enum(type(Enum)):
1088 def __new__(metacls, cls, bases, classdict):
1089 temp = type(classdict)()
1090 names = set(classdict._member_names)
1091 i = 0
1092 for k in classdict._member_names:
1093 v = classdict[k]
1094 if v is Ellipsis:
1095 v = i
1096 else:
1097 i = v
1098 i += 1
1099 temp[k] = v
1100 for k, v in classdict.items():
1101 if k not in names:
1102 temp[k] = v
1103 return super(auto_enum, metacls).__new__(
1104 metacls, cls, bases, temp)
1105
1106 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1107 pass
1108
1109 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1110 pass
1111
1112 class TestAutoNumber(AutoNumberedEnum):
1113 a = ...
1114 b = 3
1115 c = ...
1116
1117 class TestAutoInt(AutoIntEnum):
1118 a = ...
1119 b = 3
1120 c = ...
1121
1122 def test_subclasses_with_getnewargs(self):
1123 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001124 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001125 def __new__(cls, *args):
1126 _args = args
1127 name, *args = args
1128 if len(args) == 0:
1129 raise TypeError("name and value must be specified")
1130 self = int.__new__(cls, *args)
1131 self._intname = name
1132 self._args = _args
1133 return self
1134 def __getnewargs__(self):
1135 return self._args
1136 @property
1137 def __name__(self):
1138 return self._intname
1139 def __repr__(self):
1140 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001141 return "{}({!r}, {})".format(
1142 type(self).__name__,
1143 self.__name__,
1144 int.__repr__(self),
1145 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001146 def __str__(self):
1147 # str() is unchanged, even if it relies on the repr() fallback
1148 base = int
1149 base_str = base.__str__
1150 if base_str.__objclass__ is object:
1151 return base.__repr__(self)
1152 return base_str(self)
1153 # for simplicity, we only define one operator that
1154 # propagates expressions
1155 def __add__(self, other):
1156 temp = int(self) + int( other)
1157 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1158 return NamedInt(
1159 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001160 temp,
1161 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001162 else:
1163 return temp
1164
1165 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001166 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001167 x = ('the-x', 1)
1168 y = ('the-y', 2)
1169
Ethan Furman2aa27322013-07-19 19:35:56 -07001170
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001171 self.assertIs(NEI.__new__, Enum.__new__)
1172 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1173 globals()['NamedInt'] = NamedInt
1174 globals()['NEI'] = NEI
1175 NI5 = NamedInt('test', 5)
1176 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001177 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001178 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001179 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001180 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001181
Ethan Furmanca1b7942014-02-08 11:36:27 -08001182 def test_subclasses_with_getnewargs_ex(self):
1183 class NamedInt(int):
1184 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1185 def __new__(cls, *args):
1186 _args = args
1187 name, *args = args
1188 if len(args) == 0:
1189 raise TypeError("name and value must be specified")
1190 self = int.__new__(cls, *args)
1191 self._intname = name
1192 self._args = _args
1193 return self
1194 def __getnewargs_ex__(self):
1195 return self._args, {}
1196 @property
1197 def __name__(self):
1198 return self._intname
1199 def __repr__(self):
1200 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001201 return "{}({!r}, {})".format(
1202 type(self).__name__,
1203 self.__name__,
1204 int.__repr__(self),
1205 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001206 def __str__(self):
1207 # str() is unchanged, even if it relies on the repr() fallback
1208 base = int
1209 base_str = base.__str__
1210 if base_str.__objclass__ is object:
1211 return base.__repr__(self)
1212 return base_str(self)
1213 # for simplicity, we only define one operator that
1214 # propagates expressions
1215 def __add__(self, other):
1216 temp = int(self) + int( other)
1217 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1218 return NamedInt(
1219 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001220 temp,
1221 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001222 else:
1223 return temp
1224
1225 class NEI(NamedInt, Enum):
1226 __qualname__ = 'NEI' # needed for pickle protocol 4
1227 x = ('the-x', 1)
1228 y = ('the-y', 2)
1229
1230
1231 self.assertIs(NEI.__new__, Enum.__new__)
1232 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1233 globals()['NamedInt'] = NamedInt
1234 globals()['NEI'] = NEI
1235 NI5 = NamedInt('test', 5)
1236 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001237 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001238 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001239 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001240 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001241
1242 def test_subclasses_with_reduce(self):
1243 class NamedInt(int):
1244 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1245 def __new__(cls, *args):
1246 _args = args
1247 name, *args = args
1248 if len(args) == 0:
1249 raise TypeError("name and value must be specified")
1250 self = int.__new__(cls, *args)
1251 self._intname = name
1252 self._args = _args
1253 return self
1254 def __reduce__(self):
1255 return self.__class__, self._args
1256 @property
1257 def __name__(self):
1258 return self._intname
1259 def __repr__(self):
1260 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001261 return "{}({!r}, {})".format(
1262 type(self).__name__,
1263 self.__name__,
1264 int.__repr__(self),
1265 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001266 def __str__(self):
1267 # str() is unchanged, even if it relies on the repr() fallback
1268 base = int
1269 base_str = base.__str__
1270 if base_str.__objclass__ is object:
1271 return base.__repr__(self)
1272 return base_str(self)
1273 # for simplicity, we only define one operator that
1274 # propagates expressions
1275 def __add__(self, other):
1276 temp = int(self) + int( other)
1277 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1278 return NamedInt(
1279 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001280 temp,
1281 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001282 else:
1283 return temp
1284
1285 class NEI(NamedInt, Enum):
1286 __qualname__ = 'NEI' # needed for pickle protocol 4
1287 x = ('the-x', 1)
1288 y = ('the-y', 2)
1289
1290
1291 self.assertIs(NEI.__new__, Enum.__new__)
1292 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1293 globals()['NamedInt'] = NamedInt
1294 globals()['NEI'] = NEI
1295 NI5 = NamedInt('test', 5)
1296 self.assertEqual(NI5, 5)
1297 test_pickle_dump_load(self.assertEqual, NI5, 5)
1298 self.assertEqual(NEI.y.value, 2)
1299 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001300 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001301
1302 def test_subclasses_with_reduce_ex(self):
1303 class NamedInt(int):
1304 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1305 def __new__(cls, *args):
1306 _args = args
1307 name, *args = args
1308 if len(args) == 0:
1309 raise TypeError("name and value must be specified")
1310 self = int.__new__(cls, *args)
1311 self._intname = name
1312 self._args = _args
1313 return self
1314 def __reduce_ex__(self, proto):
1315 return self.__class__, self._args
1316 @property
1317 def __name__(self):
1318 return self._intname
1319 def __repr__(self):
1320 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001321 return "{}({!r}, {})".format(
1322 type(self).__name__,
1323 self.__name__,
1324 int.__repr__(self),
1325 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001326 def __str__(self):
1327 # str() is unchanged, even if it relies on the repr() fallback
1328 base = int
1329 base_str = base.__str__
1330 if base_str.__objclass__ is object:
1331 return base.__repr__(self)
1332 return base_str(self)
1333 # for simplicity, we only define one operator that
1334 # propagates expressions
1335 def __add__(self, other):
1336 temp = int(self) + int( other)
1337 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1338 return NamedInt(
1339 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001340 temp,
1341 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001342 else:
1343 return temp
1344
1345 class NEI(NamedInt, Enum):
1346 __qualname__ = 'NEI' # needed for pickle protocol 4
1347 x = ('the-x', 1)
1348 y = ('the-y', 2)
1349
Ethan Furmanca1b7942014-02-08 11:36:27 -08001350 self.assertIs(NEI.__new__, Enum.__new__)
1351 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1352 globals()['NamedInt'] = NamedInt
1353 globals()['NEI'] = NEI
1354 NI5 = NamedInt('test', 5)
1355 self.assertEqual(NI5, 5)
1356 test_pickle_dump_load(self.assertEqual, NI5, 5)
1357 self.assertEqual(NEI.y.value, 2)
1358 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001359 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001360
Ethan Furmandc870522014-02-18 12:37:12 -08001361 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001362 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001363 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001364 def __new__(cls, *args):
1365 _args = args
1366 name, *args = args
1367 if len(args) == 0:
1368 raise TypeError("name and value must be specified")
1369 self = int.__new__(cls, *args)
1370 self._intname = name
1371 self._args = _args
1372 return self
1373 @property
1374 def __name__(self):
1375 return self._intname
1376 def __repr__(self):
1377 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001378 return "{}({!r}, {})".format(
1379 type(self).__name__,
1380 self.__name__,
1381 int.__repr__(self),
1382 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001383 def __str__(self):
1384 # str() is unchanged, even if it relies on the repr() fallback
1385 base = int
1386 base_str = base.__str__
1387 if base_str.__objclass__ is object:
1388 return base.__repr__(self)
1389 return base_str(self)
1390 # for simplicity, we only define one operator that
1391 # propagates expressions
1392 def __add__(self, other):
1393 temp = int(self) + int( other)
1394 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1395 return NamedInt(
1396 '({0} + {1})'.format(self.__name__, other.__name__),
1397 temp )
1398 else:
1399 return temp
1400
1401 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001402 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001403 x = ('the-x', 1)
1404 y = ('the-y', 2)
1405
1406 self.assertIs(NEI.__new__, Enum.__new__)
1407 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1408 globals()['NamedInt'] = NamedInt
1409 globals()['NEI'] = NEI
1410 NI5 = NamedInt('test', 5)
1411 self.assertEqual(NI5, 5)
1412 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001413 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1414 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001415
Ethan Furmandc870522014-02-18 12:37:12 -08001416 def test_subclasses_without_direct_pickle_support_using_name(self):
1417 class NamedInt(int):
1418 __qualname__ = 'NamedInt'
1419 def __new__(cls, *args):
1420 _args = args
1421 name, *args = args
1422 if len(args) == 0:
1423 raise TypeError("name and value must be specified")
1424 self = int.__new__(cls, *args)
1425 self._intname = name
1426 self._args = _args
1427 return self
1428 @property
1429 def __name__(self):
1430 return self._intname
1431 def __repr__(self):
1432 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001433 return "{}({!r}, {})".format(
1434 type(self).__name__,
1435 self.__name__,
1436 int.__repr__(self),
1437 )
Ethan Furmandc870522014-02-18 12:37:12 -08001438 def __str__(self):
1439 # str() is unchanged, even if it relies on the repr() fallback
1440 base = int
1441 base_str = base.__str__
1442 if base_str.__objclass__ is object:
1443 return base.__repr__(self)
1444 return base_str(self)
1445 # for simplicity, we only define one operator that
1446 # propagates expressions
1447 def __add__(self, other):
1448 temp = int(self) + int( other)
1449 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1450 return NamedInt(
1451 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001452 temp,
1453 )
Ethan Furmandc870522014-02-18 12:37:12 -08001454 else:
1455 return temp
1456
1457 class NEI(NamedInt, Enum):
1458 __qualname__ = 'NEI'
1459 x = ('the-x', 1)
1460 y = ('the-y', 2)
1461 def __reduce_ex__(self, proto):
1462 return getattr, (self.__class__, self._name_)
1463
1464 self.assertIs(NEI.__new__, Enum.__new__)
1465 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1466 globals()['NamedInt'] = NamedInt
1467 globals()['NEI'] = NEI
1468 NI5 = NamedInt('test', 5)
1469 self.assertEqual(NI5, 5)
1470 self.assertEqual(NEI.y.value, 2)
1471 test_pickle_dump_load(self.assertIs, NEI.y)
1472 test_pickle_dump_load(self.assertIs, NEI)
1473
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001474 def test_tuple_subclass(self):
1475 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001476 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477 first = (1, 'for the money')
1478 second = (2, 'for the show')
1479 third = (3, 'for the music')
1480 self.assertIs(type(SomeTuple.first), SomeTuple)
1481 self.assertIsInstance(SomeTuple.second, tuple)
1482 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1483 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001484 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001485
1486 def test_duplicate_values_give_unique_enum_items(self):
1487 class AutoNumber(Enum):
1488 first = ()
1489 second = ()
1490 third = ()
1491 def __new__(cls):
1492 value = len(cls.__members__) + 1
1493 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001494 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001495 return obj
1496 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001497 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001498 self.assertEqual(
1499 list(AutoNumber),
1500 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1501 )
1502 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001503 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001504 self.assertIs(AutoNumber(1), AutoNumber.first)
1505
1506 def test_inherited_new_from_enhanced_enum(self):
1507 class AutoNumber(Enum):
1508 def __new__(cls):
1509 value = len(cls.__members__) + 1
1510 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001511 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001512 return obj
1513 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001514 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001515 class Color(AutoNumber):
1516 red = ()
1517 green = ()
1518 blue = ()
1519 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1520 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1521
1522 def test_inherited_new_from_mixed_enum(self):
1523 class AutoNumber(IntEnum):
1524 def __new__(cls):
1525 value = len(cls.__members__) + 1
1526 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001527 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001528 return obj
1529 class Color(AutoNumber):
1530 red = ()
1531 green = ()
1532 blue = ()
1533 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1534 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1535
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001536 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001537 class OrdinaryEnum(Enum):
1538 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001539 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1540 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001541
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001542 def test_ordered_mixin(self):
1543 class OrderedEnum(Enum):
1544 def __ge__(self, other):
1545 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001546 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 return NotImplemented
1548 def __gt__(self, other):
1549 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001550 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001551 return NotImplemented
1552 def __le__(self, other):
1553 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001554 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001555 return NotImplemented
1556 def __lt__(self, other):
1557 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001558 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001559 return NotImplemented
1560 class Grade(OrderedEnum):
1561 A = 5
1562 B = 4
1563 C = 3
1564 D = 2
1565 F = 1
1566 self.assertGreater(Grade.A, Grade.B)
1567 self.assertLessEqual(Grade.F, Grade.C)
1568 self.assertLess(Grade.D, Grade.A)
1569 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001570 self.assertEqual(Grade.B, Grade.B)
1571 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001572
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001573 def test_extending2(self):
1574 class Shade(Enum):
1575 def shade(self):
1576 print(self.name)
1577 class Color(Shade):
1578 red = 1
1579 green = 2
1580 blue = 3
1581 with self.assertRaises(TypeError):
1582 class MoreColor(Color):
1583 cyan = 4
1584 magenta = 5
1585 yellow = 6
1586
1587 def test_extending3(self):
1588 class Shade(Enum):
1589 def shade(self):
1590 return self.name
1591 class Color(Shade):
1592 def hex(self):
1593 return '%s hexlified!' % self.value
1594 class MoreColor(Color):
1595 cyan = 4
1596 magenta = 5
1597 yellow = 6
1598 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1599
orlnub1230fb9fad2018-09-12 20:28:53 +03001600 def test_subclass_duplicate_name(self):
1601 class Base(Enum):
1602 def test(self):
1603 pass
1604 class Test(Base):
1605 test = 1
1606 self.assertIs(type(Test.test), Test)
1607
1608 def test_subclass_duplicate_name_dynamic(self):
1609 from types import DynamicClassAttribute
1610 class Base(Enum):
1611 @DynamicClassAttribute
1612 def test(self):
1613 return 'dynamic'
1614 class Test(Base):
1615 test = 1
1616 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001617
1618 def test_no_duplicates(self):
1619 class UniqueEnum(Enum):
1620 def __init__(self, *args):
1621 cls = self.__class__
1622 if any(self.value == e.value for e in cls):
1623 a = self.name
1624 e = cls(self.value).name
1625 raise ValueError(
1626 "aliases not allowed in UniqueEnum: %r --> %r"
1627 % (a, e)
1628 )
1629 class Color(UniqueEnum):
1630 red = 1
1631 green = 2
1632 blue = 3
1633 with self.assertRaises(ValueError):
1634 class Color(UniqueEnum):
1635 red = 1
1636 green = 2
1637 blue = 3
1638 grene = 2
1639
1640 def test_init(self):
1641 class Planet(Enum):
1642 MERCURY = (3.303e+23, 2.4397e6)
1643 VENUS = (4.869e+24, 6.0518e6)
1644 EARTH = (5.976e+24, 6.37814e6)
1645 MARS = (6.421e+23, 3.3972e6)
1646 JUPITER = (1.9e+27, 7.1492e7)
1647 SATURN = (5.688e+26, 6.0268e7)
1648 URANUS = (8.686e+25, 2.5559e7)
1649 NEPTUNE = (1.024e+26, 2.4746e7)
1650 def __init__(self, mass, radius):
1651 self.mass = mass # in kilograms
1652 self.radius = radius # in meters
1653 @property
1654 def surface_gravity(self):
1655 # universal gravitational constant (m3 kg-1 s-2)
1656 G = 6.67300E-11
1657 return G * self.mass / (self.radius * self.radius)
1658 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1659 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1660
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001661 def test_ignore(self):
1662 class Period(timedelta, Enum):
1663 '''
1664 different lengths of time
1665 '''
1666 def __new__(cls, value, period):
1667 obj = timedelta.__new__(cls, value)
1668 obj._value_ = value
1669 obj.period = period
1670 return obj
1671 _ignore_ = 'Period i'
1672 Period = vars()
1673 for i in range(13):
1674 Period['month_%d' % i] = i*30, 'month'
1675 for i in range(53):
1676 Period['week_%d' % i] = i*7, 'week'
1677 for i in range(32):
1678 Period['day_%d' % i] = i, 'day'
1679 OneDay = day_1
1680 OneWeek = week_1
1681 OneMonth = month_1
1682 self.assertFalse(hasattr(Period, '_ignore_'))
1683 self.assertFalse(hasattr(Period, 'Period'))
1684 self.assertFalse(hasattr(Period, 'i'))
1685 self.assertTrue(isinstance(Period.day_1, timedelta))
1686 self.assertTrue(Period.month_1 is Period.day_30)
1687 self.assertTrue(Period.week_4 is Period.day_28)
1688
Ethan Furman2aa27322013-07-19 19:35:56 -07001689 def test_nonhash_value(self):
1690 class AutoNumberInAList(Enum):
1691 def __new__(cls):
1692 value = [len(cls.__members__) + 1]
1693 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001694 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001695 return obj
1696 class ColorInAList(AutoNumberInAList):
1697 red = ()
1698 green = ()
1699 blue = ()
1700 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001701 for enum, value in zip(ColorInAList, range(3)):
1702 value += 1
1703 self.assertEqual(enum.value, [value])
1704 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001705
Ethan Furmanb41803e2013-07-25 13:50:45 -07001706 def test_conflicting_types_resolved_in_new(self):
1707 class LabelledIntEnum(int, Enum):
1708 def __new__(cls, *args):
1709 value, label = args
1710 obj = int.__new__(cls, value)
1711 obj.label = label
1712 obj._value_ = value
1713 return obj
1714
1715 class LabelledList(LabelledIntEnum):
1716 unprocessed = (1, "Unprocessed")
1717 payment_complete = (2, "Payment Complete")
1718
1719 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1720 self.assertEqual(LabelledList.unprocessed, 1)
1721 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001722
Ethan Furmanc16595e2016-09-10 23:36:59 -07001723 def test_auto_number(self):
1724 class Color(Enum):
1725 red = auto()
1726 blue = auto()
1727 green = auto()
1728
1729 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1730 self.assertEqual(Color.red.value, 1)
1731 self.assertEqual(Color.blue.value, 2)
1732 self.assertEqual(Color.green.value, 3)
1733
1734 def test_auto_name(self):
1735 class Color(Enum):
1736 def _generate_next_value_(name, start, count, last):
1737 return name
1738 red = auto()
1739 blue = auto()
1740 green = auto()
1741
1742 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1743 self.assertEqual(Color.red.value, 'red')
1744 self.assertEqual(Color.blue.value, 'blue')
1745 self.assertEqual(Color.green.value, 'green')
1746
1747 def test_auto_name_inherit(self):
1748 class AutoNameEnum(Enum):
1749 def _generate_next_value_(name, start, count, last):
1750 return name
1751 class Color(AutoNameEnum):
1752 red = auto()
1753 blue = auto()
1754 green = auto()
1755
1756 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1757 self.assertEqual(Color.red.value, 'red')
1758 self.assertEqual(Color.blue.value, 'blue')
1759 self.assertEqual(Color.green.value, 'green')
1760
1761 def test_auto_garbage(self):
1762 class Color(Enum):
1763 red = 'red'
1764 blue = auto()
1765 self.assertEqual(Color.blue.value, 1)
1766
1767 def test_auto_garbage_corrected(self):
1768 class Color(Enum):
1769 red = 'red'
1770 blue = 2
1771 green = auto()
1772
1773 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1774 self.assertEqual(Color.red.value, 'red')
1775 self.assertEqual(Color.blue.value, 2)
1776 self.assertEqual(Color.green.value, 3)
1777
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001778 def test_auto_order(self):
1779 with self.assertRaises(TypeError):
1780 class Color(Enum):
1781 red = auto()
1782 green = auto()
1783 blue = auto()
1784 def _generate_next_value_(name, start, count, last):
1785 return name
1786
1787
Ethan Furman3515dcc2016-09-18 13:15:41 -07001788 def test_duplicate_auto(self):
1789 class Dupes(Enum):
1790 first = primero = auto()
1791 second = auto()
1792 third = auto()
1793 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1794
Ethan Furman019f0a02018-09-12 11:43:34 -07001795 def test_missing(self):
1796 class Color(Enum):
1797 red = 1
1798 green = 2
1799 blue = 3
1800 @classmethod
1801 def _missing_(cls, item):
1802 if item == 'three':
1803 return cls.blue
1804 elif item == 'bad return':
1805 # trigger internal error
1806 return 5
1807 elif item == 'error out':
1808 raise ZeroDivisionError
1809 else:
1810 # trigger not found
1811 return None
1812 self.assertIs(Color('three'), Color.blue)
1813 self.assertRaises(ValueError, Color, 7)
1814 try:
1815 Color('bad return')
1816 except TypeError as exc:
1817 self.assertTrue(isinstance(exc.__context__, ValueError))
1818 else:
1819 raise Exception('Exception not raised.')
1820 try:
1821 Color('error out')
1822 except ZeroDivisionError as exc:
1823 self.assertTrue(isinstance(exc.__context__, ValueError))
1824 else:
1825 raise Exception('Exception not raised.')
1826
Ethan Furman5bdab642018-09-21 19:03:09 -07001827 def test_multiple_mixin(self):
1828 class MaxMixin:
1829 @classproperty
1830 def MAX(cls):
1831 max = len(cls)
1832 cls.MAX = max
1833 return max
1834 class StrMixin:
1835 def __str__(self):
1836 return self._name_.lower()
1837 class SomeEnum(Enum):
1838 def behavior(self):
1839 return 'booyah'
1840 class AnotherEnum(Enum):
1841 def behavior(self):
1842 return 'nuhuh!'
1843 def social(self):
1844 return "what's up?"
1845 class Color(MaxMixin, Enum):
1846 RED = auto()
1847 GREEN = auto()
1848 BLUE = auto()
1849 self.assertEqual(Color.RED.value, 1)
1850 self.assertEqual(Color.GREEN.value, 2)
1851 self.assertEqual(Color.BLUE.value, 3)
1852 self.assertEqual(Color.MAX, 3)
1853 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1854 class Color(MaxMixin, StrMixin, Enum):
1855 RED = auto()
1856 GREEN = auto()
1857 BLUE = auto()
1858 self.assertEqual(Color.RED.value, 1)
1859 self.assertEqual(Color.GREEN.value, 2)
1860 self.assertEqual(Color.BLUE.value, 3)
1861 self.assertEqual(Color.MAX, 3)
1862 self.assertEqual(str(Color.BLUE), 'blue')
1863 class Color(StrMixin, MaxMixin, Enum):
1864 RED = auto()
1865 GREEN = auto()
1866 BLUE = auto()
1867 self.assertEqual(Color.RED.value, 1)
1868 self.assertEqual(Color.GREEN.value, 2)
1869 self.assertEqual(Color.BLUE.value, 3)
1870 self.assertEqual(Color.MAX, 3)
1871 self.assertEqual(str(Color.BLUE), 'blue')
1872 class CoolColor(StrMixin, SomeEnum, Enum):
1873 RED = auto()
1874 GREEN = auto()
1875 BLUE = auto()
1876 self.assertEqual(CoolColor.RED.value, 1)
1877 self.assertEqual(CoolColor.GREEN.value, 2)
1878 self.assertEqual(CoolColor.BLUE.value, 3)
1879 self.assertEqual(str(CoolColor.BLUE), 'blue')
1880 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1881 class CoolerColor(StrMixin, AnotherEnum, Enum):
1882 RED = auto()
1883 GREEN = auto()
1884 BLUE = auto()
1885 self.assertEqual(CoolerColor.RED.value, 1)
1886 self.assertEqual(CoolerColor.GREEN.value, 2)
1887 self.assertEqual(CoolerColor.BLUE.value, 3)
1888 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1889 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1890 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1891 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1892 RED = auto()
1893 GREEN = auto()
1894 BLUE = auto()
1895 self.assertEqual(CoolestColor.RED.value, 1)
1896 self.assertEqual(CoolestColor.GREEN.value, 2)
1897 self.assertEqual(CoolestColor.BLUE.value, 3)
1898 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1899 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1900 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1901 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1902 RED = auto()
1903 GREEN = auto()
1904 BLUE = auto()
1905 self.assertEqual(ConfusedColor.RED.value, 1)
1906 self.assertEqual(ConfusedColor.GREEN.value, 2)
1907 self.assertEqual(ConfusedColor.BLUE.value, 3)
1908 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1909 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1910 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1911 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1912 RED = auto()
1913 GREEN = auto()
1914 BLUE = auto()
1915 self.assertEqual(ReformedColor.RED.value, 1)
1916 self.assertEqual(ReformedColor.GREEN.value, 2)
1917 self.assertEqual(ReformedColor.BLUE.value, 3)
1918 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1919 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1920 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1921 self.assertTrue(issubclass(ReformedColor, int))
1922
Ethan Furmancd453852018-10-05 23:29:36 -07001923 def test_multiple_inherited_mixin(self):
1924 class StrEnum(str, Enum):
1925 def __new__(cls, *args, **kwargs):
1926 for a in args:
1927 if not isinstance(a, str):
1928 raise TypeError("Enumeration '%s' (%s) is not"
1929 " a string" % (a, type(a).__name__))
1930 return str.__new__(cls, *args, **kwargs)
1931 @unique
1932 class Decision1(StrEnum):
1933 REVERT = "REVERT"
1934 REVERT_ALL = "REVERT_ALL"
1935 RETRY = "RETRY"
1936 class MyEnum(StrEnum):
1937 pass
1938 @unique
1939 class Decision2(MyEnum):
1940 REVERT = "REVERT"
1941 REVERT_ALL = "REVERT_ALL"
1942 RETRY = "RETRY"
1943
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001944 def test_empty_globals(self):
1945 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1946 # when using compile and exec because f_globals is empty
1947 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1948 code = compile(code, "<string>", "exec")
1949 global_ns = {}
1950 local_ls = {}
1951 exec(code, global_ns, local_ls)
1952
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001953
Ethan Furmane8e61272016-08-20 07:19:31 -07001954class TestOrder(unittest.TestCase):
1955
1956 def test_same_members(self):
1957 class Color(Enum):
1958 _order_ = 'red green blue'
1959 red = 1
1960 green = 2
1961 blue = 3
1962
1963 def test_same_members_with_aliases(self):
1964 class Color(Enum):
1965 _order_ = 'red green blue'
1966 red = 1
1967 green = 2
1968 blue = 3
1969 verde = green
1970
1971 def test_same_members_wrong_order(self):
1972 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1973 class Color(Enum):
1974 _order_ = 'red green blue'
1975 red = 1
1976 blue = 3
1977 green = 2
1978
1979 def test_order_has_extra_members(self):
1980 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1981 class Color(Enum):
1982 _order_ = 'red green blue purple'
1983 red = 1
1984 green = 2
1985 blue = 3
1986
1987 def test_order_has_extra_members_with_aliases(self):
1988 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1989 class Color(Enum):
1990 _order_ = 'red green blue purple'
1991 red = 1
1992 green = 2
1993 blue = 3
1994 verde = green
1995
1996 def test_enum_has_extra_members(self):
1997 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1998 class Color(Enum):
1999 _order_ = 'red green blue'
2000 red = 1
2001 green = 2
2002 blue = 3
2003 purple = 4
2004
2005 def test_enum_has_extra_members_with_aliases(self):
2006 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2007 class Color(Enum):
2008 _order_ = 'red green blue'
2009 red = 1
2010 green = 2
2011 blue = 3
2012 purple = 4
2013 verde = green
2014
2015
Ethan Furman65a5a472016-09-01 23:55:19 -07002016class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002017 """Tests of the Flags."""
2018
Ethan Furman65a5a472016-09-01 23:55:19 -07002019 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002020 R, W, X = 4, 2, 1
2021
Ethan Furman65a5a472016-09-01 23:55:19 -07002022 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002023 RO = 0
2024 WO = 1
2025 RW = 2
2026 AC = 3
2027 CE = 1<<19
2028
Rahul Jha94306522018-09-10 23:51:04 +05302029 class Color(Flag):
2030 BLACK = 0
2031 RED = 1
2032 GREEN = 2
2033 BLUE = 4
2034 PURPLE = RED|BLUE
2035
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002036 def test_str(self):
2037 Perm = self.Perm
2038 self.assertEqual(str(Perm.R), 'Perm.R')
2039 self.assertEqual(str(Perm.W), 'Perm.W')
2040 self.assertEqual(str(Perm.X), 'Perm.X')
2041 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2042 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2043 self.assertEqual(str(Perm(0)), 'Perm.0')
2044 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2045 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2046 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2047 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2048 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2049 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2050
2051 Open = self.Open
2052 self.assertEqual(str(Open.RO), 'Open.RO')
2053 self.assertEqual(str(Open.WO), 'Open.WO')
2054 self.assertEqual(str(Open.AC), 'Open.AC')
2055 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2056 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002057 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002058 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2059 self.assertEqual(str(~Open.AC), 'Open.CE')
2060 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2061 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2062
2063 def test_repr(self):
2064 Perm = self.Perm
2065 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2066 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2067 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2068 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2069 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002070 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002071 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2072 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2073 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2074 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002075 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002076 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2077
2078 Open = self.Open
2079 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2080 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2081 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2082 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2083 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002084 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002085 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2086 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2087 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2088 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2089
2090 def test_or(self):
2091 Perm = self.Perm
2092 for i in Perm:
2093 for j in Perm:
2094 self.assertEqual((i | j), Perm(i.value | j.value))
2095 self.assertEqual((i | j).value, i.value | j.value)
2096 self.assertIs(type(i | j), Perm)
2097 for i in Perm:
2098 self.assertIs(i | i, i)
2099 Open = self.Open
2100 self.assertIs(Open.RO | Open.CE, Open.CE)
2101
2102 def test_and(self):
2103 Perm = self.Perm
2104 RW = Perm.R | Perm.W
2105 RX = Perm.R | Perm.X
2106 WX = Perm.W | Perm.X
2107 RWX = Perm.R | Perm.W | Perm.X
2108 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2109 for i in values:
2110 for j in values:
2111 self.assertEqual((i & j).value, i.value & j.value)
2112 self.assertIs(type(i & j), Perm)
2113 for i in Perm:
2114 self.assertIs(i & i, i)
2115 self.assertIs(i & RWX, i)
2116 self.assertIs(RWX & i, i)
2117 Open = self.Open
2118 self.assertIs(Open.RO & Open.CE, Open.RO)
2119
2120 def test_xor(self):
2121 Perm = self.Perm
2122 for i in Perm:
2123 for j in Perm:
2124 self.assertEqual((i ^ j).value, i.value ^ j.value)
2125 self.assertIs(type(i ^ j), Perm)
2126 for i in Perm:
2127 self.assertIs(i ^ Perm(0), i)
2128 self.assertIs(Perm(0) ^ i, i)
2129 Open = self.Open
2130 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2131 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2132
2133 def test_invert(self):
2134 Perm = self.Perm
2135 RW = Perm.R | Perm.W
2136 RX = Perm.R | Perm.X
2137 WX = Perm.W | Perm.X
2138 RWX = Perm.R | Perm.W | Perm.X
2139 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2140 for i in values:
2141 self.assertIs(type(~i), Perm)
2142 self.assertEqual(~~i, i)
2143 for i in Perm:
2144 self.assertIs(~~i, i)
2145 Open = self.Open
2146 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2147 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2148
Ethan Furman25d94bb2016-09-02 16:32:32 -07002149 def test_bool(self):
2150 Perm = self.Perm
2151 for f in Perm:
2152 self.assertTrue(f)
2153 Open = self.Open
2154 for f in Open:
2155 self.assertEqual(bool(f.value), bool(f))
2156
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002157 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002158 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002159 lst = list(Perm)
2160 self.assertEqual(len(lst), len(Perm))
2161 self.assertEqual(len(Perm), 3, Perm)
2162 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2163 for i, n in enumerate('R W X'.split()):
2164 v = 1<<i
2165 e = Perm(v)
2166 self.assertEqual(e.value, v)
2167 self.assertEqual(type(e.value), int)
2168 self.assertEqual(e.name, n)
2169 self.assertIn(e, Perm)
2170 self.assertIs(type(e), Perm)
2171
2172 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002173 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002174 lst = list(Perm)
2175 self.assertEqual(len(lst), len(Perm))
2176 self.assertEqual(len(Perm), 3, Perm)
2177 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2178 for i, n in enumerate('R W X'.split()):
2179 v = 8<<i
2180 e = Perm(v)
2181 self.assertEqual(e.value, v)
2182 self.assertEqual(type(e.value), int)
2183 self.assertEqual(e.name, n)
2184 self.assertIn(e, Perm)
2185 self.assertIs(type(e), Perm)
2186
2187 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002188 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002189 lst = list(Perm)
2190 self.assertEqual(len(lst), len(Perm))
2191 self.assertEqual(len(Perm), 3, Perm)
2192 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2193 for i, n in enumerate('R W X'.split()):
2194 v = 1<<i
2195 e = Perm(v)
2196 self.assertEqual(e.value, v)
2197 self.assertEqual(type(e.value), int)
2198 self.assertEqual(e.name, n)
2199 self.assertIn(e, Perm)
2200 self.assertIs(type(e), Perm)
2201
2202 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002203 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002204 lst = list(Perm)
2205 self.assertEqual(len(lst), len(Perm))
2206 self.assertEqual(len(Perm), 3, Perm)
2207 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2208 for i, n in enumerate('R W X'.split()):
2209 v = 1<<(2*i+1)
2210 e = Perm(v)
2211 self.assertEqual(e.value, v)
2212 self.assertEqual(type(e.value), int)
2213 self.assertEqual(e.name, n)
2214 self.assertIn(e, Perm)
2215 self.assertIs(type(e), Perm)
2216
2217 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002218 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002219 lst = list(Perm)
2220 self.assertEqual(len(lst), len(Perm))
2221 self.assertEqual(len(Perm), 3, Perm)
2222 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2223 for i, n in enumerate('R W X'.split()):
2224 v = 1<<(2*i+1)
2225 e = Perm(v)
2226 self.assertEqual(e.value, v)
2227 self.assertEqual(type(e.value), int)
2228 self.assertEqual(e.name, n)
2229 self.assertIn(e, Perm)
2230 self.assertIs(type(e), Perm)
2231
Ethan Furman65a5a472016-09-01 23:55:19 -07002232 def test_pickle(self):
2233 if isinstance(FlagStooges, Exception):
2234 raise FlagStooges
2235 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2236 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002237
Rahul Jha94306522018-09-10 23:51:04 +05302238 def test_contains(self):
2239 Open = self.Open
2240 Color = self.Color
2241 self.assertFalse(Color.BLACK in Open)
2242 self.assertFalse(Open.RO in Color)
2243 with self.assertRaises(TypeError):
2244 'BLACK' in Color
2245 with self.assertRaises(TypeError):
2246 'RO' in Open
2247 with self.assertRaises(TypeError):
2248 1 in Color
2249 with self.assertRaises(TypeError):
2250 1 in Open
2251
2252 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002253 Perm = self.Perm
2254 R, W, X = Perm
2255 RW = R | W
2256 RX = R | X
2257 WX = W | X
2258 RWX = R | W | X
2259 self.assertTrue(R in RW)
2260 self.assertTrue(R in RX)
2261 self.assertTrue(R in RWX)
2262 self.assertTrue(W in RW)
2263 self.assertTrue(W in WX)
2264 self.assertTrue(W in RWX)
2265 self.assertTrue(X in RX)
2266 self.assertTrue(X in WX)
2267 self.assertTrue(X in RWX)
2268 self.assertFalse(R in WX)
2269 self.assertFalse(W in RX)
2270 self.assertFalse(X in RW)
2271
Ethan Furmanc16595e2016-09-10 23:36:59 -07002272 def test_auto_number(self):
2273 class Color(Flag):
2274 red = auto()
2275 blue = auto()
2276 green = auto()
2277
2278 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2279 self.assertEqual(Color.red.value, 1)
2280 self.assertEqual(Color.blue.value, 2)
2281 self.assertEqual(Color.green.value, 4)
2282
2283 def test_auto_number_garbage(self):
2284 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2285 class Color(Flag):
2286 red = 'not an int'
2287 blue = auto()
2288
Ethan Furman3515dcc2016-09-18 13:15:41 -07002289 def test_cascading_failure(self):
2290 class Bizarre(Flag):
2291 c = 3
2292 d = 4
2293 f = 6
2294 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002295 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2296 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2297 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2298 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2299 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2300 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2301 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002302
2303 def test_duplicate_auto(self):
2304 class Dupes(Enum):
2305 first = primero = auto()
2306 second = auto()
2307 third = auto()
2308 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2309
2310 def test_bizarre(self):
2311 class Bizarre(Flag):
2312 b = 3
2313 c = 4
2314 d = 6
2315 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2316
Ethan Furman5bdab642018-09-21 19:03:09 -07002317 def test_multiple_mixin(self):
2318 class AllMixin:
2319 @classproperty
2320 def ALL(cls):
2321 members = list(cls)
2322 all_value = None
2323 if members:
2324 all_value = members[0]
2325 for member in members[1:]:
2326 all_value |= member
2327 cls.ALL = all_value
2328 return all_value
2329 class StrMixin:
2330 def __str__(self):
2331 return self._name_.lower()
2332 class Color(AllMixin, Flag):
2333 RED = auto()
2334 GREEN = auto()
2335 BLUE = auto()
2336 self.assertEqual(Color.RED.value, 1)
2337 self.assertEqual(Color.GREEN.value, 2)
2338 self.assertEqual(Color.BLUE.value, 4)
2339 self.assertEqual(Color.ALL.value, 7)
2340 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2341 class Color(AllMixin, StrMixin, Flag):
2342 RED = auto()
2343 GREEN = auto()
2344 BLUE = auto()
2345 self.assertEqual(Color.RED.value, 1)
2346 self.assertEqual(Color.GREEN.value, 2)
2347 self.assertEqual(Color.BLUE.value, 4)
2348 self.assertEqual(Color.ALL.value, 7)
2349 self.assertEqual(str(Color.BLUE), 'blue')
2350 class Color(StrMixin, AllMixin, Flag):
2351 RED = auto()
2352 GREEN = auto()
2353 BLUE = auto()
2354 self.assertEqual(Color.RED.value, 1)
2355 self.assertEqual(Color.GREEN.value, 2)
2356 self.assertEqual(Color.BLUE.value, 4)
2357 self.assertEqual(Color.ALL.value, 7)
2358 self.assertEqual(str(Color.BLUE), 'blue')
2359
Hai Shie80697d2020-05-28 06:10:27 +08002360 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002361 def test_unique_composite(self):
2362 # override __eq__ to be identity only
2363 class TestFlag(Flag):
2364 one = auto()
2365 two = auto()
2366 three = auto()
2367 four = auto()
2368 five = auto()
2369 six = auto()
2370 seven = auto()
2371 eight = auto()
2372 def __eq__(self, other):
2373 return self is other
2374 def __hash__(self):
2375 return hash(self._value_)
2376 # have multiple threads competing to complete the composite members
2377 seen = set()
2378 failed = False
2379 def cycle_enum():
2380 nonlocal failed
2381 try:
2382 for i in range(256):
2383 seen.add(TestFlag(i))
2384 except Exception:
2385 failed = True
2386 threads = [
2387 threading.Thread(target=cycle_enum)
2388 for _ in range(8)
2389 ]
Hai Shie80697d2020-05-28 06:10:27 +08002390 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002391 pass
2392 # check that only 248 members were created
2393 self.assertFalse(
2394 failed,
2395 'at least one thread failed while creating composite members')
2396 self.assertEqual(256, len(seen), 'too many composite members created')
2397
Ethan Furmanc16595e2016-09-10 23:36:59 -07002398
Ethan Furman65a5a472016-09-01 23:55:19 -07002399class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002400 """Tests of the IntFlags."""
2401
Ethan Furman65a5a472016-09-01 23:55:19 -07002402 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002403 X = 1 << 0
2404 W = 1 << 1
2405 R = 1 << 2
2406
Ethan Furman65a5a472016-09-01 23:55:19 -07002407 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002408 RO = 0
2409 WO = 1
2410 RW = 2
2411 AC = 3
2412 CE = 1<<19
2413
Rahul Jha94306522018-09-10 23:51:04 +05302414 class Color(IntFlag):
2415 BLACK = 0
2416 RED = 1
2417 GREEN = 2
2418 BLUE = 4
2419 PURPLE = RED|BLUE
2420
Ethan Furman3515dcc2016-09-18 13:15:41 -07002421 def test_type(self):
2422 Perm = self.Perm
2423 Open = self.Open
2424 for f in Perm:
2425 self.assertTrue(isinstance(f, Perm))
2426 self.assertEqual(f, f.value)
2427 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2428 self.assertEqual(Perm.W | Perm.X, 3)
2429 for f in Open:
2430 self.assertTrue(isinstance(f, Open))
2431 self.assertEqual(f, f.value)
2432 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2433 self.assertEqual(Open.WO | Open.RW, 3)
2434
2435
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002436 def test_str(self):
2437 Perm = self.Perm
2438 self.assertEqual(str(Perm.R), 'Perm.R')
2439 self.assertEqual(str(Perm.W), 'Perm.W')
2440 self.assertEqual(str(Perm.X), 'Perm.X')
2441 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2442 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2443 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2444 self.assertEqual(str(Perm(0)), 'Perm.0')
2445 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002446 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2447 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2448 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2449 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002450 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002451 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2452 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2453 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002454
2455 Open = self.Open
2456 self.assertEqual(str(Open.RO), 'Open.RO')
2457 self.assertEqual(str(Open.WO), 'Open.WO')
2458 self.assertEqual(str(Open.AC), 'Open.AC')
2459 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2460 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2461 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002462 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2463 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2464 self.assertEqual(str(~Open.AC), 'Open.CE')
2465 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2466 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2467 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002468
2469 def test_repr(self):
2470 Perm = self.Perm
2471 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2472 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2473 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2474 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2475 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2476 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002477 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2478 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002479 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2480 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2481 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2482 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002483 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002484 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2485 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2486 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002487
2488 Open = self.Open
2489 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2490 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2491 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2492 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2493 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002494 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002495 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2496 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2497 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2498 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2499 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2500 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002501
2502 def test_or(self):
2503 Perm = self.Perm
2504 for i in Perm:
2505 for j in Perm:
2506 self.assertEqual(i | j, i.value | j.value)
2507 self.assertEqual((i | j).value, i.value | j.value)
2508 self.assertIs(type(i | j), Perm)
2509 for j in range(8):
2510 self.assertEqual(i | j, i.value | j)
2511 self.assertEqual((i | j).value, i.value | j)
2512 self.assertIs(type(i | j), Perm)
2513 self.assertEqual(j | i, j | i.value)
2514 self.assertEqual((j | i).value, j | i.value)
2515 self.assertIs(type(j | i), Perm)
2516 for i in Perm:
2517 self.assertIs(i | i, i)
2518 self.assertIs(i | 0, i)
2519 self.assertIs(0 | i, i)
2520 Open = self.Open
2521 self.assertIs(Open.RO | Open.CE, Open.CE)
2522
2523 def test_and(self):
2524 Perm = self.Perm
2525 RW = Perm.R | Perm.W
2526 RX = Perm.R | Perm.X
2527 WX = Perm.W | Perm.X
2528 RWX = Perm.R | Perm.W | Perm.X
2529 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2530 for i in values:
2531 for j in values:
2532 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2533 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2534 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2535 for j in range(8):
2536 self.assertEqual(i & j, i.value & j)
2537 self.assertEqual((i & j).value, i.value & j)
2538 self.assertIs(type(i & j), Perm)
2539 self.assertEqual(j & i, j & i.value)
2540 self.assertEqual((j & i).value, j & i.value)
2541 self.assertIs(type(j & i), Perm)
2542 for i in Perm:
2543 self.assertIs(i & i, i)
2544 self.assertIs(i & 7, i)
2545 self.assertIs(7 & i, i)
2546 Open = self.Open
2547 self.assertIs(Open.RO & Open.CE, Open.RO)
2548
2549 def test_xor(self):
2550 Perm = self.Perm
2551 for i in Perm:
2552 for j in Perm:
2553 self.assertEqual(i ^ j, i.value ^ j.value)
2554 self.assertEqual((i ^ j).value, i.value ^ j.value)
2555 self.assertIs(type(i ^ j), Perm)
2556 for j in range(8):
2557 self.assertEqual(i ^ j, i.value ^ j)
2558 self.assertEqual((i ^ j).value, i.value ^ j)
2559 self.assertIs(type(i ^ j), Perm)
2560 self.assertEqual(j ^ i, j ^ i.value)
2561 self.assertEqual((j ^ i).value, j ^ i.value)
2562 self.assertIs(type(j ^ i), Perm)
2563 for i in Perm:
2564 self.assertIs(i ^ 0, i)
2565 self.assertIs(0 ^ i, i)
2566 Open = self.Open
2567 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2568 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2569
2570 def test_invert(self):
2571 Perm = self.Perm
2572 RW = Perm.R | Perm.W
2573 RX = Perm.R | Perm.X
2574 WX = Perm.W | Perm.X
2575 RWX = Perm.R | Perm.W | Perm.X
2576 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2577 for i in values:
2578 self.assertEqual(~i, ~i.value)
2579 self.assertEqual((~i).value, ~i.value)
2580 self.assertIs(type(~i), Perm)
2581 self.assertEqual(~~i, i)
2582 for i in Perm:
2583 self.assertIs(~~i, i)
2584 Open = self.Open
2585 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2586 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2587
2588 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002589 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002590 lst = list(Perm)
2591 self.assertEqual(len(lst), len(Perm))
2592 self.assertEqual(len(Perm), 3, Perm)
2593 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2594 for i, n in enumerate('R W X'.split()):
2595 v = 1<<i
2596 e = Perm(v)
2597 self.assertEqual(e.value, v)
2598 self.assertEqual(type(e.value), int)
2599 self.assertEqual(e, v)
2600 self.assertEqual(e.name, n)
2601 self.assertIn(e, Perm)
2602 self.assertIs(type(e), Perm)
2603
2604 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002605 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002606 lst = list(Perm)
2607 self.assertEqual(len(lst), len(Perm))
2608 self.assertEqual(len(Perm), 3, Perm)
2609 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2610 for i, n in enumerate('R W X'.split()):
2611 v = 8<<i
2612 e = Perm(v)
2613 self.assertEqual(e.value, v)
2614 self.assertEqual(type(e.value), int)
2615 self.assertEqual(e, v)
2616 self.assertEqual(e.name, n)
2617 self.assertIn(e, Perm)
2618 self.assertIs(type(e), Perm)
2619
2620 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002621 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002622 lst = list(Perm)
2623 self.assertEqual(len(lst), len(Perm))
2624 self.assertEqual(len(Perm), 3, Perm)
2625 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2626 for i, n in enumerate('R W X'.split()):
2627 v = 1<<i
2628 e = Perm(v)
2629 self.assertEqual(e.value, v)
2630 self.assertEqual(type(e.value), int)
2631 self.assertEqual(e, v)
2632 self.assertEqual(e.name, n)
2633 self.assertIn(e, Perm)
2634 self.assertIs(type(e), Perm)
2635
2636 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002637 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002638 lst = list(Perm)
2639 self.assertEqual(len(lst), len(Perm))
2640 self.assertEqual(len(Perm), 3, Perm)
2641 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2642 for i, n in enumerate('R W X'.split()):
2643 v = 1<<(2*i+1)
2644 e = Perm(v)
2645 self.assertEqual(e.value, v)
2646 self.assertEqual(type(e.value), int)
2647 self.assertEqual(e, v)
2648 self.assertEqual(e.name, n)
2649 self.assertIn(e, Perm)
2650 self.assertIs(type(e), Perm)
2651
2652 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002653 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002654 lst = list(Perm)
2655 self.assertEqual(len(lst), len(Perm))
2656 self.assertEqual(len(Perm), 3, Perm)
2657 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2658 for i, n in enumerate('R W X'.split()):
2659 v = 1<<(2*i+1)
2660 e = Perm(v)
2661 self.assertEqual(e.value, v)
2662 self.assertEqual(type(e.value), int)
2663 self.assertEqual(e, v)
2664 self.assertEqual(e.name, n)
2665 self.assertIn(e, Perm)
2666 self.assertIs(type(e), Perm)
2667
2668
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002669 def test_programatic_function_from_empty_list(self):
2670 Perm = enum.IntFlag('Perm', [])
2671 lst = list(Perm)
2672 self.assertEqual(len(lst), len(Perm))
2673 self.assertEqual(len(Perm), 0, Perm)
2674 Thing = enum.Enum('Thing', [])
2675 lst = list(Thing)
2676 self.assertEqual(len(lst), len(Thing))
2677 self.assertEqual(len(Thing), 0, Thing)
2678
2679
2680 def test_programatic_function_from_empty_tuple(self):
2681 Perm = enum.IntFlag('Perm', ())
2682 lst = list(Perm)
2683 self.assertEqual(len(lst), len(Perm))
2684 self.assertEqual(len(Perm), 0, Perm)
2685 Thing = enum.Enum('Thing', ())
2686 self.assertEqual(len(lst), len(Thing))
2687 self.assertEqual(len(Thing), 0, Thing)
2688
Rahul Jha94306522018-09-10 23:51:04 +05302689 def test_contains(self):
2690 Open = self.Open
2691 Color = self.Color
2692 self.assertTrue(Color.GREEN in Color)
2693 self.assertTrue(Open.RW in Open)
2694 self.assertFalse(Color.GREEN in Open)
2695 self.assertFalse(Open.RW in Color)
2696 with self.assertRaises(TypeError):
2697 'GREEN' in Color
2698 with self.assertRaises(TypeError):
2699 'RW' in Open
2700 with self.assertRaises(TypeError):
2701 2 in Color
2702 with self.assertRaises(TypeError):
2703 2 in Open
2704
2705 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002706 Perm = self.Perm
2707 R, W, X = Perm
2708 RW = R | W
2709 RX = R | X
2710 WX = W | X
2711 RWX = R | W | X
2712 self.assertTrue(R in RW)
2713 self.assertTrue(R in RX)
2714 self.assertTrue(R in RWX)
2715 self.assertTrue(W in RW)
2716 self.assertTrue(W in WX)
2717 self.assertTrue(W in RWX)
2718 self.assertTrue(X in RX)
2719 self.assertTrue(X in WX)
2720 self.assertTrue(X in RWX)
2721 self.assertFalse(R in WX)
2722 self.assertFalse(W in RX)
2723 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302724 with self.assertRaises(TypeError):
2725 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002726
Ethan Furman25d94bb2016-09-02 16:32:32 -07002727 def test_bool(self):
2728 Perm = self.Perm
2729 for f in Perm:
2730 self.assertTrue(f)
2731 Open = self.Open
2732 for f in Open:
2733 self.assertEqual(bool(f.value), bool(f))
2734
Ethan Furman5bdab642018-09-21 19:03:09 -07002735 def test_multiple_mixin(self):
2736 class AllMixin:
2737 @classproperty
2738 def ALL(cls):
2739 members = list(cls)
2740 all_value = None
2741 if members:
2742 all_value = members[0]
2743 for member in members[1:]:
2744 all_value |= member
2745 cls.ALL = all_value
2746 return all_value
2747 class StrMixin:
2748 def __str__(self):
2749 return self._name_.lower()
2750 class Color(AllMixin, IntFlag):
2751 RED = auto()
2752 GREEN = auto()
2753 BLUE = auto()
2754 self.assertEqual(Color.RED.value, 1)
2755 self.assertEqual(Color.GREEN.value, 2)
2756 self.assertEqual(Color.BLUE.value, 4)
2757 self.assertEqual(Color.ALL.value, 7)
2758 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2759 class Color(AllMixin, StrMixin, IntFlag):
2760 RED = auto()
2761 GREEN = auto()
2762 BLUE = auto()
2763 self.assertEqual(Color.RED.value, 1)
2764 self.assertEqual(Color.GREEN.value, 2)
2765 self.assertEqual(Color.BLUE.value, 4)
2766 self.assertEqual(Color.ALL.value, 7)
2767 self.assertEqual(str(Color.BLUE), 'blue')
2768 class Color(StrMixin, AllMixin, IntFlag):
2769 RED = auto()
2770 GREEN = auto()
2771 BLUE = auto()
2772 self.assertEqual(Color.RED.value, 1)
2773 self.assertEqual(Color.GREEN.value, 2)
2774 self.assertEqual(Color.BLUE.value, 4)
2775 self.assertEqual(Color.ALL.value, 7)
2776 self.assertEqual(str(Color.BLUE), 'blue')
2777
Hai Shie80697d2020-05-28 06:10:27 +08002778 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002779 def test_unique_composite(self):
2780 # override __eq__ to be identity only
2781 class TestFlag(IntFlag):
2782 one = auto()
2783 two = auto()
2784 three = auto()
2785 four = auto()
2786 five = auto()
2787 six = auto()
2788 seven = auto()
2789 eight = auto()
2790 def __eq__(self, other):
2791 return self is other
2792 def __hash__(self):
2793 return hash(self._value_)
2794 # have multiple threads competing to complete the composite members
2795 seen = set()
2796 failed = False
2797 def cycle_enum():
2798 nonlocal failed
2799 try:
2800 for i in range(256):
2801 seen.add(TestFlag(i))
2802 except Exception:
2803 failed = True
2804 threads = [
2805 threading.Thread(target=cycle_enum)
2806 for _ in range(8)
2807 ]
Hai Shie80697d2020-05-28 06:10:27 +08002808 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002809 pass
2810 # check that only 248 members were created
2811 self.assertFalse(
2812 failed,
2813 'at least one thread failed while creating composite members')
2814 self.assertEqual(256, len(seen), 'too many composite members created')
2815
2816
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002817class TestEmptyAndNonLatinStrings(unittest.TestCase):
2818
2819 def test_empty_string(self):
2820 with self.assertRaises(ValueError):
2821 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2822
2823 def test_non_latin_character_string(self):
2824 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2825 item = getattr(greek_abc, '\u03B1')
2826 self.assertEqual(item.value, 1)
2827
2828 def test_non_latin_number_string(self):
2829 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2830 item = getattr(hebrew_123, '\u05D0')
2831 self.assertEqual(item.value, 1)
2832
2833
Ethan Furmanf24bb352013-07-18 17:05:39 -07002834class TestUnique(unittest.TestCase):
2835
2836 def test_unique_clean(self):
2837 @unique
2838 class Clean(Enum):
2839 one = 1
2840 two = 'dos'
2841 tres = 4.0
2842 @unique
2843 class Cleaner(IntEnum):
2844 single = 1
2845 double = 2
2846 triple = 3
2847
2848 def test_unique_dirty(self):
2849 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2850 @unique
2851 class Dirty(Enum):
2852 one = 1
2853 two = 'dos'
2854 tres = 1
2855 with self.assertRaisesRegex(
2856 ValueError,
2857 'double.*single.*turkey.*triple',
2858 ):
2859 @unique
2860 class Dirtier(IntEnum):
2861 single = 1
2862 double = 1
2863 triple = 3
2864 turkey = 3
2865
Ethan Furman3803ad42016-05-01 10:03:53 -07002866 def test_unique_with_name(self):
2867 @unique
2868 class Silly(Enum):
2869 one = 1
2870 two = 'dos'
2871 name = 3
2872 @unique
2873 class Sillier(IntEnum):
2874 single = 1
2875 name = 2
2876 triple = 3
2877 value = 4
2878
Ethan Furmanf24bb352013-07-18 17:05:39 -07002879
Ethan Furman5bdab642018-09-21 19:03:09 -07002880
Ethan Furman3323da92015-04-11 09:39:59 -07002881expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002882Help on class Color in module %s:
2883
2884class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002885 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2886 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002887 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002888 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002889 | Method resolution order:
2890 | Color
2891 | enum.Enum
2892 | builtins.object
2893 |\x20\x20
2894 | Data and other attributes defined here:
2895 |\x20\x20
2896 | blue = <Color.blue: 3>
2897 |\x20\x20
2898 | green = <Color.green: 2>
2899 |\x20\x20
2900 | red = <Color.red: 1>
2901 |\x20\x20
2902 | ----------------------------------------------------------------------
2903 | Data descriptors inherited from enum.Enum:
2904 |\x20\x20
2905 | name
2906 | The name of the Enum member.
2907 |\x20\x20
2908 | value
2909 | The value of the Enum member.
2910 |\x20\x20
2911 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002912 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002913 |\x20\x20
2914 | __members__
2915 | Returns a mapping of member name->value.
2916 |\x20\x20\x20\x20\x20\x20
2917 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002918 | is a read-only view of the internal mapping."""
2919
2920expected_help_output_without_docs = """\
2921Help on class Color in module %s:
2922
2923class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002924 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2925 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002926 | Method resolution order:
2927 | Color
2928 | enum.Enum
2929 | builtins.object
2930 |\x20\x20
2931 | Data and other attributes defined here:
2932 |\x20\x20
2933 | blue = <Color.blue: 3>
2934 |\x20\x20
2935 | green = <Color.green: 2>
2936 |\x20\x20
2937 | red = <Color.red: 1>
2938 |\x20\x20
2939 | ----------------------------------------------------------------------
2940 | Data descriptors inherited from enum.Enum:
2941 |\x20\x20
2942 | name
2943 |\x20\x20
2944 | value
2945 |\x20\x20
2946 | ----------------------------------------------------------------------
2947 | Data descriptors inherited from enum.EnumMeta:
2948 |\x20\x20
2949 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002950
2951class TestStdLib(unittest.TestCase):
2952
Ethan Furman48a724f2015-04-11 23:23:06 -07002953 maxDiff = None
2954
Ethan Furman5875d742013-10-21 20:45:55 -07002955 class Color(Enum):
2956 red = 1
2957 green = 2
2958 blue = 3
2959
2960 def test_pydoc(self):
2961 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002962 if StrEnum.__doc__ is None:
2963 expected_text = expected_help_output_without_docs % __name__
2964 else:
2965 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002966 output = StringIO()
2967 helper = pydoc.Helper(output=output)
2968 helper(self.Color)
2969 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002970 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002971
2972 def test_inspect_getmembers(self):
2973 values = dict((
2974 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002975 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002976 ('__members__', self.Color.__members__),
2977 ('__module__', __name__),
2978 ('blue', self.Color.blue),
2979 ('green', self.Color.green),
2980 ('name', Enum.__dict__['name']),
2981 ('red', self.Color.red),
2982 ('value', Enum.__dict__['value']),
2983 ))
2984 result = dict(inspect.getmembers(self.Color))
2985 self.assertEqual(values.keys(), result.keys())
2986 failed = False
2987 for k in values.keys():
2988 if result[k] != values[k]:
2989 print()
2990 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2991 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2992 failed = True
2993 if failed:
2994 self.fail("result does not equal expected, see print above")
2995
2996 def test_inspect_classify_class_attrs(self):
2997 # indirectly test __objclass__
2998 from inspect import Attribute
2999 values = [
3000 Attribute(name='__class__', kind='data',
3001 defining_class=object, object=EnumMeta),
3002 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003003 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003004 Attribute(name='__members__', kind='property',
3005 defining_class=EnumMeta, object=EnumMeta.__members__),
3006 Attribute(name='__module__', kind='data',
3007 defining_class=self.Color, object=__name__),
3008 Attribute(name='blue', kind='data',
3009 defining_class=self.Color, object=self.Color.blue),
3010 Attribute(name='green', kind='data',
3011 defining_class=self.Color, object=self.Color.green),
3012 Attribute(name='red', kind='data',
3013 defining_class=self.Color, object=self.Color.red),
3014 Attribute(name='name', kind='data',
3015 defining_class=Enum, object=Enum.__dict__['name']),
3016 Attribute(name='value', kind='data',
3017 defining_class=Enum, object=Enum.__dict__['value']),
3018 ]
3019 values.sort(key=lambda item: item.name)
3020 result = list(inspect.classify_class_attrs(self.Color))
3021 result.sort(key=lambda item: item.name)
3022 failed = False
3023 for v, r in zip(values, result):
3024 if r != v:
3025 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3026 failed = True
3027 if failed:
3028 self.fail("result does not equal expected, see print above")
3029
Martin Panter19e69c52015-11-14 12:46:42 +00003030
3031class MiscTestCase(unittest.TestCase):
3032 def test__all__(self):
3033 support.check__all__(self, enum)
3034
3035
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003036# These are unordered here on purpose to ensure that declaration order
3037# makes no difference.
3038CONVERT_TEST_NAME_D = 5
3039CONVERT_TEST_NAME_C = 5
3040CONVERT_TEST_NAME_B = 5
3041CONVERT_TEST_NAME_A = 5 # This one should sort first.
3042CONVERT_TEST_NAME_E = 5
3043CONVERT_TEST_NAME_F = 5
3044
3045class TestIntEnumConvert(unittest.TestCase):
3046 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003047 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003048 'UnittestConvert',
3049 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003050 filter=lambda x: x.startswith('CONVERT_TEST_'))
3051 # We don't want the reverse lookup value to vary when there are
3052 # multiple possible names for a given value. It should always
3053 # report the first lexigraphical name in that case.
3054 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3055
3056 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003057 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003058 'UnittestConvert',
3059 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003060 filter=lambda x: x.startswith('CONVERT_TEST_'))
3061 # Ensure that test_type has all of the desired names and values.
3062 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3063 test_type.CONVERT_TEST_NAME_A)
3064 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3065 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3066 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3067 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3068 # Ensure that test_type only picked up names matching the filter.
3069 self.assertEqual([name for name in dir(test_type)
3070 if name[0:2] not in ('CO', '__')],
3071 [], msg='Names other than CONVERT_TEST_* found.')
3072
orlnub1230fb9fad2018-09-12 20:28:53 +03003073 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3074 '_convert was deprecated in 3.8')
3075 def test_convert_warn(self):
3076 with self.assertWarns(DeprecationWarning):
3077 enum.IntEnum._convert(
3078 'UnittestConvert',
3079 ('test.test_enum', '__main__')[__name__=='__main__'],
3080 filter=lambda x: x.startswith('CONVERT_TEST_'))
3081
3082 @unittest.skipUnless(sys.version_info >= (3, 9),
3083 '_convert was removed in 3.9')
3084 def test_convert_raise(self):
3085 with self.assertRaises(AttributeError):
3086 enum.IntEnum._convert(
3087 'UnittestConvert',
3088 ('test.test_enum', '__main__')[__name__=='__main__'],
3089 filter=lambda x: x.startswith('CONVERT_TEST_'))
3090
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003091
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003092if __name__ == '__main__':
3093 unittest.main()