blob: 0e6b1b16ca323827900d79c64d513924c834fb6e [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
Ethan Furmana4b1bb42018-01-22 07:56:37 -080013from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080014
Ethan Furman6b3d64a2013-06-14 16:55:46 -070015
16# for pickle tests
17try:
18 class Stooges(Enum):
19 LARRY = 1
20 CURLY = 2
21 MOE = 3
22except Exception as exc:
23 Stooges = exc
24
25try:
26 class IntStooges(int, Enum):
27 LARRY = 1
28 CURLY = 2
29 MOE = 3
30except Exception as exc:
31 IntStooges = exc
32
33try:
34 class FloatStooges(float, Enum):
35 LARRY = 1.39
36 CURLY = 2.72
37 MOE = 3.142596
38except Exception as exc:
39 FloatStooges = exc
40
Ethan Furman65a5a472016-09-01 23:55:19 -070041try:
42 class FlagStooges(Flag):
43 LARRY = 1
44 CURLY = 2
45 MOE = 3
46except Exception as exc:
47 FlagStooges = exc
48
Ethan Furman6b3d64a2013-06-14 16:55:46 -070049# for pickle test and subclass tests
50try:
51 class StrEnum(str, Enum):
52 'accepts only string values'
53 class Name(StrEnum):
54 BDFL = 'Guido van Rossum'
55 FLUFL = 'Barry Warsaw'
56except Exception as exc:
57 Name = exc
58
59try:
60 Question = Enum('Question', 'who what when where why', module=__name__)
61except Exception as exc:
62 Question = exc
63
64try:
65 Answer = Enum('Answer', 'him this then there because')
66except Exception as exc:
67 Answer = exc
68
Ethan Furmanca1b7942014-02-08 11:36:27 -080069try:
70 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
71except Exception as exc:
72 Theory = exc
73
Ethan Furman6b3d64a2013-06-14 16:55:46 -070074# for doctests
75try:
76 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080077 TOMATO = 1
78 BANANA = 2
79 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070080except Exception:
81 pass
82
Serhiy Storchakae50e7802015-03-31 16:56:49 +030083def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080084 if target is None:
85 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030086 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 assertion(loads(dumps(source, protocol=protocol)), target)
88
Serhiy Storchakae50e7802015-03-31 16:56:49 +030089def test_pickle_exception(assertion, exception, obj):
90 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 with assertion(exception):
92 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070093
94class TestHelpers(unittest.TestCase):
95 # _is_descriptor, _is_sunder, _is_dunder
96
97 def test_is_descriptor(self):
98 class foo:
99 pass
100 for attr in ('__get__','__set__','__delete__'):
101 obj = foo()
102 self.assertFalse(enum._is_descriptor(obj))
103 setattr(obj, attr, 1)
104 self.assertTrue(enum._is_descriptor(obj))
105
106 def test_is_sunder(self):
107 for s in ('_a_', '_aa_'):
108 self.assertTrue(enum._is_sunder(s))
109
110 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
111 '__', '___', '____', '_____',):
112 self.assertFalse(enum._is_sunder(s))
113
114 def test_is_dunder(self):
115 for s in ('__a__', '__aa__'):
116 self.assertTrue(enum._is_dunder(s))
117 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_dunder(s))
120
Ethan Furman5bdab642018-09-21 19:03:09 -0700121# for subclassing tests
122
123class classproperty:
124
125 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
126 self.fget = fget
127 self.fset = fset
128 self.fdel = fdel
129 if doc is None and fget is not None:
130 doc = fget.__doc__
131 self.__doc__ = doc
132
133 def __get__(self, instance, ownerclass):
134 return self.fget(ownerclass)
135
136
Ethan Furmanc16595e2016-09-10 23:36:59 -0700137# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700138
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700139class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800140
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700141 def setUp(self):
142 class Season(Enum):
143 SPRING = 1
144 SUMMER = 2
145 AUTUMN = 3
146 WINTER = 4
147 self.Season = Season
148
Ethan Furmanec15a822013-08-31 19:17:41 -0700149 class Konstants(float, Enum):
150 E = 2.7182818
151 PI = 3.1415926
152 TAU = 2 * PI
153 self.Konstants = Konstants
154
155 class Grades(IntEnum):
156 A = 5
157 B = 4
158 C = 3
159 D = 2
160 F = 0
161 self.Grades = Grades
162
163 class Directional(str, Enum):
164 EAST = 'east'
165 WEST = 'west'
166 NORTH = 'north'
167 SOUTH = 'south'
168 self.Directional = Directional
169
170 from datetime import date
171 class Holiday(date, Enum):
172 NEW_YEAR = 2013, 1, 1
173 IDES_OF_MARCH = 2013, 3, 15
174 self.Holiday = Holiday
175
Ethan Furman388a3922013-08-12 06:51:41 -0700176 def test_dir_on_class(self):
177 Season = self.Season
178 self.assertEqual(
179 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700180 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700181 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
182 )
183
184 def test_dir_on_item(self):
185 Season = self.Season
186 self.assertEqual(
187 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700188 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700189 )
190
Ethan Furmanc850f342013-09-15 16:59:35 -0700191 def test_dir_with_added_behavior(self):
192 class Test(Enum):
193 this = 'that'
194 these = 'those'
195 def wowser(self):
196 return ("Wowser! I'm %s!" % self.name)
197 self.assertEqual(
198 set(dir(Test)),
199 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
200 )
201 self.assertEqual(
202 set(dir(Test.this)),
203 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
204 )
205
Ethan Furman0ae550b2014-10-14 08:58:32 -0700206 def test_dir_on_sub_with_behavior_on_super(self):
207 # see issue22506
208 class SuperEnum(Enum):
209 def invisible(self):
210 return "did you see me?"
211 class SubEnum(SuperEnum):
212 sample = 5
213 self.assertEqual(
214 set(dir(SubEnum.sample)),
215 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
216 )
217
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700218 def test_enum_in_enum_out(self):
219 Season = self.Season
220 self.assertIs(Season(Season.WINTER), Season.WINTER)
221
222 def test_enum_value(self):
223 Season = self.Season
224 self.assertEqual(Season.SPRING.value, 1)
225
226 def test_intenum_value(self):
227 self.assertEqual(IntStooges.CURLY.value, 2)
228
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700229 def test_enum(self):
230 Season = self.Season
231 lst = list(Season)
232 self.assertEqual(len(lst), len(Season))
233 self.assertEqual(len(Season), 4, Season)
234 self.assertEqual(
235 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
236
237 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
238 e = Season(i)
239 self.assertEqual(e, getattr(Season, season))
240 self.assertEqual(e.value, i)
241 self.assertNotEqual(e, i)
242 self.assertEqual(e.name, season)
243 self.assertIn(e, Season)
244 self.assertIs(type(e), Season)
245 self.assertIsInstance(e, Season)
246 self.assertEqual(str(e), 'Season.' + season)
247 self.assertEqual(
248 repr(e),
249 '<Season.{0}: {1}>'.format(season, i),
250 )
251
252 def test_value_name(self):
253 Season = self.Season
254 self.assertEqual(Season.SPRING.name, 'SPRING')
255 self.assertEqual(Season.SPRING.value, 1)
256 with self.assertRaises(AttributeError):
257 Season.SPRING.name = 'invierno'
258 with self.assertRaises(AttributeError):
259 Season.SPRING.value = 2
260
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700261 def test_changing_member(self):
262 Season = self.Season
263 with self.assertRaises(AttributeError):
264 Season.WINTER = 'really cold'
265
Ethan Furman64a99722013-09-22 16:18:19 -0700266 def test_attribute_deletion(self):
267 class Season(Enum):
268 SPRING = 1
269 SUMMER = 2
270 AUTUMN = 3
271 WINTER = 4
272
273 def spam(cls):
274 pass
275
276 self.assertTrue(hasattr(Season, 'spam'))
277 del Season.spam
278 self.assertFalse(hasattr(Season, 'spam'))
279
280 with self.assertRaises(AttributeError):
281 del Season.SPRING
282 with self.assertRaises(AttributeError):
283 del Season.DRY
284 with self.assertRaises(AttributeError):
285 del Season.SPRING.name
286
Ethan Furman5de67b12016-04-13 23:52:09 -0700287 def test_bool_of_class(self):
288 class Empty(Enum):
289 pass
290 self.assertTrue(bool(Empty))
291
292 def test_bool_of_member(self):
293 class Count(Enum):
294 zero = 0
295 one = 1
296 two = 2
297 for member in Count:
298 self.assertTrue(bool(member))
299
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700300 def test_invalid_names(self):
301 with self.assertRaises(ValueError):
302 class Wrong(Enum):
303 mro = 9
304 with self.assertRaises(ValueError):
305 class Wrong(Enum):
306 _create_= 11
307 with self.assertRaises(ValueError):
308 class Wrong(Enum):
309 _get_mixins_ = 9
310 with self.assertRaises(ValueError):
311 class Wrong(Enum):
312 _find_new_ = 1
313 with self.assertRaises(ValueError):
314 class Wrong(Enum):
315 _any_name_ = 9
316
Ethan Furman6db1fd52015-09-17 21:49:12 -0700317 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800318 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700319 class Logic(Enum):
320 true = True
321 false = False
322 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800323 self.assertTrue(Logic.false)
324 # unless overridden
325 class RealLogic(Enum):
326 true = True
327 false = False
328 def __bool__(self):
329 return bool(self._value_)
330 self.assertTrue(RealLogic.true)
331 self.assertFalse(RealLogic.false)
332 # mixed Enums depend on mixed-in type
333 class IntLogic(int, Enum):
334 true = 1
335 false = 0
336 self.assertTrue(IntLogic.true)
337 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700338
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700339 def test_contains(self):
340 Season = self.Season
341 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530342 with self.assertRaises(TypeError):
343 3 in Season
344 with self.assertRaises(TypeError):
345 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700346
347 val = Season(3)
348 self.assertIn(val, Season)
349
350 class OtherEnum(Enum):
351 one = 1; two = 2
352 self.assertNotIn(OtherEnum.two, Season)
353
354 def test_comparisons(self):
355 Season = self.Season
356 with self.assertRaises(TypeError):
357 Season.SPRING < Season.WINTER
358 with self.assertRaises(TypeError):
359 Season.SPRING > 4
360
361 self.assertNotEqual(Season.SPRING, 1)
362
363 class Part(Enum):
364 SPRING = 1
365 CLIP = 2
366 BARREL = 3
367
368 self.assertNotEqual(Season.SPRING, Part.SPRING)
369 with self.assertRaises(TypeError):
370 Season.SPRING < Part.CLIP
371
372 def test_enum_duplicates(self):
373 class Season(Enum):
374 SPRING = 1
375 SUMMER = 2
376 AUTUMN = FALL = 3
377 WINTER = 4
378 ANOTHER_SPRING = 1
379 lst = list(Season)
380 self.assertEqual(
381 lst,
382 [Season.SPRING, Season.SUMMER,
383 Season.AUTUMN, Season.WINTER,
384 ])
385 self.assertIs(Season.FALL, Season.AUTUMN)
386 self.assertEqual(Season.FALL.value, 3)
387 self.assertEqual(Season.AUTUMN.value, 3)
388 self.assertIs(Season(3), Season.AUTUMN)
389 self.assertIs(Season(1), Season.SPRING)
390 self.assertEqual(Season.FALL.name, 'AUTUMN')
391 self.assertEqual(
392 [k for k,v in Season.__members__.items() if v.name != k],
393 ['FALL', 'ANOTHER_SPRING'],
394 )
395
Ethan Furman101e0742013-09-15 12:34:36 -0700396 def test_duplicate_name(self):
397 with self.assertRaises(TypeError):
398 class Color(Enum):
399 red = 1
400 green = 2
401 blue = 3
402 red = 4
403
404 with self.assertRaises(TypeError):
405 class Color(Enum):
406 red = 1
407 green = 2
408 blue = 3
409 def red(self):
410 return 'red'
411
412 with self.assertRaises(TypeError):
413 class Color(Enum):
414 @property
415 def red(self):
416 return 'redder'
417 red = 1
418 green = 2
419 blue = 3
420
421
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700422 def test_enum_with_value_name(self):
423 class Huh(Enum):
424 name = 1
425 value = 2
426 self.assertEqual(
427 list(Huh),
428 [Huh.name, Huh.value],
429 )
430 self.assertIs(type(Huh.name), Huh)
431 self.assertEqual(Huh.name.name, 'name')
432 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700433
434 def test_format_enum(self):
435 Season = self.Season
436 self.assertEqual('{}'.format(Season.SPRING),
437 '{}'.format(str(Season.SPRING)))
438 self.assertEqual( '{:}'.format(Season.SPRING),
439 '{:}'.format(str(Season.SPRING)))
440 self.assertEqual('{:20}'.format(Season.SPRING),
441 '{:20}'.format(str(Season.SPRING)))
442 self.assertEqual('{:^20}'.format(Season.SPRING),
443 '{:^20}'.format(str(Season.SPRING)))
444 self.assertEqual('{:>20}'.format(Season.SPRING),
445 '{:>20}'.format(str(Season.SPRING)))
446 self.assertEqual('{:<20}'.format(Season.SPRING),
447 '{:<20}'.format(str(Season.SPRING)))
448
thatneat2f19e822019-07-04 11:28:37 -0700449 def test_str_override_enum(self):
450 class EnumWithStrOverrides(Enum):
451 one = auto()
452 two = auto()
453
454 def __str__(self):
455 return 'Str!'
456 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
457 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
458
459 def test_format_override_enum(self):
460 class EnumWithFormatOverride(Enum):
461 one = 1.0
462 two = 2.0
463 def __format__(self, spec):
464 return 'Format!!'
465 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
466 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
467
468 def test_str_and_format_override_enum(self):
469 class EnumWithStrFormatOverrides(Enum):
470 one = auto()
471 two = auto()
472 def __str__(self):
473 return 'Str!'
474 def __format__(self, spec):
475 return 'Format!'
476 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
477 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
478
479 def test_str_override_mixin(self):
480 class MixinEnumWithStrOverride(float, Enum):
481 one = 1.0
482 two = 2.0
483 def __str__(self):
484 return 'Overridden!'
485 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
486 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
487
488 def test_str_and_format_override_mixin(self):
489 class MixinWithStrFormatOverrides(float, Enum):
490 one = 1.0
491 two = 2.0
492 def __str__(self):
493 return 'Str!'
494 def __format__(self, spec):
495 return 'Format!'
496 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
497 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
498
499 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700500 class TestFloat(float, Enum):
501 one = 1.0
502 two = 2.0
503 def __format__(self, spec):
504 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700505 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700506 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
507
508 def assertFormatIsValue(self, spec, member):
509 self.assertEqual(spec.format(member), spec.format(member.value))
510
511 def test_format_enum_date(self):
512 Holiday = self.Holiday
513 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
514 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
515 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
516 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
517 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
518 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
519 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
520 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
521
522 def test_format_enum_float(self):
523 Konstants = self.Konstants
524 self.assertFormatIsValue('{}', Konstants.TAU)
525 self.assertFormatIsValue('{:}', Konstants.TAU)
526 self.assertFormatIsValue('{:20}', Konstants.TAU)
527 self.assertFormatIsValue('{:^20}', Konstants.TAU)
528 self.assertFormatIsValue('{:>20}', Konstants.TAU)
529 self.assertFormatIsValue('{:<20}', Konstants.TAU)
530 self.assertFormatIsValue('{:n}', Konstants.TAU)
531 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
532 self.assertFormatIsValue('{:f}', Konstants.TAU)
533
534 def test_format_enum_int(self):
535 Grades = self.Grades
536 self.assertFormatIsValue('{}', Grades.C)
537 self.assertFormatIsValue('{:}', Grades.C)
538 self.assertFormatIsValue('{:20}', Grades.C)
539 self.assertFormatIsValue('{:^20}', Grades.C)
540 self.assertFormatIsValue('{:>20}', Grades.C)
541 self.assertFormatIsValue('{:<20}', Grades.C)
542 self.assertFormatIsValue('{:+}', Grades.C)
543 self.assertFormatIsValue('{:08X}', Grades.C)
544 self.assertFormatIsValue('{:b}', Grades.C)
545
546 def test_format_enum_str(self):
547 Directional = self.Directional
548 self.assertFormatIsValue('{}', Directional.WEST)
549 self.assertFormatIsValue('{:}', Directional.WEST)
550 self.assertFormatIsValue('{:20}', Directional.WEST)
551 self.assertFormatIsValue('{:^20}', Directional.WEST)
552 self.assertFormatIsValue('{:>20}', Directional.WEST)
553 self.assertFormatIsValue('{:<20}', Directional.WEST)
554
Ethan Furmana4677062020-09-16 03:58:33 -0700555 def test_object_str_override(self):
556 class Colors(Enum):
557 RED, GREEN, BLUE = 1, 2, 3
558 def __repr__(self):
559 return "test.%s" % (self._name_, )
560 __str__ = object.__str__
561 self.assertEqual(str(Colors.RED), 'test.RED')
562
Miss Islington (bot)95b81e22020-09-15 16:59:48 -0700563 def test_enum_str_override(self):
564 class MyStrEnum(Enum):
565 def __str__(self):
566 return 'MyStr'
567 class MyMethodEnum(Enum):
568 def hello(self):
569 return 'Hello! My name is %s' % self.name
570 class Test1Enum(MyMethodEnum, int, MyStrEnum):
571 One = 1
572 Two = 2
573 self.assertEqual(str(Test1Enum.One), 'MyStr')
574 #
575 class Test2Enum(MyStrEnum, MyMethodEnum):
576 One = 1
577 Two = 2
578 self.assertEqual(str(Test2Enum.One), 'MyStr')
579
580 def test_inherited_data_type(self):
581 class HexInt(int):
582 def __repr__(self):
583 return hex(self)
584 class MyEnum(HexInt, enum.Enum):
585 A = 1
586 B = 2
587 C = 3
588 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
589
590 def test_too_many_data_types(self):
591 with self.assertRaisesRegex(TypeError, 'too many data types'):
592 class Huh(str, int, Enum):
593 One = 1
594
595 class MyStr(str):
596 def hello(self):
597 return 'hello, %s' % self
598 class MyInt(int):
599 def repr(self):
600 return hex(self)
601 with self.assertRaisesRegex(TypeError, 'too many data types'):
602 class Huh(MyStr, MyInt, Enum):
603 One = 1
604
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700605 def test_hash(self):
606 Season = self.Season
607 dates = {}
608 dates[Season.WINTER] = '1225'
609 dates[Season.SPRING] = '0315'
610 dates[Season.SUMMER] = '0704'
611 dates[Season.AUTUMN] = '1031'
612 self.assertEqual(dates[Season.AUTUMN], '1031')
613
614 def test_intenum_from_scratch(self):
615 class phy(int, Enum):
616 pi = 3
617 tau = 2 * pi
618 self.assertTrue(phy.pi < phy.tau)
619
620 def test_intenum_inherited(self):
621 class IntEnum(int, Enum):
622 pass
623 class phy(IntEnum):
624 pi = 3
625 tau = 2 * pi
626 self.assertTrue(phy.pi < phy.tau)
627
628 def test_floatenum_from_scratch(self):
629 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700630 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700631 tau = 2 * pi
632 self.assertTrue(phy.pi < phy.tau)
633
634 def test_floatenum_inherited(self):
635 class FloatEnum(float, Enum):
636 pass
637 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700638 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700639 tau = 2 * pi
640 self.assertTrue(phy.pi < phy.tau)
641
642 def test_strenum_from_scratch(self):
643 class phy(str, Enum):
644 pi = 'Pi'
645 tau = 'Tau'
646 self.assertTrue(phy.pi < phy.tau)
647
648 def test_strenum_inherited(self):
649 class StrEnum(str, Enum):
650 pass
651 class phy(StrEnum):
652 pi = 'Pi'
653 tau = 'Tau'
654 self.assertTrue(phy.pi < phy.tau)
655
656
657 def test_intenum(self):
658 class WeekDay(IntEnum):
659 SUNDAY = 1
660 MONDAY = 2
661 TUESDAY = 3
662 WEDNESDAY = 4
663 THURSDAY = 5
664 FRIDAY = 6
665 SATURDAY = 7
666
667 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
668 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
669
670 lst = list(WeekDay)
671 self.assertEqual(len(lst), len(WeekDay))
672 self.assertEqual(len(WeekDay), 7)
673 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
674 target = target.split()
675 for i, weekday in enumerate(target, 1):
676 e = WeekDay(i)
677 self.assertEqual(e, i)
678 self.assertEqual(int(e), i)
679 self.assertEqual(e.name, weekday)
680 self.assertIn(e, WeekDay)
681 self.assertEqual(lst.index(e)+1, i)
682 self.assertTrue(0 < e < 8)
683 self.assertIs(type(e), WeekDay)
684 self.assertIsInstance(e, int)
685 self.assertIsInstance(e, Enum)
686
687 def test_intenum_duplicates(self):
688 class WeekDay(IntEnum):
689 SUNDAY = 1
690 MONDAY = 2
691 TUESDAY = TEUSDAY = 3
692 WEDNESDAY = 4
693 THURSDAY = 5
694 FRIDAY = 6
695 SATURDAY = 7
696 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
697 self.assertEqual(WeekDay(3).name, 'TUESDAY')
698 self.assertEqual([k for k,v in WeekDay.__members__.items()
699 if v.name != k], ['TEUSDAY', ])
700
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300701 def test_intenum_from_bytes(self):
702 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
703 with self.assertRaises(ValueError):
704 IntStooges.from_bytes(b'\x00\x05', 'big')
705
706 def test_floatenum_fromhex(self):
707 h = float.hex(FloatStooges.MOE.value)
708 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
709 h = float.hex(FloatStooges.MOE.value + 0.01)
710 with self.assertRaises(ValueError):
711 FloatStooges.fromhex(h)
712
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700713 def test_pickle_enum(self):
714 if isinstance(Stooges, Exception):
715 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800716 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
717 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700718
719 def test_pickle_int(self):
720 if isinstance(IntStooges, Exception):
721 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800722 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
723 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700724
725 def test_pickle_float(self):
726 if isinstance(FloatStooges, Exception):
727 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800728 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
729 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700730
731 def test_pickle_enum_function(self):
732 if isinstance(Answer, Exception):
733 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800734 test_pickle_dump_load(self.assertIs, Answer.him)
735 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700736
737 def test_pickle_enum_function_with_module(self):
738 if isinstance(Question, Exception):
739 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800740 test_pickle_dump_load(self.assertIs, Question.who)
741 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700742
Ethan Furmanca1b7942014-02-08 11:36:27 -0800743 def test_enum_function_with_qualname(self):
744 if isinstance(Theory, Exception):
745 raise Theory
746 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
747
748 def test_class_nested_enum_and_pickle_protocol_four(self):
749 # would normally just have this directly in the class namespace
750 class NestedEnum(Enum):
751 twigs = 'common'
752 shiny = 'rare'
753
754 self.__class__.NestedEnum = NestedEnum
755 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300756 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800757
Ethan Furman24e837f2015-03-18 17:27:57 -0700758 def test_pickle_by_name(self):
759 class ReplaceGlobalInt(IntEnum):
760 ONE = 1
761 TWO = 2
762 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
763 for proto in range(HIGHEST_PROTOCOL):
764 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
765
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700766 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800767 BadPickle = Enum(
768 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700769 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800770 # now break BadPickle to test exception raising
771 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800772 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
773 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700774
775 def test_string_enum(self):
776 class SkillLevel(str, Enum):
777 master = 'what is the sound of one hand clapping?'
778 journeyman = 'why did the chicken cross the road?'
779 apprentice = 'knock, knock!'
780 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
781
782 def test_getattr_getitem(self):
783 class Period(Enum):
784 morning = 1
785 noon = 2
786 evening = 3
787 night = 4
788 self.assertIs(Period(2), Period.noon)
789 self.assertIs(getattr(Period, 'night'), Period.night)
790 self.assertIs(Period['morning'], Period.morning)
791
792 def test_getattr_dunder(self):
793 Season = self.Season
794 self.assertTrue(getattr(Season, '__eq__'))
795
796 def test_iteration_order(self):
797 class Season(Enum):
798 SUMMER = 2
799 WINTER = 4
800 AUTUMN = 3
801 SPRING = 1
802 self.assertEqual(
803 list(Season),
804 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
805 )
806
Ethan Furman2131a4a2013-09-14 18:11:24 -0700807 def test_reversed_iteration_order(self):
808 self.assertEqual(
809 list(reversed(self.Season)),
810 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
811 self.Season.SPRING]
812 )
813
Martin Pantereb995702016-07-28 01:11:04 +0000814 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700815 SummerMonth = Enum('SummerMonth', 'june july august')
816 lst = list(SummerMonth)
817 self.assertEqual(len(lst), len(SummerMonth))
818 self.assertEqual(len(SummerMonth), 3, SummerMonth)
819 self.assertEqual(
820 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
821 lst,
822 )
823 for i, month in enumerate('june july august'.split(), 1):
824 e = SummerMonth(i)
825 self.assertEqual(int(e.value), i)
826 self.assertNotEqual(e, i)
827 self.assertEqual(e.name, month)
828 self.assertIn(e, SummerMonth)
829 self.assertIs(type(e), SummerMonth)
830
Martin Pantereb995702016-07-28 01:11:04 +0000831 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700832 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
833 lst = list(SummerMonth)
834 self.assertEqual(len(lst), len(SummerMonth))
835 self.assertEqual(len(SummerMonth), 3, SummerMonth)
836 self.assertEqual(
837 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
838 lst,
839 )
840 for i, month in enumerate('june july august'.split(), 10):
841 e = SummerMonth(i)
842 self.assertEqual(int(e.value), i)
843 self.assertNotEqual(e, i)
844 self.assertEqual(e.name, month)
845 self.assertIn(e, SummerMonth)
846 self.assertIs(type(e), SummerMonth)
847
Martin Pantereb995702016-07-28 01:11:04 +0000848 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700849 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
850 lst = list(SummerMonth)
851 self.assertEqual(len(lst), len(SummerMonth))
852 self.assertEqual(len(SummerMonth), 3, SummerMonth)
853 self.assertEqual(
854 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
855 lst,
856 )
857 for i, month in enumerate('june july august'.split(), 1):
858 e = SummerMonth(i)
859 self.assertEqual(int(e.value), i)
860 self.assertNotEqual(e, i)
861 self.assertEqual(e.name, month)
862 self.assertIn(e, SummerMonth)
863 self.assertIs(type(e), SummerMonth)
864
Martin Pantereb995702016-07-28 01:11:04 +0000865 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700866 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
867 lst = list(SummerMonth)
868 self.assertEqual(len(lst), len(SummerMonth))
869 self.assertEqual(len(SummerMonth), 3, SummerMonth)
870 self.assertEqual(
871 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
872 lst,
873 )
874 for i, month in enumerate('june july august'.split(), 20):
875 e = SummerMonth(i)
876 self.assertEqual(int(e.value), i)
877 self.assertNotEqual(e, i)
878 self.assertEqual(e.name, month)
879 self.assertIn(e, SummerMonth)
880 self.assertIs(type(e), SummerMonth)
881
Martin Pantereb995702016-07-28 01:11:04 +0000882 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700883 SummerMonth = Enum(
884 'SummerMonth',
885 (('june', 1), ('july', 2), ('august', 3))
886 )
887 lst = list(SummerMonth)
888 self.assertEqual(len(lst), len(SummerMonth))
889 self.assertEqual(len(SummerMonth), 3, SummerMonth)
890 self.assertEqual(
891 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
892 lst,
893 )
894 for i, month in enumerate('june july august'.split(), 1):
895 e = SummerMonth(i)
896 self.assertEqual(int(e.value), i)
897 self.assertNotEqual(e, i)
898 self.assertEqual(e.name, month)
899 self.assertIn(e, SummerMonth)
900 self.assertIs(type(e), SummerMonth)
901
Martin Pantereb995702016-07-28 01:11:04 +0000902 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700903 SummerMonth = Enum(
904 'SummerMonth',
905 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
906 )
907 lst = list(SummerMonth)
908 self.assertEqual(len(lst), len(SummerMonth))
909 self.assertEqual(len(SummerMonth), 3, SummerMonth)
910 self.assertEqual(
911 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
912 lst,
913 )
914 for i, month in enumerate('june july august'.split(), 1):
915 e = SummerMonth(i)
916 self.assertEqual(int(e.value), i)
917 self.assertNotEqual(e, i)
918 self.assertEqual(e.name, month)
919 self.assertIn(e, SummerMonth)
920 self.assertIs(type(e), SummerMonth)
921
Martin Pantereb995702016-07-28 01:11:04 +0000922 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700923 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
924 lst = list(SummerMonth)
925 self.assertEqual(len(lst), len(SummerMonth))
926 self.assertEqual(len(SummerMonth), 3, SummerMonth)
927 self.assertEqual(
928 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
929 lst,
930 )
931 for i, month in enumerate('june july august'.split(), 1):
932 e = SummerMonth(i)
933 self.assertEqual(e, i)
934 self.assertEqual(e.name, month)
935 self.assertIn(e, SummerMonth)
936 self.assertIs(type(e), SummerMonth)
937
Martin Pantereb995702016-07-28 01:11:04 +0000938 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700939 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
940 lst = list(SummerMonth)
941 self.assertEqual(len(lst), len(SummerMonth))
942 self.assertEqual(len(SummerMonth), 3, SummerMonth)
943 self.assertEqual(
944 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
945 lst,
946 )
947 for i, month in enumerate('june july august'.split(), 30):
948 e = SummerMonth(i)
949 self.assertEqual(e, i)
950 self.assertEqual(e.name, month)
951 self.assertIn(e, SummerMonth)
952 self.assertIs(type(e), SummerMonth)
953
Martin Pantereb995702016-07-28 01:11:04 +0000954 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700955 SummerMonth = IntEnum('SummerMonth', 'june july august')
956 lst = list(SummerMonth)
957 self.assertEqual(len(lst), len(SummerMonth))
958 self.assertEqual(len(SummerMonth), 3, SummerMonth)
959 self.assertEqual(
960 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
961 lst,
962 )
963 for i, month in enumerate('june july august'.split(), 1):
964 e = SummerMonth(i)
965 self.assertEqual(e, i)
966 self.assertEqual(e.name, month)
967 self.assertIn(e, SummerMonth)
968 self.assertIs(type(e), SummerMonth)
969
Martin Pantereb995702016-07-28 01:11:04 +0000970 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700971 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
972 lst = list(SummerMonth)
973 self.assertEqual(len(lst), len(SummerMonth))
974 self.assertEqual(len(SummerMonth), 3, SummerMonth)
975 self.assertEqual(
976 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
977 lst,
978 )
979 for i, month in enumerate('june july august'.split(), 40):
980 e = SummerMonth(i)
981 self.assertEqual(e, i)
982 self.assertEqual(e.name, month)
983 self.assertIn(e, SummerMonth)
984 self.assertIs(type(e), SummerMonth)
985
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700986 def test_subclassing(self):
987 if isinstance(Name, Exception):
988 raise Name
989 self.assertEqual(Name.BDFL, 'Guido van Rossum')
990 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
991 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800992 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700993
994 def test_extending(self):
995 class Color(Enum):
996 red = 1
997 green = 2
998 blue = 3
999 with self.assertRaises(TypeError):
1000 class MoreColor(Color):
1001 cyan = 4
1002 magenta = 5
1003 yellow = 6
Miss Islington (bot)48f99252020-09-16 07:35:14 -07001004 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1005 class EvenMoreColor(Color, IntEnum):
1006 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001007
1008 def test_exclude_methods(self):
1009 class whatever(Enum):
1010 this = 'that'
1011 these = 'those'
1012 def really(self):
1013 return 'no, not %s' % self.value
1014 self.assertIsNot(type(whatever.really), whatever)
1015 self.assertEqual(whatever.this.really(), 'no, not that')
1016
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001017 def test_wrong_inheritance_order(self):
1018 with self.assertRaises(TypeError):
1019 class Wrong(Enum, str):
1020 NotHere = 'error before this point'
1021
1022 def test_intenum_transitivity(self):
1023 class number(IntEnum):
1024 one = 1
1025 two = 2
1026 three = 3
1027 class numero(IntEnum):
1028 uno = 1
1029 dos = 2
1030 tres = 3
1031 self.assertEqual(number.one, numero.uno)
1032 self.assertEqual(number.two, numero.dos)
1033 self.assertEqual(number.three, numero.tres)
1034
1035 def test_wrong_enum_in_call(self):
1036 class Monochrome(Enum):
1037 black = 0
1038 white = 1
1039 class Gender(Enum):
1040 male = 0
1041 female = 1
1042 self.assertRaises(ValueError, Monochrome, Gender.male)
1043
1044 def test_wrong_enum_in_mixed_call(self):
1045 class Monochrome(IntEnum):
1046 black = 0
1047 white = 1
1048 class Gender(Enum):
1049 male = 0
1050 female = 1
1051 self.assertRaises(ValueError, Monochrome, Gender.male)
1052
1053 def test_mixed_enum_in_call_1(self):
1054 class Monochrome(IntEnum):
1055 black = 0
1056 white = 1
1057 class Gender(IntEnum):
1058 male = 0
1059 female = 1
1060 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1061
1062 def test_mixed_enum_in_call_2(self):
1063 class Monochrome(Enum):
1064 black = 0
1065 white = 1
1066 class Gender(IntEnum):
1067 male = 0
1068 female = 1
1069 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1070
1071 def test_flufl_enum(self):
1072 class Fluflnum(Enum):
1073 def __int__(self):
1074 return int(self.value)
1075 class MailManOptions(Fluflnum):
1076 option1 = 1
1077 option2 = 2
1078 option3 = 3
1079 self.assertEqual(int(MailManOptions.option1), 1)
1080
Ethan Furman5e5a8232013-08-04 08:42:23 -07001081 def test_introspection(self):
1082 class Number(IntEnum):
1083 one = 100
1084 two = 200
1085 self.assertIs(Number.one._member_type_, int)
1086 self.assertIs(Number._member_type_, int)
1087 class String(str, Enum):
1088 yarn = 'soft'
1089 rope = 'rough'
1090 wire = 'hard'
1091 self.assertIs(String.yarn._member_type_, str)
1092 self.assertIs(String._member_type_, str)
1093 class Plain(Enum):
1094 vanilla = 'white'
1095 one = 1
1096 self.assertIs(Plain.vanilla._member_type_, object)
1097 self.assertIs(Plain._member_type_, object)
1098
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001099 def test_no_such_enum_member(self):
1100 class Color(Enum):
1101 red = 1
1102 green = 2
1103 blue = 3
1104 with self.assertRaises(ValueError):
1105 Color(4)
1106 with self.assertRaises(KeyError):
1107 Color['chartreuse']
1108
1109 def test_new_repr(self):
1110 class Color(Enum):
1111 red = 1
1112 green = 2
1113 blue = 3
1114 def __repr__(self):
1115 return "don't you just love shades of %s?" % self.name
1116 self.assertEqual(
1117 repr(Color.blue),
1118 "don't you just love shades of blue?",
1119 )
1120
1121 def test_inherited_repr(self):
1122 class MyEnum(Enum):
1123 def __repr__(self):
1124 return "My name is %s." % self.name
1125 class MyIntEnum(int, MyEnum):
1126 this = 1
1127 that = 2
1128 theother = 3
1129 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1130
1131 def test_multiple_mixin_mro(self):
1132 class auto_enum(type(Enum)):
1133 def __new__(metacls, cls, bases, classdict):
1134 temp = type(classdict)()
1135 names = set(classdict._member_names)
1136 i = 0
1137 for k in classdict._member_names:
1138 v = classdict[k]
1139 if v is Ellipsis:
1140 v = i
1141 else:
1142 i = v
1143 i += 1
1144 temp[k] = v
1145 for k, v in classdict.items():
1146 if k not in names:
1147 temp[k] = v
1148 return super(auto_enum, metacls).__new__(
1149 metacls, cls, bases, temp)
1150
1151 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1152 pass
1153
1154 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1155 pass
1156
1157 class TestAutoNumber(AutoNumberedEnum):
1158 a = ...
1159 b = 3
1160 c = ...
1161
1162 class TestAutoInt(AutoIntEnum):
1163 a = ...
1164 b = 3
1165 c = ...
1166
1167 def test_subclasses_with_getnewargs(self):
1168 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001169 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001170 def __new__(cls, *args):
1171 _args = args
1172 name, *args = args
1173 if len(args) == 0:
1174 raise TypeError("name and value must be specified")
1175 self = int.__new__(cls, *args)
1176 self._intname = name
1177 self._args = _args
1178 return self
1179 def __getnewargs__(self):
1180 return self._args
1181 @property
1182 def __name__(self):
1183 return self._intname
1184 def __repr__(self):
1185 # repr() is updated to include the name and type info
1186 return "{}({!r}, {})".format(type(self).__name__,
1187 self.__name__,
1188 int.__repr__(self))
1189 def __str__(self):
1190 # str() is unchanged, even if it relies on the repr() fallback
1191 base = int
1192 base_str = base.__str__
1193 if base_str.__objclass__ is object:
1194 return base.__repr__(self)
1195 return base_str(self)
1196 # for simplicity, we only define one operator that
1197 # propagates expressions
1198 def __add__(self, other):
1199 temp = int(self) + int( other)
1200 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1201 return NamedInt(
1202 '({0} + {1})'.format(self.__name__, other.__name__),
1203 temp )
1204 else:
1205 return temp
1206
1207 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001208 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001209 x = ('the-x', 1)
1210 y = ('the-y', 2)
1211
Ethan Furman2aa27322013-07-19 19:35:56 -07001212
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001213 self.assertIs(NEI.__new__, Enum.__new__)
1214 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1215 globals()['NamedInt'] = NamedInt
1216 globals()['NEI'] = NEI
1217 NI5 = NamedInt('test', 5)
1218 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001219 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001220 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001221 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001222 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001223
Ethan Furmanca1b7942014-02-08 11:36:27 -08001224 def test_subclasses_with_getnewargs_ex(self):
1225 class NamedInt(int):
1226 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1227 def __new__(cls, *args):
1228 _args = args
1229 name, *args = args
1230 if len(args) == 0:
1231 raise TypeError("name and value must be specified")
1232 self = int.__new__(cls, *args)
1233 self._intname = name
1234 self._args = _args
1235 return self
1236 def __getnewargs_ex__(self):
1237 return self._args, {}
1238 @property
1239 def __name__(self):
1240 return self._intname
1241 def __repr__(self):
1242 # repr() is updated to include the name and type info
1243 return "{}({!r}, {})".format(type(self).__name__,
1244 self.__name__,
1245 int.__repr__(self))
1246 def __str__(self):
1247 # str() is unchanged, even if it relies on the repr() fallback
1248 base = int
1249 base_str = base.__str__
1250 if base_str.__objclass__ is object:
1251 return base.__repr__(self)
1252 return base_str(self)
1253 # for simplicity, we only define one operator that
1254 # propagates expressions
1255 def __add__(self, other):
1256 temp = int(self) + int( other)
1257 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1258 return NamedInt(
1259 '({0} + {1})'.format(self.__name__, other.__name__),
1260 temp )
1261 else:
1262 return temp
1263
1264 class NEI(NamedInt, Enum):
1265 __qualname__ = 'NEI' # needed for pickle protocol 4
1266 x = ('the-x', 1)
1267 y = ('the-y', 2)
1268
1269
1270 self.assertIs(NEI.__new__, Enum.__new__)
1271 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1272 globals()['NamedInt'] = NamedInt
1273 globals()['NEI'] = NEI
1274 NI5 = NamedInt('test', 5)
1275 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001276 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001277 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001278 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001279 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001280
1281 def test_subclasses_with_reduce(self):
1282 class NamedInt(int):
1283 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1284 def __new__(cls, *args):
1285 _args = args
1286 name, *args = args
1287 if len(args) == 0:
1288 raise TypeError("name and value must be specified")
1289 self = int.__new__(cls, *args)
1290 self._intname = name
1291 self._args = _args
1292 return self
1293 def __reduce__(self):
1294 return self.__class__, self._args
1295 @property
1296 def __name__(self):
1297 return self._intname
1298 def __repr__(self):
1299 # repr() is updated to include the name and type info
1300 return "{}({!r}, {})".format(type(self).__name__,
1301 self.__name__,
1302 int.__repr__(self))
1303 def __str__(self):
1304 # str() is unchanged, even if it relies on the repr() fallback
1305 base = int
1306 base_str = base.__str__
1307 if base_str.__objclass__ is object:
1308 return base.__repr__(self)
1309 return base_str(self)
1310 # for simplicity, we only define one operator that
1311 # propagates expressions
1312 def __add__(self, other):
1313 temp = int(self) + int( other)
1314 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1315 return NamedInt(
1316 '({0} + {1})'.format(self.__name__, other.__name__),
1317 temp )
1318 else:
1319 return temp
1320
1321 class NEI(NamedInt, Enum):
1322 __qualname__ = 'NEI' # needed for pickle protocol 4
1323 x = ('the-x', 1)
1324 y = ('the-y', 2)
1325
1326
1327 self.assertIs(NEI.__new__, Enum.__new__)
1328 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1329 globals()['NamedInt'] = NamedInt
1330 globals()['NEI'] = NEI
1331 NI5 = NamedInt('test', 5)
1332 self.assertEqual(NI5, 5)
1333 test_pickle_dump_load(self.assertEqual, NI5, 5)
1334 self.assertEqual(NEI.y.value, 2)
1335 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001336 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001337
1338 def test_subclasses_with_reduce_ex(self):
1339 class NamedInt(int):
1340 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1341 def __new__(cls, *args):
1342 _args = args
1343 name, *args = args
1344 if len(args) == 0:
1345 raise TypeError("name and value must be specified")
1346 self = int.__new__(cls, *args)
1347 self._intname = name
1348 self._args = _args
1349 return self
1350 def __reduce_ex__(self, proto):
1351 return self.__class__, self._args
1352 @property
1353 def __name__(self):
1354 return self._intname
1355 def __repr__(self):
1356 # repr() is updated to include the name and type info
1357 return "{}({!r}, {})".format(type(self).__name__,
1358 self.__name__,
1359 int.__repr__(self))
1360 def __str__(self):
1361 # str() is unchanged, even if it relies on the repr() fallback
1362 base = int
1363 base_str = base.__str__
1364 if base_str.__objclass__ is object:
1365 return base.__repr__(self)
1366 return base_str(self)
1367 # for simplicity, we only define one operator that
1368 # propagates expressions
1369 def __add__(self, other):
1370 temp = int(self) + int( other)
1371 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1372 return NamedInt(
1373 '({0} + {1})'.format(self.__name__, other.__name__),
1374 temp )
1375 else:
1376 return temp
1377
1378 class NEI(NamedInt, Enum):
1379 __qualname__ = 'NEI' # needed for pickle protocol 4
1380 x = ('the-x', 1)
1381 y = ('the-y', 2)
1382
1383
1384 self.assertIs(NEI.__new__, Enum.__new__)
1385 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1386 globals()['NamedInt'] = NamedInt
1387 globals()['NEI'] = NEI
1388 NI5 = NamedInt('test', 5)
1389 self.assertEqual(NI5, 5)
1390 test_pickle_dump_load(self.assertEqual, NI5, 5)
1391 self.assertEqual(NEI.y.value, 2)
1392 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001393 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001394
Ethan Furmandc870522014-02-18 12:37:12 -08001395 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001396 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001397 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001398 def __new__(cls, *args):
1399 _args = args
1400 name, *args = args
1401 if len(args) == 0:
1402 raise TypeError("name and value must be specified")
1403 self = int.__new__(cls, *args)
1404 self._intname = name
1405 self._args = _args
1406 return self
1407 @property
1408 def __name__(self):
1409 return self._intname
1410 def __repr__(self):
1411 # repr() is updated to include the name and type info
1412 return "{}({!r}, {})".format(type(self).__name__,
1413 self.__name__,
1414 int.__repr__(self))
1415 def __str__(self):
1416 # str() is unchanged, even if it relies on the repr() fallback
1417 base = int
1418 base_str = base.__str__
1419 if base_str.__objclass__ is object:
1420 return base.__repr__(self)
1421 return base_str(self)
1422 # for simplicity, we only define one operator that
1423 # propagates expressions
1424 def __add__(self, other):
1425 temp = int(self) + int( other)
1426 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1427 return NamedInt(
1428 '({0} + {1})'.format(self.__name__, other.__name__),
1429 temp )
1430 else:
1431 return temp
1432
1433 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001434 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001435 x = ('the-x', 1)
1436 y = ('the-y', 2)
1437
1438 self.assertIs(NEI.__new__, Enum.__new__)
1439 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1440 globals()['NamedInt'] = NamedInt
1441 globals()['NEI'] = NEI
1442 NI5 = NamedInt('test', 5)
1443 self.assertEqual(NI5, 5)
1444 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001445 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1446 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001447
Ethan Furmandc870522014-02-18 12:37:12 -08001448 def test_subclasses_without_direct_pickle_support_using_name(self):
1449 class NamedInt(int):
1450 __qualname__ = 'NamedInt'
1451 def __new__(cls, *args):
1452 _args = args
1453 name, *args = args
1454 if len(args) == 0:
1455 raise TypeError("name and value must be specified")
1456 self = int.__new__(cls, *args)
1457 self._intname = name
1458 self._args = _args
1459 return self
1460 @property
1461 def __name__(self):
1462 return self._intname
1463 def __repr__(self):
1464 # repr() is updated to include the name and type info
1465 return "{}({!r}, {})".format(type(self).__name__,
1466 self.__name__,
1467 int.__repr__(self))
1468 def __str__(self):
1469 # str() is unchanged, even if it relies on the repr() fallback
1470 base = int
1471 base_str = base.__str__
1472 if base_str.__objclass__ is object:
1473 return base.__repr__(self)
1474 return base_str(self)
1475 # for simplicity, we only define one operator that
1476 # propagates expressions
1477 def __add__(self, other):
1478 temp = int(self) + int( other)
1479 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1480 return NamedInt(
1481 '({0} + {1})'.format(self.__name__, other.__name__),
1482 temp )
1483 else:
1484 return temp
1485
1486 class NEI(NamedInt, Enum):
1487 __qualname__ = 'NEI'
1488 x = ('the-x', 1)
1489 y = ('the-y', 2)
1490 def __reduce_ex__(self, proto):
1491 return getattr, (self.__class__, self._name_)
1492
1493 self.assertIs(NEI.__new__, Enum.__new__)
1494 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1495 globals()['NamedInt'] = NamedInt
1496 globals()['NEI'] = NEI
1497 NI5 = NamedInt('test', 5)
1498 self.assertEqual(NI5, 5)
1499 self.assertEqual(NEI.y.value, 2)
1500 test_pickle_dump_load(self.assertIs, NEI.y)
1501 test_pickle_dump_load(self.assertIs, NEI)
1502
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001503 def test_tuple_subclass(self):
1504 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001505 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001506 first = (1, 'for the money')
1507 second = (2, 'for the show')
1508 third = (3, 'for the music')
1509 self.assertIs(type(SomeTuple.first), SomeTuple)
1510 self.assertIsInstance(SomeTuple.second, tuple)
1511 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1512 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001513 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001514
1515 def test_duplicate_values_give_unique_enum_items(self):
1516 class AutoNumber(Enum):
1517 first = ()
1518 second = ()
1519 third = ()
1520 def __new__(cls):
1521 value = len(cls.__members__) + 1
1522 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001523 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001524 return obj
1525 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001526 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001527 self.assertEqual(
1528 list(AutoNumber),
1529 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1530 )
1531 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001532 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001533 self.assertIs(AutoNumber(1), AutoNumber.first)
1534
1535 def test_inherited_new_from_enhanced_enum(self):
1536 class AutoNumber(Enum):
1537 def __new__(cls):
1538 value = len(cls.__members__) + 1
1539 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001540 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001541 return obj
1542 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001543 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001544 class Color(AutoNumber):
1545 red = ()
1546 green = ()
1547 blue = ()
1548 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1549 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1550
1551 def test_inherited_new_from_mixed_enum(self):
1552 class AutoNumber(IntEnum):
1553 def __new__(cls):
1554 value = len(cls.__members__) + 1
1555 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001556 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 return obj
1558 class Color(AutoNumber):
1559 red = ()
1560 green = ()
1561 blue = ()
1562 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1563 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1564
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001565 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001566 class OrdinaryEnum(Enum):
1567 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001568 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1569 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001570
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001571 def test_ordered_mixin(self):
1572 class OrderedEnum(Enum):
1573 def __ge__(self, other):
1574 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001575 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001576 return NotImplemented
1577 def __gt__(self, other):
1578 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001579 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001580 return NotImplemented
1581 def __le__(self, other):
1582 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001583 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001584 return NotImplemented
1585 def __lt__(self, other):
1586 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001587 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001588 return NotImplemented
1589 class Grade(OrderedEnum):
1590 A = 5
1591 B = 4
1592 C = 3
1593 D = 2
1594 F = 1
1595 self.assertGreater(Grade.A, Grade.B)
1596 self.assertLessEqual(Grade.F, Grade.C)
1597 self.assertLess(Grade.D, Grade.A)
1598 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001599 self.assertEqual(Grade.B, Grade.B)
1600 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001601
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001602 def test_extending2(self):
1603 class Shade(Enum):
1604 def shade(self):
1605 print(self.name)
1606 class Color(Shade):
1607 red = 1
1608 green = 2
1609 blue = 3
1610 with self.assertRaises(TypeError):
1611 class MoreColor(Color):
1612 cyan = 4
1613 magenta = 5
1614 yellow = 6
1615
1616 def test_extending3(self):
1617 class Shade(Enum):
1618 def shade(self):
1619 return self.name
1620 class Color(Shade):
1621 def hex(self):
1622 return '%s hexlified!' % self.value
1623 class MoreColor(Color):
1624 cyan = 4
1625 magenta = 5
1626 yellow = 6
1627 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1628
orlnub1230fb9fad2018-09-12 20:28:53 +03001629 def test_subclass_duplicate_name(self):
1630 class Base(Enum):
1631 def test(self):
1632 pass
1633 class Test(Base):
1634 test = 1
1635 self.assertIs(type(Test.test), Test)
1636
1637 def test_subclass_duplicate_name_dynamic(self):
1638 from types import DynamicClassAttribute
1639 class Base(Enum):
1640 @DynamicClassAttribute
1641 def test(self):
1642 return 'dynamic'
1643 class Test(Base):
1644 test = 1
1645 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001646
1647 def test_no_duplicates(self):
1648 class UniqueEnum(Enum):
1649 def __init__(self, *args):
1650 cls = self.__class__
1651 if any(self.value == e.value for e in cls):
1652 a = self.name
1653 e = cls(self.value).name
1654 raise ValueError(
1655 "aliases not allowed in UniqueEnum: %r --> %r"
1656 % (a, e)
1657 )
1658 class Color(UniqueEnum):
1659 red = 1
1660 green = 2
1661 blue = 3
1662 with self.assertRaises(ValueError):
1663 class Color(UniqueEnum):
1664 red = 1
1665 green = 2
1666 blue = 3
1667 grene = 2
1668
1669 def test_init(self):
1670 class Planet(Enum):
1671 MERCURY = (3.303e+23, 2.4397e6)
1672 VENUS = (4.869e+24, 6.0518e6)
1673 EARTH = (5.976e+24, 6.37814e6)
1674 MARS = (6.421e+23, 3.3972e6)
1675 JUPITER = (1.9e+27, 7.1492e7)
1676 SATURN = (5.688e+26, 6.0268e7)
1677 URANUS = (8.686e+25, 2.5559e7)
1678 NEPTUNE = (1.024e+26, 2.4746e7)
1679 def __init__(self, mass, radius):
1680 self.mass = mass # in kilograms
1681 self.radius = radius # in meters
1682 @property
1683 def surface_gravity(self):
1684 # universal gravitational constant (m3 kg-1 s-2)
1685 G = 6.67300E-11
1686 return G * self.mass / (self.radius * self.radius)
1687 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1688 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1689
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001690 def test_ignore(self):
1691 class Period(timedelta, Enum):
1692 '''
1693 different lengths of time
1694 '''
1695 def __new__(cls, value, period):
1696 obj = timedelta.__new__(cls, value)
1697 obj._value_ = value
1698 obj.period = period
1699 return obj
1700 _ignore_ = 'Period i'
1701 Period = vars()
1702 for i in range(13):
1703 Period['month_%d' % i] = i*30, 'month'
1704 for i in range(53):
1705 Period['week_%d' % i] = i*7, 'week'
1706 for i in range(32):
1707 Period['day_%d' % i] = i, 'day'
1708 OneDay = day_1
1709 OneWeek = week_1
1710 OneMonth = month_1
1711 self.assertFalse(hasattr(Period, '_ignore_'))
1712 self.assertFalse(hasattr(Period, 'Period'))
1713 self.assertFalse(hasattr(Period, 'i'))
1714 self.assertTrue(isinstance(Period.day_1, timedelta))
1715 self.assertTrue(Period.month_1 is Period.day_30)
1716 self.assertTrue(Period.week_4 is Period.day_28)
1717
Ethan Furman2aa27322013-07-19 19:35:56 -07001718 def test_nonhash_value(self):
1719 class AutoNumberInAList(Enum):
1720 def __new__(cls):
1721 value = [len(cls.__members__) + 1]
1722 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001723 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001724 return obj
1725 class ColorInAList(AutoNumberInAList):
1726 red = ()
1727 green = ()
1728 blue = ()
1729 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001730 for enum, value in zip(ColorInAList, range(3)):
1731 value += 1
1732 self.assertEqual(enum.value, [value])
1733 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001734
Ethan Furmanb41803e2013-07-25 13:50:45 -07001735 def test_conflicting_types_resolved_in_new(self):
1736 class LabelledIntEnum(int, Enum):
1737 def __new__(cls, *args):
1738 value, label = args
1739 obj = int.__new__(cls, value)
1740 obj.label = label
1741 obj._value_ = value
1742 return obj
1743
1744 class LabelledList(LabelledIntEnum):
1745 unprocessed = (1, "Unprocessed")
1746 payment_complete = (2, "Payment Complete")
1747
1748 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1749 self.assertEqual(LabelledList.unprocessed, 1)
1750 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001751
Ethan Furmanc16595e2016-09-10 23:36:59 -07001752 def test_auto_number(self):
1753 class Color(Enum):
1754 red = auto()
1755 blue = auto()
1756 green = auto()
1757
1758 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1759 self.assertEqual(Color.red.value, 1)
1760 self.assertEqual(Color.blue.value, 2)
1761 self.assertEqual(Color.green.value, 3)
1762
1763 def test_auto_name(self):
1764 class Color(Enum):
1765 def _generate_next_value_(name, start, count, last):
1766 return name
1767 red = auto()
1768 blue = auto()
1769 green = auto()
1770
1771 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1772 self.assertEqual(Color.red.value, 'red')
1773 self.assertEqual(Color.blue.value, 'blue')
1774 self.assertEqual(Color.green.value, 'green')
1775
1776 def test_auto_name_inherit(self):
1777 class AutoNameEnum(Enum):
1778 def _generate_next_value_(name, start, count, last):
1779 return name
1780 class Color(AutoNameEnum):
1781 red = auto()
1782 blue = auto()
1783 green = auto()
1784
1785 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1786 self.assertEqual(Color.red.value, 'red')
1787 self.assertEqual(Color.blue.value, 'blue')
1788 self.assertEqual(Color.green.value, 'green')
1789
1790 def test_auto_garbage(self):
1791 class Color(Enum):
1792 red = 'red'
1793 blue = auto()
1794 self.assertEqual(Color.blue.value, 1)
1795
1796 def test_auto_garbage_corrected(self):
1797 class Color(Enum):
1798 red = 'red'
1799 blue = 2
1800 green = auto()
1801
1802 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1803 self.assertEqual(Color.red.value, 'red')
1804 self.assertEqual(Color.blue.value, 2)
1805 self.assertEqual(Color.green.value, 3)
1806
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001807 def test_auto_order(self):
1808 with self.assertRaises(TypeError):
1809 class Color(Enum):
1810 red = auto()
1811 green = auto()
1812 blue = auto()
1813 def _generate_next_value_(name, start, count, last):
1814 return name
1815
Miss Islington (bot)4465df62020-09-16 17:27:09 -07001816 def test_auto_order_wierd(self):
1817 weird_auto = auto()
1818 weird_auto.value = 'pathological case'
1819 class Color(Enum):
1820 red = weird_auto
1821 def _generate_next_value_(name, start, count, last):
1822 return name
1823 blue = auto()
1824 self.assertEqual(list(Color), [Color.red, Color.blue])
1825 self.assertEqual(Color.red.value, 'pathological case')
1826 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001827
Ethan Furman3515dcc2016-09-18 13:15:41 -07001828 def test_duplicate_auto(self):
1829 class Dupes(Enum):
1830 first = primero = auto()
1831 second = auto()
1832 third = auto()
1833 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1834
Ethan Furmana9ba8ba2020-09-16 17:37:51 -07001835 def test_default_missing(self):
1836 class Color(Enum):
1837 RED = 1
1838 GREEN = 2
1839 BLUE = 3
1840 try:
1841 Color(7)
1842 except ValueError as exc:
1843 self.assertTrue(exc.__context__ is None)
1844 else:
1845 raise Exception('Exception not raised.')
1846
Ethan Furman019f0a02018-09-12 11:43:34 -07001847 def test_missing(self):
1848 class Color(Enum):
1849 red = 1
1850 green = 2
1851 blue = 3
1852 @classmethod
1853 def _missing_(cls, item):
1854 if item == 'three':
1855 return cls.blue
1856 elif item == 'bad return':
1857 # trigger internal error
1858 return 5
1859 elif item == 'error out':
1860 raise ZeroDivisionError
1861 else:
1862 # trigger not found
1863 return None
1864 self.assertIs(Color('three'), Color.blue)
Ethan Furmana9ba8ba2020-09-16 17:37:51 -07001865 try:
1866 Color(7)
1867 except ValueError as exc:
1868 self.assertTrue(exc.__context__ is None)
1869 else:
1870 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001871 try:
1872 Color('bad return')
1873 except TypeError as exc:
1874 self.assertTrue(isinstance(exc.__context__, ValueError))
1875 else:
1876 raise Exception('Exception not raised.')
1877 try:
1878 Color('error out')
1879 except ZeroDivisionError as exc:
1880 self.assertTrue(isinstance(exc.__context__, ValueError))
1881 else:
1882 raise Exception('Exception not raised.')
1883
Ethan Furman5bdab642018-09-21 19:03:09 -07001884 def test_multiple_mixin(self):
1885 class MaxMixin:
1886 @classproperty
1887 def MAX(cls):
1888 max = len(cls)
1889 cls.MAX = max
1890 return max
1891 class StrMixin:
1892 def __str__(self):
1893 return self._name_.lower()
1894 class SomeEnum(Enum):
1895 def behavior(self):
1896 return 'booyah'
1897 class AnotherEnum(Enum):
1898 def behavior(self):
1899 return 'nuhuh!'
1900 def social(self):
1901 return "what's up?"
1902 class Color(MaxMixin, Enum):
1903 RED = auto()
1904 GREEN = auto()
1905 BLUE = auto()
1906 self.assertEqual(Color.RED.value, 1)
1907 self.assertEqual(Color.GREEN.value, 2)
1908 self.assertEqual(Color.BLUE.value, 3)
1909 self.assertEqual(Color.MAX, 3)
1910 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1911 class Color(MaxMixin, StrMixin, Enum):
1912 RED = auto()
1913 GREEN = auto()
1914 BLUE = auto()
1915 self.assertEqual(Color.RED.value, 1)
1916 self.assertEqual(Color.GREEN.value, 2)
1917 self.assertEqual(Color.BLUE.value, 3)
1918 self.assertEqual(Color.MAX, 3)
1919 self.assertEqual(str(Color.BLUE), 'blue')
1920 class Color(StrMixin, MaxMixin, Enum):
1921 RED = auto()
1922 GREEN = auto()
1923 BLUE = auto()
1924 self.assertEqual(Color.RED.value, 1)
1925 self.assertEqual(Color.GREEN.value, 2)
1926 self.assertEqual(Color.BLUE.value, 3)
1927 self.assertEqual(Color.MAX, 3)
1928 self.assertEqual(str(Color.BLUE), 'blue')
1929 class CoolColor(StrMixin, SomeEnum, Enum):
1930 RED = auto()
1931 GREEN = auto()
1932 BLUE = auto()
1933 self.assertEqual(CoolColor.RED.value, 1)
1934 self.assertEqual(CoolColor.GREEN.value, 2)
1935 self.assertEqual(CoolColor.BLUE.value, 3)
1936 self.assertEqual(str(CoolColor.BLUE), 'blue')
1937 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1938 class CoolerColor(StrMixin, AnotherEnum, Enum):
1939 RED = auto()
1940 GREEN = auto()
1941 BLUE = auto()
1942 self.assertEqual(CoolerColor.RED.value, 1)
1943 self.assertEqual(CoolerColor.GREEN.value, 2)
1944 self.assertEqual(CoolerColor.BLUE.value, 3)
1945 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1946 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1947 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1948 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1949 RED = auto()
1950 GREEN = auto()
1951 BLUE = auto()
1952 self.assertEqual(CoolestColor.RED.value, 1)
1953 self.assertEqual(CoolestColor.GREEN.value, 2)
1954 self.assertEqual(CoolestColor.BLUE.value, 3)
1955 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1956 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1957 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1958 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1959 RED = auto()
1960 GREEN = auto()
1961 BLUE = auto()
1962 self.assertEqual(ConfusedColor.RED.value, 1)
1963 self.assertEqual(ConfusedColor.GREEN.value, 2)
1964 self.assertEqual(ConfusedColor.BLUE.value, 3)
1965 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1966 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1967 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1968 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1969 RED = auto()
1970 GREEN = auto()
1971 BLUE = auto()
1972 self.assertEqual(ReformedColor.RED.value, 1)
1973 self.assertEqual(ReformedColor.GREEN.value, 2)
1974 self.assertEqual(ReformedColor.BLUE.value, 3)
1975 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1976 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1977 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1978 self.assertTrue(issubclass(ReformedColor, int))
1979
Ethan Furmancd453852018-10-05 23:29:36 -07001980 def test_multiple_inherited_mixin(self):
1981 class StrEnum(str, Enum):
1982 def __new__(cls, *args, **kwargs):
1983 for a in args:
1984 if not isinstance(a, str):
1985 raise TypeError("Enumeration '%s' (%s) is not"
1986 " a string" % (a, type(a).__name__))
1987 return str.__new__(cls, *args, **kwargs)
1988 @unique
1989 class Decision1(StrEnum):
1990 REVERT = "REVERT"
1991 REVERT_ALL = "REVERT_ALL"
1992 RETRY = "RETRY"
1993 class MyEnum(StrEnum):
1994 pass
1995 @unique
1996 class Decision2(MyEnum):
1997 REVERT = "REVERT"
1998 REVERT_ALL = "REVERT_ALL"
1999 RETRY = "RETRY"
2000
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002001 def test_empty_globals(self):
2002 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2003 # when using compile and exec because f_globals is empty
2004 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2005 code = compile(code, "<string>", "exec")
2006 global_ns = {}
2007 local_ls = {}
2008 exec(code, global_ns, local_ls)
2009
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002010
Ethan Furmane8e61272016-08-20 07:19:31 -07002011class TestOrder(unittest.TestCase):
2012
2013 def test_same_members(self):
2014 class Color(Enum):
2015 _order_ = 'red green blue'
2016 red = 1
2017 green = 2
2018 blue = 3
2019
2020 def test_same_members_with_aliases(self):
2021 class Color(Enum):
2022 _order_ = 'red green blue'
2023 red = 1
2024 green = 2
2025 blue = 3
2026 verde = green
2027
2028 def test_same_members_wrong_order(self):
2029 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2030 class Color(Enum):
2031 _order_ = 'red green blue'
2032 red = 1
2033 blue = 3
2034 green = 2
2035
2036 def test_order_has_extra_members(self):
2037 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2038 class Color(Enum):
2039 _order_ = 'red green blue purple'
2040 red = 1
2041 green = 2
2042 blue = 3
2043
2044 def test_order_has_extra_members_with_aliases(self):
2045 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2046 class Color(Enum):
2047 _order_ = 'red green blue purple'
2048 red = 1
2049 green = 2
2050 blue = 3
2051 verde = green
2052
2053 def test_enum_has_extra_members(self):
2054 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2055 class Color(Enum):
2056 _order_ = 'red green blue'
2057 red = 1
2058 green = 2
2059 blue = 3
2060 purple = 4
2061
2062 def test_enum_has_extra_members_with_aliases(self):
2063 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2064 class Color(Enum):
2065 _order_ = 'red green blue'
2066 red = 1
2067 green = 2
2068 blue = 3
2069 purple = 4
2070 verde = green
2071
2072
Ethan Furman65a5a472016-09-01 23:55:19 -07002073class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002074 """Tests of the Flags."""
2075
Ethan Furman65a5a472016-09-01 23:55:19 -07002076 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002077 R, W, X = 4, 2, 1
2078
Ethan Furman65a5a472016-09-01 23:55:19 -07002079 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002080 RO = 0
2081 WO = 1
2082 RW = 2
2083 AC = 3
2084 CE = 1<<19
2085
Rahul Jha94306522018-09-10 23:51:04 +05302086 class Color(Flag):
2087 BLACK = 0
2088 RED = 1
2089 GREEN = 2
2090 BLUE = 4
2091 PURPLE = RED|BLUE
2092
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002093 def test_str(self):
2094 Perm = self.Perm
2095 self.assertEqual(str(Perm.R), 'Perm.R')
2096 self.assertEqual(str(Perm.W), 'Perm.W')
2097 self.assertEqual(str(Perm.X), 'Perm.X')
2098 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2099 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2100 self.assertEqual(str(Perm(0)), 'Perm.0')
2101 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2102 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2103 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2104 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2105 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2106 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2107
2108 Open = self.Open
2109 self.assertEqual(str(Open.RO), 'Open.RO')
2110 self.assertEqual(str(Open.WO), 'Open.WO')
2111 self.assertEqual(str(Open.AC), 'Open.AC')
2112 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2113 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002114 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002115 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2116 self.assertEqual(str(~Open.AC), 'Open.CE')
2117 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2118 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2119
2120 def test_repr(self):
2121 Perm = self.Perm
2122 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2123 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2124 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2125 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2126 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002127 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002128 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2129 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2130 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2131 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002132 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002133 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2134
2135 Open = self.Open
2136 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2137 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2138 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2139 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2140 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002141 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002142 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2143 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2144 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2145 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2146
2147 def test_or(self):
2148 Perm = self.Perm
2149 for i in Perm:
2150 for j in Perm:
2151 self.assertEqual((i | j), Perm(i.value | j.value))
2152 self.assertEqual((i | j).value, i.value | j.value)
2153 self.assertIs(type(i | j), Perm)
2154 for i in Perm:
2155 self.assertIs(i | i, i)
2156 Open = self.Open
2157 self.assertIs(Open.RO | Open.CE, Open.CE)
2158
2159 def test_and(self):
2160 Perm = self.Perm
2161 RW = Perm.R | Perm.W
2162 RX = Perm.R | Perm.X
2163 WX = Perm.W | Perm.X
2164 RWX = Perm.R | Perm.W | Perm.X
2165 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2166 for i in values:
2167 for j in values:
2168 self.assertEqual((i & j).value, i.value & j.value)
2169 self.assertIs(type(i & j), Perm)
2170 for i in Perm:
2171 self.assertIs(i & i, i)
2172 self.assertIs(i & RWX, i)
2173 self.assertIs(RWX & i, i)
2174 Open = self.Open
2175 self.assertIs(Open.RO & Open.CE, Open.RO)
2176
2177 def test_xor(self):
2178 Perm = self.Perm
2179 for i in Perm:
2180 for j in Perm:
2181 self.assertEqual((i ^ j).value, i.value ^ j.value)
2182 self.assertIs(type(i ^ j), Perm)
2183 for i in Perm:
2184 self.assertIs(i ^ Perm(0), i)
2185 self.assertIs(Perm(0) ^ i, i)
2186 Open = self.Open
2187 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2188 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2189
2190 def test_invert(self):
2191 Perm = self.Perm
2192 RW = Perm.R | Perm.W
2193 RX = Perm.R | Perm.X
2194 WX = Perm.W | Perm.X
2195 RWX = Perm.R | Perm.W | Perm.X
2196 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2197 for i in values:
2198 self.assertIs(type(~i), Perm)
2199 self.assertEqual(~~i, i)
2200 for i in Perm:
2201 self.assertIs(~~i, i)
2202 Open = self.Open
2203 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2204 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2205
Ethan Furman25d94bb2016-09-02 16:32:32 -07002206 def test_bool(self):
2207 Perm = self.Perm
2208 for f in Perm:
2209 self.assertTrue(f)
2210 Open = self.Open
2211 for f in Open:
2212 self.assertEqual(bool(f.value), bool(f))
2213
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002214 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002215 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002216 lst = list(Perm)
2217 self.assertEqual(len(lst), len(Perm))
2218 self.assertEqual(len(Perm), 3, Perm)
2219 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2220 for i, n in enumerate('R W X'.split()):
2221 v = 1<<i
2222 e = Perm(v)
2223 self.assertEqual(e.value, v)
2224 self.assertEqual(type(e.value), int)
2225 self.assertEqual(e.name, n)
2226 self.assertIn(e, Perm)
2227 self.assertIs(type(e), Perm)
2228
2229 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002230 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002231 lst = list(Perm)
2232 self.assertEqual(len(lst), len(Perm))
2233 self.assertEqual(len(Perm), 3, Perm)
2234 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2235 for i, n in enumerate('R W X'.split()):
2236 v = 8<<i
2237 e = Perm(v)
2238 self.assertEqual(e.value, v)
2239 self.assertEqual(type(e.value), int)
2240 self.assertEqual(e.name, n)
2241 self.assertIn(e, Perm)
2242 self.assertIs(type(e), Perm)
2243
2244 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002245 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002246 lst = list(Perm)
2247 self.assertEqual(len(lst), len(Perm))
2248 self.assertEqual(len(Perm), 3, Perm)
2249 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2250 for i, n in enumerate('R W X'.split()):
2251 v = 1<<i
2252 e = Perm(v)
2253 self.assertEqual(e.value, v)
2254 self.assertEqual(type(e.value), int)
2255 self.assertEqual(e.name, n)
2256 self.assertIn(e, Perm)
2257 self.assertIs(type(e), Perm)
2258
2259 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002260 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002261 lst = list(Perm)
2262 self.assertEqual(len(lst), len(Perm))
2263 self.assertEqual(len(Perm), 3, Perm)
2264 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2265 for i, n in enumerate('R W X'.split()):
2266 v = 1<<(2*i+1)
2267 e = Perm(v)
2268 self.assertEqual(e.value, v)
2269 self.assertEqual(type(e.value), int)
2270 self.assertEqual(e.name, n)
2271 self.assertIn(e, Perm)
2272 self.assertIs(type(e), Perm)
2273
2274 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002275 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002276 lst = list(Perm)
2277 self.assertEqual(len(lst), len(Perm))
2278 self.assertEqual(len(Perm), 3, Perm)
2279 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2280 for i, n in enumerate('R W X'.split()):
2281 v = 1<<(2*i+1)
2282 e = Perm(v)
2283 self.assertEqual(e.value, v)
2284 self.assertEqual(type(e.value), int)
2285 self.assertEqual(e.name, n)
2286 self.assertIn(e, Perm)
2287 self.assertIs(type(e), Perm)
2288
Ethan Furman65a5a472016-09-01 23:55:19 -07002289 def test_pickle(self):
2290 if isinstance(FlagStooges, Exception):
2291 raise FlagStooges
2292 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2293 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002294
Rahul Jha94306522018-09-10 23:51:04 +05302295 def test_contains(self):
2296 Open = self.Open
2297 Color = self.Color
2298 self.assertFalse(Color.BLACK in Open)
2299 self.assertFalse(Open.RO in Color)
2300 with self.assertRaises(TypeError):
2301 'BLACK' in Color
2302 with self.assertRaises(TypeError):
2303 'RO' in Open
2304 with self.assertRaises(TypeError):
2305 1 in Color
2306 with self.assertRaises(TypeError):
2307 1 in Open
2308
2309 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002310 Perm = self.Perm
2311 R, W, X = Perm
2312 RW = R | W
2313 RX = R | X
2314 WX = W | X
2315 RWX = R | W | X
2316 self.assertTrue(R in RW)
2317 self.assertTrue(R in RX)
2318 self.assertTrue(R in RWX)
2319 self.assertTrue(W in RW)
2320 self.assertTrue(W in WX)
2321 self.assertTrue(W in RWX)
2322 self.assertTrue(X in RX)
2323 self.assertTrue(X in WX)
2324 self.assertTrue(X in RWX)
2325 self.assertFalse(R in WX)
2326 self.assertFalse(W in RX)
2327 self.assertFalse(X in RW)
2328
Ethan Furmanc16595e2016-09-10 23:36:59 -07002329 def test_auto_number(self):
2330 class Color(Flag):
2331 red = auto()
2332 blue = auto()
2333 green = auto()
2334
2335 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2336 self.assertEqual(Color.red.value, 1)
2337 self.assertEqual(Color.blue.value, 2)
2338 self.assertEqual(Color.green.value, 4)
2339
2340 def test_auto_number_garbage(self):
2341 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2342 class Color(Flag):
2343 red = 'not an int'
2344 blue = auto()
2345
Ethan Furman3515dcc2016-09-18 13:15:41 -07002346 def test_cascading_failure(self):
2347 class Bizarre(Flag):
2348 c = 3
2349 d = 4
2350 f = 6
2351 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002352 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2353 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2354 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2355 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2356 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2357 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2358 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002359
2360 def test_duplicate_auto(self):
2361 class Dupes(Enum):
2362 first = primero = auto()
2363 second = auto()
2364 third = auto()
2365 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2366
2367 def test_bizarre(self):
2368 class Bizarre(Flag):
2369 b = 3
2370 c = 4
2371 d = 6
2372 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2373
Ethan Furman5bdab642018-09-21 19:03:09 -07002374 def test_multiple_mixin(self):
2375 class AllMixin:
2376 @classproperty
2377 def ALL(cls):
2378 members = list(cls)
2379 all_value = None
2380 if members:
2381 all_value = members[0]
2382 for member in members[1:]:
2383 all_value |= member
2384 cls.ALL = all_value
2385 return all_value
2386 class StrMixin:
2387 def __str__(self):
2388 return self._name_.lower()
2389 class Color(AllMixin, Flag):
2390 RED = auto()
2391 GREEN = auto()
2392 BLUE = auto()
2393 self.assertEqual(Color.RED.value, 1)
2394 self.assertEqual(Color.GREEN.value, 2)
2395 self.assertEqual(Color.BLUE.value, 4)
2396 self.assertEqual(Color.ALL.value, 7)
2397 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2398 class Color(AllMixin, StrMixin, Flag):
2399 RED = auto()
2400 GREEN = auto()
2401 BLUE = auto()
2402 self.assertEqual(Color.RED.value, 1)
2403 self.assertEqual(Color.GREEN.value, 2)
2404 self.assertEqual(Color.BLUE.value, 4)
2405 self.assertEqual(Color.ALL.value, 7)
2406 self.assertEqual(str(Color.BLUE), 'blue')
2407 class Color(StrMixin, AllMixin, Flag):
2408 RED = auto()
2409 GREEN = auto()
2410 BLUE = auto()
2411 self.assertEqual(Color.RED.value, 1)
2412 self.assertEqual(Color.GREEN.value, 2)
2413 self.assertEqual(Color.BLUE.value, 4)
2414 self.assertEqual(Color.ALL.value, 7)
2415 self.assertEqual(str(Color.BLUE), 'blue')
2416
Ethan Furman28cf6632017-01-24 12:12:06 -08002417 @support.reap_threads
2418 def test_unique_composite(self):
2419 # override __eq__ to be identity only
2420 class TestFlag(Flag):
2421 one = auto()
2422 two = auto()
2423 three = auto()
2424 four = auto()
2425 five = auto()
2426 six = auto()
2427 seven = auto()
2428 eight = auto()
2429 def __eq__(self, other):
2430 return self is other
2431 def __hash__(self):
2432 return hash(self._value_)
2433 # have multiple threads competing to complete the composite members
2434 seen = set()
2435 failed = False
2436 def cycle_enum():
2437 nonlocal failed
2438 try:
2439 for i in range(256):
2440 seen.add(TestFlag(i))
2441 except Exception:
2442 failed = True
2443 threads = [
2444 threading.Thread(target=cycle_enum)
2445 for _ in range(8)
2446 ]
2447 with support.start_threads(threads):
2448 pass
2449 # check that only 248 members were created
2450 self.assertFalse(
2451 failed,
2452 'at least one thread failed while creating composite members')
2453 self.assertEqual(256, len(seen), 'too many composite members created')
2454
Ethan Furmanc16595e2016-09-10 23:36:59 -07002455
Ethan Furman65a5a472016-09-01 23:55:19 -07002456class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002457 """Tests of the IntFlags."""
2458
Ethan Furman65a5a472016-09-01 23:55:19 -07002459 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002460 X = 1 << 0
2461 W = 1 << 1
2462 R = 1 << 2
2463
Ethan Furman65a5a472016-09-01 23:55:19 -07002464 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002465 RO = 0
2466 WO = 1
2467 RW = 2
2468 AC = 3
2469 CE = 1<<19
2470
Rahul Jha94306522018-09-10 23:51:04 +05302471 class Color(IntFlag):
2472 BLACK = 0
2473 RED = 1
2474 GREEN = 2
2475 BLUE = 4
2476 PURPLE = RED|BLUE
2477
Ethan Furman3515dcc2016-09-18 13:15:41 -07002478 def test_type(self):
2479 Perm = self.Perm
2480 Open = self.Open
2481 for f in Perm:
2482 self.assertTrue(isinstance(f, Perm))
2483 self.assertEqual(f, f.value)
2484 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2485 self.assertEqual(Perm.W | Perm.X, 3)
2486 for f in Open:
2487 self.assertTrue(isinstance(f, Open))
2488 self.assertEqual(f, f.value)
2489 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2490 self.assertEqual(Open.WO | Open.RW, 3)
2491
2492
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002493 def test_str(self):
2494 Perm = self.Perm
2495 self.assertEqual(str(Perm.R), 'Perm.R')
2496 self.assertEqual(str(Perm.W), 'Perm.W')
2497 self.assertEqual(str(Perm.X), 'Perm.X')
2498 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2499 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2500 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2501 self.assertEqual(str(Perm(0)), 'Perm.0')
2502 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002503 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2504 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2505 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2506 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002507 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002508 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2509 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2510 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002511
2512 Open = self.Open
2513 self.assertEqual(str(Open.RO), 'Open.RO')
2514 self.assertEqual(str(Open.WO), 'Open.WO')
2515 self.assertEqual(str(Open.AC), 'Open.AC')
2516 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2517 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2518 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002519 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2520 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2521 self.assertEqual(str(~Open.AC), 'Open.CE')
2522 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2523 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2524 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002525
2526 def test_repr(self):
2527 Perm = self.Perm
2528 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2529 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2530 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2531 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2532 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2533 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002534 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2535 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002536 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2537 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2538 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2539 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002540 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002541 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2542 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2543 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002544
2545 Open = self.Open
2546 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2547 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2548 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2549 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2550 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002551 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002552 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2553 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2554 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2555 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2556 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2557 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002558
2559 def test_or(self):
2560 Perm = self.Perm
2561 for i in Perm:
2562 for j in Perm:
2563 self.assertEqual(i | j, i.value | j.value)
2564 self.assertEqual((i | j).value, i.value | j.value)
2565 self.assertIs(type(i | j), Perm)
2566 for j in range(8):
2567 self.assertEqual(i | j, i.value | j)
2568 self.assertEqual((i | j).value, i.value | j)
2569 self.assertIs(type(i | j), Perm)
2570 self.assertEqual(j | i, j | i.value)
2571 self.assertEqual((j | i).value, j | i.value)
2572 self.assertIs(type(j | i), Perm)
2573 for i in Perm:
2574 self.assertIs(i | i, i)
2575 self.assertIs(i | 0, i)
2576 self.assertIs(0 | i, i)
2577 Open = self.Open
2578 self.assertIs(Open.RO | Open.CE, Open.CE)
2579
2580 def test_and(self):
2581 Perm = self.Perm
2582 RW = Perm.R | Perm.W
2583 RX = Perm.R | Perm.X
2584 WX = Perm.W | Perm.X
2585 RWX = Perm.R | Perm.W | Perm.X
2586 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2587 for i in values:
2588 for j in values:
2589 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2590 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2591 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2592 for j in range(8):
2593 self.assertEqual(i & j, i.value & j)
2594 self.assertEqual((i & j).value, i.value & j)
2595 self.assertIs(type(i & j), Perm)
2596 self.assertEqual(j & i, j & i.value)
2597 self.assertEqual((j & i).value, j & i.value)
2598 self.assertIs(type(j & i), Perm)
2599 for i in Perm:
2600 self.assertIs(i & i, i)
2601 self.assertIs(i & 7, i)
2602 self.assertIs(7 & i, i)
2603 Open = self.Open
2604 self.assertIs(Open.RO & Open.CE, Open.RO)
2605
2606 def test_xor(self):
2607 Perm = self.Perm
2608 for i in Perm:
2609 for j in Perm:
2610 self.assertEqual(i ^ j, i.value ^ j.value)
2611 self.assertEqual((i ^ j).value, i.value ^ j.value)
2612 self.assertIs(type(i ^ j), Perm)
2613 for j in range(8):
2614 self.assertEqual(i ^ j, i.value ^ j)
2615 self.assertEqual((i ^ j).value, i.value ^ j)
2616 self.assertIs(type(i ^ j), Perm)
2617 self.assertEqual(j ^ i, j ^ i.value)
2618 self.assertEqual((j ^ i).value, j ^ i.value)
2619 self.assertIs(type(j ^ i), Perm)
2620 for i in Perm:
2621 self.assertIs(i ^ 0, i)
2622 self.assertIs(0 ^ i, i)
2623 Open = self.Open
2624 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2625 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2626
2627 def test_invert(self):
2628 Perm = self.Perm
2629 RW = Perm.R | Perm.W
2630 RX = Perm.R | Perm.X
2631 WX = Perm.W | Perm.X
2632 RWX = Perm.R | Perm.W | Perm.X
2633 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2634 for i in values:
2635 self.assertEqual(~i, ~i.value)
2636 self.assertEqual((~i).value, ~i.value)
2637 self.assertIs(type(~i), Perm)
2638 self.assertEqual(~~i, i)
2639 for i in Perm:
2640 self.assertIs(~~i, i)
2641 Open = self.Open
2642 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2643 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2644
2645 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002646 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002647 lst = list(Perm)
2648 self.assertEqual(len(lst), len(Perm))
2649 self.assertEqual(len(Perm), 3, Perm)
2650 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2651 for i, n in enumerate('R W X'.split()):
2652 v = 1<<i
2653 e = Perm(v)
2654 self.assertEqual(e.value, v)
2655 self.assertEqual(type(e.value), int)
2656 self.assertEqual(e, v)
2657 self.assertEqual(e.name, n)
2658 self.assertIn(e, Perm)
2659 self.assertIs(type(e), Perm)
2660
2661 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002662 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002663 lst = list(Perm)
2664 self.assertEqual(len(lst), len(Perm))
2665 self.assertEqual(len(Perm), 3, Perm)
2666 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2667 for i, n in enumerate('R W X'.split()):
2668 v = 8<<i
2669 e = Perm(v)
2670 self.assertEqual(e.value, v)
2671 self.assertEqual(type(e.value), int)
2672 self.assertEqual(e, v)
2673 self.assertEqual(e.name, n)
2674 self.assertIn(e, Perm)
2675 self.assertIs(type(e), Perm)
2676
2677 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002678 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002679 lst = list(Perm)
2680 self.assertEqual(len(lst), len(Perm))
2681 self.assertEqual(len(Perm), 3, Perm)
2682 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2683 for i, n in enumerate('R W X'.split()):
2684 v = 1<<i
2685 e = Perm(v)
2686 self.assertEqual(e.value, v)
2687 self.assertEqual(type(e.value), int)
2688 self.assertEqual(e, v)
2689 self.assertEqual(e.name, n)
2690 self.assertIn(e, Perm)
2691 self.assertIs(type(e), Perm)
2692
2693 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002694 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002695 lst = list(Perm)
2696 self.assertEqual(len(lst), len(Perm))
2697 self.assertEqual(len(Perm), 3, Perm)
2698 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2699 for i, n in enumerate('R W X'.split()):
2700 v = 1<<(2*i+1)
2701 e = Perm(v)
2702 self.assertEqual(e.value, v)
2703 self.assertEqual(type(e.value), int)
2704 self.assertEqual(e, v)
2705 self.assertEqual(e.name, n)
2706 self.assertIn(e, Perm)
2707 self.assertIs(type(e), Perm)
2708
2709 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002710 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002711 lst = list(Perm)
2712 self.assertEqual(len(lst), len(Perm))
2713 self.assertEqual(len(Perm), 3, Perm)
2714 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2715 for i, n in enumerate('R W X'.split()):
2716 v = 1<<(2*i+1)
2717 e = Perm(v)
2718 self.assertEqual(e.value, v)
2719 self.assertEqual(type(e.value), int)
2720 self.assertEqual(e, v)
2721 self.assertEqual(e.name, n)
2722 self.assertIn(e, Perm)
2723 self.assertIs(type(e), Perm)
2724
2725
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002726 def test_programatic_function_from_empty_list(self):
2727 Perm = enum.IntFlag('Perm', [])
2728 lst = list(Perm)
2729 self.assertEqual(len(lst), len(Perm))
2730 self.assertEqual(len(Perm), 0, Perm)
2731 Thing = enum.Enum('Thing', [])
2732 lst = list(Thing)
2733 self.assertEqual(len(lst), len(Thing))
2734 self.assertEqual(len(Thing), 0, Thing)
2735
2736
2737 def test_programatic_function_from_empty_tuple(self):
2738 Perm = enum.IntFlag('Perm', ())
2739 lst = list(Perm)
2740 self.assertEqual(len(lst), len(Perm))
2741 self.assertEqual(len(Perm), 0, Perm)
2742 Thing = enum.Enum('Thing', ())
2743 self.assertEqual(len(lst), len(Thing))
2744 self.assertEqual(len(Thing), 0, Thing)
2745
Rahul Jha94306522018-09-10 23:51:04 +05302746 def test_contains(self):
2747 Open = self.Open
2748 Color = self.Color
2749 self.assertTrue(Color.GREEN in Color)
2750 self.assertTrue(Open.RW in Open)
2751 self.assertFalse(Color.GREEN in Open)
2752 self.assertFalse(Open.RW in Color)
2753 with self.assertRaises(TypeError):
2754 'GREEN' in Color
2755 with self.assertRaises(TypeError):
2756 'RW' in Open
2757 with self.assertRaises(TypeError):
2758 2 in Color
2759 with self.assertRaises(TypeError):
2760 2 in Open
2761
2762 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002763 Perm = self.Perm
2764 R, W, X = Perm
2765 RW = R | W
2766 RX = R | X
2767 WX = W | X
2768 RWX = R | W | X
2769 self.assertTrue(R in RW)
2770 self.assertTrue(R in RX)
2771 self.assertTrue(R in RWX)
2772 self.assertTrue(W in RW)
2773 self.assertTrue(W in WX)
2774 self.assertTrue(W in RWX)
2775 self.assertTrue(X in RX)
2776 self.assertTrue(X in WX)
2777 self.assertTrue(X in RWX)
2778 self.assertFalse(R in WX)
2779 self.assertFalse(W in RX)
2780 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302781 with self.assertRaises(TypeError):
2782 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002783
Ethan Furman25d94bb2016-09-02 16:32:32 -07002784 def test_bool(self):
2785 Perm = self.Perm
2786 for f in Perm:
2787 self.assertTrue(f)
2788 Open = self.Open
2789 for f in Open:
2790 self.assertEqual(bool(f.value), bool(f))
2791
Ethan Furman5bdab642018-09-21 19:03:09 -07002792 def test_multiple_mixin(self):
2793 class AllMixin:
2794 @classproperty
2795 def ALL(cls):
2796 members = list(cls)
2797 all_value = None
2798 if members:
2799 all_value = members[0]
2800 for member in members[1:]:
2801 all_value |= member
2802 cls.ALL = all_value
2803 return all_value
2804 class StrMixin:
2805 def __str__(self):
2806 return self._name_.lower()
2807 class Color(AllMixin, IntFlag):
2808 RED = auto()
2809 GREEN = auto()
2810 BLUE = auto()
2811 self.assertEqual(Color.RED.value, 1)
2812 self.assertEqual(Color.GREEN.value, 2)
2813 self.assertEqual(Color.BLUE.value, 4)
2814 self.assertEqual(Color.ALL.value, 7)
2815 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2816 class Color(AllMixin, StrMixin, IntFlag):
2817 RED = auto()
2818 GREEN = auto()
2819 BLUE = auto()
2820 self.assertEqual(Color.RED.value, 1)
2821 self.assertEqual(Color.GREEN.value, 2)
2822 self.assertEqual(Color.BLUE.value, 4)
2823 self.assertEqual(Color.ALL.value, 7)
2824 self.assertEqual(str(Color.BLUE), 'blue')
2825 class Color(StrMixin, AllMixin, IntFlag):
2826 RED = auto()
2827 GREEN = auto()
2828 BLUE = auto()
2829 self.assertEqual(Color.RED.value, 1)
2830 self.assertEqual(Color.GREEN.value, 2)
2831 self.assertEqual(Color.BLUE.value, 4)
2832 self.assertEqual(Color.ALL.value, 7)
2833 self.assertEqual(str(Color.BLUE), 'blue')
2834
Ethan Furman28cf6632017-01-24 12:12:06 -08002835 @support.reap_threads
2836 def test_unique_composite(self):
2837 # override __eq__ to be identity only
2838 class TestFlag(IntFlag):
2839 one = auto()
2840 two = auto()
2841 three = auto()
2842 four = auto()
2843 five = auto()
2844 six = auto()
2845 seven = auto()
2846 eight = auto()
2847 def __eq__(self, other):
2848 return self is other
2849 def __hash__(self):
2850 return hash(self._value_)
2851 # have multiple threads competing to complete the composite members
2852 seen = set()
2853 failed = False
2854 def cycle_enum():
2855 nonlocal failed
2856 try:
2857 for i in range(256):
2858 seen.add(TestFlag(i))
2859 except Exception:
2860 failed = True
2861 threads = [
2862 threading.Thread(target=cycle_enum)
2863 for _ in range(8)
2864 ]
2865 with support.start_threads(threads):
2866 pass
2867 # check that only 248 members were created
2868 self.assertFalse(
2869 failed,
2870 'at least one thread failed while creating composite members')
2871 self.assertEqual(256, len(seen), 'too many composite members created')
2872
2873
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002874class TestEmptyAndNonLatinStrings(unittest.TestCase):
2875
2876 def test_empty_string(self):
2877 with self.assertRaises(ValueError):
2878 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2879
2880 def test_non_latin_character_string(self):
2881 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2882 item = getattr(greek_abc, '\u03B1')
2883 self.assertEqual(item.value, 1)
2884
2885 def test_non_latin_number_string(self):
2886 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2887 item = getattr(hebrew_123, '\u05D0')
2888 self.assertEqual(item.value, 1)
2889
2890
Ethan Furmanf24bb352013-07-18 17:05:39 -07002891class TestUnique(unittest.TestCase):
2892
2893 def test_unique_clean(self):
2894 @unique
2895 class Clean(Enum):
2896 one = 1
2897 two = 'dos'
2898 tres = 4.0
2899 @unique
2900 class Cleaner(IntEnum):
2901 single = 1
2902 double = 2
2903 triple = 3
2904
2905 def test_unique_dirty(self):
2906 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2907 @unique
2908 class Dirty(Enum):
2909 one = 1
2910 two = 'dos'
2911 tres = 1
2912 with self.assertRaisesRegex(
2913 ValueError,
2914 'double.*single.*turkey.*triple',
2915 ):
2916 @unique
2917 class Dirtier(IntEnum):
2918 single = 1
2919 double = 1
2920 triple = 3
2921 turkey = 3
2922
Ethan Furman3803ad42016-05-01 10:03:53 -07002923 def test_unique_with_name(self):
2924 @unique
2925 class Silly(Enum):
2926 one = 1
2927 two = 'dos'
2928 name = 3
2929 @unique
2930 class Sillier(IntEnum):
2931 single = 1
2932 name = 2
2933 triple = 3
2934 value = 4
2935
Ethan Furmanf24bb352013-07-18 17:05:39 -07002936
Ethan Furman5bdab642018-09-21 19:03:09 -07002937
Ethan Furman3323da92015-04-11 09:39:59 -07002938expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002939Help on class Color in module %s:
2940
2941class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002942 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2943 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002944 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002945 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002946 | Method resolution order:
2947 | Color
2948 | enum.Enum
2949 | builtins.object
2950 |\x20\x20
2951 | Data and other attributes defined here:
2952 |\x20\x20
2953 | blue = <Color.blue: 3>
2954 |\x20\x20
2955 | green = <Color.green: 2>
2956 |\x20\x20
2957 | red = <Color.red: 1>
2958 |\x20\x20
2959 | ----------------------------------------------------------------------
2960 | Data descriptors inherited from enum.Enum:
2961 |\x20\x20
2962 | name
2963 | The name of the Enum member.
2964 |\x20\x20
2965 | value
2966 | The value of the Enum member.
2967 |\x20\x20
2968 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002969 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002970 |\x20\x20
2971 | __members__
2972 | Returns a mapping of member name->value.
2973 |\x20\x20\x20\x20\x20\x20
2974 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002975 | is a read-only view of the internal mapping."""
2976
2977expected_help_output_without_docs = """\
2978Help on class Color in module %s:
2979
2980class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002981 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2982 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002983 | Method resolution order:
2984 | Color
2985 | enum.Enum
2986 | builtins.object
2987 |\x20\x20
2988 | Data and other attributes defined here:
2989 |\x20\x20
2990 | blue = <Color.blue: 3>
2991 |\x20\x20
2992 | green = <Color.green: 2>
2993 |\x20\x20
2994 | red = <Color.red: 1>
2995 |\x20\x20
2996 | ----------------------------------------------------------------------
2997 | Data descriptors inherited from enum.Enum:
2998 |\x20\x20
2999 | name
3000 |\x20\x20
3001 | value
3002 |\x20\x20
3003 | ----------------------------------------------------------------------
3004 | Data descriptors inherited from enum.EnumMeta:
3005 |\x20\x20
3006 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003007
3008class TestStdLib(unittest.TestCase):
3009
Ethan Furman48a724f2015-04-11 23:23:06 -07003010 maxDiff = None
3011
Ethan Furman5875d742013-10-21 20:45:55 -07003012 class Color(Enum):
3013 red = 1
3014 green = 2
3015 blue = 3
3016
3017 def test_pydoc(self):
3018 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003019 if StrEnum.__doc__ is None:
3020 expected_text = expected_help_output_without_docs % __name__
3021 else:
3022 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003023 output = StringIO()
3024 helper = pydoc.Helper(output=output)
3025 helper(self.Color)
3026 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003027 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003028
3029 def test_inspect_getmembers(self):
3030 values = dict((
3031 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003032 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003033 ('__members__', self.Color.__members__),
3034 ('__module__', __name__),
3035 ('blue', self.Color.blue),
3036 ('green', self.Color.green),
3037 ('name', Enum.__dict__['name']),
3038 ('red', self.Color.red),
3039 ('value', Enum.__dict__['value']),
3040 ))
3041 result = dict(inspect.getmembers(self.Color))
3042 self.assertEqual(values.keys(), result.keys())
3043 failed = False
3044 for k in values.keys():
3045 if result[k] != values[k]:
3046 print()
3047 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3048 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3049 failed = True
3050 if failed:
3051 self.fail("result does not equal expected, see print above")
3052
3053 def test_inspect_classify_class_attrs(self):
3054 # indirectly test __objclass__
3055 from inspect import Attribute
3056 values = [
3057 Attribute(name='__class__', kind='data',
3058 defining_class=object, object=EnumMeta),
3059 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003060 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003061 Attribute(name='__members__', kind='property',
3062 defining_class=EnumMeta, object=EnumMeta.__members__),
3063 Attribute(name='__module__', kind='data',
3064 defining_class=self.Color, object=__name__),
3065 Attribute(name='blue', kind='data',
3066 defining_class=self.Color, object=self.Color.blue),
3067 Attribute(name='green', kind='data',
3068 defining_class=self.Color, object=self.Color.green),
3069 Attribute(name='red', kind='data',
3070 defining_class=self.Color, object=self.Color.red),
3071 Attribute(name='name', kind='data',
3072 defining_class=Enum, object=Enum.__dict__['name']),
3073 Attribute(name='value', kind='data',
3074 defining_class=Enum, object=Enum.__dict__['value']),
3075 ]
3076 values.sort(key=lambda item: item.name)
3077 result = list(inspect.classify_class_attrs(self.Color))
3078 result.sort(key=lambda item: item.name)
3079 failed = False
3080 for v, r in zip(values, result):
3081 if r != v:
3082 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3083 failed = True
3084 if failed:
3085 self.fail("result does not equal expected, see print above")
3086
Martin Panter19e69c52015-11-14 12:46:42 +00003087
3088class MiscTestCase(unittest.TestCase):
3089 def test__all__(self):
3090 support.check__all__(self, enum)
3091
3092
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003093# These are unordered here on purpose to ensure that declaration order
3094# makes no difference.
3095CONVERT_TEST_NAME_D = 5
3096CONVERT_TEST_NAME_C = 5
3097CONVERT_TEST_NAME_B = 5
3098CONVERT_TEST_NAME_A = 5 # This one should sort first.
3099CONVERT_TEST_NAME_E = 5
3100CONVERT_TEST_NAME_F = 5
3101
3102class TestIntEnumConvert(unittest.TestCase):
3103 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003104 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003105 'UnittestConvert',
3106 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003107 filter=lambda x: x.startswith('CONVERT_TEST_'))
3108 # We don't want the reverse lookup value to vary when there are
3109 # multiple possible names for a given value. It should always
3110 # report the first lexigraphical name in that case.
3111 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3112
3113 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003114 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003115 'UnittestConvert',
3116 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003117 filter=lambda x: x.startswith('CONVERT_TEST_'))
3118 # Ensure that test_type has all of the desired names and values.
3119 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3120 test_type.CONVERT_TEST_NAME_A)
3121 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3122 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3123 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3124 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3125 # Ensure that test_type only picked up names matching the filter.
3126 self.assertEqual([name for name in dir(test_type)
3127 if name[0:2] not in ('CO', '__')],
3128 [], msg='Names other than CONVERT_TEST_* found.')
3129
orlnub1230fb9fad2018-09-12 20:28:53 +03003130 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3131 '_convert was deprecated in 3.8')
3132 def test_convert_warn(self):
3133 with self.assertWarns(DeprecationWarning):
3134 enum.IntEnum._convert(
3135 'UnittestConvert',
3136 ('test.test_enum', '__main__')[__name__=='__main__'],
3137 filter=lambda x: x.startswith('CONVERT_TEST_'))
3138
3139 @unittest.skipUnless(sys.version_info >= (3, 9),
3140 '_convert was removed in 3.9')
3141 def test_convert_raise(self):
3142 with self.assertRaises(AttributeError):
3143 enum.IntEnum._convert(
3144 'UnittestConvert',
3145 ('test.test_enum', '__main__')[__name__=='__main__'],
3146 filter=lambda x: x.startswith('CONVERT_TEST_'))
3147
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003148
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003149if __name__ == '__main__':
3150 unittest.main()