blob: 6f547165acfee38a752821f611f8149284732d62 [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 Furman019f0a02018-09-12 11:43:34 -07001835 def test_missing(self):
1836 class Color(Enum):
1837 red = 1
1838 green = 2
1839 blue = 3
1840 @classmethod
1841 def _missing_(cls, item):
1842 if item == 'three':
1843 return cls.blue
1844 elif item == 'bad return':
1845 # trigger internal error
1846 return 5
1847 elif item == 'error out':
1848 raise ZeroDivisionError
1849 else:
1850 # trigger not found
1851 return None
1852 self.assertIs(Color('three'), Color.blue)
1853 self.assertRaises(ValueError, Color, 7)
1854 try:
1855 Color('bad return')
1856 except TypeError as exc:
1857 self.assertTrue(isinstance(exc.__context__, ValueError))
1858 else:
1859 raise Exception('Exception not raised.')
1860 try:
1861 Color('error out')
1862 except ZeroDivisionError as exc:
1863 self.assertTrue(isinstance(exc.__context__, ValueError))
1864 else:
1865 raise Exception('Exception not raised.')
1866
Ethan Furman5bdab642018-09-21 19:03:09 -07001867 def test_multiple_mixin(self):
1868 class MaxMixin:
1869 @classproperty
1870 def MAX(cls):
1871 max = len(cls)
1872 cls.MAX = max
1873 return max
1874 class StrMixin:
1875 def __str__(self):
1876 return self._name_.lower()
1877 class SomeEnum(Enum):
1878 def behavior(self):
1879 return 'booyah'
1880 class AnotherEnum(Enum):
1881 def behavior(self):
1882 return 'nuhuh!'
1883 def social(self):
1884 return "what's up?"
1885 class Color(MaxMixin, Enum):
1886 RED = auto()
1887 GREEN = auto()
1888 BLUE = auto()
1889 self.assertEqual(Color.RED.value, 1)
1890 self.assertEqual(Color.GREEN.value, 2)
1891 self.assertEqual(Color.BLUE.value, 3)
1892 self.assertEqual(Color.MAX, 3)
1893 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1894 class Color(MaxMixin, StrMixin, Enum):
1895 RED = auto()
1896 GREEN = auto()
1897 BLUE = auto()
1898 self.assertEqual(Color.RED.value, 1)
1899 self.assertEqual(Color.GREEN.value, 2)
1900 self.assertEqual(Color.BLUE.value, 3)
1901 self.assertEqual(Color.MAX, 3)
1902 self.assertEqual(str(Color.BLUE), 'blue')
1903 class Color(StrMixin, MaxMixin, Enum):
1904 RED = auto()
1905 GREEN = auto()
1906 BLUE = auto()
1907 self.assertEqual(Color.RED.value, 1)
1908 self.assertEqual(Color.GREEN.value, 2)
1909 self.assertEqual(Color.BLUE.value, 3)
1910 self.assertEqual(Color.MAX, 3)
1911 self.assertEqual(str(Color.BLUE), 'blue')
1912 class CoolColor(StrMixin, SomeEnum, Enum):
1913 RED = auto()
1914 GREEN = auto()
1915 BLUE = auto()
1916 self.assertEqual(CoolColor.RED.value, 1)
1917 self.assertEqual(CoolColor.GREEN.value, 2)
1918 self.assertEqual(CoolColor.BLUE.value, 3)
1919 self.assertEqual(str(CoolColor.BLUE), 'blue')
1920 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1921 class CoolerColor(StrMixin, AnotherEnum, Enum):
1922 RED = auto()
1923 GREEN = auto()
1924 BLUE = auto()
1925 self.assertEqual(CoolerColor.RED.value, 1)
1926 self.assertEqual(CoolerColor.GREEN.value, 2)
1927 self.assertEqual(CoolerColor.BLUE.value, 3)
1928 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1929 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1930 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1931 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1932 RED = auto()
1933 GREEN = auto()
1934 BLUE = auto()
1935 self.assertEqual(CoolestColor.RED.value, 1)
1936 self.assertEqual(CoolestColor.GREEN.value, 2)
1937 self.assertEqual(CoolestColor.BLUE.value, 3)
1938 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1939 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1940 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1941 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1942 RED = auto()
1943 GREEN = auto()
1944 BLUE = auto()
1945 self.assertEqual(ConfusedColor.RED.value, 1)
1946 self.assertEqual(ConfusedColor.GREEN.value, 2)
1947 self.assertEqual(ConfusedColor.BLUE.value, 3)
1948 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1949 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1950 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1951 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1952 RED = auto()
1953 GREEN = auto()
1954 BLUE = auto()
1955 self.assertEqual(ReformedColor.RED.value, 1)
1956 self.assertEqual(ReformedColor.GREEN.value, 2)
1957 self.assertEqual(ReformedColor.BLUE.value, 3)
1958 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1959 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1960 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1961 self.assertTrue(issubclass(ReformedColor, int))
1962
Ethan Furmancd453852018-10-05 23:29:36 -07001963 def test_multiple_inherited_mixin(self):
1964 class StrEnum(str, Enum):
1965 def __new__(cls, *args, **kwargs):
1966 for a in args:
1967 if not isinstance(a, str):
1968 raise TypeError("Enumeration '%s' (%s) is not"
1969 " a string" % (a, type(a).__name__))
1970 return str.__new__(cls, *args, **kwargs)
1971 @unique
1972 class Decision1(StrEnum):
1973 REVERT = "REVERT"
1974 REVERT_ALL = "REVERT_ALL"
1975 RETRY = "RETRY"
1976 class MyEnum(StrEnum):
1977 pass
1978 @unique
1979 class Decision2(MyEnum):
1980 REVERT = "REVERT"
1981 REVERT_ALL = "REVERT_ALL"
1982 RETRY = "RETRY"
1983
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001984 def test_empty_globals(self):
1985 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1986 # when using compile and exec because f_globals is empty
1987 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1988 code = compile(code, "<string>", "exec")
1989 global_ns = {}
1990 local_ls = {}
1991 exec(code, global_ns, local_ls)
1992
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001993
Ethan Furmane8e61272016-08-20 07:19:31 -07001994class TestOrder(unittest.TestCase):
1995
1996 def test_same_members(self):
1997 class Color(Enum):
1998 _order_ = 'red green blue'
1999 red = 1
2000 green = 2
2001 blue = 3
2002
2003 def test_same_members_with_aliases(self):
2004 class Color(Enum):
2005 _order_ = 'red green blue'
2006 red = 1
2007 green = 2
2008 blue = 3
2009 verde = green
2010
2011 def test_same_members_wrong_order(self):
2012 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2013 class Color(Enum):
2014 _order_ = 'red green blue'
2015 red = 1
2016 blue = 3
2017 green = 2
2018
2019 def test_order_has_extra_members(self):
2020 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2021 class Color(Enum):
2022 _order_ = 'red green blue purple'
2023 red = 1
2024 green = 2
2025 blue = 3
2026
2027 def test_order_has_extra_members_with_aliases(self):
2028 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2029 class Color(Enum):
2030 _order_ = 'red green blue purple'
2031 red = 1
2032 green = 2
2033 blue = 3
2034 verde = green
2035
2036 def test_enum_has_extra_members(self):
2037 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2038 class Color(Enum):
2039 _order_ = 'red green blue'
2040 red = 1
2041 green = 2
2042 blue = 3
2043 purple = 4
2044
2045 def test_enum_has_extra_members_with_aliases(self):
2046 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2047 class Color(Enum):
2048 _order_ = 'red green blue'
2049 red = 1
2050 green = 2
2051 blue = 3
2052 purple = 4
2053 verde = green
2054
2055
Ethan Furman65a5a472016-09-01 23:55:19 -07002056class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002057 """Tests of the Flags."""
2058
Ethan Furman65a5a472016-09-01 23:55:19 -07002059 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002060 R, W, X = 4, 2, 1
2061
Ethan Furman65a5a472016-09-01 23:55:19 -07002062 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002063 RO = 0
2064 WO = 1
2065 RW = 2
2066 AC = 3
2067 CE = 1<<19
2068
Rahul Jha94306522018-09-10 23:51:04 +05302069 class Color(Flag):
2070 BLACK = 0
2071 RED = 1
2072 GREEN = 2
2073 BLUE = 4
2074 PURPLE = RED|BLUE
2075
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002076 def test_str(self):
2077 Perm = self.Perm
2078 self.assertEqual(str(Perm.R), 'Perm.R')
2079 self.assertEqual(str(Perm.W), 'Perm.W')
2080 self.assertEqual(str(Perm.X), 'Perm.X')
2081 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2082 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2083 self.assertEqual(str(Perm(0)), 'Perm.0')
2084 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2085 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2086 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2087 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2088 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2089 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2090
2091 Open = self.Open
2092 self.assertEqual(str(Open.RO), 'Open.RO')
2093 self.assertEqual(str(Open.WO), 'Open.WO')
2094 self.assertEqual(str(Open.AC), 'Open.AC')
2095 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2096 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002097 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002098 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2099 self.assertEqual(str(~Open.AC), 'Open.CE')
2100 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2101 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2102
2103 def test_repr(self):
2104 Perm = self.Perm
2105 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2106 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2107 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2108 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2109 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002110 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002111 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2112 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2113 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2114 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002115 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002116 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2117
2118 Open = self.Open
2119 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2120 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2121 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2122 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2123 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002124 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002125 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2126 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2127 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2128 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2129
2130 def test_or(self):
2131 Perm = self.Perm
2132 for i in Perm:
2133 for j in Perm:
2134 self.assertEqual((i | j), Perm(i.value | j.value))
2135 self.assertEqual((i | j).value, i.value | j.value)
2136 self.assertIs(type(i | j), Perm)
2137 for i in Perm:
2138 self.assertIs(i | i, i)
2139 Open = self.Open
2140 self.assertIs(Open.RO | Open.CE, Open.CE)
2141
2142 def test_and(self):
2143 Perm = self.Perm
2144 RW = Perm.R | Perm.W
2145 RX = Perm.R | Perm.X
2146 WX = Perm.W | Perm.X
2147 RWX = Perm.R | Perm.W | Perm.X
2148 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2149 for i in values:
2150 for j in values:
2151 self.assertEqual((i & j).value, i.value & j.value)
2152 self.assertIs(type(i & j), Perm)
2153 for i in Perm:
2154 self.assertIs(i & i, i)
2155 self.assertIs(i & RWX, i)
2156 self.assertIs(RWX & i, i)
2157 Open = self.Open
2158 self.assertIs(Open.RO & Open.CE, Open.RO)
2159
2160 def test_xor(self):
2161 Perm = self.Perm
2162 for i in Perm:
2163 for j in Perm:
2164 self.assertEqual((i ^ j).value, i.value ^ j.value)
2165 self.assertIs(type(i ^ j), Perm)
2166 for i in Perm:
2167 self.assertIs(i ^ Perm(0), i)
2168 self.assertIs(Perm(0) ^ i, i)
2169 Open = self.Open
2170 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2171 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2172
2173 def test_invert(self):
2174 Perm = self.Perm
2175 RW = Perm.R | Perm.W
2176 RX = Perm.R | Perm.X
2177 WX = Perm.W | Perm.X
2178 RWX = Perm.R | Perm.W | Perm.X
2179 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2180 for i in values:
2181 self.assertIs(type(~i), Perm)
2182 self.assertEqual(~~i, i)
2183 for i in Perm:
2184 self.assertIs(~~i, i)
2185 Open = self.Open
2186 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2187 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2188
Ethan Furman25d94bb2016-09-02 16:32:32 -07002189 def test_bool(self):
2190 Perm = self.Perm
2191 for f in Perm:
2192 self.assertTrue(f)
2193 Open = self.Open
2194 for f in Open:
2195 self.assertEqual(bool(f.value), bool(f))
2196
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002197 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002198 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002199 lst = list(Perm)
2200 self.assertEqual(len(lst), len(Perm))
2201 self.assertEqual(len(Perm), 3, Perm)
2202 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2203 for i, n in enumerate('R W X'.split()):
2204 v = 1<<i
2205 e = Perm(v)
2206 self.assertEqual(e.value, v)
2207 self.assertEqual(type(e.value), int)
2208 self.assertEqual(e.name, n)
2209 self.assertIn(e, Perm)
2210 self.assertIs(type(e), Perm)
2211
2212 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002213 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002214 lst = list(Perm)
2215 self.assertEqual(len(lst), len(Perm))
2216 self.assertEqual(len(Perm), 3, Perm)
2217 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2218 for i, n in enumerate('R W X'.split()):
2219 v = 8<<i
2220 e = Perm(v)
2221 self.assertEqual(e.value, v)
2222 self.assertEqual(type(e.value), int)
2223 self.assertEqual(e.name, n)
2224 self.assertIn(e, Perm)
2225 self.assertIs(type(e), Perm)
2226
2227 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002228 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002229 lst = list(Perm)
2230 self.assertEqual(len(lst), len(Perm))
2231 self.assertEqual(len(Perm), 3, Perm)
2232 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2233 for i, n in enumerate('R W X'.split()):
2234 v = 1<<i
2235 e = Perm(v)
2236 self.assertEqual(e.value, v)
2237 self.assertEqual(type(e.value), int)
2238 self.assertEqual(e.name, n)
2239 self.assertIn(e, Perm)
2240 self.assertIs(type(e), Perm)
2241
2242 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002243 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002244 lst = list(Perm)
2245 self.assertEqual(len(lst), len(Perm))
2246 self.assertEqual(len(Perm), 3, Perm)
2247 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2248 for i, n in enumerate('R W X'.split()):
2249 v = 1<<(2*i+1)
2250 e = Perm(v)
2251 self.assertEqual(e.value, v)
2252 self.assertEqual(type(e.value), int)
2253 self.assertEqual(e.name, n)
2254 self.assertIn(e, Perm)
2255 self.assertIs(type(e), Perm)
2256
2257 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002258 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002259 lst = list(Perm)
2260 self.assertEqual(len(lst), len(Perm))
2261 self.assertEqual(len(Perm), 3, Perm)
2262 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2263 for i, n in enumerate('R W X'.split()):
2264 v = 1<<(2*i+1)
2265 e = Perm(v)
2266 self.assertEqual(e.value, v)
2267 self.assertEqual(type(e.value), int)
2268 self.assertEqual(e.name, n)
2269 self.assertIn(e, Perm)
2270 self.assertIs(type(e), Perm)
2271
Ethan Furman65a5a472016-09-01 23:55:19 -07002272 def test_pickle(self):
2273 if isinstance(FlagStooges, Exception):
2274 raise FlagStooges
2275 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2276 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002277
Rahul Jha94306522018-09-10 23:51:04 +05302278 def test_contains(self):
2279 Open = self.Open
2280 Color = self.Color
2281 self.assertFalse(Color.BLACK in Open)
2282 self.assertFalse(Open.RO in Color)
2283 with self.assertRaises(TypeError):
2284 'BLACK' in Color
2285 with self.assertRaises(TypeError):
2286 'RO' in Open
2287 with self.assertRaises(TypeError):
2288 1 in Color
2289 with self.assertRaises(TypeError):
2290 1 in Open
2291
2292 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002293 Perm = self.Perm
2294 R, W, X = Perm
2295 RW = R | W
2296 RX = R | X
2297 WX = W | X
2298 RWX = R | W | X
2299 self.assertTrue(R in RW)
2300 self.assertTrue(R in RX)
2301 self.assertTrue(R in RWX)
2302 self.assertTrue(W in RW)
2303 self.assertTrue(W in WX)
2304 self.assertTrue(W in RWX)
2305 self.assertTrue(X in RX)
2306 self.assertTrue(X in WX)
2307 self.assertTrue(X in RWX)
2308 self.assertFalse(R in WX)
2309 self.assertFalse(W in RX)
2310 self.assertFalse(X in RW)
2311
Ethan Furmanc16595e2016-09-10 23:36:59 -07002312 def test_auto_number(self):
2313 class Color(Flag):
2314 red = auto()
2315 blue = auto()
2316 green = auto()
2317
2318 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2319 self.assertEqual(Color.red.value, 1)
2320 self.assertEqual(Color.blue.value, 2)
2321 self.assertEqual(Color.green.value, 4)
2322
2323 def test_auto_number_garbage(self):
2324 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2325 class Color(Flag):
2326 red = 'not an int'
2327 blue = auto()
2328
Ethan Furman3515dcc2016-09-18 13:15:41 -07002329 def test_cascading_failure(self):
2330 class Bizarre(Flag):
2331 c = 3
2332 d = 4
2333 f = 6
2334 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002335 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2336 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2337 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2338 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2339 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2340 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2341 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002342
2343 def test_duplicate_auto(self):
2344 class Dupes(Enum):
2345 first = primero = auto()
2346 second = auto()
2347 third = auto()
2348 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2349
2350 def test_bizarre(self):
2351 class Bizarre(Flag):
2352 b = 3
2353 c = 4
2354 d = 6
2355 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2356
Ethan Furman5bdab642018-09-21 19:03:09 -07002357 def test_multiple_mixin(self):
2358 class AllMixin:
2359 @classproperty
2360 def ALL(cls):
2361 members = list(cls)
2362 all_value = None
2363 if members:
2364 all_value = members[0]
2365 for member in members[1:]:
2366 all_value |= member
2367 cls.ALL = all_value
2368 return all_value
2369 class StrMixin:
2370 def __str__(self):
2371 return self._name_.lower()
2372 class Color(AllMixin, Flag):
2373 RED = auto()
2374 GREEN = auto()
2375 BLUE = auto()
2376 self.assertEqual(Color.RED.value, 1)
2377 self.assertEqual(Color.GREEN.value, 2)
2378 self.assertEqual(Color.BLUE.value, 4)
2379 self.assertEqual(Color.ALL.value, 7)
2380 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2381 class Color(AllMixin, StrMixin, Flag):
2382 RED = auto()
2383 GREEN = auto()
2384 BLUE = auto()
2385 self.assertEqual(Color.RED.value, 1)
2386 self.assertEqual(Color.GREEN.value, 2)
2387 self.assertEqual(Color.BLUE.value, 4)
2388 self.assertEqual(Color.ALL.value, 7)
2389 self.assertEqual(str(Color.BLUE), 'blue')
2390 class Color(StrMixin, AllMixin, Flag):
2391 RED = auto()
2392 GREEN = auto()
2393 BLUE = auto()
2394 self.assertEqual(Color.RED.value, 1)
2395 self.assertEqual(Color.GREEN.value, 2)
2396 self.assertEqual(Color.BLUE.value, 4)
2397 self.assertEqual(Color.ALL.value, 7)
2398 self.assertEqual(str(Color.BLUE), 'blue')
2399
Ethan Furman28cf6632017-01-24 12:12:06 -08002400 @support.reap_threads
2401 def test_unique_composite(self):
2402 # override __eq__ to be identity only
2403 class TestFlag(Flag):
2404 one = auto()
2405 two = auto()
2406 three = auto()
2407 four = auto()
2408 five = auto()
2409 six = auto()
2410 seven = auto()
2411 eight = auto()
2412 def __eq__(self, other):
2413 return self is other
2414 def __hash__(self):
2415 return hash(self._value_)
2416 # have multiple threads competing to complete the composite members
2417 seen = set()
2418 failed = False
2419 def cycle_enum():
2420 nonlocal failed
2421 try:
2422 for i in range(256):
2423 seen.add(TestFlag(i))
2424 except Exception:
2425 failed = True
2426 threads = [
2427 threading.Thread(target=cycle_enum)
2428 for _ in range(8)
2429 ]
2430 with support.start_threads(threads):
2431 pass
2432 # check that only 248 members were created
2433 self.assertFalse(
2434 failed,
2435 'at least one thread failed while creating composite members')
2436 self.assertEqual(256, len(seen), 'too many composite members created')
2437
Ethan Furmanc16595e2016-09-10 23:36:59 -07002438
Ethan Furman65a5a472016-09-01 23:55:19 -07002439class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002440 """Tests of the IntFlags."""
2441
Ethan Furman65a5a472016-09-01 23:55:19 -07002442 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002443 X = 1 << 0
2444 W = 1 << 1
2445 R = 1 << 2
2446
Ethan Furman65a5a472016-09-01 23:55:19 -07002447 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002448 RO = 0
2449 WO = 1
2450 RW = 2
2451 AC = 3
2452 CE = 1<<19
2453
Rahul Jha94306522018-09-10 23:51:04 +05302454 class Color(IntFlag):
2455 BLACK = 0
2456 RED = 1
2457 GREEN = 2
2458 BLUE = 4
2459 PURPLE = RED|BLUE
2460
Ethan Furman3515dcc2016-09-18 13:15:41 -07002461 def test_type(self):
2462 Perm = self.Perm
2463 Open = self.Open
2464 for f in Perm:
2465 self.assertTrue(isinstance(f, Perm))
2466 self.assertEqual(f, f.value)
2467 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2468 self.assertEqual(Perm.W | Perm.X, 3)
2469 for f in Open:
2470 self.assertTrue(isinstance(f, Open))
2471 self.assertEqual(f, f.value)
2472 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2473 self.assertEqual(Open.WO | Open.RW, 3)
2474
2475
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002476 def test_str(self):
2477 Perm = self.Perm
2478 self.assertEqual(str(Perm.R), 'Perm.R')
2479 self.assertEqual(str(Perm.W), 'Perm.W')
2480 self.assertEqual(str(Perm.X), 'Perm.X')
2481 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2482 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2483 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2484 self.assertEqual(str(Perm(0)), 'Perm.0')
2485 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002486 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2487 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2488 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2489 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002490 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002491 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2492 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2493 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002494
2495 Open = self.Open
2496 self.assertEqual(str(Open.RO), 'Open.RO')
2497 self.assertEqual(str(Open.WO), 'Open.WO')
2498 self.assertEqual(str(Open.AC), 'Open.AC')
2499 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2500 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2501 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002502 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2503 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2504 self.assertEqual(str(~Open.AC), 'Open.CE')
2505 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2506 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2507 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002508
2509 def test_repr(self):
2510 Perm = self.Perm
2511 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2512 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2513 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2514 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2515 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2516 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002517 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2518 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002519 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2520 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2521 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2522 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002523 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002524 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2525 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2526 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002527
2528 Open = self.Open
2529 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2530 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2531 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2532 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2533 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002534 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002535 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2536 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2537 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2538 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2539 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2540 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002541
2542 def test_or(self):
2543 Perm = self.Perm
2544 for i in Perm:
2545 for j in Perm:
2546 self.assertEqual(i | j, i.value | j.value)
2547 self.assertEqual((i | j).value, i.value | j.value)
2548 self.assertIs(type(i | j), Perm)
2549 for j in range(8):
2550 self.assertEqual(i | j, i.value | j)
2551 self.assertEqual((i | j).value, i.value | j)
2552 self.assertIs(type(i | j), Perm)
2553 self.assertEqual(j | i, j | i.value)
2554 self.assertEqual((j | i).value, j | i.value)
2555 self.assertIs(type(j | i), Perm)
2556 for i in Perm:
2557 self.assertIs(i | i, i)
2558 self.assertIs(i | 0, i)
2559 self.assertIs(0 | i, i)
2560 Open = self.Open
2561 self.assertIs(Open.RO | Open.CE, Open.CE)
2562
2563 def test_and(self):
2564 Perm = self.Perm
2565 RW = Perm.R | Perm.W
2566 RX = Perm.R | Perm.X
2567 WX = Perm.W | Perm.X
2568 RWX = Perm.R | Perm.W | Perm.X
2569 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2570 for i in values:
2571 for j in values:
2572 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2573 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2574 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2575 for j in range(8):
2576 self.assertEqual(i & j, i.value & j)
2577 self.assertEqual((i & j).value, i.value & j)
2578 self.assertIs(type(i & j), Perm)
2579 self.assertEqual(j & i, j & i.value)
2580 self.assertEqual((j & i).value, j & i.value)
2581 self.assertIs(type(j & i), Perm)
2582 for i in Perm:
2583 self.assertIs(i & i, i)
2584 self.assertIs(i & 7, i)
2585 self.assertIs(7 & i, i)
2586 Open = self.Open
2587 self.assertIs(Open.RO & Open.CE, Open.RO)
2588
2589 def test_xor(self):
2590 Perm = self.Perm
2591 for i in Perm:
2592 for j in Perm:
2593 self.assertEqual(i ^ j, i.value ^ j.value)
2594 self.assertEqual((i ^ j).value, i.value ^ j.value)
2595 self.assertIs(type(i ^ j), Perm)
2596 for j in range(8):
2597 self.assertEqual(i ^ j, i.value ^ j)
2598 self.assertEqual((i ^ j).value, i.value ^ j)
2599 self.assertIs(type(i ^ j), Perm)
2600 self.assertEqual(j ^ i, j ^ i.value)
2601 self.assertEqual((j ^ i).value, j ^ i.value)
2602 self.assertIs(type(j ^ i), Perm)
2603 for i in Perm:
2604 self.assertIs(i ^ 0, i)
2605 self.assertIs(0 ^ i, i)
2606 Open = self.Open
2607 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2608 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2609
2610 def test_invert(self):
2611 Perm = self.Perm
2612 RW = Perm.R | Perm.W
2613 RX = Perm.R | Perm.X
2614 WX = Perm.W | Perm.X
2615 RWX = Perm.R | Perm.W | Perm.X
2616 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2617 for i in values:
2618 self.assertEqual(~i, ~i.value)
2619 self.assertEqual((~i).value, ~i.value)
2620 self.assertIs(type(~i), Perm)
2621 self.assertEqual(~~i, i)
2622 for i in Perm:
2623 self.assertIs(~~i, i)
2624 Open = self.Open
2625 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2626 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2627
2628 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002629 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002630 lst = list(Perm)
2631 self.assertEqual(len(lst), len(Perm))
2632 self.assertEqual(len(Perm), 3, Perm)
2633 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2634 for i, n in enumerate('R W X'.split()):
2635 v = 1<<i
2636 e = Perm(v)
2637 self.assertEqual(e.value, v)
2638 self.assertEqual(type(e.value), int)
2639 self.assertEqual(e, v)
2640 self.assertEqual(e.name, n)
2641 self.assertIn(e, Perm)
2642 self.assertIs(type(e), Perm)
2643
2644 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002645 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002646 lst = list(Perm)
2647 self.assertEqual(len(lst), len(Perm))
2648 self.assertEqual(len(Perm), 3, Perm)
2649 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2650 for i, n in enumerate('R W X'.split()):
2651 v = 8<<i
2652 e = Perm(v)
2653 self.assertEqual(e.value, v)
2654 self.assertEqual(type(e.value), int)
2655 self.assertEqual(e, v)
2656 self.assertEqual(e.name, n)
2657 self.assertIn(e, Perm)
2658 self.assertIs(type(e), Perm)
2659
2660 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002661 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002662 lst = list(Perm)
2663 self.assertEqual(len(lst), len(Perm))
2664 self.assertEqual(len(Perm), 3, Perm)
2665 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2666 for i, n in enumerate('R W X'.split()):
2667 v = 1<<i
2668 e = Perm(v)
2669 self.assertEqual(e.value, v)
2670 self.assertEqual(type(e.value), int)
2671 self.assertEqual(e, v)
2672 self.assertEqual(e.name, n)
2673 self.assertIn(e, Perm)
2674 self.assertIs(type(e), Perm)
2675
2676 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002677 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002678 lst = list(Perm)
2679 self.assertEqual(len(lst), len(Perm))
2680 self.assertEqual(len(Perm), 3, Perm)
2681 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2682 for i, n in enumerate('R W X'.split()):
2683 v = 1<<(2*i+1)
2684 e = Perm(v)
2685 self.assertEqual(e.value, v)
2686 self.assertEqual(type(e.value), int)
2687 self.assertEqual(e, v)
2688 self.assertEqual(e.name, n)
2689 self.assertIn(e, Perm)
2690 self.assertIs(type(e), Perm)
2691
2692 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002693 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002694 lst = list(Perm)
2695 self.assertEqual(len(lst), len(Perm))
2696 self.assertEqual(len(Perm), 3, Perm)
2697 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2698 for i, n in enumerate('R W X'.split()):
2699 v = 1<<(2*i+1)
2700 e = Perm(v)
2701 self.assertEqual(e.value, v)
2702 self.assertEqual(type(e.value), int)
2703 self.assertEqual(e, v)
2704 self.assertEqual(e.name, n)
2705 self.assertIn(e, Perm)
2706 self.assertIs(type(e), Perm)
2707
2708
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002709 def test_programatic_function_from_empty_list(self):
2710 Perm = enum.IntFlag('Perm', [])
2711 lst = list(Perm)
2712 self.assertEqual(len(lst), len(Perm))
2713 self.assertEqual(len(Perm), 0, Perm)
2714 Thing = enum.Enum('Thing', [])
2715 lst = list(Thing)
2716 self.assertEqual(len(lst), len(Thing))
2717 self.assertEqual(len(Thing), 0, Thing)
2718
2719
2720 def test_programatic_function_from_empty_tuple(self):
2721 Perm = enum.IntFlag('Perm', ())
2722 lst = list(Perm)
2723 self.assertEqual(len(lst), len(Perm))
2724 self.assertEqual(len(Perm), 0, Perm)
2725 Thing = enum.Enum('Thing', ())
2726 self.assertEqual(len(lst), len(Thing))
2727 self.assertEqual(len(Thing), 0, Thing)
2728
Rahul Jha94306522018-09-10 23:51:04 +05302729 def test_contains(self):
2730 Open = self.Open
2731 Color = self.Color
2732 self.assertTrue(Color.GREEN in Color)
2733 self.assertTrue(Open.RW in Open)
2734 self.assertFalse(Color.GREEN in Open)
2735 self.assertFalse(Open.RW in Color)
2736 with self.assertRaises(TypeError):
2737 'GREEN' in Color
2738 with self.assertRaises(TypeError):
2739 'RW' in Open
2740 with self.assertRaises(TypeError):
2741 2 in Color
2742 with self.assertRaises(TypeError):
2743 2 in Open
2744
2745 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002746 Perm = self.Perm
2747 R, W, X = Perm
2748 RW = R | W
2749 RX = R | X
2750 WX = W | X
2751 RWX = R | W | X
2752 self.assertTrue(R in RW)
2753 self.assertTrue(R in RX)
2754 self.assertTrue(R in RWX)
2755 self.assertTrue(W in RW)
2756 self.assertTrue(W in WX)
2757 self.assertTrue(W in RWX)
2758 self.assertTrue(X in RX)
2759 self.assertTrue(X in WX)
2760 self.assertTrue(X in RWX)
2761 self.assertFalse(R in WX)
2762 self.assertFalse(W in RX)
2763 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302764 with self.assertRaises(TypeError):
2765 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002766
Ethan Furman25d94bb2016-09-02 16:32:32 -07002767 def test_bool(self):
2768 Perm = self.Perm
2769 for f in Perm:
2770 self.assertTrue(f)
2771 Open = self.Open
2772 for f in Open:
2773 self.assertEqual(bool(f.value), bool(f))
2774
Ethan Furman5bdab642018-09-21 19:03:09 -07002775 def test_multiple_mixin(self):
2776 class AllMixin:
2777 @classproperty
2778 def ALL(cls):
2779 members = list(cls)
2780 all_value = None
2781 if members:
2782 all_value = members[0]
2783 for member in members[1:]:
2784 all_value |= member
2785 cls.ALL = all_value
2786 return all_value
2787 class StrMixin:
2788 def __str__(self):
2789 return self._name_.lower()
2790 class Color(AllMixin, IntFlag):
2791 RED = auto()
2792 GREEN = auto()
2793 BLUE = auto()
2794 self.assertEqual(Color.RED.value, 1)
2795 self.assertEqual(Color.GREEN.value, 2)
2796 self.assertEqual(Color.BLUE.value, 4)
2797 self.assertEqual(Color.ALL.value, 7)
2798 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2799 class Color(AllMixin, StrMixin, IntFlag):
2800 RED = auto()
2801 GREEN = auto()
2802 BLUE = auto()
2803 self.assertEqual(Color.RED.value, 1)
2804 self.assertEqual(Color.GREEN.value, 2)
2805 self.assertEqual(Color.BLUE.value, 4)
2806 self.assertEqual(Color.ALL.value, 7)
2807 self.assertEqual(str(Color.BLUE), 'blue')
2808 class Color(StrMixin, AllMixin, IntFlag):
2809 RED = auto()
2810 GREEN = auto()
2811 BLUE = auto()
2812 self.assertEqual(Color.RED.value, 1)
2813 self.assertEqual(Color.GREEN.value, 2)
2814 self.assertEqual(Color.BLUE.value, 4)
2815 self.assertEqual(Color.ALL.value, 7)
2816 self.assertEqual(str(Color.BLUE), 'blue')
2817
Ethan Furman28cf6632017-01-24 12:12:06 -08002818 @support.reap_threads
2819 def test_unique_composite(self):
2820 # override __eq__ to be identity only
2821 class TestFlag(IntFlag):
2822 one = auto()
2823 two = auto()
2824 three = auto()
2825 four = auto()
2826 five = auto()
2827 six = auto()
2828 seven = auto()
2829 eight = auto()
2830 def __eq__(self, other):
2831 return self is other
2832 def __hash__(self):
2833 return hash(self._value_)
2834 # have multiple threads competing to complete the composite members
2835 seen = set()
2836 failed = False
2837 def cycle_enum():
2838 nonlocal failed
2839 try:
2840 for i in range(256):
2841 seen.add(TestFlag(i))
2842 except Exception:
2843 failed = True
2844 threads = [
2845 threading.Thread(target=cycle_enum)
2846 for _ in range(8)
2847 ]
2848 with support.start_threads(threads):
2849 pass
2850 # check that only 248 members were created
2851 self.assertFalse(
2852 failed,
2853 'at least one thread failed while creating composite members')
2854 self.assertEqual(256, len(seen), 'too many composite members created')
2855
2856
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002857class TestEmptyAndNonLatinStrings(unittest.TestCase):
2858
2859 def test_empty_string(self):
2860 with self.assertRaises(ValueError):
2861 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2862
2863 def test_non_latin_character_string(self):
2864 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2865 item = getattr(greek_abc, '\u03B1')
2866 self.assertEqual(item.value, 1)
2867
2868 def test_non_latin_number_string(self):
2869 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2870 item = getattr(hebrew_123, '\u05D0')
2871 self.assertEqual(item.value, 1)
2872
2873
Ethan Furmanf24bb352013-07-18 17:05:39 -07002874class TestUnique(unittest.TestCase):
2875
2876 def test_unique_clean(self):
2877 @unique
2878 class Clean(Enum):
2879 one = 1
2880 two = 'dos'
2881 tres = 4.0
2882 @unique
2883 class Cleaner(IntEnum):
2884 single = 1
2885 double = 2
2886 triple = 3
2887
2888 def test_unique_dirty(self):
2889 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2890 @unique
2891 class Dirty(Enum):
2892 one = 1
2893 two = 'dos'
2894 tres = 1
2895 with self.assertRaisesRegex(
2896 ValueError,
2897 'double.*single.*turkey.*triple',
2898 ):
2899 @unique
2900 class Dirtier(IntEnum):
2901 single = 1
2902 double = 1
2903 triple = 3
2904 turkey = 3
2905
Ethan Furman3803ad42016-05-01 10:03:53 -07002906 def test_unique_with_name(self):
2907 @unique
2908 class Silly(Enum):
2909 one = 1
2910 two = 'dos'
2911 name = 3
2912 @unique
2913 class Sillier(IntEnum):
2914 single = 1
2915 name = 2
2916 triple = 3
2917 value = 4
2918
Ethan Furmanf24bb352013-07-18 17:05:39 -07002919
Ethan Furman5bdab642018-09-21 19:03:09 -07002920
Ethan Furman3323da92015-04-11 09:39:59 -07002921expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002922Help on class Color in module %s:
2923
2924class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002925 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2926 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002927 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002928 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002929 | Method resolution order:
2930 | Color
2931 | enum.Enum
2932 | builtins.object
2933 |\x20\x20
2934 | Data and other attributes defined here:
2935 |\x20\x20
2936 | blue = <Color.blue: 3>
2937 |\x20\x20
2938 | green = <Color.green: 2>
2939 |\x20\x20
2940 | red = <Color.red: 1>
2941 |\x20\x20
2942 | ----------------------------------------------------------------------
2943 | Data descriptors inherited from enum.Enum:
2944 |\x20\x20
2945 | name
2946 | The name of the Enum member.
2947 |\x20\x20
2948 | value
2949 | The value of the Enum member.
2950 |\x20\x20
2951 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002952 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002953 |\x20\x20
2954 | __members__
2955 | Returns a mapping of member name->value.
2956 |\x20\x20\x20\x20\x20\x20
2957 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002958 | is a read-only view of the internal mapping."""
2959
2960expected_help_output_without_docs = """\
2961Help on class Color in module %s:
2962
2963class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002964 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2965 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002966 | Method resolution order:
2967 | Color
2968 | enum.Enum
2969 | builtins.object
2970 |\x20\x20
2971 | Data and other attributes defined here:
2972 |\x20\x20
2973 | blue = <Color.blue: 3>
2974 |\x20\x20
2975 | green = <Color.green: 2>
2976 |\x20\x20
2977 | red = <Color.red: 1>
2978 |\x20\x20
2979 | ----------------------------------------------------------------------
2980 | Data descriptors inherited from enum.Enum:
2981 |\x20\x20
2982 | name
2983 |\x20\x20
2984 | value
2985 |\x20\x20
2986 | ----------------------------------------------------------------------
2987 | Data descriptors inherited from enum.EnumMeta:
2988 |\x20\x20
2989 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002990
2991class TestStdLib(unittest.TestCase):
2992
Ethan Furman48a724f2015-04-11 23:23:06 -07002993 maxDiff = None
2994
Ethan Furman5875d742013-10-21 20:45:55 -07002995 class Color(Enum):
2996 red = 1
2997 green = 2
2998 blue = 3
2999
3000 def test_pydoc(self):
3001 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003002 if StrEnum.__doc__ is None:
3003 expected_text = expected_help_output_without_docs % __name__
3004 else:
3005 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003006 output = StringIO()
3007 helper = pydoc.Helper(output=output)
3008 helper(self.Color)
3009 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003010 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003011
3012 def test_inspect_getmembers(self):
3013 values = dict((
3014 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003015 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003016 ('__members__', self.Color.__members__),
3017 ('__module__', __name__),
3018 ('blue', self.Color.blue),
3019 ('green', self.Color.green),
3020 ('name', Enum.__dict__['name']),
3021 ('red', self.Color.red),
3022 ('value', Enum.__dict__['value']),
3023 ))
3024 result = dict(inspect.getmembers(self.Color))
3025 self.assertEqual(values.keys(), result.keys())
3026 failed = False
3027 for k in values.keys():
3028 if result[k] != values[k]:
3029 print()
3030 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3031 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3032 failed = True
3033 if failed:
3034 self.fail("result does not equal expected, see print above")
3035
3036 def test_inspect_classify_class_attrs(self):
3037 # indirectly test __objclass__
3038 from inspect import Attribute
3039 values = [
3040 Attribute(name='__class__', kind='data',
3041 defining_class=object, object=EnumMeta),
3042 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003043 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003044 Attribute(name='__members__', kind='property',
3045 defining_class=EnumMeta, object=EnumMeta.__members__),
3046 Attribute(name='__module__', kind='data',
3047 defining_class=self.Color, object=__name__),
3048 Attribute(name='blue', kind='data',
3049 defining_class=self.Color, object=self.Color.blue),
3050 Attribute(name='green', kind='data',
3051 defining_class=self.Color, object=self.Color.green),
3052 Attribute(name='red', kind='data',
3053 defining_class=self.Color, object=self.Color.red),
3054 Attribute(name='name', kind='data',
3055 defining_class=Enum, object=Enum.__dict__['name']),
3056 Attribute(name='value', kind='data',
3057 defining_class=Enum, object=Enum.__dict__['value']),
3058 ]
3059 values.sort(key=lambda item: item.name)
3060 result = list(inspect.classify_class_attrs(self.Color))
3061 result.sort(key=lambda item: item.name)
3062 failed = False
3063 for v, r in zip(values, result):
3064 if r != v:
3065 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3066 failed = True
3067 if failed:
3068 self.fail("result does not equal expected, see print above")
3069
Martin Panter19e69c52015-11-14 12:46:42 +00003070
3071class MiscTestCase(unittest.TestCase):
3072 def test__all__(self):
3073 support.check__all__(self, enum)
3074
3075
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003076# These are unordered here on purpose to ensure that declaration order
3077# makes no difference.
3078CONVERT_TEST_NAME_D = 5
3079CONVERT_TEST_NAME_C = 5
3080CONVERT_TEST_NAME_B = 5
3081CONVERT_TEST_NAME_A = 5 # This one should sort first.
3082CONVERT_TEST_NAME_E = 5
3083CONVERT_TEST_NAME_F = 5
3084
3085class TestIntEnumConvert(unittest.TestCase):
3086 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003087 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003088 'UnittestConvert',
3089 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003090 filter=lambda x: x.startswith('CONVERT_TEST_'))
3091 # We don't want the reverse lookup value to vary when there are
3092 # multiple possible names for a given value. It should always
3093 # report the first lexigraphical name in that case.
3094 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3095
3096 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003097 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003098 'UnittestConvert',
3099 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003100 filter=lambda x: x.startswith('CONVERT_TEST_'))
3101 # Ensure that test_type has all of the desired names and values.
3102 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3103 test_type.CONVERT_TEST_NAME_A)
3104 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3105 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3106 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3107 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3108 # Ensure that test_type only picked up names matching the filter.
3109 self.assertEqual([name for name in dir(test_type)
3110 if name[0:2] not in ('CO', '__')],
3111 [], msg='Names other than CONVERT_TEST_* found.')
3112
orlnub1230fb9fad2018-09-12 20:28:53 +03003113 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3114 '_convert was deprecated in 3.8')
3115 def test_convert_warn(self):
3116 with self.assertWarns(DeprecationWarning):
3117 enum.IntEnum._convert(
3118 'UnittestConvert',
3119 ('test.test_enum', '__main__')[__name__=='__main__'],
3120 filter=lambda x: x.startswith('CONVERT_TEST_'))
3121
3122 @unittest.skipUnless(sys.version_info >= (3, 9),
3123 '_convert was removed in 3.9')
3124 def test_convert_raise(self):
3125 with self.assertRaises(AttributeError):
3126 enum.IntEnum._convert(
3127 'UnittestConvert',
3128 ('test.test_enum', '__main__')[__name__=='__main__'],
3129 filter=lambda x: x.startswith('CONVERT_TEST_'))
3130
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003131
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003132if __name__ == '__main__':
3133 unittest.main()