blob: 0983513d58147355fbdbf832c298f5abfdb87179 [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
1004
1005 def test_exclude_methods(self):
1006 class whatever(Enum):
1007 this = 'that'
1008 these = 'those'
1009 def really(self):
1010 return 'no, not %s' % self.value
1011 self.assertIsNot(type(whatever.really), whatever)
1012 self.assertEqual(whatever.this.really(), 'no, not that')
1013
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001014 def test_wrong_inheritance_order(self):
1015 with self.assertRaises(TypeError):
1016 class Wrong(Enum, str):
1017 NotHere = 'error before this point'
1018
1019 def test_intenum_transitivity(self):
1020 class number(IntEnum):
1021 one = 1
1022 two = 2
1023 three = 3
1024 class numero(IntEnum):
1025 uno = 1
1026 dos = 2
1027 tres = 3
1028 self.assertEqual(number.one, numero.uno)
1029 self.assertEqual(number.two, numero.dos)
1030 self.assertEqual(number.three, numero.tres)
1031
1032 def test_wrong_enum_in_call(self):
1033 class Monochrome(Enum):
1034 black = 0
1035 white = 1
1036 class Gender(Enum):
1037 male = 0
1038 female = 1
1039 self.assertRaises(ValueError, Monochrome, Gender.male)
1040
1041 def test_wrong_enum_in_mixed_call(self):
1042 class Monochrome(IntEnum):
1043 black = 0
1044 white = 1
1045 class Gender(Enum):
1046 male = 0
1047 female = 1
1048 self.assertRaises(ValueError, Monochrome, Gender.male)
1049
1050 def test_mixed_enum_in_call_1(self):
1051 class Monochrome(IntEnum):
1052 black = 0
1053 white = 1
1054 class Gender(IntEnum):
1055 male = 0
1056 female = 1
1057 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1058
1059 def test_mixed_enum_in_call_2(self):
1060 class Monochrome(Enum):
1061 black = 0
1062 white = 1
1063 class Gender(IntEnum):
1064 male = 0
1065 female = 1
1066 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1067
1068 def test_flufl_enum(self):
1069 class Fluflnum(Enum):
1070 def __int__(self):
1071 return int(self.value)
1072 class MailManOptions(Fluflnum):
1073 option1 = 1
1074 option2 = 2
1075 option3 = 3
1076 self.assertEqual(int(MailManOptions.option1), 1)
1077
Ethan Furman5e5a8232013-08-04 08:42:23 -07001078 def test_introspection(self):
1079 class Number(IntEnum):
1080 one = 100
1081 two = 200
1082 self.assertIs(Number.one._member_type_, int)
1083 self.assertIs(Number._member_type_, int)
1084 class String(str, Enum):
1085 yarn = 'soft'
1086 rope = 'rough'
1087 wire = 'hard'
1088 self.assertIs(String.yarn._member_type_, str)
1089 self.assertIs(String._member_type_, str)
1090 class Plain(Enum):
1091 vanilla = 'white'
1092 one = 1
1093 self.assertIs(Plain.vanilla._member_type_, object)
1094 self.assertIs(Plain._member_type_, object)
1095
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001096 def test_no_such_enum_member(self):
1097 class Color(Enum):
1098 red = 1
1099 green = 2
1100 blue = 3
1101 with self.assertRaises(ValueError):
1102 Color(4)
1103 with self.assertRaises(KeyError):
1104 Color['chartreuse']
1105
1106 def test_new_repr(self):
1107 class Color(Enum):
1108 red = 1
1109 green = 2
1110 blue = 3
1111 def __repr__(self):
1112 return "don't you just love shades of %s?" % self.name
1113 self.assertEqual(
1114 repr(Color.blue),
1115 "don't you just love shades of blue?",
1116 )
1117
1118 def test_inherited_repr(self):
1119 class MyEnum(Enum):
1120 def __repr__(self):
1121 return "My name is %s." % self.name
1122 class MyIntEnum(int, MyEnum):
1123 this = 1
1124 that = 2
1125 theother = 3
1126 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1127
1128 def test_multiple_mixin_mro(self):
1129 class auto_enum(type(Enum)):
1130 def __new__(metacls, cls, bases, classdict):
1131 temp = type(classdict)()
1132 names = set(classdict._member_names)
1133 i = 0
1134 for k in classdict._member_names:
1135 v = classdict[k]
1136 if v is Ellipsis:
1137 v = i
1138 else:
1139 i = v
1140 i += 1
1141 temp[k] = v
1142 for k, v in classdict.items():
1143 if k not in names:
1144 temp[k] = v
1145 return super(auto_enum, metacls).__new__(
1146 metacls, cls, bases, temp)
1147
1148 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1149 pass
1150
1151 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1152 pass
1153
1154 class TestAutoNumber(AutoNumberedEnum):
1155 a = ...
1156 b = 3
1157 c = ...
1158
1159 class TestAutoInt(AutoIntEnum):
1160 a = ...
1161 b = 3
1162 c = ...
1163
1164 def test_subclasses_with_getnewargs(self):
1165 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001166 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001167 def __new__(cls, *args):
1168 _args = args
1169 name, *args = args
1170 if len(args) == 0:
1171 raise TypeError("name and value must be specified")
1172 self = int.__new__(cls, *args)
1173 self._intname = name
1174 self._args = _args
1175 return self
1176 def __getnewargs__(self):
1177 return self._args
1178 @property
1179 def __name__(self):
1180 return self._intname
1181 def __repr__(self):
1182 # repr() is updated to include the name and type info
1183 return "{}({!r}, {})".format(type(self).__name__,
1184 self.__name__,
1185 int.__repr__(self))
1186 def __str__(self):
1187 # str() is unchanged, even if it relies on the repr() fallback
1188 base = int
1189 base_str = base.__str__
1190 if base_str.__objclass__ is object:
1191 return base.__repr__(self)
1192 return base_str(self)
1193 # for simplicity, we only define one operator that
1194 # propagates expressions
1195 def __add__(self, other):
1196 temp = int(self) + int( other)
1197 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1198 return NamedInt(
1199 '({0} + {1})'.format(self.__name__, other.__name__),
1200 temp )
1201 else:
1202 return temp
1203
1204 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001205 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001206 x = ('the-x', 1)
1207 y = ('the-y', 2)
1208
Ethan Furman2aa27322013-07-19 19:35:56 -07001209
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001210 self.assertIs(NEI.__new__, Enum.__new__)
1211 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1212 globals()['NamedInt'] = NamedInt
1213 globals()['NEI'] = NEI
1214 NI5 = NamedInt('test', 5)
1215 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001216 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001217 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001218 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001219 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001220
Ethan Furmanca1b7942014-02-08 11:36:27 -08001221 def test_subclasses_with_getnewargs_ex(self):
1222 class NamedInt(int):
1223 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1224 def __new__(cls, *args):
1225 _args = args
1226 name, *args = args
1227 if len(args) == 0:
1228 raise TypeError("name and value must be specified")
1229 self = int.__new__(cls, *args)
1230 self._intname = name
1231 self._args = _args
1232 return self
1233 def __getnewargs_ex__(self):
1234 return self._args, {}
1235 @property
1236 def __name__(self):
1237 return self._intname
1238 def __repr__(self):
1239 # repr() is updated to include the name and type info
1240 return "{}({!r}, {})".format(type(self).__name__,
1241 self.__name__,
1242 int.__repr__(self))
1243 def __str__(self):
1244 # str() is unchanged, even if it relies on the repr() fallback
1245 base = int
1246 base_str = base.__str__
1247 if base_str.__objclass__ is object:
1248 return base.__repr__(self)
1249 return base_str(self)
1250 # for simplicity, we only define one operator that
1251 # propagates expressions
1252 def __add__(self, other):
1253 temp = int(self) + int( other)
1254 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1255 return NamedInt(
1256 '({0} + {1})'.format(self.__name__, other.__name__),
1257 temp )
1258 else:
1259 return temp
1260
1261 class NEI(NamedInt, Enum):
1262 __qualname__ = 'NEI' # needed for pickle protocol 4
1263 x = ('the-x', 1)
1264 y = ('the-y', 2)
1265
1266
1267 self.assertIs(NEI.__new__, Enum.__new__)
1268 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1269 globals()['NamedInt'] = NamedInt
1270 globals()['NEI'] = NEI
1271 NI5 = NamedInt('test', 5)
1272 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001273 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001274 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001275 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001276 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001277
1278 def test_subclasses_with_reduce(self):
1279 class NamedInt(int):
1280 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1281 def __new__(cls, *args):
1282 _args = args
1283 name, *args = args
1284 if len(args) == 0:
1285 raise TypeError("name and value must be specified")
1286 self = int.__new__(cls, *args)
1287 self._intname = name
1288 self._args = _args
1289 return self
1290 def __reduce__(self):
1291 return self.__class__, self._args
1292 @property
1293 def __name__(self):
1294 return self._intname
1295 def __repr__(self):
1296 # repr() is updated to include the name and type info
1297 return "{}({!r}, {})".format(type(self).__name__,
1298 self.__name__,
1299 int.__repr__(self))
1300 def __str__(self):
1301 # str() is unchanged, even if it relies on the repr() fallback
1302 base = int
1303 base_str = base.__str__
1304 if base_str.__objclass__ is object:
1305 return base.__repr__(self)
1306 return base_str(self)
1307 # for simplicity, we only define one operator that
1308 # propagates expressions
1309 def __add__(self, other):
1310 temp = int(self) + int( other)
1311 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1312 return NamedInt(
1313 '({0} + {1})'.format(self.__name__, other.__name__),
1314 temp )
1315 else:
1316 return temp
1317
1318 class NEI(NamedInt, Enum):
1319 __qualname__ = 'NEI' # needed for pickle protocol 4
1320 x = ('the-x', 1)
1321 y = ('the-y', 2)
1322
1323
1324 self.assertIs(NEI.__new__, Enum.__new__)
1325 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1326 globals()['NamedInt'] = NamedInt
1327 globals()['NEI'] = NEI
1328 NI5 = NamedInt('test', 5)
1329 self.assertEqual(NI5, 5)
1330 test_pickle_dump_load(self.assertEqual, NI5, 5)
1331 self.assertEqual(NEI.y.value, 2)
1332 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001333 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001334
1335 def test_subclasses_with_reduce_ex(self):
1336 class NamedInt(int):
1337 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1338 def __new__(cls, *args):
1339 _args = args
1340 name, *args = args
1341 if len(args) == 0:
1342 raise TypeError("name and value must be specified")
1343 self = int.__new__(cls, *args)
1344 self._intname = name
1345 self._args = _args
1346 return self
1347 def __reduce_ex__(self, proto):
1348 return self.__class__, self._args
1349 @property
1350 def __name__(self):
1351 return self._intname
1352 def __repr__(self):
1353 # repr() is updated to include the name and type info
1354 return "{}({!r}, {})".format(type(self).__name__,
1355 self.__name__,
1356 int.__repr__(self))
1357 def __str__(self):
1358 # str() is unchanged, even if it relies on the repr() fallback
1359 base = int
1360 base_str = base.__str__
1361 if base_str.__objclass__ is object:
1362 return base.__repr__(self)
1363 return base_str(self)
1364 # for simplicity, we only define one operator that
1365 # propagates expressions
1366 def __add__(self, other):
1367 temp = int(self) + int( other)
1368 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1369 return NamedInt(
1370 '({0} + {1})'.format(self.__name__, other.__name__),
1371 temp )
1372 else:
1373 return temp
1374
1375 class NEI(NamedInt, Enum):
1376 __qualname__ = 'NEI' # needed for pickle protocol 4
1377 x = ('the-x', 1)
1378 y = ('the-y', 2)
1379
1380
1381 self.assertIs(NEI.__new__, Enum.__new__)
1382 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1383 globals()['NamedInt'] = NamedInt
1384 globals()['NEI'] = NEI
1385 NI5 = NamedInt('test', 5)
1386 self.assertEqual(NI5, 5)
1387 test_pickle_dump_load(self.assertEqual, NI5, 5)
1388 self.assertEqual(NEI.y.value, 2)
1389 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001390 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001391
Ethan Furmandc870522014-02-18 12:37:12 -08001392 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001393 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001394 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001395 def __new__(cls, *args):
1396 _args = args
1397 name, *args = args
1398 if len(args) == 0:
1399 raise TypeError("name and value must be specified")
1400 self = int.__new__(cls, *args)
1401 self._intname = name
1402 self._args = _args
1403 return self
1404 @property
1405 def __name__(self):
1406 return self._intname
1407 def __repr__(self):
1408 # repr() is updated to include the name and type info
1409 return "{}({!r}, {})".format(type(self).__name__,
1410 self.__name__,
1411 int.__repr__(self))
1412 def __str__(self):
1413 # str() is unchanged, even if it relies on the repr() fallback
1414 base = int
1415 base_str = base.__str__
1416 if base_str.__objclass__ is object:
1417 return base.__repr__(self)
1418 return base_str(self)
1419 # for simplicity, we only define one operator that
1420 # propagates expressions
1421 def __add__(self, other):
1422 temp = int(self) + int( other)
1423 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1424 return NamedInt(
1425 '({0} + {1})'.format(self.__name__, other.__name__),
1426 temp )
1427 else:
1428 return temp
1429
1430 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001431 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001432 x = ('the-x', 1)
1433 y = ('the-y', 2)
1434
1435 self.assertIs(NEI.__new__, Enum.__new__)
1436 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1437 globals()['NamedInt'] = NamedInt
1438 globals()['NEI'] = NEI
1439 NI5 = NamedInt('test', 5)
1440 self.assertEqual(NI5, 5)
1441 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001442 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1443 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001444
Ethan Furmandc870522014-02-18 12:37:12 -08001445 def test_subclasses_without_direct_pickle_support_using_name(self):
1446 class NamedInt(int):
1447 __qualname__ = 'NamedInt'
1448 def __new__(cls, *args):
1449 _args = args
1450 name, *args = args
1451 if len(args) == 0:
1452 raise TypeError("name and value must be specified")
1453 self = int.__new__(cls, *args)
1454 self._intname = name
1455 self._args = _args
1456 return self
1457 @property
1458 def __name__(self):
1459 return self._intname
1460 def __repr__(self):
1461 # repr() is updated to include the name and type info
1462 return "{}({!r}, {})".format(type(self).__name__,
1463 self.__name__,
1464 int.__repr__(self))
1465 def __str__(self):
1466 # str() is unchanged, even if it relies on the repr() fallback
1467 base = int
1468 base_str = base.__str__
1469 if base_str.__objclass__ is object:
1470 return base.__repr__(self)
1471 return base_str(self)
1472 # for simplicity, we only define one operator that
1473 # propagates expressions
1474 def __add__(self, other):
1475 temp = int(self) + int( other)
1476 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1477 return NamedInt(
1478 '({0} + {1})'.format(self.__name__, other.__name__),
1479 temp )
1480 else:
1481 return temp
1482
1483 class NEI(NamedInt, Enum):
1484 __qualname__ = 'NEI'
1485 x = ('the-x', 1)
1486 y = ('the-y', 2)
1487 def __reduce_ex__(self, proto):
1488 return getattr, (self.__class__, self._name_)
1489
1490 self.assertIs(NEI.__new__, Enum.__new__)
1491 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1492 globals()['NamedInt'] = NamedInt
1493 globals()['NEI'] = NEI
1494 NI5 = NamedInt('test', 5)
1495 self.assertEqual(NI5, 5)
1496 self.assertEqual(NEI.y.value, 2)
1497 test_pickle_dump_load(self.assertIs, NEI.y)
1498 test_pickle_dump_load(self.assertIs, NEI)
1499
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001500 def test_tuple_subclass(self):
1501 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001502 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001503 first = (1, 'for the money')
1504 second = (2, 'for the show')
1505 third = (3, 'for the music')
1506 self.assertIs(type(SomeTuple.first), SomeTuple)
1507 self.assertIsInstance(SomeTuple.second, tuple)
1508 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1509 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001510 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001511
1512 def test_duplicate_values_give_unique_enum_items(self):
1513 class AutoNumber(Enum):
1514 first = ()
1515 second = ()
1516 third = ()
1517 def __new__(cls):
1518 value = len(cls.__members__) + 1
1519 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001520 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001521 return obj
1522 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001523 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001524 self.assertEqual(
1525 list(AutoNumber),
1526 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1527 )
1528 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001529 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001530 self.assertIs(AutoNumber(1), AutoNumber.first)
1531
1532 def test_inherited_new_from_enhanced_enum(self):
1533 class AutoNumber(Enum):
1534 def __new__(cls):
1535 value = len(cls.__members__) + 1
1536 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001537 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001538 return obj
1539 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001540 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001541 class Color(AutoNumber):
1542 red = ()
1543 green = ()
1544 blue = ()
1545 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1546 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1547
1548 def test_inherited_new_from_mixed_enum(self):
1549 class AutoNumber(IntEnum):
1550 def __new__(cls):
1551 value = len(cls.__members__) + 1
1552 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001553 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001554 return obj
1555 class Color(AutoNumber):
1556 red = ()
1557 green = ()
1558 blue = ()
1559 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1560 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1561
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001562 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001563 class OrdinaryEnum(Enum):
1564 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001565 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1566 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001567
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001568 def test_ordered_mixin(self):
1569 class OrderedEnum(Enum):
1570 def __ge__(self, other):
1571 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001572 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001573 return NotImplemented
1574 def __gt__(self, other):
1575 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001576 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 return NotImplemented
1578 def __le__(self, other):
1579 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001580 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001581 return NotImplemented
1582 def __lt__(self, other):
1583 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001584 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001585 return NotImplemented
1586 class Grade(OrderedEnum):
1587 A = 5
1588 B = 4
1589 C = 3
1590 D = 2
1591 F = 1
1592 self.assertGreater(Grade.A, Grade.B)
1593 self.assertLessEqual(Grade.F, Grade.C)
1594 self.assertLess(Grade.D, Grade.A)
1595 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001596 self.assertEqual(Grade.B, Grade.B)
1597 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001598
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001599 def test_extending2(self):
1600 class Shade(Enum):
1601 def shade(self):
1602 print(self.name)
1603 class Color(Shade):
1604 red = 1
1605 green = 2
1606 blue = 3
1607 with self.assertRaises(TypeError):
1608 class MoreColor(Color):
1609 cyan = 4
1610 magenta = 5
1611 yellow = 6
1612
1613 def test_extending3(self):
1614 class Shade(Enum):
1615 def shade(self):
1616 return self.name
1617 class Color(Shade):
1618 def hex(self):
1619 return '%s hexlified!' % self.value
1620 class MoreColor(Color):
1621 cyan = 4
1622 magenta = 5
1623 yellow = 6
1624 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1625
orlnub1230fb9fad2018-09-12 20:28:53 +03001626 def test_subclass_duplicate_name(self):
1627 class Base(Enum):
1628 def test(self):
1629 pass
1630 class Test(Base):
1631 test = 1
1632 self.assertIs(type(Test.test), Test)
1633
1634 def test_subclass_duplicate_name_dynamic(self):
1635 from types import DynamicClassAttribute
1636 class Base(Enum):
1637 @DynamicClassAttribute
1638 def test(self):
1639 return 'dynamic'
1640 class Test(Base):
1641 test = 1
1642 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001643
1644 def test_no_duplicates(self):
1645 class UniqueEnum(Enum):
1646 def __init__(self, *args):
1647 cls = self.__class__
1648 if any(self.value == e.value for e in cls):
1649 a = self.name
1650 e = cls(self.value).name
1651 raise ValueError(
1652 "aliases not allowed in UniqueEnum: %r --> %r"
1653 % (a, e)
1654 )
1655 class Color(UniqueEnum):
1656 red = 1
1657 green = 2
1658 blue = 3
1659 with self.assertRaises(ValueError):
1660 class Color(UniqueEnum):
1661 red = 1
1662 green = 2
1663 blue = 3
1664 grene = 2
1665
1666 def test_init(self):
1667 class Planet(Enum):
1668 MERCURY = (3.303e+23, 2.4397e6)
1669 VENUS = (4.869e+24, 6.0518e6)
1670 EARTH = (5.976e+24, 6.37814e6)
1671 MARS = (6.421e+23, 3.3972e6)
1672 JUPITER = (1.9e+27, 7.1492e7)
1673 SATURN = (5.688e+26, 6.0268e7)
1674 URANUS = (8.686e+25, 2.5559e7)
1675 NEPTUNE = (1.024e+26, 2.4746e7)
1676 def __init__(self, mass, radius):
1677 self.mass = mass # in kilograms
1678 self.radius = radius # in meters
1679 @property
1680 def surface_gravity(self):
1681 # universal gravitational constant (m3 kg-1 s-2)
1682 G = 6.67300E-11
1683 return G * self.mass / (self.radius * self.radius)
1684 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1685 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1686
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001687 def test_ignore(self):
1688 class Period(timedelta, Enum):
1689 '''
1690 different lengths of time
1691 '''
1692 def __new__(cls, value, period):
1693 obj = timedelta.__new__(cls, value)
1694 obj._value_ = value
1695 obj.period = period
1696 return obj
1697 _ignore_ = 'Period i'
1698 Period = vars()
1699 for i in range(13):
1700 Period['month_%d' % i] = i*30, 'month'
1701 for i in range(53):
1702 Period['week_%d' % i] = i*7, 'week'
1703 for i in range(32):
1704 Period['day_%d' % i] = i, 'day'
1705 OneDay = day_1
1706 OneWeek = week_1
1707 OneMonth = month_1
1708 self.assertFalse(hasattr(Period, '_ignore_'))
1709 self.assertFalse(hasattr(Period, 'Period'))
1710 self.assertFalse(hasattr(Period, 'i'))
1711 self.assertTrue(isinstance(Period.day_1, timedelta))
1712 self.assertTrue(Period.month_1 is Period.day_30)
1713 self.assertTrue(Period.week_4 is Period.day_28)
1714
Ethan Furman2aa27322013-07-19 19:35:56 -07001715 def test_nonhash_value(self):
1716 class AutoNumberInAList(Enum):
1717 def __new__(cls):
1718 value = [len(cls.__members__) + 1]
1719 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001720 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001721 return obj
1722 class ColorInAList(AutoNumberInAList):
1723 red = ()
1724 green = ()
1725 blue = ()
1726 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001727 for enum, value in zip(ColorInAList, range(3)):
1728 value += 1
1729 self.assertEqual(enum.value, [value])
1730 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001731
Ethan Furmanb41803e2013-07-25 13:50:45 -07001732 def test_conflicting_types_resolved_in_new(self):
1733 class LabelledIntEnum(int, Enum):
1734 def __new__(cls, *args):
1735 value, label = args
1736 obj = int.__new__(cls, value)
1737 obj.label = label
1738 obj._value_ = value
1739 return obj
1740
1741 class LabelledList(LabelledIntEnum):
1742 unprocessed = (1, "Unprocessed")
1743 payment_complete = (2, "Payment Complete")
1744
1745 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1746 self.assertEqual(LabelledList.unprocessed, 1)
1747 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001748
Ethan Furmanc16595e2016-09-10 23:36:59 -07001749 def test_auto_number(self):
1750 class Color(Enum):
1751 red = auto()
1752 blue = auto()
1753 green = auto()
1754
1755 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1756 self.assertEqual(Color.red.value, 1)
1757 self.assertEqual(Color.blue.value, 2)
1758 self.assertEqual(Color.green.value, 3)
1759
1760 def test_auto_name(self):
1761 class Color(Enum):
1762 def _generate_next_value_(name, start, count, last):
1763 return name
1764 red = auto()
1765 blue = auto()
1766 green = auto()
1767
1768 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1769 self.assertEqual(Color.red.value, 'red')
1770 self.assertEqual(Color.blue.value, 'blue')
1771 self.assertEqual(Color.green.value, 'green')
1772
1773 def test_auto_name_inherit(self):
1774 class AutoNameEnum(Enum):
1775 def _generate_next_value_(name, start, count, last):
1776 return name
1777 class Color(AutoNameEnum):
1778 red = auto()
1779 blue = auto()
1780 green = auto()
1781
1782 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1783 self.assertEqual(Color.red.value, 'red')
1784 self.assertEqual(Color.blue.value, 'blue')
1785 self.assertEqual(Color.green.value, 'green')
1786
1787 def test_auto_garbage(self):
1788 class Color(Enum):
1789 red = 'red'
1790 blue = auto()
1791 self.assertEqual(Color.blue.value, 1)
1792
1793 def test_auto_garbage_corrected(self):
1794 class Color(Enum):
1795 red = 'red'
1796 blue = 2
1797 green = auto()
1798
1799 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1800 self.assertEqual(Color.red.value, 'red')
1801 self.assertEqual(Color.blue.value, 2)
1802 self.assertEqual(Color.green.value, 3)
1803
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001804 def test_auto_order(self):
1805 with self.assertRaises(TypeError):
1806 class Color(Enum):
1807 red = auto()
1808 green = auto()
1809 blue = auto()
1810 def _generate_next_value_(name, start, count, last):
1811 return name
1812
1813
Ethan Furman3515dcc2016-09-18 13:15:41 -07001814 def test_duplicate_auto(self):
1815 class Dupes(Enum):
1816 first = primero = auto()
1817 second = auto()
1818 third = auto()
1819 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1820
Ethan Furman019f0a02018-09-12 11:43:34 -07001821 def test_missing(self):
1822 class Color(Enum):
1823 red = 1
1824 green = 2
1825 blue = 3
1826 @classmethod
1827 def _missing_(cls, item):
1828 if item == 'three':
1829 return cls.blue
1830 elif item == 'bad return':
1831 # trigger internal error
1832 return 5
1833 elif item == 'error out':
1834 raise ZeroDivisionError
1835 else:
1836 # trigger not found
1837 return None
1838 self.assertIs(Color('three'), Color.blue)
1839 self.assertRaises(ValueError, Color, 7)
1840 try:
1841 Color('bad return')
1842 except TypeError as exc:
1843 self.assertTrue(isinstance(exc.__context__, ValueError))
1844 else:
1845 raise Exception('Exception not raised.')
1846 try:
1847 Color('error out')
1848 except ZeroDivisionError as exc:
1849 self.assertTrue(isinstance(exc.__context__, ValueError))
1850 else:
1851 raise Exception('Exception not raised.')
1852
Ethan Furman5bdab642018-09-21 19:03:09 -07001853 def test_multiple_mixin(self):
1854 class MaxMixin:
1855 @classproperty
1856 def MAX(cls):
1857 max = len(cls)
1858 cls.MAX = max
1859 return max
1860 class StrMixin:
1861 def __str__(self):
1862 return self._name_.lower()
1863 class SomeEnum(Enum):
1864 def behavior(self):
1865 return 'booyah'
1866 class AnotherEnum(Enum):
1867 def behavior(self):
1868 return 'nuhuh!'
1869 def social(self):
1870 return "what's up?"
1871 class Color(MaxMixin, Enum):
1872 RED = auto()
1873 GREEN = auto()
1874 BLUE = auto()
1875 self.assertEqual(Color.RED.value, 1)
1876 self.assertEqual(Color.GREEN.value, 2)
1877 self.assertEqual(Color.BLUE.value, 3)
1878 self.assertEqual(Color.MAX, 3)
1879 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1880 class Color(MaxMixin, StrMixin, Enum):
1881 RED = auto()
1882 GREEN = auto()
1883 BLUE = auto()
1884 self.assertEqual(Color.RED.value, 1)
1885 self.assertEqual(Color.GREEN.value, 2)
1886 self.assertEqual(Color.BLUE.value, 3)
1887 self.assertEqual(Color.MAX, 3)
1888 self.assertEqual(str(Color.BLUE), 'blue')
1889 class Color(StrMixin, MaxMixin, Enum):
1890 RED = auto()
1891 GREEN = auto()
1892 BLUE = auto()
1893 self.assertEqual(Color.RED.value, 1)
1894 self.assertEqual(Color.GREEN.value, 2)
1895 self.assertEqual(Color.BLUE.value, 3)
1896 self.assertEqual(Color.MAX, 3)
1897 self.assertEqual(str(Color.BLUE), 'blue')
1898 class CoolColor(StrMixin, SomeEnum, Enum):
1899 RED = auto()
1900 GREEN = auto()
1901 BLUE = auto()
1902 self.assertEqual(CoolColor.RED.value, 1)
1903 self.assertEqual(CoolColor.GREEN.value, 2)
1904 self.assertEqual(CoolColor.BLUE.value, 3)
1905 self.assertEqual(str(CoolColor.BLUE), 'blue')
1906 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1907 class CoolerColor(StrMixin, AnotherEnum, Enum):
1908 RED = auto()
1909 GREEN = auto()
1910 BLUE = auto()
1911 self.assertEqual(CoolerColor.RED.value, 1)
1912 self.assertEqual(CoolerColor.GREEN.value, 2)
1913 self.assertEqual(CoolerColor.BLUE.value, 3)
1914 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1915 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1916 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1917 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1918 RED = auto()
1919 GREEN = auto()
1920 BLUE = auto()
1921 self.assertEqual(CoolestColor.RED.value, 1)
1922 self.assertEqual(CoolestColor.GREEN.value, 2)
1923 self.assertEqual(CoolestColor.BLUE.value, 3)
1924 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1925 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1926 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1927 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1928 RED = auto()
1929 GREEN = auto()
1930 BLUE = auto()
1931 self.assertEqual(ConfusedColor.RED.value, 1)
1932 self.assertEqual(ConfusedColor.GREEN.value, 2)
1933 self.assertEqual(ConfusedColor.BLUE.value, 3)
1934 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1935 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1936 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1937 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1938 RED = auto()
1939 GREEN = auto()
1940 BLUE = auto()
1941 self.assertEqual(ReformedColor.RED.value, 1)
1942 self.assertEqual(ReformedColor.GREEN.value, 2)
1943 self.assertEqual(ReformedColor.BLUE.value, 3)
1944 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1945 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1946 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1947 self.assertTrue(issubclass(ReformedColor, int))
1948
Ethan Furmancd453852018-10-05 23:29:36 -07001949 def test_multiple_inherited_mixin(self):
1950 class StrEnum(str, Enum):
1951 def __new__(cls, *args, **kwargs):
1952 for a in args:
1953 if not isinstance(a, str):
1954 raise TypeError("Enumeration '%s' (%s) is not"
1955 " a string" % (a, type(a).__name__))
1956 return str.__new__(cls, *args, **kwargs)
1957 @unique
1958 class Decision1(StrEnum):
1959 REVERT = "REVERT"
1960 REVERT_ALL = "REVERT_ALL"
1961 RETRY = "RETRY"
1962 class MyEnum(StrEnum):
1963 pass
1964 @unique
1965 class Decision2(MyEnum):
1966 REVERT = "REVERT"
1967 REVERT_ALL = "REVERT_ALL"
1968 RETRY = "RETRY"
1969
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001970 def test_empty_globals(self):
1971 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1972 # when using compile and exec because f_globals is empty
1973 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1974 code = compile(code, "<string>", "exec")
1975 global_ns = {}
1976 local_ls = {}
1977 exec(code, global_ns, local_ls)
1978
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001979
Ethan Furmane8e61272016-08-20 07:19:31 -07001980class TestOrder(unittest.TestCase):
1981
1982 def test_same_members(self):
1983 class Color(Enum):
1984 _order_ = 'red green blue'
1985 red = 1
1986 green = 2
1987 blue = 3
1988
1989 def test_same_members_with_aliases(self):
1990 class Color(Enum):
1991 _order_ = 'red green blue'
1992 red = 1
1993 green = 2
1994 blue = 3
1995 verde = green
1996
1997 def test_same_members_wrong_order(self):
1998 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1999 class Color(Enum):
2000 _order_ = 'red green blue'
2001 red = 1
2002 blue = 3
2003 green = 2
2004
2005 def test_order_has_extra_members(self):
2006 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2007 class Color(Enum):
2008 _order_ = 'red green blue purple'
2009 red = 1
2010 green = 2
2011 blue = 3
2012
2013 def test_order_has_extra_members_with_aliases(self):
2014 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2015 class Color(Enum):
2016 _order_ = 'red green blue purple'
2017 red = 1
2018 green = 2
2019 blue = 3
2020 verde = green
2021
2022 def test_enum_has_extra_members(self):
2023 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2024 class Color(Enum):
2025 _order_ = 'red green blue'
2026 red = 1
2027 green = 2
2028 blue = 3
2029 purple = 4
2030
2031 def test_enum_has_extra_members_with_aliases(self):
2032 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2033 class Color(Enum):
2034 _order_ = 'red green blue'
2035 red = 1
2036 green = 2
2037 blue = 3
2038 purple = 4
2039 verde = green
2040
2041
Ethan Furman65a5a472016-09-01 23:55:19 -07002042class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002043 """Tests of the Flags."""
2044
Ethan Furman65a5a472016-09-01 23:55:19 -07002045 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002046 R, W, X = 4, 2, 1
2047
Ethan Furman65a5a472016-09-01 23:55:19 -07002048 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002049 RO = 0
2050 WO = 1
2051 RW = 2
2052 AC = 3
2053 CE = 1<<19
2054
Rahul Jha94306522018-09-10 23:51:04 +05302055 class Color(Flag):
2056 BLACK = 0
2057 RED = 1
2058 GREEN = 2
2059 BLUE = 4
2060 PURPLE = RED|BLUE
2061
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002062 def test_str(self):
2063 Perm = self.Perm
2064 self.assertEqual(str(Perm.R), 'Perm.R')
2065 self.assertEqual(str(Perm.W), 'Perm.W')
2066 self.assertEqual(str(Perm.X), 'Perm.X')
2067 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2068 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2069 self.assertEqual(str(Perm(0)), 'Perm.0')
2070 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2071 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2072 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2073 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2074 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2075 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2076
2077 Open = self.Open
2078 self.assertEqual(str(Open.RO), 'Open.RO')
2079 self.assertEqual(str(Open.WO), 'Open.WO')
2080 self.assertEqual(str(Open.AC), 'Open.AC')
2081 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2082 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002083 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002084 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2085 self.assertEqual(str(~Open.AC), 'Open.CE')
2086 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2087 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2088
2089 def test_repr(self):
2090 Perm = self.Perm
2091 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2092 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2093 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2094 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2095 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002096 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002097 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2098 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2099 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2100 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002101 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002102 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2103
2104 Open = self.Open
2105 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2106 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2107 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2108 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2109 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002110 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002111 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2112 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2113 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2114 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2115
2116 def test_or(self):
2117 Perm = self.Perm
2118 for i in Perm:
2119 for j in Perm:
2120 self.assertEqual((i | j), Perm(i.value | j.value))
2121 self.assertEqual((i | j).value, i.value | j.value)
2122 self.assertIs(type(i | j), Perm)
2123 for i in Perm:
2124 self.assertIs(i | i, i)
2125 Open = self.Open
2126 self.assertIs(Open.RO | Open.CE, Open.CE)
2127
2128 def test_and(self):
2129 Perm = self.Perm
2130 RW = Perm.R | Perm.W
2131 RX = Perm.R | Perm.X
2132 WX = Perm.W | Perm.X
2133 RWX = Perm.R | Perm.W | Perm.X
2134 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2135 for i in values:
2136 for j in values:
2137 self.assertEqual((i & j).value, i.value & j.value)
2138 self.assertIs(type(i & j), Perm)
2139 for i in Perm:
2140 self.assertIs(i & i, i)
2141 self.assertIs(i & RWX, i)
2142 self.assertIs(RWX & i, i)
2143 Open = self.Open
2144 self.assertIs(Open.RO & Open.CE, Open.RO)
2145
2146 def test_xor(self):
2147 Perm = self.Perm
2148 for i in Perm:
2149 for j in Perm:
2150 self.assertEqual((i ^ j).value, i.value ^ j.value)
2151 self.assertIs(type(i ^ j), Perm)
2152 for i in Perm:
2153 self.assertIs(i ^ Perm(0), i)
2154 self.assertIs(Perm(0) ^ i, i)
2155 Open = self.Open
2156 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2157 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2158
2159 def test_invert(self):
2160 Perm = self.Perm
2161 RW = Perm.R | Perm.W
2162 RX = Perm.R | Perm.X
2163 WX = Perm.W | Perm.X
2164 RWX = Perm.R | Perm.W | Perm.X
2165 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2166 for i in values:
2167 self.assertIs(type(~i), Perm)
2168 self.assertEqual(~~i, i)
2169 for i in Perm:
2170 self.assertIs(~~i, i)
2171 Open = self.Open
2172 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2173 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2174
Ethan Furman25d94bb2016-09-02 16:32:32 -07002175 def test_bool(self):
2176 Perm = self.Perm
2177 for f in Perm:
2178 self.assertTrue(f)
2179 Open = self.Open
2180 for f in Open:
2181 self.assertEqual(bool(f.value), bool(f))
2182
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002183 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002184 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002185 lst = list(Perm)
2186 self.assertEqual(len(lst), len(Perm))
2187 self.assertEqual(len(Perm), 3, Perm)
2188 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2189 for i, n in enumerate('R W X'.split()):
2190 v = 1<<i
2191 e = Perm(v)
2192 self.assertEqual(e.value, v)
2193 self.assertEqual(type(e.value), int)
2194 self.assertEqual(e.name, n)
2195 self.assertIn(e, Perm)
2196 self.assertIs(type(e), Perm)
2197
2198 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002199 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002200 lst = list(Perm)
2201 self.assertEqual(len(lst), len(Perm))
2202 self.assertEqual(len(Perm), 3, Perm)
2203 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2204 for i, n in enumerate('R W X'.split()):
2205 v = 8<<i
2206 e = Perm(v)
2207 self.assertEqual(e.value, v)
2208 self.assertEqual(type(e.value), int)
2209 self.assertEqual(e.name, n)
2210 self.assertIn(e, Perm)
2211 self.assertIs(type(e), Perm)
2212
2213 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002214 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002215 lst = list(Perm)
2216 self.assertEqual(len(lst), len(Perm))
2217 self.assertEqual(len(Perm), 3, Perm)
2218 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2219 for i, n in enumerate('R W X'.split()):
2220 v = 1<<i
2221 e = Perm(v)
2222 self.assertEqual(e.value, v)
2223 self.assertEqual(type(e.value), int)
2224 self.assertEqual(e.name, n)
2225 self.assertIn(e, Perm)
2226 self.assertIs(type(e), Perm)
2227
2228 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002229 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002230 lst = list(Perm)
2231 self.assertEqual(len(lst), len(Perm))
2232 self.assertEqual(len(Perm), 3, Perm)
2233 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2234 for i, n in enumerate('R W X'.split()):
2235 v = 1<<(2*i+1)
2236 e = Perm(v)
2237 self.assertEqual(e.value, v)
2238 self.assertEqual(type(e.value), int)
2239 self.assertEqual(e.name, n)
2240 self.assertIn(e, Perm)
2241 self.assertIs(type(e), Perm)
2242
2243 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002244 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002245 lst = list(Perm)
2246 self.assertEqual(len(lst), len(Perm))
2247 self.assertEqual(len(Perm), 3, Perm)
2248 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2249 for i, n in enumerate('R W X'.split()):
2250 v = 1<<(2*i+1)
2251 e = Perm(v)
2252 self.assertEqual(e.value, v)
2253 self.assertEqual(type(e.value), int)
2254 self.assertEqual(e.name, n)
2255 self.assertIn(e, Perm)
2256 self.assertIs(type(e), Perm)
2257
Ethan Furman65a5a472016-09-01 23:55:19 -07002258 def test_pickle(self):
2259 if isinstance(FlagStooges, Exception):
2260 raise FlagStooges
2261 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2262 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002263
Rahul Jha94306522018-09-10 23:51:04 +05302264 def test_contains(self):
2265 Open = self.Open
2266 Color = self.Color
2267 self.assertFalse(Color.BLACK in Open)
2268 self.assertFalse(Open.RO in Color)
2269 with self.assertRaises(TypeError):
2270 'BLACK' in Color
2271 with self.assertRaises(TypeError):
2272 'RO' in Open
2273 with self.assertRaises(TypeError):
2274 1 in Color
2275 with self.assertRaises(TypeError):
2276 1 in Open
2277
2278 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002279 Perm = self.Perm
2280 R, W, X = Perm
2281 RW = R | W
2282 RX = R | X
2283 WX = W | X
2284 RWX = R | W | X
2285 self.assertTrue(R in RW)
2286 self.assertTrue(R in RX)
2287 self.assertTrue(R in RWX)
2288 self.assertTrue(W in RW)
2289 self.assertTrue(W in WX)
2290 self.assertTrue(W in RWX)
2291 self.assertTrue(X in RX)
2292 self.assertTrue(X in WX)
2293 self.assertTrue(X in RWX)
2294 self.assertFalse(R in WX)
2295 self.assertFalse(W in RX)
2296 self.assertFalse(X in RW)
2297
Ethan Furmanc16595e2016-09-10 23:36:59 -07002298 def test_auto_number(self):
2299 class Color(Flag):
2300 red = auto()
2301 blue = auto()
2302 green = auto()
2303
2304 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2305 self.assertEqual(Color.red.value, 1)
2306 self.assertEqual(Color.blue.value, 2)
2307 self.assertEqual(Color.green.value, 4)
2308
2309 def test_auto_number_garbage(self):
2310 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2311 class Color(Flag):
2312 red = 'not an int'
2313 blue = auto()
2314
Ethan Furman3515dcc2016-09-18 13:15:41 -07002315 def test_cascading_failure(self):
2316 class Bizarre(Flag):
2317 c = 3
2318 d = 4
2319 f = 6
2320 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002321 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2322 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2323 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2324 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2325 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2326 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2327 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002328
2329 def test_duplicate_auto(self):
2330 class Dupes(Enum):
2331 first = primero = auto()
2332 second = auto()
2333 third = auto()
2334 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2335
2336 def test_bizarre(self):
2337 class Bizarre(Flag):
2338 b = 3
2339 c = 4
2340 d = 6
2341 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2342
Ethan Furman5bdab642018-09-21 19:03:09 -07002343 def test_multiple_mixin(self):
2344 class AllMixin:
2345 @classproperty
2346 def ALL(cls):
2347 members = list(cls)
2348 all_value = None
2349 if members:
2350 all_value = members[0]
2351 for member in members[1:]:
2352 all_value |= member
2353 cls.ALL = all_value
2354 return all_value
2355 class StrMixin:
2356 def __str__(self):
2357 return self._name_.lower()
2358 class Color(AllMixin, Flag):
2359 RED = auto()
2360 GREEN = auto()
2361 BLUE = auto()
2362 self.assertEqual(Color.RED.value, 1)
2363 self.assertEqual(Color.GREEN.value, 2)
2364 self.assertEqual(Color.BLUE.value, 4)
2365 self.assertEqual(Color.ALL.value, 7)
2366 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2367 class Color(AllMixin, StrMixin, Flag):
2368 RED = auto()
2369 GREEN = auto()
2370 BLUE = auto()
2371 self.assertEqual(Color.RED.value, 1)
2372 self.assertEqual(Color.GREEN.value, 2)
2373 self.assertEqual(Color.BLUE.value, 4)
2374 self.assertEqual(Color.ALL.value, 7)
2375 self.assertEqual(str(Color.BLUE), 'blue')
2376 class Color(StrMixin, AllMixin, Flag):
2377 RED = auto()
2378 GREEN = auto()
2379 BLUE = auto()
2380 self.assertEqual(Color.RED.value, 1)
2381 self.assertEqual(Color.GREEN.value, 2)
2382 self.assertEqual(Color.BLUE.value, 4)
2383 self.assertEqual(Color.ALL.value, 7)
2384 self.assertEqual(str(Color.BLUE), 'blue')
2385
Ethan Furman28cf6632017-01-24 12:12:06 -08002386 @support.reap_threads
2387 def test_unique_composite(self):
2388 # override __eq__ to be identity only
2389 class TestFlag(Flag):
2390 one = auto()
2391 two = auto()
2392 three = auto()
2393 four = auto()
2394 five = auto()
2395 six = auto()
2396 seven = auto()
2397 eight = auto()
2398 def __eq__(self, other):
2399 return self is other
2400 def __hash__(self):
2401 return hash(self._value_)
2402 # have multiple threads competing to complete the composite members
2403 seen = set()
2404 failed = False
2405 def cycle_enum():
2406 nonlocal failed
2407 try:
2408 for i in range(256):
2409 seen.add(TestFlag(i))
2410 except Exception:
2411 failed = True
2412 threads = [
2413 threading.Thread(target=cycle_enum)
2414 for _ in range(8)
2415 ]
2416 with support.start_threads(threads):
2417 pass
2418 # check that only 248 members were created
2419 self.assertFalse(
2420 failed,
2421 'at least one thread failed while creating composite members')
2422 self.assertEqual(256, len(seen), 'too many composite members created')
2423
Ethan Furmanc16595e2016-09-10 23:36:59 -07002424
Ethan Furman65a5a472016-09-01 23:55:19 -07002425class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002426 """Tests of the IntFlags."""
2427
Ethan Furman65a5a472016-09-01 23:55:19 -07002428 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002429 X = 1 << 0
2430 W = 1 << 1
2431 R = 1 << 2
2432
Ethan Furman65a5a472016-09-01 23:55:19 -07002433 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002434 RO = 0
2435 WO = 1
2436 RW = 2
2437 AC = 3
2438 CE = 1<<19
2439
Rahul Jha94306522018-09-10 23:51:04 +05302440 class Color(IntFlag):
2441 BLACK = 0
2442 RED = 1
2443 GREEN = 2
2444 BLUE = 4
2445 PURPLE = RED|BLUE
2446
Ethan Furman3515dcc2016-09-18 13:15:41 -07002447 def test_type(self):
2448 Perm = self.Perm
2449 Open = self.Open
2450 for f in Perm:
2451 self.assertTrue(isinstance(f, Perm))
2452 self.assertEqual(f, f.value)
2453 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2454 self.assertEqual(Perm.W | Perm.X, 3)
2455 for f in Open:
2456 self.assertTrue(isinstance(f, Open))
2457 self.assertEqual(f, f.value)
2458 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2459 self.assertEqual(Open.WO | Open.RW, 3)
2460
2461
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002462 def test_str(self):
2463 Perm = self.Perm
2464 self.assertEqual(str(Perm.R), 'Perm.R')
2465 self.assertEqual(str(Perm.W), 'Perm.W')
2466 self.assertEqual(str(Perm.X), 'Perm.X')
2467 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2468 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2469 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2470 self.assertEqual(str(Perm(0)), 'Perm.0')
2471 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002472 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2473 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2474 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2475 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002476 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002477 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2478 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2479 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002480
2481 Open = self.Open
2482 self.assertEqual(str(Open.RO), 'Open.RO')
2483 self.assertEqual(str(Open.WO), 'Open.WO')
2484 self.assertEqual(str(Open.AC), 'Open.AC')
2485 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2486 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2487 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002488 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2489 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2490 self.assertEqual(str(~Open.AC), 'Open.CE')
2491 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2492 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2493 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002494
2495 def test_repr(self):
2496 Perm = self.Perm
2497 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2498 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2499 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2500 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2501 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2502 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002503 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2504 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002505 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2506 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2507 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2508 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002509 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002510 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2511 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2512 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002513
2514 Open = self.Open
2515 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2516 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2517 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2518 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2519 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002520 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002521 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2522 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2523 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2524 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2525 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2526 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002527
2528 def test_or(self):
2529 Perm = self.Perm
2530 for i in Perm:
2531 for j in Perm:
2532 self.assertEqual(i | j, i.value | j.value)
2533 self.assertEqual((i | j).value, i.value | j.value)
2534 self.assertIs(type(i | j), Perm)
2535 for j in range(8):
2536 self.assertEqual(i | j, i.value | j)
2537 self.assertEqual((i | j).value, i.value | j)
2538 self.assertIs(type(i | j), Perm)
2539 self.assertEqual(j | i, j | i.value)
2540 self.assertEqual((j | i).value, j | i.value)
2541 self.assertIs(type(j | i), Perm)
2542 for i in Perm:
2543 self.assertIs(i | i, i)
2544 self.assertIs(i | 0, i)
2545 self.assertIs(0 | i, i)
2546 Open = self.Open
2547 self.assertIs(Open.RO | Open.CE, Open.CE)
2548
2549 def test_and(self):
2550 Perm = self.Perm
2551 RW = Perm.R | Perm.W
2552 RX = Perm.R | Perm.X
2553 WX = Perm.W | Perm.X
2554 RWX = Perm.R | Perm.W | Perm.X
2555 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2556 for i in values:
2557 for j in values:
2558 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2559 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2560 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2561 for j in range(8):
2562 self.assertEqual(i & j, i.value & j)
2563 self.assertEqual((i & j).value, i.value & j)
2564 self.assertIs(type(i & j), Perm)
2565 self.assertEqual(j & i, j & i.value)
2566 self.assertEqual((j & i).value, j & i.value)
2567 self.assertIs(type(j & i), Perm)
2568 for i in Perm:
2569 self.assertIs(i & i, i)
2570 self.assertIs(i & 7, i)
2571 self.assertIs(7 & i, i)
2572 Open = self.Open
2573 self.assertIs(Open.RO & Open.CE, Open.RO)
2574
2575 def test_xor(self):
2576 Perm = self.Perm
2577 for i in Perm:
2578 for j in Perm:
2579 self.assertEqual(i ^ j, i.value ^ j.value)
2580 self.assertEqual((i ^ j).value, i.value ^ j.value)
2581 self.assertIs(type(i ^ j), Perm)
2582 for j in range(8):
2583 self.assertEqual(i ^ j, i.value ^ j)
2584 self.assertEqual((i ^ j).value, i.value ^ j)
2585 self.assertIs(type(i ^ j), Perm)
2586 self.assertEqual(j ^ i, j ^ i.value)
2587 self.assertEqual((j ^ i).value, j ^ i.value)
2588 self.assertIs(type(j ^ i), Perm)
2589 for i in Perm:
2590 self.assertIs(i ^ 0, i)
2591 self.assertIs(0 ^ i, i)
2592 Open = self.Open
2593 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2594 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2595
2596 def test_invert(self):
2597 Perm = self.Perm
2598 RW = Perm.R | Perm.W
2599 RX = Perm.R | Perm.X
2600 WX = Perm.W | Perm.X
2601 RWX = Perm.R | Perm.W | Perm.X
2602 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2603 for i in values:
2604 self.assertEqual(~i, ~i.value)
2605 self.assertEqual((~i).value, ~i.value)
2606 self.assertIs(type(~i), Perm)
2607 self.assertEqual(~~i, i)
2608 for i in Perm:
2609 self.assertIs(~~i, i)
2610 Open = self.Open
2611 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2612 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2613
2614 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002615 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002616 lst = list(Perm)
2617 self.assertEqual(len(lst), len(Perm))
2618 self.assertEqual(len(Perm), 3, Perm)
2619 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2620 for i, n in enumerate('R W X'.split()):
2621 v = 1<<i
2622 e = Perm(v)
2623 self.assertEqual(e.value, v)
2624 self.assertEqual(type(e.value), int)
2625 self.assertEqual(e, v)
2626 self.assertEqual(e.name, n)
2627 self.assertIn(e, Perm)
2628 self.assertIs(type(e), Perm)
2629
2630 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002631 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002632 lst = list(Perm)
2633 self.assertEqual(len(lst), len(Perm))
2634 self.assertEqual(len(Perm), 3, Perm)
2635 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2636 for i, n in enumerate('R W X'.split()):
2637 v = 8<<i
2638 e = Perm(v)
2639 self.assertEqual(e.value, v)
2640 self.assertEqual(type(e.value), int)
2641 self.assertEqual(e, v)
2642 self.assertEqual(e.name, n)
2643 self.assertIn(e, Perm)
2644 self.assertIs(type(e), Perm)
2645
2646 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002647 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002648 lst = list(Perm)
2649 self.assertEqual(len(lst), len(Perm))
2650 self.assertEqual(len(Perm), 3, Perm)
2651 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2652 for i, n in enumerate('R W X'.split()):
2653 v = 1<<i
2654 e = Perm(v)
2655 self.assertEqual(e.value, v)
2656 self.assertEqual(type(e.value), int)
2657 self.assertEqual(e, v)
2658 self.assertEqual(e.name, n)
2659 self.assertIn(e, Perm)
2660 self.assertIs(type(e), Perm)
2661
2662 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002663 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002664 lst = list(Perm)
2665 self.assertEqual(len(lst), len(Perm))
2666 self.assertEqual(len(Perm), 3, Perm)
2667 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2668 for i, n in enumerate('R W X'.split()):
2669 v = 1<<(2*i+1)
2670 e = Perm(v)
2671 self.assertEqual(e.value, v)
2672 self.assertEqual(type(e.value), int)
2673 self.assertEqual(e, v)
2674 self.assertEqual(e.name, n)
2675 self.assertIn(e, Perm)
2676 self.assertIs(type(e), Perm)
2677
2678 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002679 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002680 lst = list(Perm)
2681 self.assertEqual(len(lst), len(Perm))
2682 self.assertEqual(len(Perm), 3, Perm)
2683 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2684 for i, n in enumerate('R W X'.split()):
2685 v = 1<<(2*i+1)
2686 e = Perm(v)
2687 self.assertEqual(e.value, v)
2688 self.assertEqual(type(e.value), int)
2689 self.assertEqual(e, v)
2690 self.assertEqual(e.name, n)
2691 self.assertIn(e, Perm)
2692 self.assertIs(type(e), Perm)
2693
2694
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002695 def test_programatic_function_from_empty_list(self):
2696 Perm = enum.IntFlag('Perm', [])
2697 lst = list(Perm)
2698 self.assertEqual(len(lst), len(Perm))
2699 self.assertEqual(len(Perm), 0, Perm)
2700 Thing = enum.Enum('Thing', [])
2701 lst = list(Thing)
2702 self.assertEqual(len(lst), len(Thing))
2703 self.assertEqual(len(Thing), 0, Thing)
2704
2705
2706 def test_programatic_function_from_empty_tuple(self):
2707 Perm = enum.IntFlag('Perm', ())
2708 lst = list(Perm)
2709 self.assertEqual(len(lst), len(Perm))
2710 self.assertEqual(len(Perm), 0, Perm)
2711 Thing = enum.Enum('Thing', ())
2712 self.assertEqual(len(lst), len(Thing))
2713 self.assertEqual(len(Thing), 0, Thing)
2714
Rahul Jha94306522018-09-10 23:51:04 +05302715 def test_contains(self):
2716 Open = self.Open
2717 Color = self.Color
2718 self.assertTrue(Color.GREEN in Color)
2719 self.assertTrue(Open.RW in Open)
2720 self.assertFalse(Color.GREEN in Open)
2721 self.assertFalse(Open.RW in Color)
2722 with self.assertRaises(TypeError):
2723 'GREEN' in Color
2724 with self.assertRaises(TypeError):
2725 'RW' in Open
2726 with self.assertRaises(TypeError):
2727 2 in Color
2728 with self.assertRaises(TypeError):
2729 2 in Open
2730
2731 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002732 Perm = self.Perm
2733 R, W, X = Perm
2734 RW = R | W
2735 RX = R | X
2736 WX = W | X
2737 RWX = R | W | X
2738 self.assertTrue(R in RW)
2739 self.assertTrue(R in RX)
2740 self.assertTrue(R in RWX)
2741 self.assertTrue(W in RW)
2742 self.assertTrue(W in WX)
2743 self.assertTrue(W in RWX)
2744 self.assertTrue(X in RX)
2745 self.assertTrue(X in WX)
2746 self.assertTrue(X in RWX)
2747 self.assertFalse(R in WX)
2748 self.assertFalse(W in RX)
2749 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302750 with self.assertRaises(TypeError):
2751 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002752
Ethan Furman25d94bb2016-09-02 16:32:32 -07002753 def test_bool(self):
2754 Perm = self.Perm
2755 for f in Perm:
2756 self.assertTrue(f)
2757 Open = self.Open
2758 for f in Open:
2759 self.assertEqual(bool(f.value), bool(f))
2760
Ethan Furman5bdab642018-09-21 19:03:09 -07002761 def test_multiple_mixin(self):
2762 class AllMixin:
2763 @classproperty
2764 def ALL(cls):
2765 members = list(cls)
2766 all_value = None
2767 if members:
2768 all_value = members[0]
2769 for member in members[1:]:
2770 all_value |= member
2771 cls.ALL = all_value
2772 return all_value
2773 class StrMixin:
2774 def __str__(self):
2775 return self._name_.lower()
2776 class Color(AllMixin, IntFlag):
2777 RED = auto()
2778 GREEN = auto()
2779 BLUE = auto()
2780 self.assertEqual(Color.RED.value, 1)
2781 self.assertEqual(Color.GREEN.value, 2)
2782 self.assertEqual(Color.BLUE.value, 4)
2783 self.assertEqual(Color.ALL.value, 7)
2784 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2785 class Color(AllMixin, StrMixin, IntFlag):
2786 RED = auto()
2787 GREEN = auto()
2788 BLUE = auto()
2789 self.assertEqual(Color.RED.value, 1)
2790 self.assertEqual(Color.GREEN.value, 2)
2791 self.assertEqual(Color.BLUE.value, 4)
2792 self.assertEqual(Color.ALL.value, 7)
2793 self.assertEqual(str(Color.BLUE), 'blue')
2794 class Color(StrMixin, AllMixin, IntFlag):
2795 RED = auto()
2796 GREEN = auto()
2797 BLUE = auto()
2798 self.assertEqual(Color.RED.value, 1)
2799 self.assertEqual(Color.GREEN.value, 2)
2800 self.assertEqual(Color.BLUE.value, 4)
2801 self.assertEqual(Color.ALL.value, 7)
2802 self.assertEqual(str(Color.BLUE), 'blue')
2803
Ethan Furman28cf6632017-01-24 12:12:06 -08002804 @support.reap_threads
2805 def test_unique_composite(self):
2806 # override __eq__ to be identity only
2807 class TestFlag(IntFlag):
2808 one = auto()
2809 two = auto()
2810 three = auto()
2811 four = auto()
2812 five = auto()
2813 six = auto()
2814 seven = auto()
2815 eight = auto()
2816 def __eq__(self, other):
2817 return self is other
2818 def __hash__(self):
2819 return hash(self._value_)
2820 # have multiple threads competing to complete the composite members
2821 seen = set()
2822 failed = False
2823 def cycle_enum():
2824 nonlocal failed
2825 try:
2826 for i in range(256):
2827 seen.add(TestFlag(i))
2828 except Exception:
2829 failed = True
2830 threads = [
2831 threading.Thread(target=cycle_enum)
2832 for _ in range(8)
2833 ]
2834 with support.start_threads(threads):
2835 pass
2836 # check that only 248 members were created
2837 self.assertFalse(
2838 failed,
2839 'at least one thread failed while creating composite members')
2840 self.assertEqual(256, len(seen), 'too many composite members created')
2841
2842
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002843class TestEmptyAndNonLatinStrings(unittest.TestCase):
2844
2845 def test_empty_string(self):
2846 with self.assertRaises(ValueError):
2847 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2848
2849 def test_non_latin_character_string(self):
2850 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2851 item = getattr(greek_abc, '\u03B1')
2852 self.assertEqual(item.value, 1)
2853
2854 def test_non_latin_number_string(self):
2855 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2856 item = getattr(hebrew_123, '\u05D0')
2857 self.assertEqual(item.value, 1)
2858
2859
Ethan Furmanf24bb352013-07-18 17:05:39 -07002860class TestUnique(unittest.TestCase):
2861
2862 def test_unique_clean(self):
2863 @unique
2864 class Clean(Enum):
2865 one = 1
2866 two = 'dos'
2867 tres = 4.0
2868 @unique
2869 class Cleaner(IntEnum):
2870 single = 1
2871 double = 2
2872 triple = 3
2873
2874 def test_unique_dirty(self):
2875 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2876 @unique
2877 class Dirty(Enum):
2878 one = 1
2879 two = 'dos'
2880 tres = 1
2881 with self.assertRaisesRegex(
2882 ValueError,
2883 'double.*single.*turkey.*triple',
2884 ):
2885 @unique
2886 class Dirtier(IntEnum):
2887 single = 1
2888 double = 1
2889 triple = 3
2890 turkey = 3
2891
Ethan Furman3803ad42016-05-01 10:03:53 -07002892 def test_unique_with_name(self):
2893 @unique
2894 class Silly(Enum):
2895 one = 1
2896 two = 'dos'
2897 name = 3
2898 @unique
2899 class Sillier(IntEnum):
2900 single = 1
2901 name = 2
2902 triple = 3
2903 value = 4
2904
Ethan Furmanf24bb352013-07-18 17:05:39 -07002905
Ethan Furman5bdab642018-09-21 19:03:09 -07002906
Ethan Furman3323da92015-04-11 09:39:59 -07002907expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002908Help on class Color in module %s:
2909
2910class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002911 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2912 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002913 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002914 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002915 | Method resolution order:
2916 | Color
2917 | enum.Enum
2918 | builtins.object
2919 |\x20\x20
2920 | Data and other attributes defined here:
2921 |\x20\x20
2922 | blue = <Color.blue: 3>
2923 |\x20\x20
2924 | green = <Color.green: 2>
2925 |\x20\x20
2926 | red = <Color.red: 1>
2927 |\x20\x20
2928 | ----------------------------------------------------------------------
2929 | Data descriptors inherited from enum.Enum:
2930 |\x20\x20
2931 | name
2932 | The name of the Enum member.
2933 |\x20\x20
2934 | value
2935 | The value of the Enum member.
2936 |\x20\x20
2937 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002938 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002939 |\x20\x20
2940 | __members__
2941 | Returns a mapping of member name->value.
2942 |\x20\x20\x20\x20\x20\x20
2943 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002944 | is a read-only view of the internal mapping."""
2945
2946expected_help_output_without_docs = """\
2947Help on class Color in module %s:
2948
2949class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002950 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2951 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002952 | Method resolution order:
2953 | Color
2954 | enum.Enum
2955 | builtins.object
2956 |\x20\x20
2957 | Data and other attributes defined here:
2958 |\x20\x20
2959 | blue = <Color.blue: 3>
2960 |\x20\x20
2961 | green = <Color.green: 2>
2962 |\x20\x20
2963 | red = <Color.red: 1>
2964 |\x20\x20
2965 | ----------------------------------------------------------------------
2966 | Data descriptors inherited from enum.Enum:
2967 |\x20\x20
2968 | name
2969 |\x20\x20
2970 | value
2971 |\x20\x20
2972 | ----------------------------------------------------------------------
2973 | Data descriptors inherited from enum.EnumMeta:
2974 |\x20\x20
2975 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002976
2977class TestStdLib(unittest.TestCase):
2978
Ethan Furman48a724f2015-04-11 23:23:06 -07002979 maxDiff = None
2980
Ethan Furman5875d742013-10-21 20:45:55 -07002981 class Color(Enum):
2982 red = 1
2983 green = 2
2984 blue = 3
2985
2986 def test_pydoc(self):
2987 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002988 if StrEnum.__doc__ is None:
2989 expected_text = expected_help_output_without_docs % __name__
2990 else:
2991 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002992 output = StringIO()
2993 helper = pydoc.Helper(output=output)
2994 helper(self.Color)
2995 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002996 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002997
2998 def test_inspect_getmembers(self):
2999 values = dict((
3000 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003001 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003002 ('__members__', self.Color.__members__),
3003 ('__module__', __name__),
3004 ('blue', self.Color.blue),
3005 ('green', self.Color.green),
3006 ('name', Enum.__dict__['name']),
3007 ('red', self.Color.red),
3008 ('value', Enum.__dict__['value']),
3009 ))
3010 result = dict(inspect.getmembers(self.Color))
3011 self.assertEqual(values.keys(), result.keys())
3012 failed = False
3013 for k in values.keys():
3014 if result[k] != values[k]:
3015 print()
3016 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3017 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3018 failed = True
3019 if failed:
3020 self.fail("result does not equal expected, see print above")
3021
3022 def test_inspect_classify_class_attrs(self):
3023 # indirectly test __objclass__
3024 from inspect import Attribute
3025 values = [
3026 Attribute(name='__class__', kind='data',
3027 defining_class=object, object=EnumMeta),
3028 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003029 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003030 Attribute(name='__members__', kind='property',
3031 defining_class=EnumMeta, object=EnumMeta.__members__),
3032 Attribute(name='__module__', kind='data',
3033 defining_class=self.Color, object=__name__),
3034 Attribute(name='blue', kind='data',
3035 defining_class=self.Color, object=self.Color.blue),
3036 Attribute(name='green', kind='data',
3037 defining_class=self.Color, object=self.Color.green),
3038 Attribute(name='red', kind='data',
3039 defining_class=self.Color, object=self.Color.red),
3040 Attribute(name='name', kind='data',
3041 defining_class=Enum, object=Enum.__dict__['name']),
3042 Attribute(name='value', kind='data',
3043 defining_class=Enum, object=Enum.__dict__['value']),
3044 ]
3045 values.sort(key=lambda item: item.name)
3046 result = list(inspect.classify_class_attrs(self.Color))
3047 result.sort(key=lambda item: item.name)
3048 failed = False
3049 for v, r in zip(values, result):
3050 if r != v:
3051 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3052 failed = True
3053 if failed:
3054 self.fail("result does not equal expected, see print above")
3055
Martin Panter19e69c52015-11-14 12:46:42 +00003056
3057class MiscTestCase(unittest.TestCase):
3058 def test__all__(self):
3059 support.check__all__(self, enum)
3060
3061
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003062# These are unordered here on purpose to ensure that declaration order
3063# makes no difference.
3064CONVERT_TEST_NAME_D = 5
3065CONVERT_TEST_NAME_C = 5
3066CONVERT_TEST_NAME_B = 5
3067CONVERT_TEST_NAME_A = 5 # This one should sort first.
3068CONVERT_TEST_NAME_E = 5
3069CONVERT_TEST_NAME_F = 5
3070
3071class TestIntEnumConvert(unittest.TestCase):
3072 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003073 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003074 'UnittestConvert',
3075 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003076 filter=lambda x: x.startswith('CONVERT_TEST_'))
3077 # We don't want the reverse lookup value to vary when there are
3078 # multiple possible names for a given value. It should always
3079 # report the first lexigraphical name in that case.
3080 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3081
3082 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003083 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003084 'UnittestConvert',
3085 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003086 filter=lambda x: x.startswith('CONVERT_TEST_'))
3087 # Ensure that test_type has all of the desired names and values.
3088 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3089 test_type.CONVERT_TEST_NAME_A)
3090 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3091 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3092 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3093 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3094 # Ensure that test_type only picked up names matching the filter.
3095 self.assertEqual([name for name in dir(test_type)
3096 if name[0:2] not in ('CO', '__')],
3097 [], msg='Names other than CONVERT_TEST_* found.')
3098
orlnub1230fb9fad2018-09-12 20:28:53 +03003099 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3100 '_convert was deprecated in 3.8')
3101 def test_convert_warn(self):
3102 with self.assertWarns(DeprecationWarning):
3103 enum.IntEnum._convert(
3104 'UnittestConvert',
3105 ('test.test_enum', '__main__')[__name__=='__main__'],
3106 filter=lambda x: x.startswith('CONVERT_TEST_'))
3107
3108 @unittest.skipUnless(sys.version_info >= (3, 9),
3109 '_convert was removed in 3.9')
3110 def test_convert_raise(self):
3111 with self.assertRaises(AttributeError):
3112 enum.IntEnum._convert(
3113 'UnittestConvert',
3114 ('test.test_enum', '__main__')[__name__=='__main__'],
3115 filter=lambda x: x.startswith('CONVERT_TEST_'))
3116
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003117
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003118if __name__ == '__main__':
3119 unittest.main()