blob: 0ecf6413b131324d5ee76e8ee41ca6274acfa967 [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
1816
Ethan Furman3515dcc2016-09-18 13:15:41 -07001817 def test_duplicate_auto(self):
1818 class Dupes(Enum):
1819 first = primero = auto()
1820 second = auto()
1821 third = auto()
1822 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1823
Ethan Furman019f0a02018-09-12 11:43:34 -07001824 def test_missing(self):
1825 class Color(Enum):
1826 red = 1
1827 green = 2
1828 blue = 3
1829 @classmethod
1830 def _missing_(cls, item):
1831 if item == 'three':
1832 return cls.blue
1833 elif item == 'bad return':
1834 # trigger internal error
1835 return 5
1836 elif item == 'error out':
1837 raise ZeroDivisionError
1838 else:
1839 # trigger not found
1840 return None
1841 self.assertIs(Color('three'), Color.blue)
1842 self.assertRaises(ValueError, Color, 7)
1843 try:
1844 Color('bad return')
1845 except TypeError as exc:
1846 self.assertTrue(isinstance(exc.__context__, ValueError))
1847 else:
1848 raise Exception('Exception not raised.')
1849 try:
1850 Color('error out')
1851 except ZeroDivisionError as exc:
1852 self.assertTrue(isinstance(exc.__context__, ValueError))
1853 else:
1854 raise Exception('Exception not raised.')
1855
Ethan Furman5bdab642018-09-21 19:03:09 -07001856 def test_multiple_mixin(self):
1857 class MaxMixin:
1858 @classproperty
1859 def MAX(cls):
1860 max = len(cls)
1861 cls.MAX = max
1862 return max
1863 class StrMixin:
1864 def __str__(self):
1865 return self._name_.lower()
1866 class SomeEnum(Enum):
1867 def behavior(self):
1868 return 'booyah'
1869 class AnotherEnum(Enum):
1870 def behavior(self):
1871 return 'nuhuh!'
1872 def social(self):
1873 return "what's up?"
1874 class Color(MaxMixin, Enum):
1875 RED = auto()
1876 GREEN = auto()
1877 BLUE = auto()
1878 self.assertEqual(Color.RED.value, 1)
1879 self.assertEqual(Color.GREEN.value, 2)
1880 self.assertEqual(Color.BLUE.value, 3)
1881 self.assertEqual(Color.MAX, 3)
1882 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1883 class Color(MaxMixin, StrMixin, Enum):
1884 RED = auto()
1885 GREEN = auto()
1886 BLUE = auto()
1887 self.assertEqual(Color.RED.value, 1)
1888 self.assertEqual(Color.GREEN.value, 2)
1889 self.assertEqual(Color.BLUE.value, 3)
1890 self.assertEqual(Color.MAX, 3)
1891 self.assertEqual(str(Color.BLUE), 'blue')
1892 class Color(StrMixin, MaxMixin, Enum):
1893 RED = auto()
1894 GREEN = auto()
1895 BLUE = auto()
1896 self.assertEqual(Color.RED.value, 1)
1897 self.assertEqual(Color.GREEN.value, 2)
1898 self.assertEqual(Color.BLUE.value, 3)
1899 self.assertEqual(Color.MAX, 3)
1900 self.assertEqual(str(Color.BLUE), 'blue')
1901 class CoolColor(StrMixin, SomeEnum, Enum):
1902 RED = auto()
1903 GREEN = auto()
1904 BLUE = auto()
1905 self.assertEqual(CoolColor.RED.value, 1)
1906 self.assertEqual(CoolColor.GREEN.value, 2)
1907 self.assertEqual(CoolColor.BLUE.value, 3)
1908 self.assertEqual(str(CoolColor.BLUE), 'blue')
1909 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1910 class CoolerColor(StrMixin, AnotherEnum, Enum):
1911 RED = auto()
1912 GREEN = auto()
1913 BLUE = auto()
1914 self.assertEqual(CoolerColor.RED.value, 1)
1915 self.assertEqual(CoolerColor.GREEN.value, 2)
1916 self.assertEqual(CoolerColor.BLUE.value, 3)
1917 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1918 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1919 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1920 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1921 RED = auto()
1922 GREEN = auto()
1923 BLUE = auto()
1924 self.assertEqual(CoolestColor.RED.value, 1)
1925 self.assertEqual(CoolestColor.GREEN.value, 2)
1926 self.assertEqual(CoolestColor.BLUE.value, 3)
1927 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1928 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1929 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1930 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1931 RED = auto()
1932 GREEN = auto()
1933 BLUE = auto()
1934 self.assertEqual(ConfusedColor.RED.value, 1)
1935 self.assertEqual(ConfusedColor.GREEN.value, 2)
1936 self.assertEqual(ConfusedColor.BLUE.value, 3)
1937 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1938 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1939 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1940 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1941 RED = auto()
1942 GREEN = auto()
1943 BLUE = auto()
1944 self.assertEqual(ReformedColor.RED.value, 1)
1945 self.assertEqual(ReformedColor.GREEN.value, 2)
1946 self.assertEqual(ReformedColor.BLUE.value, 3)
1947 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1948 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1949 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1950 self.assertTrue(issubclass(ReformedColor, int))
1951
Ethan Furmancd453852018-10-05 23:29:36 -07001952 def test_multiple_inherited_mixin(self):
1953 class StrEnum(str, Enum):
1954 def __new__(cls, *args, **kwargs):
1955 for a in args:
1956 if not isinstance(a, str):
1957 raise TypeError("Enumeration '%s' (%s) is not"
1958 " a string" % (a, type(a).__name__))
1959 return str.__new__(cls, *args, **kwargs)
1960 @unique
1961 class Decision1(StrEnum):
1962 REVERT = "REVERT"
1963 REVERT_ALL = "REVERT_ALL"
1964 RETRY = "RETRY"
1965 class MyEnum(StrEnum):
1966 pass
1967 @unique
1968 class Decision2(MyEnum):
1969 REVERT = "REVERT"
1970 REVERT_ALL = "REVERT_ALL"
1971 RETRY = "RETRY"
1972
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001973 def test_empty_globals(self):
1974 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1975 # when using compile and exec because f_globals is empty
1976 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1977 code = compile(code, "<string>", "exec")
1978 global_ns = {}
1979 local_ls = {}
1980 exec(code, global_ns, local_ls)
1981
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001982
Ethan Furmane8e61272016-08-20 07:19:31 -07001983class TestOrder(unittest.TestCase):
1984
1985 def test_same_members(self):
1986 class Color(Enum):
1987 _order_ = 'red green blue'
1988 red = 1
1989 green = 2
1990 blue = 3
1991
1992 def test_same_members_with_aliases(self):
1993 class Color(Enum):
1994 _order_ = 'red green blue'
1995 red = 1
1996 green = 2
1997 blue = 3
1998 verde = green
1999
2000 def test_same_members_wrong_order(self):
2001 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2002 class Color(Enum):
2003 _order_ = 'red green blue'
2004 red = 1
2005 blue = 3
2006 green = 2
2007
2008 def test_order_has_extra_members(self):
2009 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2010 class Color(Enum):
2011 _order_ = 'red green blue purple'
2012 red = 1
2013 green = 2
2014 blue = 3
2015
2016 def test_order_has_extra_members_with_aliases(self):
2017 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2018 class Color(Enum):
2019 _order_ = 'red green blue purple'
2020 red = 1
2021 green = 2
2022 blue = 3
2023 verde = green
2024
2025 def test_enum_has_extra_members(self):
2026 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2027 class Color(Enum):
2028 _order_ = 'red green blue'
2029 red = 1
2030 green = 2
2031 blue = 3
2032 purple = 4
2033
2034 def test_enum_has_extra_members_with_aliases(self):
2035 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2036 class Color(Enum):
2037 _order_ = 'red green blue'
2038 red = 1
2039 green = 2
2040 blue = 3
2041 purple = 4
2042 verde = green
2043
2044
Ethan Furman65a5a472016-09-01 23:55:19 -07002045class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002046 """Tests of the Flags."""
2047
Ethan Furman65a5a472016-09-01 23:55:19 -07002048 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002049 R, W, X = 4, 2, 1
2050
Ethan Furman65a5a472016-09-01 23:55:19 -07002051 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002052 RO = 0
2053 WO = 1
2054 RW = 2
2055 AC = 3
2056 CE = 1<<19
2057
Rahul Jha94306522018-09-10 23:51:04 +05302058 class Color(Flag):
2059 BLACK = 0
2060 RED = 1
2061 GREEN = 2
2062 BLUE = 4
2063 PURPLE = RED|BLUE
2064
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002065 def test_str(self):
2066 Perm = self.Perm
2067 self.assertEqual(str(Perm.R), 'Perm.R')
2068 self.assertEqual(str(Perm.W), 'Perm.W')
2069 self.assertEqual(str(Perm.X), 'Perm.X')
2070 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2071 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2072 self.assertEqual(str(Perm(0)), 'Perm.0')
2073 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2074 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2075 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2076 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2077 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2078 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2079
2080 Open = self.Open
2081 self.assertEqual(str(Open.RO), 'Open.RO')
2082 self.assertEqual(str(Open.WO), 'Open.WO')
2083 self.assertEqual(str(Open.AC), 'Open.AC')
2084 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2085 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002086 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002087 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2088 self.assertEqual(str(~Open.AC), 'Open.CE')
2089 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2090 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2091
2092 def test_repr(self):
2093 Perm = self.Perm
2094 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2095 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2096 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2097 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2098 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002099 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002100 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2101 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2102 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2103 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002104 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002105 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2106
2107 Open = self.Open
2108 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2109 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2110 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2111 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2112 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002113 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002114 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2115 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2116 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2117 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2118
2119 def test_or(self):
2120 Perm = self.Perm
2121 for i in Perm:
2122 for j in Perm:
2123 self.assertEqual((i | j), Perm(i.value | j.value))
2124 self.assertEqual((i | j).value, i.value | j.value)
2125 self.assertIs(type(i | j), Perm)
2126 for i in Perm:
2127 self.assertIs(i | i, i)
2128 Open = self.Open
2129 self.assertIs(Open.RO | Open.CE, Open.CE)
2130
2131 def test_and(self):
2132 Perm = self.Perm
2133 RW = Perm.R | Perm.W
2134 RX = Perm.R | Perm.X
2135 WX = Perm.W | Perm.X
2136 RWX = Perm.R | Perm.W | Perm.X
2137 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2138 for i in values:
2139 for j in values:
2140 self.assertEqual((i & j).value, i.value & j.value)
2141 self.assertIs(type(i & j), Perm)
2142 for i in Perm:
2143 self.assertIs(i & i, i)
2144 self.assertIs(i & RWX, i)
2145 self.assertIs(RWX & i, i)
2146 Open = self.Open
2147 self.assertIs(Open.RO & Open.CE, Open.RO)
2148
2149 def test_xor(self):
2150 Perm = self.Perm
2151 for i in Perm:
2152 for j in Perm:
2153 self.assertEqual((i ^ j).value, i.value ^ j.value)
2154 self.assertIs(type(i ^ j), Perm)
2155 for i in Perm:
2156 self.assertIs(i ^ Perm(0), i)
2157 self.assertIs(Perm(0) ^ i, i)
2158 Open = self.Open
2159 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2160 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2161
2162 def test_invert(self):
2163 Perm = self.Perm
2164 RW = Perm.R | Perm.W
2165 RX = Perm.R | Perm.X
2166 WX = Perm.W | Perm.X
2167 RWX = Perm.R | Perm.W | Perm.X
2168 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2169 for i in values:
2170 self.assertIs(type(~i), Perm)
2171 self.assertEqual(~~i, i)
2172 for i in Perm:
2173 self.assertIs(~~i, i)
2174 Open = self.Open
2175 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2176 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2177
Ethan Furman25d94bb2016-09-02 16:32:32 -07002178 def test_bool(self):
2179 Perm = self.Perm
2180 for f in Perm:
2181 self.assertTrue(f)
2182 Open = self.Open
2183 for f in Open:
2184 self.assertEqual(bool(f.value), bool(f))
2185
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002186 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002187 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002188 lst = list(Perm)
2189 self.assertEqual(len(lst), len(Perm))
2190 self.assertEqual(len(Perm), 3, Perm)
2191 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2192 for i, n in enumerate('R W X'.split()):
2193 v = 1<<i
2194 e = Perm(v)
2195 self.assertEqual(e.value, v)
2196 self.assertEqual(type(e.value), int)
2197 self.assertEqual(e.name, n)
2198 self.assertIn(e, Perm)
2199 self.assertIs(type(e), Perm)
2200
2201 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002202 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002203 lst = list(Perm)
2204 self.assertEqual(len(lst), len(Perm))
2205 self.assertEqual(len(Perm), 3, Perm)
2206 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2207 for i, n in enumerate('R W X'.split()):
2208 v = 8<<i
2209 e = Perm(v)
2210 self.assertEqual(e.value, v)
2211 self.assertEqual(type(e.value), int)
2212 self.assertEqual(e.name, n)
2213 self.assertIn(e, Perm)
2214 self.assertIs(type(e), Perm)
2215
2216 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002217 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002218 lst = list(Perm)
2219 self.assertEqual(len(lst), len(Perm))
2220 self.assertEqual(len(Perm), 3, Perm)
2221 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2222 for i, n in enumerate('R W X'.split()):
2223 v = 1<<i
2224 e = Perm(v)
2225 self.assertEqual(e.value, v)
2226 self.assertEqual(type(e.value), int)
2227 self.assertEqual(e.name, n)
2228 self.assertIn(e, Perm)
2229 self.assertIs(type(e), Perm)
2230
2231 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002232 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002233 lst = list(Perm)
2234 self.assertEqual(len(lst), len(Perm))
2235 self.assertEqual(len(Perm), 3, Perm)
2236 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2237 for i, n in enumerate('R W X'.split()):
2238 v = 1<<(2*i+1)
2239 e = Perm(v)
2240 self.assertEqual(e.value, v)
2241 self.assertEqual(type(e.value), int)
2242 self.assertEqual(e.name, n)
2243 self.assertIn(e, Perm)
2244 self.assertIs(type(e), Perm)
2245
2246 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002247 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002248 lst = list(Perm)
2249 self.assertEqual(len(lst), len(Perm))
2250 self.assertEqual(len(Perm), 3, Perm)
2251 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2252 for i, n in enumerate('R W X'.split()):
2253 v = 1<<(2*i+1)
2254 e = Perm(v)
2255 self.assertEqual(e.value, v)
2256 self.assertEqual(type(e.value), int)
2257 self.assertEqual(e.name, n)
2258 self.assertIn(e, Perm)
2259 self.assertIs(type(e), Perm)
2260
Ethan Furman65a5a472016-09-01 23:55:19 -07002261 def test_pickle(self):
2262 if isinstance(FlagStooges, Exception):
2263 raise FlagStooges
2264 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2265 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002266
Rahul Jha94306522018-09-10 23:51:04 +05302267 def test_contains(self):
2268 Open = self.Open
2269 Color = self.Color
2270 self.assertFalse(Color.BLACK in Open)
2271 self.assertFalse(Open.RO in Color)
2272 with self.assertRaises(TypeError):
2273 'BLACK' in Color
2274 with self.assertRaises(TypeError):
2275 'RO' in Open
2276 with self.assertRaises(TypeError):
2277 1 in Color
2278 with self.assertRaises(TypeError):
2279 1 in Open
2280
2281 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002282 Perm = self.Perm
2283 R, W, X = Perm
2284 RW = R | W
2285 RX = R | X
2286 WX = W | X
2287 RWX = R | W | X
2288 self.assertTrue(R in RW)
2289 self.assertTrue(R in RX)
2290 self.assertTrue(R in RWX)
2291 self.assertTrue(W in RW)
2292 self.assertTrue(W in WX)
2293 self.assertTrue(W in RWX)
2294 self.assertTrue(X in RX)
2295 self.assertTrue(X in WX)
2296 self.assertTrue(X in RWX)
2297 self.assertFalse(R in WX)
2298 self.assertFalse(W in RX)
2299 self.assertFalse(X in RW)
2300
Ethan Furmanc16595e2016-09-10 23:36:59 -07002301 def test_auto_number(self):
2302 class Color(Flag):
2303 red = auto()
2304 blue = auto()
2305 green = auto()
2306
2307 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2308 self.assertEqual(Color.red.value, 1)
2309 self.assertEqual(Color.blue.value, 2)
2310 self.assertEqual(Color.green.value, 4)
2311
2312 def test_auto_number_garbage(self):
2313 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2314 class Color(Flag):
2315 red = 'not an int'
2316 blue = auto()
2317
Ethan Furman3515dcc2016-09-18 13:15:41 -07002318 def test_cascading_failure(self):
2319 class Bizarre(Flag):
2320 c = 3
2321 d = 4
2322 f = 6
2323 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002324 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2325 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2326 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2327 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2328 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2329 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2330 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002331
2332 def test_duplicate_auto(self):
2333 class Dupes(Enum):
2334 first = primero = auto()
2335 second = auto()
2336 third = auto()
2337 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2338
2339 def test_bizarre(self):
2340 class Bizarre(Flag):
2341 b = 3
2342 c = 4
2343 d = 6
2344 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2345
Ethan Furman5bdab642018-09-21 19:03:09 -07002346 def test_multiple_mixin(self):
2347 class AllMixin:
2348 @classproperty
2349 def ALL(cls):
2350 members = list(cls)
2351 all_value = None
2352 if members:
2353 all_value = members[0]
2354 for member in members[1:]:
2355 all_value |= member
2356 cls.ALL = all_value
2357 return all_value
2358 class StrMixin:
2359 def __str__(self):
2360 return self._name_.lower()
2361 class Color(AllMixin, Flag):
2362 RED = auto()
2363 GREEN = auto()
2364 BLUE = auto()
2365 self.assertEqual(Color.RED.value, 1)
2366 self.assertEqual(Color.GREEN.value, 2)
2367 self.assertEqual(Color.BLUE.value, 4)
2368 self.assertEqual(Color.ALL.value, 7)
2369 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2370 class Color(AllMixin, StrMixin, Flag):
2371 RED = auto()
2372 GREEN = auto()
2373 BLUE = auto()
2374 self.assertEqual(Color.RED.value, 1)
2375 self.assertEqual(Color.GREEN.value, 2)
2376 self.assertEqual(Color.BLUE.value, 4)
2377 self.assertEqual(Color.ALL.value, 7)
2378 self.assertEqual(str(Color.BLUE), 'blue')
2379 class Color(StrMixin, AllMixin, Flag):
2380 RED = auto()
2381 GREEN = auto()
2382 BLUE = auto()
2383 self.assertEqual(Color.RED.value, 1)
2384 self.assertEqual(Color.GREEN.value, 2)
2385 self.assertEqual(Color.BLUE.value, 4)
2386 self.assertEqual(Color.ALL.value, 7)
2387 self.assertEqual(str(Color.BLUE), 'blue')
2388
Ethan Furman28cf6632017-01-24 12:12:06 -08002389 @support.reap_threads
2390 def test_unique_composite(self):
2391 # override __eq__ to be identity only
2392 class TestFlag(Flag):
2393 one = auto()
2394 two = auto()
2395 three = auto()
2396 four = auto()
2397 five = auto()
2398 six = auto()
2399 seven = auto()
2400 eight = auto()
2401 def __eq__(self, other):
2402 return self is other
2403 def __hash__(self):
2404 return hash(self._value_)
2405 # have multiple threads competing to complete the composite members
2406 seen = set()
2407 failed = False
2408 def cycle_enum():
2409 nonlocal failed
2410 try:
2411 for i in range(256):
2412 seen.add(TestFlag(i))
2413 except Exception:
2414 failed = True
2415 threads = [
2416 threading.Thread(target=cycle_enum)
2417 for _ in range(8)
2418 ]
2419 with support.start_threads(threads):
2420 pass
2421 # check that only 248 members were created
2422 self.assertFalse(
2423 failed,
2424 'at least one thread failed while creating composite members')
2425 self.assertEqual(256, len(seen), 'too many composite members created')
2426
Ethan Furmanc16595e2016-09-10 23:36:59 -07002427
Ethan Furman65a5a472016-09-01 23:55:19 -07002428class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002429 """Tests of the IntFlags."""
2430
Ethan Furman65a5a472016-09-01 23:55:19 -07002431 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002432 X = 1 << 0
2433 W = 1 << 1
2434 R = 1 << 2
2435
Ethan Furman65a5a472016-09-01 23:55:19 -07002436 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002437 RO = 0
2438 WO = 1
2439 RW = 2
2440 AC = 3
2441 CE = 1<<19
2442
Rahul Jha94306522018-09-10 23:51:04 +05302443 class Color(IntFlag):
2444 BLACK = 0
2445 RED = 1
2446 GREEN = 2
2447 BLUE = 4
2448 PURPLE = RED|BLUE
2449
Ethan Furman3515dcc2016-09-18 13:15:41 -07002450 def test_type(self):
2451 Perm = self.Perm
2452 Open = self.Open
2453 for f in Perm:
2454 self.assertTrue(isinstance(f, Perm))
2455 self.assertEqual(f, f.value)
2456 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2457 self.assertEqual(Perm.W | Perm.X, 3)
2458 for f in Open:
2459 self.assertTrue(isinstance(f, Open))
2460 self.assertEqual(f, f.value)
2461 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2462 self.assertEqual(Open.WO | Open.RW, 3)
2463
2464
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002465 def test_str(self):
2466 Perm = self.Perm
2467 self.assertEqual(str(Perm.R), 'Perm.R')
2468 self.assertEqual(str(Perm.W), 'Perm.W')
2469 self.assertEqual(str(Perm.X), 'Perm.X')
2470 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2471 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2472 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2473 self.assertEqual(str(Perm(0)), 'Perm.0')
2474 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002475 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2476 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2477 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2478 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002479 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002480 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2481 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2482 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002483
2484 Open = self.Open
2485 self.assertEqual(str(Open.RO), 'Open.RO')
2486 self.assertEqual(str(Open.WO), 'Open.WO')
2487 self.assertEqual(str(Open.AC), 'Open.AC')
2488 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2489 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2490 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002491 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2492 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2493 self.assertEqual(str(~Open.AC), 'Open.CE')
2494 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2495 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2496 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002497
2498 def test_repr(self):
2499 Perm = self.Perm
2500 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2501 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2502 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2503 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2504 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2505 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002506 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2507 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002508 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2509 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2510 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2511 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002512 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002513 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2514 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2515 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002516
2517 Open = self.Open
2518 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2519 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2520 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2521 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2522 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002523 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002524 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2525 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2526 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2527 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2528 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2529 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002530
2531 def test_or(self):
2532 Perm = self.Perm
2533 for i in Perm:
2534 for j in Perm:
2535 self.assertEqual(i | j, i.value | j.value)
2536 self.assertEqual((i | j).value, i.value | j.value)
2537 self.assertIs(type(i | j), Perm)
2538 for j in range(8):
2539 self.assertEqual(i | j, i.value | j)
2540 self.assertEqual((i | j).value, i.value | j)
2541 self.assertIs(type(i | j), Perm)
2542 self.assertEqual(j | i, j | i.value)
2543 self.assertEqual((j | i).value, j | i.value)
2544 self.assertIs(type(j | i), Perm)
2545 for i in Perm:
2546 self.assertIs(i | i, i)
2547 self.assertIs(i | 0, i)
2548 self.assertIs(0 | i, i)
2549 Open = self.Open
2550 self.assertIs(Open.RO | Open.CE, Open.CE)
2551
2552 def test_and(self):
2553 Perm = self.Perm
2554 RW = Perm.R | Perm.W
2555 RX = Perm.R | Perm.X
2556 WX = Perm.W | Perm.X
2557 RWX = Perm.R | Perm.W | Perm.X
2558 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2559 for i in values:
2560 for j in values:
2561 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2562 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2563 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2564 for j in range(8):
2565 self.assertEqual(i & j, i.value & j)
2566 self.assertEqual((i & j).value, i.value & j)
2567 self.assertIs(type(i & j), Perm)
2568 self.assertEqual(j & i, j & i.value)
2569 self.assertEqual((j & i).value, j & i.value)
2570 self.assertIs(type(j & i), Perm)
2571 for i in Perm:
2572 self.assertIs(i & i, i)
2573 self.assertIs(i & 7, i)
2574 self.assertIs(7 & i, i)
2575 Open = self.Open
2576 self.assertIs(Open.RO & Open.CE, Open.RO)
2577
2578 def test_xor(self):
2579 Perm = self.Perm
2580 for i in Perm:
2581 for j in Perm:
2582 self.assertEqual(i ^ j, i.value ^ j.value)
2583 self.assertEqual((i ^ j).value, i.value ^ j.value)
2584 self.assertIs(type(i ^ j), Perm)
2585 for j in range(8):
2586 self.assertEqual(i ^ j, i.value ^ j)
2587 self.assertEqual((i ^ j).value, i.value ^ j)
2588 self.assertIs(type(i ^ j), Perm)
2589 self.assertEqual(j ^ i, j ^ i.value)
2590 self.assertEqual((j ^ i).value, j ^ i.value)
2591 self.assertIs(type(j ^ i), Perm)
2592 for i in Perm:
2593 self.assertIs(i ^ 0, i)
2594 self.assertIs(0 ^ i, i)
2595 Open = self.Open
2596 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2597 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2598
2599 def test_invert(self):
2600 Perm = self.Perm
2601 RW = Perm.R | Perm.W
2602 RX = Perm.R | Perm.X
2603 WX = Perm.W | Perm.X
2604 RWX = Perm.R | Perm.W | Perm.X
2605 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2606 for i in values:
2607 self.assertEqual(~i, ~i.value)
2608 self.assertEqual((~i).value, ~i.value)
2609 self.assertIs(type(~i), Perm)
2610 self.assertEqual(~~i, i)
2611 for i in Perm:
2612 self.assertIs(~~i, i)
2613 Open = self.Open
2614 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2615 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2616
2617 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002618 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002619 lst = list(Perm)
2620 self.assertEqual(len(lst), len(Perm))
2621 self.assertEqual(len(Perm), 3, Perm)
2622 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2623 for i, n in enumerate('R W X'.split()):
2624 v = 1<<i
2625 e = Perm(v)
2626 self.assertEqual(e.value, v)
2627 self.assertEqual(type(e.value), int)
2628 self.assertEqual(e, v)
2629 self.assertEqual(e.name, n)
2630 self.assertIn(e, Perm)
2631 self.assertIs(type(e), Perm)
2632
2633 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002634 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002635 lst = list(Perm)
2636 self.assertEqual(len(lst), len(Perm))
2637 self.assertEqual(len(Perm), 3, Perm)
2638 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2639 for i, n in enumerate('R W X'.split()):
2640 v = 8<<i
2641 e = Perm(v)
2642 self.assertEqual(e.value, v)
2643 self.assertEqual(type(e.value), int)
2644 self.assertEqual(e, v)
2645 self.assertEqual(e.name, n)
2646 self.assertIn(e, Perm)
2647 self.assertIs(type(e), Perm)
2648
2649 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002650 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002651 lst = list(Perm)
2652 self.assertEqual(len(lst), len(Perm))
2653 self.assertEqual(len(Perm), 3, Perm)
2654 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2655 for i, n in enumerate('R W X'.split()):
2656 v = 1<<i
2657 e = Perm(v)
2658 self.assertEqual(e.value, v)
2659 self.assertEqual(type(e.value), int)
2660 self.assertEqual(e, v)
2661 self.assertEqual(e.name, n)
2662 self.assertIn(e, Perm)
2663 self.assertIs(type(e), Perm)
2664
2665 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002666 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002667 lst = list(Perm)
2668 self.assertEqual(len(lst), len(Perm))
2669 self.assertEqual(len(Perm), 3, Perm)
2670 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2671 for i, n in enumerate('R W X'.split()):
2672 v = 1<<(2*i+1)
2673 e = Perm(v)
2674 self.assertEqual(e.value, v)
2675 self.assertEqual(type(e.value), int)
2676 self.assertEqual(e, v)
2677 self.assertEqual(e.name, n)
2678 self.assertIn(e, Perm)
2679 self.assertIs(type(e), Perm)
2680
2681 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002682 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002683 lst = list(Perm)
2684 self.assertEqual(len(lst), len(Perm))
2685 self.assertEqual(len(Perm), 3, Perm)
2686 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2687 for i, n in enumerate('R W X'.split()):
2688 v = 1<<(2*i+1)
2689 e = Perm(v)
2690 self.assertEqual(e.value, v)
2691 self.assertEqual(type(e.value), int)
2692 self.assertEqual(e, v)
2693 self.assertEqual(e.name, n)
2694 self.assertIn(e, Perm)
2695 self.assertIs(type(e), Perm)
2696
2697
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002698 def test_programatic_function_from_empty_list(self):
2699 Perm = enum.IntFlag('Perm', [])
2700 lst = list(Perm)
2701 self.assertEqual(len(lst), len(Perm))
2702 self.assertEqual(len(Perm), 0, Perm)
2703 Thing = enum.Enum('Thing', [])
2704 lst = list(Thing)
2705 self.assertEqual(len(lst), len(Thing))
2706 self.assertEqual(len(Thing), 0, Thing)
2707
2708
2709 def test_programatic_function_from_empty_tuple(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 self.assertEqual(len(lst), len(Thing))
2716 self.assertEqual(len(Thing), 0, Thing)
2717
Rahul Jha94306522018-09-10 23:51:04 +05302718 def test_contains(self):
2719 Open = self.Open
2720 Color = self.Color
2721 self.assertTrue(Color.GREEN in Color)
2722 self.assertTrue(Open.RW in Open)
2723 self.assertFalse(Color.GREEN in Open)
2724 self.assertFalse(Open.RW in Color)
2725 with self.assertRaises(TypeError):
2726 'GREEN' in Color
2727 with self.assertRaises(TypeError):
2728 'RW' in Open
2729 with self.assertRaises(TypeError):
2730 2 in Color
2731 with self.assertRaises(TypeError):
2732 2 in Open
2733
2734 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002735 Perm = self.Perm
2736 R, W, X = Perm
2737 RW = R | W
2738 RX = R | X
2739 WX = W | X
2740 RWX = R | W | X
2741 self.assertTrue(R in RW)
2742 self.assertTrue(R in RX)
2743 self.assertTrue(R in RWX)
2744 self.assertTrue(W in RW)
2745 self.assertTrue(W in WX)
2746 self.assertTrue(W in RWX)
2747 self.assertTrue(X in RX)
2748 self.assertTrue(X in WX)
2749 self.assertTrue(X in RWX)
2750 self.assertFalse(R in WX)
2751 self.assertFalse(W in RX)
2752 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302753 with self.assertRaises(TypeError):
2754 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002755
Ethan Furman25d94bb2016-09-02 16:32:32 -07002756 def test_bool(self):
2757 Perm = self.Perm
2758 for f in Perm:
2759 self.assertTrue(f)
2760 Open = self.Open
2761 for f in Open:
2762 self.assertEqual(bool(f.value), bool(f))
2763
Ethan Furman5bdab642018-09-21 19:03:09 -07002764 def test_multiple_mixin(self):
2765 class AllMixin:
2766 @classproperty
2767 def ALL(cls):
2768 members = list(cls)
2769 all_value = None
2770 if members:
2771 all_value = members[0]
2772 for member in members[1:]:
2773 all_value |= member
2774 cls.ALL = all_value
2775 return all_value
2776 class StrMixin:
2777 def __str__(self):
2778 return self._name_.lower()
2779 class Color(AllMixin, IntFlag):
2780 RED = auto()
2781 GREEN = auto()
2782 BLUE = auto()
2783 self.assertEqual(Color.RED.value, 1)
2784 self.assertEqual(Color.GREEN.value, 2)
2785 self.assertEqual(Color.BLUE.value, 4)
2786 self.assertEqual(Color.ALL.value, 7)
2787 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2788 class Color(AllMixin, StrMixin, IntFlag):
2789 RED = auto()
2790 GREEN = auto()
2791 BLUE = auto()
2792 self.assertEqual(Color.RED.value, 1)
2793 self.assertEqual(Color.GREEN.value, 2)
2794 self.assertEqual(Color.BLUE.value, 4)
2795 self.assertEqual(Color.ALL.value, 7)
2796 self.assertEqual(str(Color.BLUE), 'blue')
2797 class Color(StrMixin, AllMixin, IntFlag):
2798 RED = auto()
2799 GREEN = auto()
2800 BLUE = auto()
2801 self.assertEqual(Color.RED.value, 1)
2802 self.assertEqual(Color.GREEN.value, 2)
2803 self.assertEqual(Color.BLUE.value, 4)
2804 self.assertEqual(Color.ALL.value, 7)
2805 self.assertEqual(str(Color.BLUE), 'blue')
2806
Ethan Furman28cf6632017-01-24 12:12:06 -08002807 @support.reap_threads
2808 def test_unique_composite(self):
2809 # override __eq__ to be identity only
2810 class TestFlag(IntFlag):
2811 one = auto()
2812 two = auto()
2813 three = auto()
2814 four = auto()
2815 five = auto()
2816 six = auto()
2817 seven = auto()
2818 eight = auto()
2819 def __eq__(self, other):
2820 return self is other
2821 def __hash__(self):
2822 return hash(self._value_)
2823 # have multiple threads competing to complete the composite members
2824 seen = set()
2825 failed = False
2826 def cycle_enum():
2827 nonlocal failed
2828 try:
2829 for i in range(256):
2830 seen.add(TestFlag(i))
2831 except Exception:
2832 failed = True
2833 threads = [
2834 threading.Thread(target=cycle_enum)
2835 for _ in range(8)
2836 ]
2837 with support.start_threads(threads):
2838 pass
2839 # check that only 248 members were created
2840 self.assertFalse(
2841 failed,
2842 'at least one thread failed while creating composite members')
2843 self.assertEqual(256, len(seen), 'too many composite members created')
2844
2845
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002846class TestEmptyAndNonLatinStrings(unittest.TestCase):
2847
2848 def test_empty_string(self):
2849 with self.assertRaises(ValueError):
2850 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2851
2852 def test_non_latin_character_string(self):
2853 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2854 item = getattr(greek_abc, '\u03B1')
2855 self.assertEqual(item.value, 1)
2856
2857 def test_non_latin_number_string(self):
2858 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2859 item = getattr(hebrew_123, '\u05D0')
2860 self.assertEqual(item.value, 1)
2861
2862
Ethan Furmanf24bb352013-07-18 17:05:39 -07002863class TestUnique(unittest.TestCase):
2864
2865 def test_unique_clean(self):
2866 @unique
2867 class Clean(Enum):
2868 one = 1
2869 two = 'dos'
2870 tres = 4.0
2871 @unique
2872 class Cleaner(IntEnum):
2873 single = 1
2874 double = 2
2875 triple = 3
2876
2877 def test_unique_dirty(self):
2878 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2879 @unique
2880 class Dirty(Enum):
2881 one = 1
2882 two = 'dos'
2883 tres = 1
2884 with self.assertRaisesRegex(
2885 ValueError,
2886 'double.*single.*turkey.*triple',
2887 ):
2888 @unique
2889 class Dirtier(IntEnum):
2890 single = 1
2891 double = 1
2892 triple = 3
2893 turkey = 3
2894
Ethan Furman3803ad42016-05-01 10:03:53 -07002895 def test_unique_with_name(self):
2896 @unique
2897 class Silly(Enum):
2898 one = 1
2899 two = 'dos'
2900 name = 3
2901 @unique
2902 class Sillier(IntEnum):
2903 single = 1
2904 name = 2
2905 triple = 3
2906 value = 4
2907
Ethan Furmanf24bb352013-07-18 17:05:39 -07002908
Ethan Furman5bdab642018-09-21 19:03:09 -07002909
Ethan Furman3323da92015-04-11 09:39:59 -07002910expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002911Help on class Color in module %s:
2912
2913class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002914 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2915 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002916 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002917 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002918 | Method resolution order:
2919 | Color
2920 | enum.Enum
2921 | builtins.object
2922 |\x20\x20
2923 | Data and other attributes defined here:
2924 |\x20\x20
2925 | blue = <Color.blue: 3>
2926 |\x20\x20
2927 | green = <Color.green: 2>
2928 |\x20\x20
2929 | red = <Color.red: 1>
2930 |\x20\x20
2931 | ----------------------------------------------------------------------
2932 | Data descriptors inherited from enum.Enum:
2933 |\x20\x20
2934 | name
2935 | The name of the Enum member.
2936 |\x20\x20
2937 | value
2938 | The value of the Enum member.
2939 |\x20\x20
2940 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002941 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002942 |\x20\x20
2943 | __members__
2944 | Returns a mapping of member name->value.
2945 |\x20\x20\x20\x20\x20\x20
2946 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002947 | is a read-only view of the internal mapping."""
2948
2949expected_help_output_without_docs = """\
2950Help on class Color in module %s:
2951
2952class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002953 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2954 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002955 | Method resolution order:
2956 | Color
2957 | enum.Enum
2958 | builtins.object
2959 |\x20\x20
2960 | Data and other attributes defined here:
2961 |\x20\x20
2962 | blue = <Color.blue: 3>
2963 |\x20\x20
2964 | green = <Color.green: 2>
2965 |\x20\x20
2966 | red = <Color.red: 1>
2967 |\x20\x20
2968 | ----------------------------------------------------------------------
2969 | Data descriptors inherited from enum.Enum:
2970 |\x20\x20
2971 | name
2972 |\x20\x20
2973 | value
2974 |\x20\x20
2975 | ----------------------------------------------------------------------
2976 | Data descriptors inherited from enum.EnumMeta:
2977 |\x20\x20
2978 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002979
2980class TestStdLib(unittest.TestCase):
2981
Ethan Furman48a724f2015-04-11 23:23:06 -07002982 maxDiff = None
2983
Ethan Furman5875d742013-10-21 20:45:55 -07002984 class Color(Enum):
2985 red = 1
2986 green = 2
2987 blue = 3
2988
2989 def test_pydoc(self):
2990 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002991 if StrEnum.__doc__ is None:
2992 expected_text = expected_help_output_without_docs % __name__
2993 else:
2994 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002995 output = StringIO()
2996 helper = pydoc.Helper(output=output)
2997 helper(self.Color)
2998 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002999 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003000
3001 def test_inspect_getmembers(self):
3002 values = dict((
3003 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003004 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003005 ('__members__', self.Color.__members__),
3006 ('__module__', __name__),
3007 ('blue', self.Color.blue),
3008 ('green', self.Color.green),
3009 ('name', Enum.__dict__['name']),
3010 ('red', self.Color.red),
3011 ('value', Enum.__dict__['value']),
3012 ))
3013 result = dict(inspect.getmembers(self.Color))
3014 self.assertEqual(values.keys(), result.keys())
3015 failed = False
3016 for k in values.keys():
3017 if result[k] != values[k]:
3018 print()
3019 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3020 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3021 failed = True
3022 if failed:
3023 self.fail("result does not equal expected, see print above")
3024
3025 def test_inspect_classify_class_attrs(self):
3026 # indirectly test __objclass__
3027 from inspect import Attribute
3028 values = [
3029 Attribute(name='__class__', kind='data',
3030 defining_class=object, object=EnumMeta),
3031 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003032 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003033 Attribute(name='__members__', kind='property',
3034 defining_class=EnumMeta, object=EnumMeta.__members__),
3035 Attribute(name='__module__', kind='data',
3036 defining_class=self.Color, object=__name__),
3037 Attribute(name='blue', kind='data',
3038 defining_class=self.Color, object=self.Color.blue),
3039 Attribute(name='green', kind='data',
3040 defining_class=self.Color, object=self.Color.green),
3041 Attribute(name='red', kind='data',
3042 defining_class=self.Color, object=self.Color.red),
3043 Attribute(name='name', kind='data',
3044 defining_class=Enum, object=Enum.__dict__['name']),
3045 Attribute(name='value', kind='data',
3046 defining_class=Enum, object=Enum.__dict__['value']),
3047 ]
3048 values.sort(key=lambda item: item.name)
3049 result = list(inspect.classify_class_attrs(self.Color))
3050 result.sort(key=lambda item: item.name)
3051 failed = False
3052 for v, r in zip(values, result):
3053 if r != v:
3054 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3055 failed = True
3056 if failed:
3057 self.fail("result does not equal expected, see print above")
3058
Martin Panter19e69c52015-11-14 12:46:42 +00003059
3060class MiscTestCase(unittest.TestCase):
3061 def test__all__(self):
3062 support.check__all__(self, enum)
3063
3064
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003065# These are unordered here on purpose to ensure that declaration order
3066# makes no difference.
3067CONVERT_TEST_NAME_D = 5
3068CONVERT_TEST_NAME_C = 5
3069CONVERT_TEST_NAME_B = 5
3070CONVERT_TEST_NAME_A = 5 # This one should sort first.
3071CONVERT_TEST_NAME_E = 5
3072CONVERT_TEST_NAME_F = 5
3073
3074class TestIntEnumConvert(unittest.TestCase):
3075 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003076 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003077 'UnittestConvert',
3078 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003079 filter=lambda x: x.startswith('CONVERT_TEST_'))
3080 # We don't want the reverse lookup value to vary when there are
3081 # multiple possible names for a given value. It should always
3082 # report the first lexigraphical name in that case.
3083 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3084
3085 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003086 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003087 'UnittestConvert',
3088 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003089 filter=lambda x: x.startswith('CONVERT_TEST_'))
3090 # Ensure that test_type has all of the desired names and values.
3091 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3092 test_type.CONVERT_TEST_NAME_A)
3093 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3094 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3095 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3096 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3097 # Ensure that test_type only picked up names matching the filter.
3098 self.assertEqual([name for name in dir(test_type)
3099 if name[0:2] not in ('CO', '__')],
3100 [], msg='Names other than CONVERT_TEST_* found.')
3101
orlnub1230fb9fad2018-09-12 20:28:53 +03003102 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3103 '_convert was deprecated in 3.8')
3104 def test_convert_warn(self):
3105 with self.assertWarns(DeprecationWarning):
3106 enum.IntEnum._convert(
3107 'UnittestConvert',
3108 ('test.test_enum', '__main__')[__name__=='__main__'],
3109 filter=lambda x: x.startswith('CONVERT_TEST_'))
3110
3111 @unittest.skipUnless(sys.version_info >= (3, 9),
3112 '_convert was removed in 3.9')
3113 def test_convert_raise(self):
3114 with self.assertRaises(AttributeError):
3115 enum.IntEnum._convert(
3116 'UnittestConvert',
3117 ('test.test_enum', '__main__')[__name__=='__main__'],
3118 filter=lambda x: x.startswith('CONVERT_TEST_'))
3119
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003120
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003121if __name__ == '__main__':
3122 unittest.main()