blob: 1df0313da0a7e0ae58e94c287f274c9ad6dc0c00 [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 Furman6b3d64a2013-06-14 16:55:46 -0700555 def test_hash(self):
556 Season = self.Season
557 dates = {}
558 dates[Season.WINTER] = '1225'
559 dates[Season.SPRING] = '0315'
560 dates[Season.SUMMER] = '0704'
561 dates[Season.AUTUMN] = '1031'
562 self.assertEqual(dates[Season.AUTUMN], '1031')
563
564 def test_intenum_from_scratch(self):
565 class phy(int, Enum):
566 pi = 3
567 tau = 2 * pi
568 self.assertTrue(phy.pi < phy.tau)
569
570 def test_intenum_inherited(self):
571 class IntEnum(int, Enum):
572 pass
573 class phy(IntEnum):
574 pi = 3
575 tau = 2 * pi
576 self.assertTrue(phy.pi < phy.tau)
577
578 def test_floatenum_from_scratch(self):
579 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700580 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700581 tau = 2 * pi
582 self.assertTrue(phy.pi < phy.tau)
583
584 def test_floatenum_inherited(self):
585 class FloatEnum(float, Enum):
586 pass
587 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700588 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700589 tau = 2 * pi
590 self.assertTrue(phy.pi < phy.tau)
591
592 def test_strenum_from_scratch(self):
593 class phy(str, Enum):
594 pi = 'Pi'
595 tau = 'Tau'
596 self.assertTrue(phy.pi < phy.tau)
597
598 def test_strenum_inherited(self):
599 class StrEnum(str, Enum):
600 pass
601 class phy(StrEnum):
602 pi = 'Pi'
603 tau = 'Tau'
604 self.assertTrue(phy.pi < phy.tau)
605
606
607 def test_intenum(self):
608 class WeekDay(IntEnum):
609 SUNDAY = 1
610 MONDAY = 2
611 TUESDAY = 3
612 WEDNESDAY = 4
613 THURSDAY = 5
614 FRIDAY = 6
615 SATURDAY = 7
616
617 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
618 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
619
620 lst = list(WeekDay)
621 self.assertEqual(len(lst), len(WeekDay))
622 self.assertEqual(len(WeekDay), 7)
623 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
624 target = target.split()
625 for i, weekday in enumerate(target, 1):
626 e = WeekDay(i)
627 self.assertEqual(e, i)
628 self.assertEqual(int(e), i)
629 self.assertEqual(e.name, weekday)
630 self.assertIn(e, WeekDay)
631 self.assertEqual(lst.index(e)+1, i)
632 self.assertTrue(0 < e < 8)
633 self.assertIs(type(e), WeekDay)
634 self.assertIsInstance(e, int)
635 self.assertIsInstance(e, Enum)
636
637 def test_intenum_duplicates(self):
638 class WeekDay(IntEnum):
639 SUNDAY = 1
640 MONDAY = 2
641 TUESDAY = TEUSDAY = 3
642 WEDNESDAY = 4
643 THURSDAY = 5
644 FRIDAY = 6
645 SATURDAY = 7
646 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
647 self.assertEqual(WeekDay(3).name, 'TUESDAY')
648 self.assertEqual([k for k,v in WeekDay.__members__.items()
649 if v.name != k], ['TEUSDAY', ])
650
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300651 def test_intenum_from_bytes(self):
652 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
653 with self.assertRaises(ValueError):
654 IntStooges.from_bytes(b'\x00\x05', 'big')
655
656 def test_floatenum_fromhex(self):
657 h = float.hex(FloatStooges.MOE.value)
658 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
659 h = float.hex(FloatStooges.MOE.value + 0.01)
660 with self.assertRaises(ValueError):
661 FloatStooges.fromhex(h)
662
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700663 def test_pickle_enum(self):
664 if isinstance(Stooges, Exception):
665 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800666 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
667 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700668
669 def test_pickle_int(self):
670 if isinstance(IntStooges, Exception):
671 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800672 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
673 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700674
675 def test_pickle_float(self):
676 if isinstance(FloatStooges, Exception):
677 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800678 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
679 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700680
681 def test_pickle_enum_function(self):
682 if isinstance(Answer, Exception):
683 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800684 test_pickle_dump_load(self.assertIs, Answer.him)
685 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700686
687 def test_pickle_enum_function_with_module(self):
688 if isinstance(Question, Exception):
689 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800690 test_pickle_dump_load(self.assertIs, Question.who)
691 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700692
Ethan Furmanca1b7942014-02-08 11:36:27 -0800693 def test_enum_function_with_qualname(self):
694 if isinstance(Theory, Exception):
695 raise Theory
696 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
697
698 def test_class_nested_enum_and_pickle_protocol_four(self):
699 # would normally just have this directly in the class namespace
700 class NestedEnum(Enum):
701 twigs = 'common'
702 shiny = 'rare'
703
704 self.__class__.NestedEnum = NestedEnum
705 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300706 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800707
Ethan Furman24e837f2015-03-18 17:27:57 -0700708 def test_pickle_by_name(self):
709 class ReplaceGlobalInt(IntEnum):
710 ONE = 1
711 TWO = 2
712 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
713 for proto in range(HIGHEST_PROTOCOL):
714 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
715
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700716 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800717 BadPickle = Enum(
718 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700719 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800720 # now break BadPickle to test exception raising
721 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800722 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
723 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700724
725 def test_string_enum(self):
726 class SkillLevel(str, Enum):
727 master = 'what is the sound of one hand clapping?'
728 journeyman = 'why did the chicken cross the road?'
729 apprentice = 'knock, knock!'
730 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
731
732 def test_getattr_getitem(self):
733 class Period(Enum):
734 morning = 1
735 noon = 2
736 evening = 3
737 night = 4
738 self.assertIs(Period(2), Period.noon)
739 self.assertIs(getattr(Period, 'night'), Period.night)
740 self.assertIs(Period['morning'], Period.morning)
741
742 def test_getattr_dunder(self):
743 Season = self.Season
744 self.assertTrue(getattr(Season, '__eq__'))
745
746 def test_iteration_order(self):
747 class Season(Enum):
748 SUMMER = 2
749 WINTER = 4
750 AUTUMN = 3
751 SPRING = 1
752 self.assertEqual(
753 list(Season),
754 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
755 )
756
Ethan Furman2131a4a2013-09-14 18:11:24 -0700757 def test_reversed_iteration_order(self):
758 self.assertEqual(
759 list(reversed(self.Season)),
760 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
761 self.Season.SPRING]
762 )
763
Martin Pantereb995702016-07-28 01:11:04 +0000764 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700765 SummerMonth = Enum('SummerMonth', 'june july august')
766 lst = list(SummerMonth)
767 self.assertEqual(len(lst), len(SummerMonth))
768 self.assertEqual(len(SummerMonth), 3, SummerMonth)
769 self.assertEqual(
770 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
771 lst,
772 )
773 for i, month in enumerate('june july august'.split(), 1):
774 e = SummerMonth(i)
775 self.assertEqual(int(e.value), i)
776 self.assertNotEqual(e, i)
777 self.assertEqual(e.name, month)
778 self.assertIn(e, SummerMonth)
779 self.assertIs(type(e), SummerMonth)
780
Martin Pantereb995702016-07-28 01:11:04 +0000781 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700782 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
783 lst = list(SummerMonth)
784 self.assertEqual(len(lst), len(SummerMonth))
785 self.assertEqual(len(SummerMonth), 3, SummerMonth)
786 self.assertEqual(
787 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
788 lst,
789 )
790 for i, month in enumerate('june july august'.split(), 10):
791 e = SummerMonth(i)
792 self.assertEqual(int(e.value), i)
793 self.assertNotEqual(e, i)
794 self.assertEqual(e.name, month)
795 self.assertIn(e, SummerMonth)
796 self.assertIs(type(e), SummerMonth)
797
Martin Pantereb995702016-07-28 01:11:04 +0000798 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700799 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
800 lst = list(SummerMonth)
801 self.assertEqual(len(lst), len(SummerMonth))
802 self.assertEqual(len(SummerMonth), 3, SummerMonth)
803 self.assertEqual(
804 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
805 lst,
806 )
807 for i, month in enumerate('june july august'.split(), 1):
808 e = SummerMonth(i)
809 self.assertEqual(int(e.value), i)
810 self.assertNotEqual(e, i)
811 self.assertEqual(e.name, month)
812 self.assertIn(e, SummerMonth)
813 self.assertIs(type(e), SummerMonth)
814
Martin Pantereb995702016-07-28 01:11:04 +0000815 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700816 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
817 lst = list(SummerMonth)
818 self.assertEqual(len(lst), len(SummerMonth))
819 self.assertEqual(len(SummerMonth), 3, SummerMonth)
820 self.assertEqual(
821 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
822 lst,
823 )
824 for i, month in enumerate('june july august'.split(), 20):
825 e = SummerMonth(i)
826 self.assertEqual(int(e.value), i)
827 self.assertNotEqual(e, i)
828 self.assertEqual(e.name, month)
829 self.assertIn(e, SummerMonth)
830 self.assertIs(type(e), SummerMonth)
831
Martin Pantereb995702016-07-28 01:11:04 +0000832 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700833 SummerMonth = Enum(
834 'SummerMonth',
835 (('june', 1), ('july', 2), ('august', 3))
836 )
837 lst = list(SummerMonth)
838 self.assertEqual(len(lst), len(SummerMonth))
839 self.assertEqual(len(SummerMonth), 3, SummerMonth)
840 self.assertEqual(
841 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
842 lst,
843 )
844 for i, month in enumerate('june july august'.split(), 1):
845 e = SummerMonth(i)
846 self.assertEqual(int(e.value), i)
847 self.assertNotEqual(e, i)
848 self.assertEqual(e.name, month)
849 self.assertIn(e, SummerMonth)
850 self.assertIs(type(e), SummerMonth)
851
Martin Pantereb995702016-07-28 01:11:04 +0000852 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700853 SummerMonth = Enum(
854 'SummerMonth',
855 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
856 )
857 lst = list(SummerMonth)
858 self.assertEqual(len(lst), len(SummerMonth))
859 self.assertEqual(len(SummerMonth), 3, SummerMonth)
860 self.assertEqual(
861 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
862 lst,
863 )
864 for i, month in enumerate('june july august'.split(), 1):
865 e = SummerMonth(i)
866 self.assertEqual(int(e.value), i)
867 self.assertNotEqual(e, i)
868 self.assertEqual(e.name, month)
869 self.assertIn(e, SummerMonth)
870 self.assertIs(type(e), SummerMonth)
871
Martin Pantereb995702016-07-28 01:11:04 +0000872 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700873 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
874 lst = list(SummerMonth)
875 self.assertEqual(len(lst), len(SummerMonth))
876 self.assertEqual(len(SummerMonth), 3, SummerMonth)
877 self.assertEqual(
878 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
879 lst,
880 )
881 for i, month in enumerate('june july august'.split(), 1):
882 e = SummerMonth(i)
883 self.assertEqual(e, i)
884 self.assertEqual(e.name, month)
885 self.assertIn(e, SummerMonth)
886 self.assertIs(type(e), SummerMonth)
887
Martin Pantereb995702016-07-28 01:11:04 +0000888 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700889 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
890 lst = list(SummerMonth)
891 self.assertEqual(len(lst), len(SummerMonth))
892 self.assertEqual(len(SummerMonth), 3, SummerMonth)
893 self.assertEqual(
894 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
895 lst,
896 )
897 for i, month in enumerate('june july august'.split(), 30):
898 e = SummerMonth(i)
899 self.assertEqual(e, i)
900 self.assertEqual(e.name, month)
901 self.assertIn(e, SummerMonth)
902 self.assertIs(type(e), SummerMonth)
903
Martin Pantereb995702016-07-28 01:11:04 +0000904 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700905 SummerMonth = IntEnum('SummerMonth', 'june july august')
906 lst = list(SummerMonth)
907 self.assertEqual(len(lst), len(SummerMonth))
908 self.assertEqual(len(SummerMonth), 3, SummerMonth)
909 self.assertEqual(
910 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
911 lst,
912 )
913 for i, month in enumerate('june july august'.split(), 1):
914 e = SummerMonth(i)
915 self.assertEqual(e, i)
916 self.assertEqual(e.name, month)
917 self.assertIn(e, SummerMonth)
918 self.assertIs(type(e), SummerMonth)
919
Martin Pantereb995702016-07-28 01:11:04 +0000920 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700921 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
922 lst = list(SummerMonth)
923 self.assertEqual(len(lst), len(SummerMonth))
924 self.assertEqual(len(SummerMonth), 3, SummerMonth)
925 self.assertEqual(
926 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
927 lst,
928 )
929 for i, month in enumerate('june july august'.split(), 40):
930 e = SummerMonth(i)
931 self.assertEqual(e, i)
932 self.assertEqual(e.name, month)
933 self.assertIn(e, SummerMonth)
934 self.assertIs(type(e), SummerMonth)
935
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700936 def test_subclassing(self):
937 if isinstance(Name, Exception):
938 raise Name
939 self.assertEqual(Name.BDFL, 'Guido van Rossum')
940 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
941 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800942 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700943
944 def test_extending(self):
945 class Color(Enum):
946 red = 1
947 green = 2
948 blue = 3
949 with self.assertRaises(TypeError):
950 class MoreColor(Color):
951 cyan = 4
952 magenta = 5
953 yellow = 6
954
955 def test_exclude_methods(self):
956 class whatever(Enum):
957 this = 'that'
958 these = 'those'
959 def really(self):
960 return 'no, not %s' % self.value
961 self.assertIsNot(type(whatever.really), whatever)
962 self.assertEqual(whatever.this.really(), 'no, not that')
963
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700964 def test_wrong_inheritance_order(self):
965 with self.assertRaises(TypeError):
966 class Wrong(Enum, str):
967 NotHere = 'error before this point'
968
969 def test_intenum_transitivity(self):
970 class number(IntEnum):
971 one = 1
972 two = 2
973 three = 3
974 class numero(IntEnum):
975 uno = 1
976 dos = 2
977 tres = 3
978 self.assertEqual(number.one, numero.uno)
979 self.assertEqual(number.two, numero.dos)
980 self.assertEqual(number.three, numero.tres)
981
982 def test_wrong_enum_in_call(self):
983 class Monochrome(Enum):
984 black = 0
985 white = 1
986 class Gender(Enum):
987 male = 0
988 female = 1
989 self.assertRaises(ValueError, Monochrome, Gender.male)
990
991 def test_wrong_enum_in_mixed_call(self):
992 class Monochrome(IntEnum):
993 black = 0
994 white = 1
995 class Gender(Enum):
996 male = 0
997 female = 1
998 self.assertRaises(ValueError, Monochrome, Gender.male)
999
1000 def test_mixed_enum_in_call_1(self):
1001 class Monochrome(IntEnum):
1002 black = 0
1003 white = 1
1004 class Gender(IntEnum):
1005 male = 0
1006 female = 1
1007 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1008
1009 def test_mixed_enum_in_call_2(self):
1010 class Monochrome(Enum):
1011 black = 0
1012 white = 1
1013 class Gender(IntEnum):
1014 male = 0
1015 female = 1
1016 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1017
1018 def test_flufl_enum(self):
1019 class Fluflnum(Enum):
1020 def __int__(self):
1021 return int(self.value)
1022 class MailManOptions(Fluflnum):
1023 option1 = 1
1024 option2 = 2
1025 option3 = 3
1026 self.assertEqual(int(MailManOptions.option1), 1)
1027
Ethan Furman5e5a8232013-08-04 08:42:23 -07001028 def test_introspection(self):
1029 class Number(IntEnum):
1030 one = 100
1031 two = 200
1032 self.assertIs(Number.one._member_type_, int)
1033 self.assertIs(Number._member_type_, int)
1034 class String(str, Enum):
1035 yarn = 'soft'
1036 rope = 'rough'
1037 wire = 'hard'
1038 self.assertIs(String.yarn._member_type_, str)
1039 self.assertIs(String._member_type_, str)
1040 class Plain(Enum):
1041 vanilla = 'white'
1042 one = 1
1043 self.assertIs(Plain.vanilla._member_type_, object)
1044 self.assertIs(Plain._member_type_, object)
1045
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001046 def test_no_such_enum_member(self):
1047 class Color(Enum):
1048 red = 1
1049 green = 2
1050 blue = 3
1051 with self.assertRaises(ValueError):
1052 Color(4)
1053 with self.assertRaises(KeyError):
1054 Color['chartreuse']
1055
1056 def test_new_repr(self):
1057 class Color(Enum):
1058 red = 1
1059 green = 2
1060 blue = 3
1061 def __repr__(self):
1062 return "don't you just love shades of %s?" % self.name
1063 self.assertEqual(
1064 repr(Color.blue),
1065 "don't you just love shades of blue?",
1066 )
1067
1068 def test_inherited_repr(self):
1069 class MyEnum(Enum):
1070 def __repr__(self):
1071 return "My name is %s." % self.name
1072 class MyIntEnum(int, MyEnum):
1073 this = 1
1074 that = 2
1075 theother = 3
1076 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1077
1078 def test_multiple_mixin_mro(self):
1079 class auto_enum(type(Enum)):
1080 def __new__(metacls, cls, bases, classdict):
1081 temp = type(classdict)()
1082 names = set(classdict._member_names)
1083 i = 0
1084 for k in classdict._member_names:
1085 v = classdict[k]
1086 if v is Ellipsis:
1087 v = i
1088 else:
1089 i = v
1090 i += 1
1091 temp[k] = v
1092 for k, v in classdict.items():
1093 if k not in names:
1094 temp[k] = v
1095 return super(auto_enum, metacls).__new__(
1096 metacls, cls, bases, temp)
1097
1098 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1099 pass
1100
1101 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1102 pass
1103
1104 class TestAutoNumber(AutoNumberedEnum):
1105 a = ...
1106 b = 3
1107 c = ...
1108
1109 class TestAutoInt(AutoIntEnum):
1110 a = ...
1111 b = 3
1112 c = ...
1113
1114 def test_subclasses_with_getnewargs(self):
1115 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001116 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001117 def __new__(cls, *args):
1118 _args = args
1119 name, *args = args
1120 if len(args) == 0:
1121 raise TypeError("name and value must be specified")
1122 self = int.__new__(cls, *args)
1123 self._intname = name
1124 self._args = _args
1125 return self
1126 def __getnewargs__(self):
1127 return self._args
1128 @property
1129 def __name__(self):
1130 return self._intname
1131 def __repr__(self):
1132 # repr() is updated to include the name and type info
1133 return "{}({!r}, {})".format(type(self).__name__,
1134 self.__name__,
1135 int.__repr__(self))
1136 def __str__(self):
1137 # str() is unchanged, even if it relies on the repr() fallback
1138 base = int
1139 base_str = base.__str__
1140 if base_str.__objclass__ is object:
1141 return base.__repr__(self)
1142 return base_str(self)
1143 # for simplicity, we only define one operator that
1144 # propagates expressions
1145 def __add__(self, other):
1146 temp = int(self) + int( other)
1147 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1148 return NamedInt(
1149 '({0} + {1})'.format(self.__name__, other.__name__),
1150 temp )
1151 else:
1152 return temp
1153
1154 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001155 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001156 x = ('the-x', 1)
1157 y = ('the-y', 2)
1158
Ethan Furman2aa27322013-07-19 19:35:56 -07001159
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001160 self.assertIs(NEI.__new__, Enum.__new__)
1161 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1162 globals()['NamedInt'] = NamedInt
1163 globals()['NEI'] = NEI
1164 NI5 = NamedInt('test', 5)
1165 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001166 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001167 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001168 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001169 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001170
Ethan Furmanca1b7942014-02-08 11:36:27 -08001171 def test_subclasses_with_getnewargs_ex(self):
1172 class NamedInt(int):
1173 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1174 def __new__(cls, *args):
1175 _args = args
1176 name, *args = args
1177 if len(args) == 0:
1178 raise TypeError("name and value must be specified")
1179 self = int.__new__(cls, *args)
1180 self._intname = name
1181 self._args = _args
1182 return self
1183 def __getnewargs_ex__(self):
1184 return self._args, {}
1185 @property
1186 def __name__(self):
1187 return self._intname
1188 def __repr__(self):
1189 # repr() is updated to include the name and type info
1190 return "{}({!r}, {})".format(type(self).__name__,
1191 self.__name__,
1192 int.__repr__(self))
1193 def __str__(self):
1194 # str() is unchanged, even if it relies on the repr() fallback
1195 base = int
1196 base_str = base.__str__
1197 if base_str.__objclass__ is object:
1198 return base.__repr__(self)
1199 return base_str(self)
1200 # for simplicity, we only define one operator that
1201 # propagates expressions
1202 def __add__(self, other):
1203 temp = int(self) + int( other)
1204 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1205 return NamedInt(
1206 '({0} + {1})'.format(self.__name__, other.__name__),
1207 temp )
1208 else:
1209 return temp
1210
1211 class NEI(NamedInt, Enum):
1212 __qualname__ = 'NEI' # needed for pickle protocol 4
1213 x = ('the-x', 1)
1214 y = ('the-y', 2)
1215
1216
1217 self.assertIs(NEI.__new__, Enum.__new__)
1218 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1219 globals()['NamedInt'] = NamedInt
1220 globals()['NEI'] = NEI
1221 NI5 = NamedInt('test', 5)
1222 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001223 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001224 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001225 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001226 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001227
1228 def test_subclasses_with_reduce(self):
1229 class NamedInt(int):
1230 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1231 def __new__(cls, *args):
1232 _args = args
1233 name, *args = args
1234 if len(args) == 0:
1235 raise TypeError("name and value must be specified")
1236 self = int.__new__(cls, *args)
1237 self._intname = name
1238 self._args = _args
1239 return self
1240 def __reduce__(self):
1241 return self.__class__, self._args
1242 @property
1243 def __name__(self):
1244 return self._intname
1245 def __repr__(self):
1246 # repr() is updated to include the name and type info
1247 return "{}({!r}, {})".format(type(self).__name__,
1248 self.__name__,
1249 int.__repr__(self))
1250 def __str__(self):
1251 # str() is unchanged, even if it relies on the repr() fallback
1252 base = int
1253 base_str = base.__str__
1254 if base_str.__objclass__ is object:
1255 return base.__repr__(self)
1256 return base_str(self)
1257 # for simplicity, we only define one operator that
1258 # propagates expressions
1259 def __add__(self, other):
1260 temp = int(self) + int( other)
1261 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1262 return NamedInt(
1263 '({0} + {1})'.format(self.__name__, other.__name__),
1264 temp )
1265 else:
1266 return temp
1267
1268 class NEI(NamedInt, Enum):
1269 __qualname__ = 'NEI' # needed for pickle protocol 4
1270 x = ('the-x', 1)
1271 y = ('the-y', 2)
1272
1273
1274 self.assertIs(NEI.__new__, Enum.__new__)
1275 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1276 globals()['NamedInt'] = NamedInt
1277 globals()['NEI'] = NEI
1278 NI5 = NamedInt('test', 5)
1279 self.assertEqual(NI5, 5)
1280 test_pickle_dump_load(self.assertEqual, NI5, 5)
1281 self.assertEqual(NEI.y.value, 2)
1282 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001283 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001284
1285 def test_subclasses_with_reduce_ex(self):
1286 class NamedInt(int):
1287 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1288 def __new__(cls, *args):
1289 _args = args
1290 name, *args = args
1291 if len(args) == 0:
1292 raise TypeError("name and value must be specified")
1293 self = int.__new__(cls, *args)
1294 self._intname = name
1295 self._args = _args
1296 return self
1297 def __reduce_ex__(self, proto):
1298 return self.__class__, self._args
1299 @property
1300 def __name__(self):
1301 return self._intname
1302 def __repr__(self):
1303 # repr() is updated to include the name and type info
1304 return "{}({!r}, {})".format(type(self).__name__,
1305 self.__name__,
1306 int.__repr__(self))
1307 def __str__(self):
1308 # str() is unchanged, even if it relies on the repr() fallback
1309 base = int
1310 base_str = base.__str__
1311 if base_str.__objclass__ is object:
1312 return base.__repr__(self)
1313 return base_str(self)
1314 # for simplicity, we only define one operator that
1315 # propagates expressions
1316 def __add__(self, other):
1317 temp = int(self) + int( other)
1318 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1319 return NamedInt(
1320 '({0} + {1})'.format(self.__name__, other.__name__),
1321 temp )
1322 else:
1323 return temp
1324
1325 class NEI(NamedInt, Enum):
1326 __qualname__ = 'NEI' # needed for pickle protocol 4
1327 x = ('the-x', 1)
1328 y = ('the-y', 2)
1329
1330
1331 self.assertIs(NEI.__new__, Enum.__new__)
1332 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1333 globals()['NamedInt'] = NamedInt
1334 globals()['NEI'] = NEI
1335 NI5 = NamedInt('test', 5)
1336 self.assertEqual(NI5, 5)
1337 test_pickle_dump_load(self.assertEqual, NI5, 5)
1338 self.assertEqual(NEI.y.value, 2)
1339 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001340 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001341
Ethan Furmandc870522014-02-18 12:37:12 -08001342 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001343 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001344 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001345 def __new__(cls, *args):
1346 _args = args
1347 name, *args = args
1348 if len(args) == 0:
1349 raise TypeError("name and value must be specified")
1350 self = int.__new__(cls, *args)
1351 self._intname = name
1352 self._args = _args
1353 return self
1354 @property
1355 def __name__(self):
1356 return self._intname
1357 def __repr__(self):
1358 # repr() is updated to include the name and type info
1359 return "{}({!r}, {})".format(type(self).__name__,
1360 self.__name__,
1361 int.__repr__(self))
1362 def __str__(self):
1363 # str() is unchanged, even if it relies on the repr() fallback
1364 base = int
1365 base_str = base.__str__
1366 if base_str.__objclass__ is object:
1367 return base.__repr__(self)
1368 return base_str(self)
1369 # for simplicity, we only define one operator that
1370 # propagates expressions
1371 def __add__(self, other):
1372 temp = int(self) + int( other)
1373 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1374 return NamedInt(
1375 '({0} + {1})'.format(self.__name__, other.__name__),
1376 temp )
1377 else:
1378 return temp
1379
1380 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001381 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001382 x = ('the-x', 1)
1383 y = ('the-y', 2)
1384
1385 self.assertIs(NEI.__new__, Enum.__new__)
1386 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1387 globals()['NamedInt'] = NamedInt
1388 globals()['NEI'] = NEI
1389 NI5 = NamedInt('test', 5)
1390 self.assertEqual(NI5, 5)
1391 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001392 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1393 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001394
Ethan Furmandc870522014-02-18 12:37:12 -08001395 def test_subclasses_without_direct_pickle_support_using_name(self):
1396 class NamedInt(int):
1397 __qualname__ = 'NamedInt'
1398 def __new__(cls, *args):
1399 _args = args
1400 name, *args = args
1401 if len(args) == 0:
1402 raise TypeError("name and value must be specified")
1403 self = int.__new__(cls, *args)
1404 self._intname = name
1405 self._args = _args
1406 return self
1407 @property
1408 def __name__(self):
1409 return self._intname
1410 def __repr__(self):
1411 # repr() is updated to include the name and type info
1412 return "{}({!r}, {})".format(type(self).__name__,
1413 self.__name__,
1414 int.__repr__(self))
1415 def __str__(self):
1416 # str() is unchanged, even if it relies on the repr() fallback
1417 base = int
1418 base_str = base.__str__
1419 if base_str.__objclass__ is object:
1420 return base.__repr__(self)
1421 return base_str(self)
1422 # for simplicity, we only define one operator that
1423 # propagates expressions
1424 def __add__(self, other):
1425 temp = int(self) + int( other)
1426 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1427 return NamedInt(
1428 '({0} + {1})'.format(self.__name__, other.__name__),
1429 temp )
1430 else:
1431 return temp
1432
1433 class NEI(NamedInt, Enum):
1434 __qualname__ = 'NEI'
1435 x = ('the-x', 1)
1436 y = ('the-y', 2)
1437 def __reduce_ex__(self, proto):
1438 return getattr, (self.__class__, self._name_)
1439
1440 self.assertIs(NEI.__new__, Enum.__new__)
1441 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1442 globals()['NamedInt'] = NamedInt
1443 globals()['NEI'] = NEI
1444 NI5 = NamedInt('test', 5)
1445 self.assertEqual(NI5, 5)
1446 self.assertEqual(NEI.y.value, 2)
1447 test_pickle_dump_load(self.assertIs, NEI.y)
1448 test_pickle_dump_load(self.assertIs, NEI)
1449
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001450 def test_tuple_subclass(self):
1451 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001452 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001453 first = (1, 'for the money')
1454 second = (2, 'for the show')
1455 third = (3, 'for the music')
1456 self.assertIs(type(SomeTuple.first), SomeTuple)
1457 self.assertIsInstance(SomeTuple.second, tuple)
1458 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1459 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001460 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001461
1462 def test_duplicate_values_give_unique_enum_items(self):
1463 class AutoNumber(Enum):
1464 first = ()
1465 second = ()
1466 third = ()
1467 def __new__(cls):
1468 value = len(cls.__members__) + 1
1469 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001470 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001471 return obj
1472 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001473 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001474 self.assertEqual(
1475 list(AutoNumber),
1476 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1477 )
1478 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001479 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001480 self.assertIs(AutoNumber(1), AutoNumber.first)
1481
1482 def test_inherited_new_from_enhanced_enum(self):
1483 class AutoNumber(Enum):
1484 def __new__(cls):
1485 value = len(cls.__members__) + 1
1486 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001487 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001488 return obj
1489 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001490 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001491 class Color(AutoNumber):
1492 red = ()
1493 green = ()
1494 blue = ()
1495 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1496 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1497
1498 def test_inherited_new_from_mixed_enum(self):
1499 class AutoNumber(IntEnum):
1500 def __new__(cls):
1501 value = len(cls.__members__) + 1
1502 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001503 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001504 return obj
1505 class Color(AutoNumber):
1506 red = ()
1507 green = ()
1508 blue = ()
1509 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1510 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1511
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001512 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001513 class OrdinaryEnum(Enum):
1514 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001515 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1516 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001517
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001518 def test_ordered_mixin(self):
1519 class OrderedEnum(Enum):
1520 def __ge__(self, other):
1521 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001522 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001523 return NotImplemented
1524 def __gt__(self, other):
1525 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001526 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001527 return NotImplemented
1528 def __le__(self, other):
1529 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001530 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001531 return NotImplemented
1532 def __lt__(self, other):
1533 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001534 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001535 return NotImplemented
1536 class Grade(OrderedEnum):
1537 A = 5
1538 B = 4
1539 C = 3
1540 D = 2
1541 F = 1
1542 self.assertGreater(Grade.A, Grade.B)
1543 self.assertLessEqual(Grade.F, Grade.C)
1544 self.assertLess(Grade.D, Grade.A)
1545 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001546 self.assertEqual(Grade.B, Grade.B)
1547 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001548
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001549 def test_extending2(self):
1550 class Shade(Enum):
1551 def shade(self):
1552 print(self.name)
1553 class Color(Shade):
1554 red = 1
1555 green = 2
1556 blue = 3
1557 with self.assertRaises(TypeError):
1558 class MoreColor(Color):
1559 cyan = 4
1560 magenta = 5
1561 yellow = 6
1562
1563 def test_extending3(self):
1564 class Shade(Enum):
1565 def shade(self):
1566 return self.name
1567 class Color(Shade):
1568 def hex(self):
1569 return '%s hexlified!' % self.value
1570 class MoreColor(Color):
1571 cyan = 4
1572 magenta = 5
1573 yellow = 6
1574 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1575
orlnub1230fb9fad2018-09-12 20:28:53 +03001576 def test_subclass_duplicate_name(self):
1577 class Base(Enum):
1578 def test(self):
1579 pass
1580 class Test(Base):
1581 test = 1
1582 self.assertIs(type(Test.test), Test)
1583
1584 def test_subclass_duplicate_name_dynamic(self):
1585 from types import DynamicClassAttribute
1586 class Base(Enum):
1587 @DynamicClassAttribute
1588 def test(self):
1589 return 'dynamic'
1590 class Test(Base):
1591 test = 1
1592 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001593
1594 def test_no_duplicates(self):
1595 class UniqueEnum(Enum):
1596 def __init__(self, *args):
1597 cls = self.__class__
1598 if any(self.value == e.value for e in cls):
1599 a = self.name
1600 e = cls(self.value).name
1601 raise ValueError(
1602 "aliases not allowed in UniqueEnum: %r --> %r"
1603 % (a, e)
1604 )
1605 class Color(UniqueEnum):
1606 red = 1
1607 green = 2
1608 blue = 3
1609 with self.assertRaises(ValueError):
1610 class Color(UniqueEnum):
1611 red = 1
1612 green = 2
1613 blue = 3
1614 grene = 2
1615
1616 def test_init(self):
1617 class Planet(Enum):
1618 MERCURY = (3.303e+23, 2.4397e6)
1619 VENUS = (4.869e+24, 6.0518e6)
1620 EARTH = (5.976e+24, 6.37814e6)
1621 MARS = (6.421e+23, 3.3972e6)
1622 JUPITER = (1.9e+27, 7.1492e7)
1623 SATURN = (5.688e+26, 6.0268e7)
1624 URANUS = (8.686e+25, 2.5559e7)
1625 NEPTUNE = (1.024e+26, 2.4746e7)
1626 def __init__(self, mass, radius):
1627 self.mass = mass # in kilograms
1628 self.radius = radius # in meters
1629 @property
1630 def surface_gravity(self):
1631 # universal gravitational constant (m3 kg-1 s-2)
1632 G = 6.67300E-11
1633 return G * self.mass / (self.radius * self.radius)
1634 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1635 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1636
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001637 def test_ignore(self):
1638 class Period(timedelta, Enum):
1639 '''
1640 different lengths of time
1641 '''
1642 def __new__(cls, value, period):
1643 obj = timedelta.__new__(cls, value)
1644 obj._value_ = value
1645 obj.period = period
1646 return obj
1647 _ignore_ = 'Period i'
1648 Period = vars()
1649 for i in range(13):
1650 Period['month_%d' % i] = i*30, 'month'
1651 for i in range(53):
1652 Period['week_%d' % i] = i*7, 'week'
1653 for i in range(32):
1654 Period['day_%d' % i] = i, 'day'
1655 OneDay = day_1
1656 OneWeek = week_1
1657 OneMonth = month_1
1658 self.assertFalse(hasattr(Period, '_ignore_'))
1659 self.assertFalse(hasattr(Period, 'Period'))
1660 self.assertFalse(hasattr(Period, 'i'))
1661 self.assertTrue(isinstance(Period.day_1, timedelta))
1662 self.assertTrue(Period.month_1 is Period.day_30)
1663 self.assertTrue(Period.week_4 is Period.day_28)
1664
Ethan Furman2aa27322013-07-19 19:35:56 -07001665 def test_nonhash_value(self):
1666 class AutoNumberInAList(Enum):
1667 def __new__(cls):
1668 value = [len(cls.__members__) + 1]
1669 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001670 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001671 return obj
1672 class ColorInAList(AutoNumberInAList):
1673 red = ()
1674 green = ()
1675 blue = ()
1676 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001677 for enum, value in zip(ColorInAList, range(3)):
1678 value += 1
1679 self.assertEqual(enum.value, [value])
1680 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001681
Ethan Furmanb41803e2013-07-25 13:50:45 -07001682 def test_conflicting_types_resolved_in_new(self):
1683 class LabelledIntEnum(int, Enum):
1684 def __new__(cls, *args):
1685 value, label = args
1686 obj = int.__new__(cls, value)
1687 obj.label = label
1688 obj._value_ = value
1689 return obj
1690
1691 class LabelledList(LabelledIntEnum):
1692 unprocessed = (1, "Unprocessed")
1693 payment_complete = (2, "Payment Complete")
1694
1695 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1696 self.assertEqual(LabelledList.unprocessed, 1)
1697 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001698
Ethan Furmanc16595e2016-09-10 23:36:59 -07001699 def test_auto_number(self):
1700 class Color(Enum):
1701 red = auto()
1702 blue = auto()
1703 green = auto()
1704
1705 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1706 self.assertEqual(Color.red.value, 1)
1707 self.assertEqual(Color.blue.value, 2)
1708 self.assertEqual(Color.green.value, 3)
1709
1710 def test_auto_name(self):
1711 class Color(Enum):
1712 def _generate_next_value_(name, start, count, last):
1713 return name
1714 red = auto()
1715 blue = auto()
1716 green = auto()
1717
1718 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1719 self.assertEqual(Color.red.value, 'red')
1720 self.assertEqual(Color.blue.value, 'blue')
1721 self.assertEqual(Color.green.value, 'green')
1722
1723 def test_auto_name_inherit(self):
1724 class AutoNameEnum(Enum):
1725 def _generate_next_value_(name, start, count, last):
1726 return name
1727 class Color(AutoNameEnum):
1728 red = auto()
1729 blue = auto()
1730 green = auto()
1731
1732 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1733 self.assertEqual(Color.red.value, 'red')
1734 self.assertEqual(Color.blue.value, 'blue')
1735 self.assertEqual(Color.green.value, 'green')
1736
1737 def test_auto_garbage(self):
1738 class Color(Enum):
1739 red = 'red'
1740 blue = auto()
1741 self.assertEqual(Color.blue.value, 1)
1742
1743 def test_auto_garbage_corrected(self):
1744 class Color(Enum):
1745 red = 'red'
1746 blue = 2
1747 green = auto()
1748
1749 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1750 self.assertEqual(Color.red.value, 'red')
1751 self.assertEqual(Color.blue.value, 2)
1752 self.assertEqual(Color.green.value, 3)
1753
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001754 def test_auto_order(self):
1755 with self.assertRaises(TypeError):
1756 class Color(Enum):
1757 red = auto()
1758 green = auto()
1759 blue = auto()
1760 def _generate_next_value_(name, start, count, last):
1761 return name
1762
1763
Ethan Furman3515dcc2016-09-18 13:15:41 -07001764 def test_duplicate_auto(self):
1765 class Dupes(Enum):
1766 first = primero = auto()
1767 second = auto()
1768 third = auto()
1769 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1770
Ethan Furman019f0a02018-09-12 11:43:34 -07001771 def test_missing(self):
1772 class Color(Enum):
1773 red = 1
1774 green = 2
1775 blue = 3
1776 @classmethod
1777 def _missing_(cls, item):
1778 if item == 'three':
1779 return cls.blue
1780 elif item == 'bad return':
1781 # trigger internal error
1782 return 5
1783 elif item == 'error out':
1784 raise ZeroDivisionError
1785 else:
1786 # trigger not found
1787 return None
1788 self.assertIs(Color('three'), Color.blue)
1789 self.assertRaises(ValueError, Color, 7)
1790 try:
1791 Color('bad return')
1792 except TypeError as exc:
1793 self.assertTrue(isinstance(exc.__context__, ValueError))
1794 else:
1795 raise Exception('Exception not raised.')
1796 try:
1797 Color('error out')
1798 except ZeroDivisionError as exc:
1799 self.assertTrue(isinstance(exc.__context__, ValueError))
1800 else:
1801 raise Exception('Exception not raised.')
1802
Ethan Furman5bdab642018-09-21 19:03:09 -07001803 def test_multiple_mixin(self):
1804 class MaxMixin:
1805 @classproperty
1806 def MAX(cls):
1807 max = len(cls)
1808 cls.MAX = max
1809 return max
1810 class StrMixin:
1811 def __str__(self):
1812 return self._name_.lower()
1813 class SomeEnum(Enum):
1814 def behavior(self):
1815 return 'booyah'
1816 class AnotherEnum(Enum):
1817 def behavior(self):
1818 return 'nuhuh!'
1819 def social(self):
1820 return "what's up?"
1821 class Color(MaxMixin, Enum):
1822 RED = auto()
1823 GREEN = auto()
1824 BLUE = auto()
1825 self.assertEqual(Color.RED.value, 1)
1826 self.assertEqual(Color.GREEN.value, 2)
1827 self.assertEqual(Color.BLUE.value, 3)
1828 self.assertEqual(Color.MAX, 3)
1829 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1830 class Color(MaxMixin, StrMixin, Enum):
1831 RED = auto()
1832 GREEN = auto()
1833 BLUE = auto()
1834 self.assertEqual(Color.RED.value, 1)
1835 self.assertEqual(Color.GREEN.value, 2)
1836 self.assertEqual(Color.BLUE.value, 3)
1837 self.assertEqual(Color.MAX, 3)
1838 self.assertEqual(str(Color.BLUE), 'blue')
1839 class Color(StrMixin, MaxMixin, Enum):
1840 RED = auto()
1841 GREEN = auto()
1842 BLUE = auto()
1843 self.assertEqual(Color.RED.value, 1)
1844 self.assertEqual(Color.GREEN.value, 2)
1845 self.assertEqual(Color.BLUE.value, 3)
1846 self.assertEqual(Color.MAX, 3)
1847 self.assertEqual(str(Color.BLUE), 'blue')
1848 class CoolColor(StrMixin, SomeEnum, Enum):
1849 RED = auto()
1850 GREEN = auto()
1851 BLUE = auto()
1852 self.assertEqual(CoolColor.RED.value, 1)
1853 self.assertEqual(CoolColor.GREEN.value, 2)
1854 self.assertEqual(CoolColor.BLUE.value, 3)
1855 self.assertEqual(str(CoolColor.BLUE), 'blue')
1856 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1857 class CoolerColor(StrMixin, AnotherEnum, Enum):
1858 RED = auto()
1859 GREEN = auto()
1860 BLUE = auto()
1861 self.assertEqual(CoolerColor.RED.value, 1)
1862 self.assertEqual(CoolerColor.GREEN.value, 2)
1863 self.assertEqual(CoolerColor.BLUE.value, 3)
1864 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1865 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1866 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1867 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1868 RED = auto()
1869 GREEN = auto()
1870 BLUE = auto()
1871 self.assertEqual(CoolestColor.RED.value, 1)
1872 self.assertEqual(CoolestColor.GREEN.value, 2)
1873 self.assertEqual(CoolestColor.BLUE.value, 3)
1874 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1875 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1876 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1877 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1878 RED = auto()
1879 GREEN = auto()
1880 BLUE = auto()
1881 self.assertEqual(ConfusedColor.RED.value, 1)
1882 self.assertEqual(ConfusedColor.GREEN.value, 2)
1883 self.assertEqual(ConfusedColor.BLUE.value, 3)
1884 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1885 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1886 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1887 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1888 RED = auto()
1889 GREEN = auto()
1890 BLUE = auto()
1891 self.assertEqual(ReformedColor.RED.value, 1)
1892 self.assertEqual(ReformedColor.GREEN.value, 2)
1893 self.assertEqual(ReformedColor.BLUE.value, 3)
1894 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1895 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1896 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1897 self.assertTrue(issubclass(ReformedColor, int))
1898
Ethan Furmancd453852018-10-05 23:29:36 -07001899 def test_multiple_inherited_mixin(self):
1900 class StrEnum(str, Enum):
1901 def __new__(cls, *args, **kwargs):
1902 for a in args:
1903 if not isinstance(a, str):
1904 raise TypeError("Enumeration '%s' (%s) is not"
1905 " a string" % (a, type(a).__name__))
1906 return str.__new__(cls, *args, **kwargs)
1907 @unique
1908 class Decision1(StrEnum):
1909 REVERT = "REVERT"
1910 REVERT_ALL = "REVERT_ALL"
1911 RETRY = "RETRY"
1912 class MyEnum(StrEnum):
1913 pass
1914 @unique
1915 class Decision2(MyEnum):
1916 REVERT = "REVERT"
1917 REVERT_ALL = "REVERT_ALL"
1918 RETRY = "RETRY"
1919
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001920 def test_empty_globals(self):
1921 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1922 # when using compile and exec because f_globals is empty
1923 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1924 code = compile(code, "<string>", "exec")
1925 global_ns = {}
1926 local_ls = {}
1927 exec(code, global_ns, local_ls)
1928
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001929
Ethan Furmane8e61272016-08-20 07:19:31 -07001930class TestOrder(unittest.TestCase):
1931
1932 def test_same_members(self):
1933 class Color(Enum):
1934 _order_ = 'red green blue'
1935 red = 1
1936 green = 2
1937 blue = 3
1938
1939 def test_same_members_with_aliases(self):
1940 class Color(Enum):
1941 _order_ = 'red green blue'
1942 red = 1
1943 green = 2
1944 blue = 3
1945 verde = green
1946
1947 def test_same_members_wrong_order(self):
1948 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1949 class Color(Enum):
1950 _order_ = 'red green blue'
1951 red = 1
1952 blue = 3
1953 green = 2
1954
1955 def test_order_has_extra_members(self):
1956 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1957 class Color(Enum):
1958 _order_ = 'red green blue purple'
1959 red = 1
1960 green = 2
1961 blue = 3
1962
1963 def test_order_has_extra_members_with_aliases(self):
1964 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1965 class Color(Enum):
1966 _order_ = 'red green blue purple'
1967 red = 1
1968 green = 2
1969 blue = 3
1970 verde = green
1971
1972 def test_enum_has_extra_members(self):
1973 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1974 class Color(Enum):
1975 _order_ = 'red green blue'
1976 red = 1
1977 green = 2
1978 blue = 3
1979 purple = 4
1980
1981 def test_enum_has_extra_members_with_aliases(self):
1982 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1983 class Color(Enum):
1984 _order_ = 'red green blue'
1985 red = 1
1986 green = 2
1987 blue = 3
1988 purple = 4
1989 verde = green
1990
1991
Ethan Furman65a5a472016-09-01 23:55:19 -07001992class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001993 """Tests of the Flags."""
1994
Ethan Furman65a5a472016-09-01 23:55:19 -07001995 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001996 R, W, X = 4, 2, 1
1997
Ethan Furman65a5a472016-09-01 23:55:19 -07001998 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001999 RO = 0
2000 WO = 1
2001 RW = 2
2002 AC = 3
2003 CE = 1<<19
2004
Rahul Jha94306522018-09-10 23:51:04 +05302005 class Color(Flag):
2006 BLACK = 0
2007 RED = 1
2008 GREEN = 2
2009 BLUE = 4
2010 PURPLE = RED|BLUE
2011
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002012 def test_str(self):
2013 Perm = self.Perm
2014 self.assertEqual(str(Perm.R), 'Perm.R')
2015 self.assertEqual(str(Perm.W), 'Perm.W')
2016 self.assertEqual(str(Perm.X), 'Perm.X')
2017 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2018 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2019 self.assertEqual(str(Perm(0)), 'Perm.0')
2020 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2021 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2022 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2023 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2024 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2025 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2026
2027 Open = self.Open
2028 self.assertEqual(str(Open.RO), 'Open.RO')
2029 self.assertEqual(str(Open.WO), 'Open.WO')
2030 self.assertEqual(str(Open.AC), 'Open.AC')
2031 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2032 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002033 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002034 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2035 self.assertEqual(str(~Open.AC), 'Open.CE')
2036 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2037 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2038
2039 def test_repr(self):
2040 Perm = self.Perm
2041 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2042 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2043 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2044 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2045 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002046 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002047 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2048 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2049 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2050 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002051 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002052 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2053
2054 Open = self.Open
2055 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2056 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2057 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2058 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2059 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002060 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002061 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2062 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2063 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2064 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2065
2066 def test_or(self):
2067 Perm = self.Perm
2068 for i in Perm:
2069 for j in Perm:
2070 self.assertEqual((i | j), Perm(i.value | j.value))
2071 self.assertEqual((i | j).value, i.value | j.value)
2072 self.assertIs(type(i | j), Perm)
2073 for i in Perm:
2074 self.assertIs(i | i, i)
2075 Open = self.Open
2076 self.assertIs(Open.RO | Open.CE, Open.CE)
2077
2078 def test_and(self):
2079 Perm = self.Perm
2080 RW = Perm.R | Perm.W
2081 RX = Perm.R | Perm.X
2082 WX = Perm.W | Perm.X
2083 RWX = Perm.R | Perm.W | Perm.X
2084 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2085 for i in values:
2086 for j in values:
2087 self.assertEqual((i & j).value, i.value & j.value)
2088 self.assertIs(type(i & j), Perm)
2089 for i in Perm:
2090 self.assertIs(i & i, i)
2091 self.assertIs(i & RWX, i)
2092 self.assertIs(RWX & i, i)
2093 Open = self.Open
2094 self.assertIs(Open.RO & Open.CE, Open.RO)
2095
2096 def test_xor(self):
2097 Perm = self.Perm
2098 for i in Perm:
2099 for j in Perm:
2100 self.assertEqual((i ^ j).value, i.value ^ j.value)
2101 self.assertIs(type(i ^ j), Perm)
2102 for i in Perm:
2103 self.assertIs(i ^ Perm(0), i)
2104 self.assertIs(Perm(0) ^ i, i)
2105 Open = self.Open
2106 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2107 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2108
2109 def test_invert(self):
2110 Perm = self.Perm
2111 RW = Perm.R | Perm.W
2112 RX = Perm.R | Perm.X
2113 WX = Perm.W | Perm.X
2114 RWX = Perm.R | Perm.W | Perm.X
2115 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2116 for i in values:
2117 self.assertIs(type(~i), Perm)
2118 self.assertEqual(~~i, i)
2119 for i in Perm:
2120 self.assertIs(~~i, i)
2121 Open = self.Open
2122 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2123 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2124
Ethan Furman25d94bb2016-09-02 16:32:32 -07002125 def test_bool(self):
2126 Perm = self.Perm
2127 for f in Perm:
2128 self.assertTrue(f)
2129 Open = self.Open
2130 for f in Open:
2131 self.assertEqual(bool(f.value), bool(f))
2132
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002133 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002134 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002135 lst = list(Perm)
2136 self.assertEqual(len(lst), len(Perm))
2137 self.assertEqual(len(Perm), 3, Perm)
2138 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2139 for i, n in enumerate('R W X'.split()):
2140 v = 1<<i
2141 e = Perm(v)
2142 self.assertEqual(e.value, v)
2143 self.assertEqual(type(e.value), int)
2144 self.assertEqual(e.name, n)
2145 self.assertIn(e, Perm)
2146 self.assertIs(type(e), Perm)
2147
2148 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002149 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002150 lst = list(Perm)
2151 self.assertEqual(len(lst), len(Perm))
2152 self.assertEqual(len(Perm), 3, Perm)
2153 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2154 for i, n in enumerate('R W X'.split()):
2155 v = 8<<i
2156 e = Perm(v)
2157 self.assertEqual(e.value, v)
2158 self.assertEqual(type(e.value), int)
2159 self.assertEqual(e.name, n)
2160 self.assertIn(e, Perm)
2161 self.assertIs(type(e), Perm)
2162
2163 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002164 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002165 lst = list(Perm)
2166 self.assertEqual(len(lst), len(Perm))
2167 self.assertEqual(len(Perm), 3, Perm)
2168 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2169 for i, n in enumerate('R W X'.split()):
2170 v = 1<<i
2171 e = Perm(v)
2172 self.assertEqual(e.value, v)
2173 self.assertEqual(type(e.value), int)
2174 self.assertEqual(e.name, n)
2175 self.assertIn(e, Perm)
2176 self.assertIs(type(e), Perm)
2177
2178 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002179 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002180 lst = list(Perm)
2181 self.assertEqual(len(lst), len(Perm))
2182 self.assertEqual(len(Perm), 3, Perm)
2183 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2184 for i, n in enumerate('R W X'.split()):
2185 v = 1<<(2*i+1)
2186 e = Perm(v)
2187 self.assertEqual(e.value, v)
2188 self.assertEqual(type(e.value), int)
2189 self.assertEqual(e.name, n)
2190 self.assertIn(e, Perm)
2191 self.assertIs(type(e), Perm)
2192
2193 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002194 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002195 lst = list(Perm)
2196 self.assertEqual(len(lst), len(Perm))
2197 self.assertEqual(len(Perm), 3, Perm)
2198 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2199 for i, n in enumerate('R W X'.split()):
2200 v = 1<<(2*i+1)
2201 e = Perm(v)
2202 self.assertEqual(e.value, v)
2203 self.assertEqual(type(e.value), int)
2204 self.assertEqual(e.name, n)
2205 self.assertIn(e, Perm)
2206 self.assertIs(type(e), Perm)
2207
Ethan Furman65a5a472016-09-01 23:55:19 -07002208 def test_pickle(self):
2209 if isinstance(FlagStooges, Exception):
2210 raise FlagStooges
2211 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2212 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002213
Rahul Jha94306522018-09-10 23:51:04 +05302214 def test_contains(self):
2215 Open = self.Open
2216 Color = self.Color
2217 self.assertFalse(Color.BLACK in Open)
2218 self.assertFalse(Open.RO in Color)
2219 with self.assertRaises(TypeError):
2220 'BLACK' in Color
2221 with self.assertRaises(TypeError):
2222 'RO' in Open
2223 with self.assertRaises(TypeError):
2224 1 in Color
2225 with self.assertRaises(TypeError):
2226 1 in Open
2227
2228 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002229 Perm = self.Perm
2230 R, W, X = Perm
2231 RW = R | W
2232 RX = R | X
2233 WX = W | X
2234 RWX = R | W | X
2235 self.assertTrue(R in RW)
2236 self.assertTrue(R in RX)
2237 self.assertTrue(R in RWX)
2238 self.assertTrue(W in RW)
2239 self.assertTrue(W in WX)
2240 self.assertTrue(W in RWX)
2241 self.assertTrue(X in RX)
2242 self.assertTrue(X in WX)
2243 self.assertTrue(X in RWX)
2244 self.assertFalse(R in WX)
2245 self.assertFalse(W in RX)
2246 self.assertFalse(X in RW)
2247
Ethan Furmanc16595e2016-09-10 23:36:59 -07002248 def test_auto_number(self):
2249 class Color(Flag):
2250 red = auto()
2251 blue = auto()
2252 green = auto()
2253
2254 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2255 self.assertEqual(Color.red.value, 1)
2256 self.assertEqual(Color.blue.value, 2)
2257 self.assertEqual(Color.green.value, 4)
2258
2259 def test_auto_number_garbage(self):
2260 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2261 class Color(Flag):
2262 red = 'not an int'
2263 blue = auto()
2264
Ethan Furman3515dcc2016-09-18 13:15:41 -07002265 def test_cascading_failure(self):
2266 class Bizarre(Flag):
2267 c = 3
2268 d = 4
2269 f = 6
2270 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002271 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2272 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2273 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2274 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2275 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2276 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2277 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002278
2279 def test_duplicate_auto(self):
2280 class Dupes(Enum):
2281 first = primero = auto()
2282 second = auto()
2283 third = auto()
2284 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2285
2286 def test_bizarre(self):
2287 class Bizarre(Flag):
2288 b = 3
2289 c = 4
2290 d = 6
2291 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2292
Ethan Furman5bdab642018-09-21 19:03:09 -07002293 def test_multiple_mixin(self):
2294 class AllMixin:
2295 @classproperty
2296 def ALL(cls):
2297 members = list(cls)
2298 all_value = None
2299 if members:
2300 all_value = members[0]
2301 for member in members[1:]:
2302 all_value |= member
2303 cls.ALL = all_value
2304 return all_value
2305 class StrMixin:
2306 def __str__(self):
2307 return self._name_.lower()
2308 class Color(AllMixin, Flag):
2309 RED = auto()
2310 GREEN = auto()
2311 BLUE = auto()
2312 self.assertEqual(Color.RED.value, 1)
2313 self.assertEqual(Color.GREEN.value, 2)
2314 self.assertEqual(Color.BLUE.value, 4)
2315 self.assertEqual(Color.ALL.value, 7)
2316 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2317 class Color(AllMixin, StrMixin, Flag):
2318 RED = auto()
2319 GREEN = auto()
2320 BLUE = auto()
2321 self.assertEqual(Color.RED.value, 1)
2322 self.assertEqual(Color.GREEN.value, 2)
2323 self.assertEqual(Color.BLUE.value, 4)
2324 self.assertEqual(Color.ALL.value, 7)
2325 self.assertEqual(str(Color.BLUE), 'blue')
2326 class Color(StrMixin, AllMixin, Flag):
2327 RED = auto()
2328 GREEN = auto()
2329 BLUE = auto()
2330 self.assertEqual(Color.RED.value, 1)
2331 self.assertEqual(Color.GREEN.value, 2)
2332 self.assertEqual(Color.BLUE.value, 4)
2333 self.assertEqual(Color.ALL.value, 7)
2334 self.assertEqual(str(Color.BLUE), 'blue')
2335
Ethan Furman28cf6632017-01-24 12:12:06 -08002336 @support.reap_threads
2337 def test_unique_composite(self):
2338 # override __eq__ to be identity only
2339 class TestFlag(Flag):
2340 one = auto()
2341 two = auto()
2342 three = auto()
2343 four = auto()
2344 five = auto()
2345 six = auto()
2346 seven = auto()
2347 eight = auto()
2348 def __eq__(self, other):
2349 return self is other
2350 def __hash__(self):
2351 return hash(self._value_)
2352 # have multiple threads competing to complete the composite members
2353 seen = set()
2354 failed = False
2355 def cycle_enum():
2356 nonlocal failed
2357 try:
2358 for i in range(256):
2359 seen.add(TestFlag(i))
2360 except Exception:
2361 failed = True
2362 threads = [
2363 threading.Thread(target=cycle_enum)
2364 for _ in range(8)
2365 ]
2366 with support.start_threads(threads):
2367 pass
2368 # check that only 248 members were created
2369 self.assertFalse(
2370 failed,
2371 'at least one thread failed while creating composite members')
2372 self.assertEqual(256, len(seen), 'too many composite members created')
2373
Ethan Furmanc16595e2016-09-10 23:36:59 -07002374
Ethan Furman65a5a472016-09-01 23:55:19 -07002375class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002376 """Tests of the IntFlags."""
2377
Ethan Furman65a5a472016-09-01 23:55:19 -07002378 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002379 X = 1 << 0
2380 W = 1 << 1
2381 R = 1 << 2
2382
Ethan Furman65a5a472016-09-01 23:55:19 -07002383 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002384 RO = 0
2385 WO = 1
2386 RW = 2
2387 AC = 3
2388 CE = 1<<19
2389
Rahul Jha94306522018-09-10 23:51:04 +05302390 class Color(IntFlag):
2391 BLACK = 0
2392 RED = 1
2393 GREEN = 2
2394 BLUE = 4
2395 PURPLE = RED|BLUE
2396
Ethan Furman3515dcc2016-09-18 13:15:41 -07002397 def test_type(self):
2398 Perm = self.Perm
2399 Open = self.Open
2400 for f in Perm:
2401 self.assertTrue(isinstance(f, Perm))
2402 self.assertEqual(f, f.value)
2403 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2404 self.assertEqual(Perm.W | Perm.X, 3)
2405 for f in Open:
2406 self.assertTrue(isinstance(f, Open))
2407 self.assertEqual(f, f.value)
2408 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2409 self.assertEqual(Open.WO | Open.RW, 3)
2410
2411
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002412 def test_str(self):
2413 Perm = self.Perm
2414 self.assertEqual(str(Perm.R), 'Perm.R')
2415 self.assertEqual(str(Perm.W), 'Perm.W')
2416 self.assertEqual(str(Perm.X), 'Perm.X')
2417 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2418 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2419 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2420 self.assertEqual(str(Perm(0)), 'Perm.0')
2421 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002422 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2423 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2424 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2425 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002426 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002427 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2428 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2429 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002430
2431 Open = self.Open
2432 self.assertEqual(str(Open.RO), 'Open.RO')
2433 self.assertEqual(str(Open.WO), 'Open.WO')
2434 self.assertEqual(str(Open.AC), 'Open.AC')
2435 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2436 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2437 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002438 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2439 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2440 self.assertEqual(str(~Open.AC), 'Open.CE')
2441 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2442 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2443 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002444
2445 def test_repr(self):
2446 Perm = self.Perm
2447 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2448 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2449 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2450 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2451 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2452 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002453 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2454 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002455 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2456 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2457 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2458 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002459 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002460 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2461 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2462 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002463
2464 Open = self.Open
2465 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2466 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2467 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2468 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2469 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002470 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002471 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2472 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2473 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2474 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2475 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2476 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002477
2478 def test_or(self):
2479 Perm = self.Perm
2480 for i in Perm:
2481 for j in Perm:
2482 self.assertEqual(i | j, i.value | j.value)
2483 self.assertEqual((i | j).value, i.value | j.value)
2484 self.assertIs(type(i | j), Perm)
2485 for j in range(8):
2486 self.assertEqual(i | j, i.value | j)
2487 self.assertEqual((i | j).value, i.value | j)
2488 self.assertIs(type(i | j), Perm)
2489 self.assertEqual(j | i, j | i.value)
2490 self.assertEqual((j | i).value, j | i.value)
2491 self.assertIs(type(j | i), Perm)
2492 for i in Perm:
2493 self.assertIs(i | i, i)
2494 self.assertIs(i | 0, i)
2495 self.assertIs(0 | i, i)
2496 Open = self.Open
2497 self.assertIs(Open.RO | Open.CE, Open.CE)
2498
2499 def test_and(self):
2500 Perm = self.Perm
2501 RW = Perm.R | Perm.W
2502 RX = Perm.R | Perm.X
2503 WX = Perm.W | Perm.X
2504 RWX = Perm.R | Perm.W | Perm.X
2505 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2506 for i in values:
2507 for j in values:
2508 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2509 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2510 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2511 for j in range(8):
2512 self.assertEqual(i & j, i.value & j)
2513 self.assertEqual((i & j).value, i.value & j)
2514 self.assertIs(type(i & j), Perm)
2515 self.assertEqual(j & i, j & i.value)
2516 self.assertEqual((j & i).value, j & i.value)
2517 self.assertIs(type(j & i), Perm)
2518 for i in Perm:
2519 self.assertIs(i & i, i)
2520 self.assertIs(i & 7, i)
2521 self.assertIs(7 & i, i)
2522 Open = self.Open
2523 self.assertIs(Open.RO & Open.CE, Open.RO)
2524
2525 def test_xor(self):
2526 Perm = self.Perm
2527 for i in Perm:
2528 for j in Perm:
2529 self.assertEqual(i ^ j, i.value ^ j.value)
2530 self.assertEqual((i ^ j).value, i.value ^ j.value)
2531 self.assertIs(type(i ^ j), Perm)
2532 for j in range(8):
2533 self.assertEqual(i ^ j, i.value ^ j)
2534 self.assertEqual((i ^ j).value, i.value ^ j)
2535 self.assertIs(type(i ^ j), Perm)
2536 self.assertEqual(j ^ i, j ^ i.value)
2537 self.assertEqual((j ^ i).value, j ^ i.value)
2538 self.assertIs(type(j ^ i), Perm)
2539 for i in Perm:
2540 self.assertIs(i ^ 0, i)
2541 self.assertIs(0 ^ i, i)
2542 Open = self.Open
2543 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2544 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2545
2546 def test_invert(self):
2547 Perm = self.Perm
2548 RW = Perm.R | Perm.W
2549 RX = Perm.R | Perm.X
2550 WX = Perm.W | Perm.X
2551 RWX = Perm.R | Perm.W | Perm.X
2552 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2553 for i in values:
2554 self.assertEqual(~i, ~i.value)
2555 self.assertEqual((~i).value, ~i.value)
2556 self.assertIs(type(~i), Perm)
2557 self.assertEqual(~~i, i)
2558 for i in Perm:
2559 self.assertIs(~~i, i)
2560 Open = self.Open
2561 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2562 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2563
2564 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002565 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002566 lst = list(Perm)
2567 self.assertEqual(len(lst), len(Perm))
2568 self.assertEqual(len(Perm), 3, Perm)
2569 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2570 for i, n in enumerate('R W X'.split()):
2571 v = 1<<i
2572 e = Perm(v)
2573 self.assertEqual(e.value, v)
2574 self.assertEqual(type(e.value), int)
2575 self.assertEqual(e, v)
2576 self.assertEqual(e.name, n)
2577 self.assertIn(e, Perm)
2578 self.assertIs(type(e), Perm)
2579
2580 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002581 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002582 lst = list(Perm)
2583 self.assertEqual(len(lst), len(Perm))
2584 self.assertEqual(len(Perm), 3, Perm)
2585 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2586 for i, n in enumerate('R W X'.split()):
2587 v = 8<<i
2588 e = Perm(v)
2589 self.assertEqual(e.value, v)
2590 self.assertEqual(type(e.value), int)
2591 self.assertEqual(e, v)
2592 self.assertEqual(e.name, n)
2593 self.assertIn(e, Perm)
2594 self.assertIs(type(e), Perm)
2595
2596 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002597 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002598 lst = list(Perm)
2599 self.assertEqual(len(lst), len(Perm))
2600 self.assertEqual(len(Perm), 3, Perm)
2601 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2602 for i, n in enumerate('R W X'.split()):
2603 v = 1<<i
2604 e = Perm(v)
2605 self.assertEqual(e.value, v)
2606 self.assertEqual(type(e.value), int)
2607 self.assertEqual(e, v)
2608 self.assertEqual(e.name, n)
2609 self.assertIn(e, Perm)
2610 self.assertIs(type(e), Perm)
2611
2612 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002613 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002614 lst = list(Perm)
2615 self.assertEqual(len(lst), len(Perm))
2616 self.assertEqual(len(Perm), 3, Perm)
2617 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2618 for i, n in enumerate('R W X'.split()):
2619 v = 1<<(2*i+1)
2620 e = Perm(v)
2621 self.assertEqual(e.value, v)
2622 self.assertEqual(type(e.value), int)
2623 self.assertEqual(e, v)
2624 self.assertEqual(e.name, n)
2625 self.assertIn(e, Perm)
2626 self.assertIs(type(e), Perm)
2627
2628 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002629 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002630 lst = list(Perm)
2631 self.assertEqual(len(lst), len(Perm))
2632 self.assertEqual(len(Perm), 3, Perm)
2633 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2634 for i, n in enumerate('R W X'.split()):
2635 v = 1<<(2*i+1)
2636 e = Perm(v)
2637 self.assertEqual(e.value, v)
2638 self.assertEqual(type(e.value), int)
2639 self.assertEqual(e, v)
2640 self.assertEqual(e.name, n)
2641 self.assertIn(e, Perm)
2642 self.assertIs(type(e), Perm)
2643
2644
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002645 def test_programatic_function_from_empty_list(self):
2646 Perm = enum.IntFlag('Perm', [])
2647 lst = list(Perm)
2648 self.assertEqual(len(lst), len(Perm))
2649 self.assertEqual(len(Perm), 0, Perm)
2650 Thing = enum.Enum('Thing', [])
2651 lst = list(Thing)
2652 self.assertEqual(len(lst), len(Thing))
2653 self.assertEqual(len(Thing), 0, Thing)
2654
2655
2656 def test_programatic_function_from_empty_tuple(self):
2657 Perm = enum.IntFlag('Perm', ())
2658 lst = list(Perm)
2659 self.assertEqual(len(lst), len(Perm))
2660 self.assertEqual(len(Perm), 0, Perm)
2661 Thing = enum.Enum('Thing', ())
2662 self.assertEqual(len(lst), len(Thing))
2663 self.assertEqual(len(Thing), 0, Thing)
2664
Rahul Jha94306522018-09-10 23:51:04 +05302665 def test_contains(self):
2666 Open = self.Open
2667 Color = self.Color
2668 self.assertTrue(Color.GREEN in Color)
2669 self.assertTrue(Open.RW in Open)
2670 self.assertFalse(Color.GREEN in Open)
2671 self.assertFalse(Open.RW in Color)
2672 with self.assertRaises(TypeError):
2673 'GREEN' in Color
2674 with self.assertRaises(TypeError):
2675 'RW' in Open
2676 with self.assertRaises(TypeError):
2677 2 in Color
2678 with self.assertRaises(TypeError):
2679 2 in Open
2680
2681 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002682 Perm = self.Perm
2683 R, W, X = Perm
2684 RW = R | W
2685 RX = R | X
2686 WX = W | X
2687 RWX = R | W | X
2688 self.assertTrue(R in RW)
2689 self.assertTrue(R in RX)
2690 self.assertTrue(R in RWX)
2691 self.assertTrue(W in RW)
2692 self.assertTrue(W in WX)
2693 self.assertTrue(W in RWX)
2694 self.assertTrue(X in RX)
2695 self.assertTrue(X in WX)
2696 self.assertTrue(X in RWX)
2697 self.assertFalse(R in WX)
2698 self.assertFalse(W in RX)
2699 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302700 with self.assertRaises(TypeError):
2701 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002702
Ethan Furman25d94bb2016-09-02 16:32:32 -07002703 def test_bool(self):
2704 Perm = self.Perm
2705 for f in Perm:
2706 self.assertTrue(f)
2707 Open = self.Open
2708 for f in Open:
2709 self.assertEqual(bool(f.value), bool(f))
2710
Ethan Furman5bdab642018-09-21 19:03:09 -07002711 def test_multiple_mixin(self):
2712 class AllMixin:
2713 @classproperty
2714 def ALL(cls):
2715 members = list(cls)
2716 all_value = None
2717 if members:
2718 all_value = members[0]
2719 for member in members[1:]:
2720 all_value |= member
2721 cls.ALL = all_value
2722 return all_value
2723 class StrMixin:
2724 def __str__(self):
2725 return self._name_.lower()
2726 class Color(AllMixin, IntFlag):
2727 RED = auto()
2728 GREEN = auto()
2729 BLUE = auto()
2730 self.assertEqual(Color.RED.value, 1)
2731 self.assertEqual(Color.GREEN.value, 2)
2732 self.assertEqual(Color.BLUE.value, 4)
2733 self.assertEqual(Color.ALL.value, 7)
2734 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2735 class Color(AllMixin, StrMixin, IntFlag):
2736 RED = auto()
2737 GREEN = auto()
2738 BLUE = auto()
2739 self.assertEqual(Color.RED.value, 1)
2740 self.assertEqual(Color.GREEN.value, 2)
2741 self.assertEqual(Color.BLUE.value, 4)
2742 self.assertEqual(Color.ALL.value, 7)
2743 self.assertEqual(str(Color.BLUE), 'blue')
2744 class Color(StrMixin, AllMixin, IntFlag):
2745 RED = auto()
2746 GREEN = auto()
2747 BLUE = auto()
2748 self.assertEqual(Color.RED.value, 1)
2749 self.assertEqual(Color.GREEN.value, 2)
2750 self.assertEqual(Color.BLUE.value, 4)
2751 self.assertEqual(Color.ALL.value, 7)
2752 self.assertEqual(str(Color.BLUE), 'blue')
2753
Ethan Furman28cf6632017-01-24 12:12:06 -08002754 @support.reap_threads
2755 def test_unique_composite(self):
2756 # override __eq__ to be identity only
2757 class TestFlag(IntFlag):
2758 one = auto()
2759 two = auto()
2760 three = auto()
2761 four = auto()
2762 five = auto()
2763 six = auto()
2764 seven = auto()
2765 eight = auto()
2766 def __eq__(self, other):
2767 return self is other
2768 def __hash__(self):
2769 return hash(self._value_)
2770 # have multiple threads competing to complete the composite members
2771 seen = set()
2772 failed = False
2773 def cycle_enum():
2774 nonlocal failed
2775 try:
2776 for i in range(256):
2777 seen.add(TestFlag(i))
2778 except Exception:
2779 failed = True
2780 threads = [
2781 threading.Thread(target=cycle_enum)
2782 for _ in range(8)
2783 ]
2784 with support.start_threads(threads):
2785 pass
2786 # check that only 248 members were created
2787 self.assertFalse(
2788 failed,
2789 'at least one thread failed while creating composite members')
2790 self.assertEqual(256, len(seen), 'too many composite members created')
2791
2792
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002793class TestEmptyAndNonLatinStrings(unittest.TestCase):
2794
2795 def test_empty_string(self):
2796 with self.assertRaises(ValueError):
2797 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2798
2799 def test_non_latin_character_string(self):
2800 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2801 item = getattr(greek_abc, '\u03B1')
2802 self.assertEqual(item.value, 1)
2803
2804 def test_non_latin_number_string(self):
2805 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2806 item = getattr(hebrew_123, '\u05D0')
2807 self.assertEqual(item.value, 1)
2808
2809
Ethan Furmanf24bb352013-07-18 17:05:39 -07002810class TestUnique(unittest.TestCase):
2811
2812 def test_unique_clean(self):
2813 @unique
2814 class Clean(Enum):
2815 one = 1
2816 two = 'dos'
2817 tres = 4.0
2818 @unique
2819 class Cleaner(IntEnum):
2820 single = 1
2821 double = 2
2822 triple = 3
2823
2824 def test_unique_dirty(self):
2825 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2826 @unique
2827 class Dirty(Enum):
2828 one = 1
2829 two = 'dos'
2830 tres = 1
2831 with self.assertRaisesRegex(
2832 ValueError,
2833 'double.*single.*turkey.*triple',
2834 ):
2835 @unique
2836 class Dirtier(IntEnum):
2837 single = 1
2838 double = 1
2839 triple = 3
2840 turkey = 3
2841
Ethan Furman3803ad42016-05-01 10:03:53 -07002842 def test_unique_with_name(self):
2843 @unique
2844 class Silly(Enum):
2845 one = 1
2846 two = 'dos'
2847 name = 3
2848 @unique
2849 class Sillier(IntEnum):
2850 single = 1
2851 name = 2
2852 triple = 3
2853 value = 4
2854
Ethan Furmanf24bb352013-07-18 17:05:39 -07002855
Ethan Furman5bdab642018-09-21 19:03:09 -07002856
Ethan Furman3323da92015-04-11 09:39:59 -07002857expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002858Help on class Color in module %s:
2859
2860class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002861 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2862 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002863 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002864 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002865 | Method resolution order:
2866 | Color
2867 | enum.Enum
2868 | builtins.object
2869 |\x20\x20
2870 | Data and other attributes defined here:
2871 |\x20\x20
2872 | blue = <Color.blue: 3>
2873 |\x20\x20
2874 | green = <Color.green: 2>
2875 |\x20\x20
2876 | red = <Color.red: 1>
2877 |\x20\x20
2878 | ----------------------------------------------------------------------
2879 | Data descriptors inherited from enum.Enum:
2880 |\x20\x20
2881 | name
2882 | The name of the Enum member.
2883 |\x20\x20
2884 | value
2885 | The value of the Enum member.
2886 |\x20\x20
2887 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002888 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002889 |\x20\x20
2890 | __members__
2891 | Returns a mapping of member name->value.
2892 |\x20\x20\x20\x20\x20\x20
2893 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002894 | is a read-only view of the internal mapping."""
2895
2896expected_help_output_without_docs = """\
2897Help on class Color in module %s:
2898
2899class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002900 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2901 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002902 | Method resolution order:
2903 | Color
2904 | enum.Enum
2905 | builtins.object
2906 |\x20\x20
2907 | Data and other attributes defined here:
2908 |\x20\x20
2909 | blue = <Color.blue: 3>
2910 |\x20\x20
2911 | green = <Color.green: 2>
2912 |\x20\x20
2913 | red = <Color.red: 1>
2914 |\x20\x20
2915 | ----------------------------------------------------------------------
2916 | Data descriptors inherited from enum.Enum:
2917 |\x20\x20
2918 | name
2919 |\x20\x20
2920 | value
2921 |\x20\x20
2922 | ----------------------------------------------------------------------
2923 | Data descriptors inherited from enum.EnumMeta:
2924 |\x20\x20
2925 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002926
2927class TestStdLib(unittest.TestCase):
2928
Ethan Furman48a724f2015-04-11 23:23:06 -07002929 maxDiff = None
2930
Ethan Furman5875d742013-10-21 20:45:55 -07002931 class Color(Enum):
2932 red = 1
2933 green = 2
2934 blue = 3
2935
2936 def test_pydoc(self):
2937 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002938 if StrEnum.__doc__ is None:
2939 expected_text = expected_help_output_without_docs % __name__
2940 else:
2941 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002942 output = StringIO()
2943 helper = pydoc.Helper(output=output)
2944 helper(self.Color)
2945 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002946 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002947
2948 def test_inspect_getmembers(self):
2949 values = dict((
2950 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002951 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002952 ('__members__', self.Color.__members__),
2953 ('__module__', __name__),
2954 ('blue', self.Color.blue),
2955 ('green', self.Color.green),
2956 ('name', Enum.__dict__['name']),
2957 ('red', self.Color.red),
2958 ('value', Enum.__dict__['value']),
2959 ))
2960 result = dict(inspect.getmembers(self.Color))
2961 self.assertEqual(values.keys(), result.keys())
2962 failed = False
2963 for k in values.keys():
2964 if result[k] != values[k]:
2965 print()
2966 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2967 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2968 failed = True
2969 if failed:
2970 self.fail("result does not equal expected, see print above")
2971
2972 def test_inspect_classify_class_attrs(self):
2973 # indirectly test __objclass__
2974 from inspect import Attribute
2975 values = [
2976 Attribute(name='__class__', kind='data',
2977 defining_class=object, object=EnumMeta),
2978 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002979 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002980 Attribute(name='__members__', kind='property',
2981 defining_class=EnumMeta, object=EnumMeta.__members__),
2982 Attribute(name='__module__', kind='data',
2983 defining_class=self.Color, object=__name__),
2984 Attribute(name='blue', kind='data',
2985 defining_class=self.Color, object=self.Color.blue),
2986 Attribute(name='green', kind='data',
2987 defining_class=self.Color, object=self.Color.green),
2988 Attribute(name='red', kind='data',
2989 defining_class=self.Color, object=self.Color.red),
2990 Attribute(name='name', kind='data',
2991 defining_class=Enum, object=Enum.__dict__['name']),
2992 Attribute(name='value', kind='data',
2993 defining_class=Enum, object=Enum.__dict__['value']),
2994 ]
2995 values.sort(key=lambda item: item.name)
2996 result = list(inspect.classify_class_attrs(self.Color))
2997 result.sort(key=lambda item: item.name)
2998 failed = False
2999 for v, r in zip(values, result):
3000 if r != v:
3001 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3002 failed = True
3003 if failed:
3004 self.fail("result does not equal expected, see print above")
3005
Martin Panter19e69c52015-11-14 12:46:42 +00003006
3007class MiscTestCase(unittest.TestCase):
3008 def test__all__(self):
3009 support.check__all__(self, enum)
3010
3011
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003012# These are unordered here on purpose to ensure that declaration order
3013# makes no difference.
3014CONVERT_TEST_NAME_D = 5
3015CONVERT_TEST_NAME_C = 5
3016CONVERT_TEST_NAME_B = 5
3017CONVERT_TEST_NAME_A = 5 # This one should sort first.
3018CONVERT_TEST_NAME_E = 5
3019CONVERT_TEST_NAME_F = 5
3020
3021class TestIntEnumConvert(unittest.TestCase):
3022 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003023 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003024 'UnittestConvert',
3025 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003026 filter=lambda x: x.startswith('CONVERT_TEST_'))
3027 # We don't want the reverse lookup value to vary when there are
3028 # multiple possible names for a given value. It should always
3029 # report the first lexigraphical name in that case.
3030 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3031
3032 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003033 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003034 'UnittestConvert',
3035 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003036 filter=lambda x: x.startswith('CONVERT_TEST_'))
3037 # Ensure that test_type has all of the desired names and values.
3038 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3039 test_type.CONVERT_TEST_NAME_A)
3040 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3041 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3042 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3043 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3044 # Ensure that test_type only picked up names matching the filter.
3045 self.assertEqual([name for name in dir(test_type)
3046 if name[0:2] not in ('CO', '__')],
3047 [], msg='Names other than CONVERT_TEST_* found.')
3048
orlnub1230fb9fad2018-09-12 20:28:53 +03003049 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3050 '_convert was deprecated in 3.8')
3051 def test_convert_warn(self):
3052 with self.assertWarns(DeprecationWarning):
3053 enum.IntEnum._convert(
3054 'UnittestConvert',
3055 ('test.test_enum', '__main__')[__name__=='__main__'],
3056 filter=lambda x: x.startswith('CONVERT_TEST_'))
3057
3058 @unittest.skipUnless(sys.version_info >= (3, 9),
3059 '_convert was removed in 3.9')
3060 def test_convert_raise(self):
3061 with self.assertRaises(AttributeError):
3062 enum.IntEnum._convert(
3063 'UnittestConvert',
3064 ('test.test_enum', '__main__')[__name__=='__main__'],
3065 filter=lambda x: x.startswith('CONVERT_TEST_'))
3066
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003067
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003068if __name__ == '__main__':
3069 unittest.main()