blob: b505a6ed13423d0de73dd8a4ab12c061a58da18b [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
Miss Islington (bot)95b81e22020-09-15 16:59:48 -0700555 def test_enum_str_override(self):
556 class MyStrEnum(Enum):
557 def __str__(self):
558 return 'MyStr'
559 class MyMethodEnum(Enum):
560 def hello(self):
561 return 'Hello! My name is %s' % self.name
562 class Test1Enum(MyMethodEnum, int, MyStrEnum):
563 One = 1
564 Two = 2
565 self.assertEqual(str(Test1Enum.One), 'MyStr')
566 #
567 class Test2Enum(MyStrEnum, MyMethodEnum):
568 One = 1
569 Two = 2
570 self.assertEqual(str(Test2Enum.One), 'MyStr')
571
572 def test_inherited_data_type(self):
573 class HexInt(int):
574 def __repr__(self):
575 return hex(self)
576 class MyEnum(HexInt, enum.Enum):
577 A = 1
578 B = 2
579 C = 3
580 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
581
582 def test_too_many_data_types(self):
583 with self.assertRaisesRegex(TypeError, 'too many data types'):
584 class Huh(str, int, Enum):
585 One = 1
586
587 class MyStr(str):
588 def hello(self):
589 return 'hello, %s' % self
590 class MyInt(int):
591 def repr(self):
592 return hex(self)
593 with self.assertRaisesRegex(TypeError, 'too many data types'):
594 class Huh(MyStr, MyInt, Enum):
595 One = 1
596
597
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700598 def test_hash(self):
599 Season = self.Season
600 dates = {}
601 dates[Season.WINTER] = '1225'
602 dates[Season.SPRING] = '0315'
603 dates[Season.SUMMER] = '0704'
604 dates[Season.AUTUMN] = '1031'
605 self.assertEqual(dates[Season.AUTUMN], '1031')
606
607 def test_intenum_from_scratch(self):
608 class phy(int, Enum):
609 pi = 3
610 tau = 2 * pi
611 self.assertTrue(phy.pi < phy.tau)
612
613 def test_intenum_inherited(self):
614 class IntEnum(int, Enum):
615 pass
616 class phy(IntEnum):
617 pi = 3
618 tau = 2 * pi
619 self.assertTrue(phy.pi < phy.tau)
620
621 def test_floatenum_from_scratch(self):
622 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700623 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700624 tau = 2 * pi
625 self.assertTrue(phy.pi < phy.tau)
626
627 def test_floatenum_inherited(self):
628 class FloatEnum(float, Enum):
629 pass
630 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700631 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700632 tau = 2 * pi
633 self.assertTrue(phy.pi < phy.tau)
634
635 def test_strenum_from_scratch(self):
636 class phy(str, Enum):
637 pi = 'Pi'
638 tau = 'Tau'
639 self.assertTrue(phy.pi < phy.tau)
640
641 def test_strenum_inherited(self):
642 class StrEnum(str, Enum):
643 pass
644 class phy(StrEnum):
645 pi = 'Pi'
646 tau = 'Tau'
647 self.assertTrue(phy.pi < phy.tau)
648
649
650 def test_intenum(self):
651 class WeekDay(IntEnum):
652 SUNDAY = 1
653 MONDAY = 2
654 TUESDAY = 3
655 WEDNESDAY = 4
656 THURSDAY = 5
657 FRIDAY = 6
658 SATURDAY = 7
659
660 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
661 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
662
663 lst = list(WeekDay)
664 self.assertEqual(len(lst), len(WeekDay))
665 self.assertEqual(len(WeekDay), 7)
666 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
667 target = target.split()
668 for i, weekday in enumerate(target, 1):
669 e = WeekDay(i)
670 self.assertEqual(e, i)
671 self.assertEqual(int(e), i)
672 self.assertEqual(e.name, weekday)
673 self.assertIn(e, WeekDay)
674 self.assertEqual(lst.index(e)+1, i)
675 self.assertTrue(0 < e < 8)
676 self.assertIs(type(e), WeekDay)
677 self.assertIsInstance(e, int)
678 self.assertIsInstance(e, Enum)
679
680 def test_intenum_duplicates(self):
681 class WeekDay(IntEnum):
682 SUNDAY = 1
683 MONDAY = 2
684 TUESDAY = TEUSDAY = 3
685 WEDNESDAY = 4
686 THURSDAY = 5
687 FRIDAY = 6
688 SATURDAY = 7
689 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
690 self.assertEqual(WeekDay(3).name, 'TUESDAY')
691 self.assertEqual([k for k,v in WeekDay.__members__.items()
692 if v.name != k], ['TEUSDAY', ])
693
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300694 def test_intenum_from_bytes(self):
695 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
696 with self.assertRaises(ValueError):
697 IntStooges.from_bytes(b'\x00\x05', 'big')
698
699 def test_floatenum_fromhex(self):
700 h = float.hex(FloatStooges.MOE.value)
701 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
702 h = float.hex(FloatStooges.MOE.value + 0.01)
703 with self.assertRaises(ValueError):
704 FloatStooges.fromhex(h)
705
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700706 def test_pickle_enum(self):
707 if isinstance(Stooges, Exception):
708 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800709 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
710 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700711
712 def test_pickle_int(self):
713 if isinstance(IntStooges, Exception):
714 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800715 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
716 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700717
718 def test_pickle_float(self):
719 if isinstance(FloatStooges, Exception):
720 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800721 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
722 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700723
724 def test_pickle_enum_function(self):
725 if isinstance(Answer, Exception):
726 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800727 test_pickle_dump_load(self.assertIs, Answer.him)
728 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700729
730 def test_pickle_enum_function_with_module(self):
731 if isinstance(Question, Exception):
732 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800733 test_pickle_dump_load(self.assertIs, Question.who)
734 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700735
Ethan Furmanca1b7942014-02-08 11:36:27 -0800736 def test_enum_function_with_qualname(self):
737 if isinstance(Theory, Exception):
738 raise Theory
739 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
740
741 def test_class_nested_enum_and_pickle_protocol_four(self):
742 # would normally just have this directly in the class namespace
743 class NestedEnum(Enum):
744 twigs = 'common'
745 shiny = 'rare'
746
747 self.__class__.NestedEnum = NestedEnum
748 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300749 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800750
Ethan Furman24e837f2015-03-18 17:27:57 -0700751 def test_pickle_by_name(self):
752 class ReplaceGlobalInt(IntEnum):
753 ONE = 1
754 TWO = 2
755 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
756 for proto in range(HIGHEST_PROTOCOL):
757 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
758
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700759 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800760 BadPickle = Enum(
761 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700762 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800763 # now break BadPickle to test exception raising
764 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800765 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
766 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700767
768 def test_string_enum(self):
769 class SkillLevel(str, Enum):
770 master = 'what is the sound of one hand clapping?'
771 journeyman = 'why did the chicken cross the road?'
772 apprentice = 'knock, knock!'
773 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
774
775 def test_getattr_getitem(self):
776 class Period(Enum):
777 morning = 1
778 noon = 2
779 evening = 3
780 night = 4
781 self.assertIs(Period(2), Period.noon)
782 self.assertIs(getattr(Period, 'night'), Period.night)
783 self.assertIs(Period['morning'], Period.morning)
784
785 def test_getattr_dunder(self):
786 Season = self.Season
787 self.assertTrue(getattr(Season, '__eq__'))
788
789 def test_iteration_order(self):
790 class Season(Enum):
791 SUMMER = 2
792 WINTER = 4
793 AUTUMN = 3
794 SPRING = 1
795 self.assertEqual(
796 list(Season),
797 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
798 )
799
Ethan Furman2131a4a2013-09-14 18:11:24 -0700800 def test_reversed_iteration_order(self):
801 self.assertEqual(
802 list(reversed(self.Season)),
803 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
804 self.Season.SPRING]
805 )
806
Martin Pantereb995702016-07-28 01:11:04 +0000807 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700808 SummerMonth = Enum('SummerMonth', 'june july august')
809 lst = list(SummerMonth)
810 self.assertEqual(len(lst), len(SummerMonth))
811 self.assertEqual(len(SummerMonth), 3, SummerMonth)
812 self.assertEqual(
813 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
814 lst,
815 )
816 for i, month in enumerate('june july august'.split(), 1):
817 e = SummerMonth(i)
818 self.assertEqual(int(e.value), i)
819 self.assertNotEqual(e, i)
820 self.assertEqual(e.name, month)
821 self.assertIn(e, SummerMonth)
822 self.assertIs(type(e), SummerMonth)
823
Martin Pantereb995702016-07-28 01:11:04 +0000824 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700825 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
826 lst = list(SummerMonth)
827 self.assertEqual(len(lst), len(SummerMonth))
828 self.assertEqual(len(SummerMonth), 3, SummerMonth)
829 self.assertEqual(
830 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
831 lst,
832 )
833 for i, month in enumerate('june july august'.split(), 10):
834 e = SummerMonth(i)
835 self.assertEqual(int(e.value), i)
836 self.assertNotEqual(e, i)
837 self.assertEqual(e.name, month)
838 self.assertIn(e, SummerMonth)
839 self.assertIs(type(e), SummerMonth)
840
Martin Pantereb995702016-07-28 01:11:04 +0000841 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700842 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
843 lst = list(SummerMonth)
844 self.assertEqual(len(lst), len(SummerMonth))
845 self.assertEqual(len(SummerMonth), 3, SummerMonth)
846 self.assertEqual(
847 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
848 lst,
849 )
850 for i, month in enumerate('june july august'.split(), 1):
851 e = SummerMonth(i)
852 self.assertEqual(int(e.value), i)
853 self.assertNotEqual(e, i)
854 self.assertEqual(e.name, month)
855 self.assertIn(e, SummerMonth)
856 self.assertIs(type(e), SummerMonth)
857
Martin Pantereb995702016-07-28 01:11:04 +0000858 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700859 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
860 lst = list(SummerMonth)
861 self.assertEqual(len(lst), len(SummerMonth))
862 self.assertEqual(len(SummerMonth), 3, SummerMonth)
863 self.assertEqual(
864 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
865 lst,
866 )
867 for i, month in enumerate('june july august'.split(), 20):
868 e = SummerMonth(i)
869 self.assertEqual(int(e.value), i)
870 self.assertNotEqual(e, i)
871 self.assertEqual(e.name, month)
872 self.assertIn(e, SummerMonth)
873 self.assertIs(type(e), SummerMonth)
874
Martin Pantereb995702016-07-28 01:11:04 +0000875 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700876 SummerMonth = Enum(
877 'SummerMonth',
878 (('june', 1), ('july', 2), ('august', 3))
879 )
880 lst = list(SummerMonth)
881 self.assertEqual(len(lst), len(SummerMonth))
882 self.assertEqual(len(SummerMonth), 3, SummerMonth)
883 self.assertEqual(
884 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
885 lst,
886 )
887 for i, month in enumerate('june july august'.split(), 1):
888 e = SummerMonth(i)
889 self.assertEqual(int(e.value), i)
890 self.assertNotEqual(e, i)
891 self.assertEqual(e.name, month)
892 self.assertIn(e, SummerMonth)
893 self.assertIs(type(e), SummerMonth)
894
Martin Pantereb995702016-07-28 01:11:04 +0000895 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700896 SummerMonth = Enum(
897 'SummerMonth',
898 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
899 )
900 lst = list(SummerMonth)
901 self.assertEqual(len(lst), len(SummerMonth))
902 self.assertEqual(len(SummerMonth), 3, SummerMonth)
903 self.assertEqual(
904 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
905 lst,
906 )
907 for i, month in enumerate('june july august'.split(), 1):
908 e = SummerMonth(i)
909 self.assertEqual(int(e.value), i)
910 self.assertNotEqual(e, i)
911 self.assertEqual(e.name, month)
912 self.assertIn(e, SummerMonth)
913 self.assertIs(type(e), SummerMonth)
914
Martin Pantereb995702016-07-28 01:11:04 +0000915 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700916 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
917 lst = list(SummerMonth)
918 self.assertEqual(len(lst), len(SummerMonth))
919 self.assertEqual(len(SummerMonth), 3, SummerMonth)
920 self.assertEqual(
921 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
922 lst,
923 )
924 for i, month in enumerate('june july august'.split(), 1):
925 e = SummerMonth(i)
926 self.assertEqual(e, i)
927 self.assertEqual(e.name, month)
928 self.assertIn(e, SummerMonth)
929 self.assertIs(type(e), SummerMonth)
930
Martin Pantereb995702016-07-28 01:11:04 +0000931 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700932 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
933 lst = list(SummerMonth)
934 self.assertEqual(len(lst), len(SummerMonth))
935 self.assertEqual(len(SummerMonth), 3, SummerMonth)
936 self.assertEqual(
937 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
938 lst,
939 )
940 for i, month in enumerate('june july august'.split(), 30):
941 e = SummerMonth(i)
942 self.assertEqual(e, i)
943 self.assertEqual(e.name, month)
944 self.assertIn(e, SummerMonth)
945 self.assertIs(type(e), SummerMonth)
946
Martin Pantereb995702016-07-28 01:11:04 +0000947 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700948 SummerMonth = IntEnum('SummerMonth', 'june july august')
949 lst = list(SummerMonth)
950 self.assertEqual(len(lst), len(SummerMonth))
951 self.assertEqual(len(SummerMonth), 3, SummerMonth)
952 self.assertEqual(
953 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
954 lst,
955 )
956 for i, month in enumerate('june july august'.split(), 1):
957 e = SummerMonth(i)
958 self.assertEqual(e, i)
959 self.assertEqual(e.name, month)
960 self.assertIn(e, SummerMonth)
961 self.assertIs(type(e), SummerMonth)
962
Martin Pantereb995702016-07-28 01:11:04 +0000963 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700964 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
965 lst = list(SummerMonth)
966 self.assertEqual(len(lst), len(SummerMonth))
967 self.assertEqual(len(SummerMonth), 3, SummerMonth)
968 self.assertEqual(
969 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
970 lst,
971 )
972 for i, month in enumerate('june july august'.split(), 40):
973 e = SummerMonth(i)
974 self.assertEqual(e, i)
975 self.assertEqual(e.name, month)
976 self.assertIn(e, SummerMonth)
977 self.assertIs(type(e), SummerMonth)
978
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700979 def test_subclassing(self):
980 if isinstance(Name, Exception):
981 raise Name
982 self.assertEqual(Name.BDFL, 'Guido van Rossum')
983 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
984 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800985 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700986
987 def test_extending(self):
988 class Color(Enum):
989 red = 1
990 green = 2
991 blue = 3
992 with self.assertRaises(TypeError):
993 class MoreColor(Color):
994 cyan = 4
995 magenta = 5
996 yellow = 6
997
998 def test_exclude_methods(self):
999 class whatever(Enum):
1000 this = 'that'
1001 these = 'those'
1002 def really(self):
1003 return 'no, not %s' % self.value
1004 self.assertIsNot(type(whatever.really), whatever)
1005 self.assertEqual(whatever.this.really(), 'no, not that')
1006
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001007 def test_wrong_inheritance_order(self):
1008 with self.assertRaises(TypeError):
1009 class Wrong(Enum, str):
1010 NotHere = 'error before this point'
1011
1012 def test_intenum_transitivity(self):
1013 class number(IntEnum):
1014 one = 1
1015 two = 2
1016 three = 3
1017 class numero(IntEnum):
1018 uno = 1
1019 dos = 2
1020 tres = 3
1021 self.assertEqual(number.one, numero.uno)
1022 self.assertEqual(number.two, numero.dos)
1023 self.assertEqual(number.three, numero.tres)
1024
1025 def test_wrong_enum_in_call(self):
1026 class Monochrome(Enum):
1027 black = 0
1028 white = 1
1029 class Gender(Enum):
1030 male = 0
1031 female = 1
1032 self.assertRaises(ValueError, Monochrome, Gender.male)
1033
1034 def test_wrong_enum_in_mixed_call(self):
1035 class Monochrome(IntEnum):
1036 black = 0
1037 white = 1
1038 class Gender(Enum):
1039 male = 0
1040 female = 1
1041 self.assertRaises(ValueError, Monochrome, Gender.male)
1042
1043 def test_mixed_enum_in_call_1(self):
1044 class Monochrome(IntEnum):
1045 black = 0
1046 white = 1
1047 class Gender(IntEnum):
1048 male = 0
1049 female = 1
1050 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1051
1052 def test_mixed_enum_in_call_2(self):
1053 class Monochrome(Enum):
1054 black = 0
1055 white = 1
1056 class Gender(IntEnum):
1057 male = 0
1058 female = 1
1059 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1060
1061 def test_flufl_enum(self):
1062 class Fluflnum(Enum):
1063 def __int__(self):
1064 return int(self.value)
1065 class MailManOptions(Fluflnum):
1066 option1 = 1
1067 option2 = 2
1068 option3 = 3
1069 self.assertEqual(int(MailManOptions.option1), 1)
1070
Ethan Furman5e5a8232013-08-04 08:42:23 -07001071 def test_introspection(self):
1072 class Number(IntEnum):
1073 one = 100
1074 two = 200
1075 self.assertIs(Number.one._member_type_, int)
1076 self.assertIs(Number._member_type_, int)
1077 class String(str, Enum):
1078 yarn = 'soft'
1079 rope = 'rough'
1080 wire = 'hard'
1081 self.assertIs(String.yarn._member_type_, str)
1082 self.assertIs(String._member_type_, str)
1083 class Plain(Enum):
1084 vanilla = 'white'
1085 one = 1
1086 self.assertIs(Plain.vanilla._member_type_, object)
1087 self.assertIs(Plain._member_type_, object)
1088
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001089 def test_no_such_enum_member(self):
1090 class Color(Enum):
1091 red = 1
1092 green = 2
1093 blue = 3
1094 with self.assertRaises(ValueError):
1095 Color(4)
1096 with self.assertRaises(KeyError):
1097 Color['chartreuse']
1098
1099 def test_new_repr(self):
1100 class Color(Enum):
1101 red = 1
1102 green = 2
1103 blue = 3
1104 def __repr__(self):
1105 return "don't you just love shades of %s?" % self.name
1106 self.assertEqual(
1107 repr(Color.blue),
1108 "don't you just love shades of blue?",
1109 )
1110
1111 def test_inherited_repr(self):
1112 class MyEnum(Enum):
1113 def __repr__(self):
1114 return "My name is %s." % self.name
1115 class MyIntEnum(int, MyEnum):
1116 this = 1
1117 that = 2
1118 theother = 3
1119 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1120
1121 def test_multiple_mixin_mro(self):
1122 class auto_enum(type(Enum)):
1123 def __new__(metacls, cls, bases, classdict):
1124 temp = type(classdict)()
1125 names = set(classdict._member_names)
1126 i = 0
1127 for k in classdict._member_names:
1128 v = classdict[k]
1129 if v is Ellipsis:
1130 v = i
1131 else:
1132 i = v
1133 i += 1
1134 temp[k] = v
1135 for k, v in classdict.items():
1136 if k not in names:
1137 temp[k] = v
1138 return super(auto_enum, metacls).__new__(
1139 metacls, cls, bases, temp)
1140
1141 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1142 pass
1143
1144 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1145 pass
1146
1147 class TestAutoNumber(AutoNumberedEnum):
1148 a = ...
1149 b = 3
1150 c = ...
1151
1152 class TestAutoInt(AutoIntEnum):
1153 a = ...
1154 b = 3
1155 c = ...
1156
1157 def test_subclasses_with_getnewargs(self):
1158 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001159 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001160 def __new__(cls, *args):
1161 _args = args
1162 name, *args = args
1163 if len(args) == 0:
1164 raise TypeError("name and value must be specified")
1165 self = int.__new__(cls, *args)
1166 self._intname = name
1167 self._args = _args
1168 return self
1169 def __getnewargs__(self):
1170 return self._args
1171 @property
1172 def __name__(self):
1173 return self._intname
1174 def __repr__(self):
1175 # repr() is updated to include the name and type info
1176 return "{}({!r}, {})".format(type(self).__name__,
1177 self.__name__,
1178 int.__repr__(self))
1179 def __str__(self):
1180 # str() is unchanged, even if it relies on the repr() fallback
1181 base = int
1182 base_str = base.__str__
1183 if base_str.__objclass__ is object:
1184 return base.__repr__(self)
1185 return base_str(self)
1186 # for simplicity, we only define one operator that
1187 # propagates expressions
1188 def __add__(self, other):
1189 temp = int(self) + int( other)
1190 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1191 return NamedInt(
1192 '({0} + {1})'.format(self.__name__, other.__name__),
1193 temp )
1194 else:
1195 return temp
1196
1197 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001198 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001199 x = ('the-x', 1)
1200 y = ('the-y', 2)
1201
Ethan Furman2aa27322013-07-19 19:35:56 -07001202
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001203 self.assertIs(NEI.__new__, Enum.__new__)
1204 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1205 globals()['NamedInt'] = NamedInt
1206 globals()['NEI'] = NEI
1207 NI5 = NamedInt('test', 5)
1208 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001209 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001210 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001211 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001212 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001213
Ethan Furmanca1b7942014-02-08 11:36:27 -08001214 def test_subclasses_with_getnewargs_ex(self):
1215 class NamedInt(int):
1216 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1217 def __new__(cls, *args):
1218 _args = args
1219 name, *args = args
1220 if len(args) == 0:
1221 raise TypeError("name and value must be specified")
1222 self = int.__new__(cls, *args)
1223 self._intname = name
1224 self._args = _args
1225 return self
1226 def __getnewargs_ex__(self):
1227 return self._args, {}
1228 @property
1229 def __name__(self):
1230 return self._intname
1231 def __repr__(self):
1232 # repr() is updated to include the name and type info
1233 return "{}({!r}, {})".format(type(self).__name__,
1234 self.__name__,
1235 int.__repr__(self))
1236 def __str__(self):
1237 # str() is unchanged, even if it relies on the repr() fallback
1238 base = int
1239 base_str = base.__str__
1240 if base_str.__objclass__ is object:
1241 return base.__repr__(self)
1242 return base_str(self)
1243 # for simplicity, we only define one operator that
1244 # propagates expressions
1245 def __add__(self, other):
1246 temp = int(self) + int( other)
1247 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1248 return NamedInt(
1249 '({0} + {1})'.format(self.__name__, other.__name__),
1250 temp )
1251 else:
1252 return temp
1253
1254 class NEI(NamedInt, Enum):
1255 __qualname__ = 'NEI' # needed for pickle protocol 4
1256 x = ('the-x', 1)
1257 y = ('the-y', 2)
1258
1259
1260 self.assertIs(NEI.__new__, Enum.__new__)
1261 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1262 globals()['NamedInt'] = NamedInt
1263 globals()['NEI'] = NEI
1264 NI5 = NamedInt('test', 5)
1265 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001266 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001267 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001268 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001269 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001270
1271 def test_subclasses_with_reduce(self):
1272 class NamedInt(int):
1273 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1274 def __new__(cls, *args):
1275 _args = args
1276 name, *args = args
1277 if len(args) == 0:
1278 raise TypeError("name and value must be specified")
1279 self = int.__new__(cls, *args)
1280 self._intname = name
1281 self._args = _args
1282 return self
1283 def __reduce__(self):
1284 return self.__class__, self._args
1285 @property
1286 def __name__(self):
1287 return self._intname
1288 def __repr__(self):
1289 # repr() is updated to include the name and type info
1290 return "{}({!r}, {})".format(type(self).__name__,
1291 self.__name__,
1292 int.__repr__(self))
1293 def __str__(self):
1294 # str() is unchanged, even if it relies on the repr() fallback
1295 base = int
1296 base_str = base.__str__
1297 if base_str.__objclass__ is object:
1298 return base.__repr__(self)
1299 return base_str(self)
1300 # for simplicity, we only define one operator that
1301 # propagates expressions
1302 def __add__(self, other):
1303 temp = int(self) + int( other)
1304 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1305 return NamedInt(
1306 '({0} + {1})'.format(self.__name__, other.__name__),
1307 temp )
1308 else:
1309 return temp
1310
1311 class NEI(NamedInt, Enum):
1312 __qualname__ = 'NEI' # needed for pickle protocol 4
1313 x = ('the-x', 1)
1314 y = ('the-y', 2)
1315
1316
1317 self.assertIs(NEI.__new__, Enum.__new__)
1318 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1319 globals()['NamedInt'] = NamedInt
1320 globals()['NEI'] = NEI
1321 NI5 = NamedInt('test', 5)
1322 self.assertEqual(NI5, 5)
1323 test_pickle_dump_load(self.assertEqual, NI5, 5)
1324 self.assertEqual(NEI.y.value, 2)
1325 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001326 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001327
1328 def test_subclasses_with_reduce_ex(self):
1329 class NamedInt(int):
1330 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1331 def __new__(cls, *args):
1332 _args = args
1333 name, *args = args
1334 if len(args) == 0:
1335 raise TypeError("name and value must be specified")
1336 self = int.__new__(cls, *args)
1337 self._intname = name
1338 self._args = _args
1339 return self
1340 def __reduce_ex__(self, proto):
1341 return self.__class__, self._args
1342 @property
1343 def __name__(self):
1344 return self._intname
1345 def __repr__(self):
1346 # repr() is updated to include the name and type info
1347 return "{}({!r}, {})".format(type(self).__name__,
1348 self.__name__,
1349 int.__repr__(self))
1350 def __str__(self):
1351 # str() is unchanged, even if it relies on the repr() fallback
1352 base = int
1353 base_str = base.__str__
1354 if base_str.__objclass__ is object:
1355 return base.__repr__(self)
1356 return base_str(self)
1357 # for simplicity, we only define one operator that
1358 # propagates expressions
1359 def __add__(self, other):
1360 temp = int(self) + int( other)
1361 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1362 return NamedInt(
1363 '({0} + {1})'.format(self.__name__, other.__name__),
1364 temp )
1365 else:
1366 return temp
1367
1368 class NEI(NamedInt, Enum):
1369 __qualname__ = 'NEI' # needed for pickle protocol 4
1370 x = ('the-x', 1)
1371 y = ('the-y', 2)
1372
1373
1374 self.assertIs(NEI.__new__, Enum.__new__)
1375 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1376 globals()['NamedInt'] = NamedInt
1377 globals()['NEI'] = NEI
1378 NI5 = NamedInt('test', 5)
1379 self.assertEqual(NI5, 5)
1380 test_pickle_dump_load(self.assertEqual, NI5, 5)
1381 self.assertEqual(NEI.y.value, 2)
1382 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001383 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001384
Ethan Furmandc870522014-02-18 12:37:12 -08001385 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001386 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001387 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001388 def __new__(cls, *args):
1389 _args = args
1390 name, *args = args
1391 if len(args) == 0:
1392 raise TypeError("name and value must be specified")
1393 self = int.__new__(cls, *args)
1394 self._intname = name
1395 self._args = _args
1396 return self
1397 @property
1398 def __name__(self):
1399 return self._intname
1400 def __repr__(self):
1401 # repr() is updated to include the name and type info
1402 return "{}({!r}, {})".format(type(self).__name__,
1403 self.__name__,
1404 int.__repr__(self))
1405 def __str__(self):
1406 # str() is unchanged, even if it relies on the repr() fallback
1407 base = int
1408 base_str = base.__str__
1409 if base_str.__objclass__ is object:
1410 return base.__repr__(self)
1411 return base_str(self)
1412 # for simplicity, we only define one operator that
1413 # propagates expressions
1414 def __add__(self, other):
1415 temp = int(self) + int( other)
1416 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1417 return NamedInt(
1418 '({0} + {1})'.format(self.__name__, other.__name__),
1419 temp )
1420 else:
1421 return temp
1422
1423 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001424 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001425 x = ('the-x', 1)
1426 y = ('the-y', 2)
1427
1428 self.assertIs(NEI.__new__, Enum.__new__)
1429 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1430 globals()['NamedInt'] = NamedInt
1431 globals()['NEI'] = NEI
1432 NI5 = NamedInt('test', 5)
1433 self.assertEqual(NI5, 5)
1434 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001435 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1436 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001437
Ethan Furmandc870522014-02-18 12:37:12 -08001438 def test_subclasses_without_direct_pickle_support_using_name(self):
1439 class NamedInt(int):
1440 __qualname__ = 'NamedInt'
1441 def __new__(cls, *args):
1442 _args = args
1443 name, *args = args
1444 if len(args) == 0:
1445 raise TypeError("name and value must be specified")
1446 self = int.__new__(cls, *args)
1447 self._intname = name
1448 self._args = _args
1449 return self
1450 @property
1451 def __name__(self):
1452 return self._intname
1453 def __repr__(self):
1454 # repr() is updated to include the name and type info
1455 return "{}({!r}, {})".format(type(self).__name__,
1456 self.__name__,
1457 int.__repr__(self))
1458 def __str__(self):
1459 # str() is unchanged, even if it relies on the repr() fallback
1460 base = int
1461 base_str = base.__str__
1462 if base_str.__objclass__ is object:
1463 return base.__repr__(self)
1464 return base_str(self)
1465 # for simplicity, we only define one operator that
1466 # propagates expressions
1467 def __add__(self, other):
1468 temp = int(self) + int( other)
1469 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1470 return NamedInt(
1471 '({0} + {1})'.format(self.__name__, other.__name__),
1472 temp )
1473 else:
1474 return temp
1475
1476 class NEI(NamedInt, Enum):
1477 __qualname__ = 'NEI'
1478 x = ('the-x', 1)
1479 y = ('the-y', 2)
1480 def __reduce_ex__(self, proto):
1481 return getattr, (self.__class__, self._name_)
1482
1483 self.assertIs(NEI.__new__, Enum.__new__)
1484 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1485 globals()['NamedInt'] = NamedInt
1486 globals()['NEI'] = NEI
1487 NI5 = NamedInt('test', 5)
1488 self.assertEqual(NI5, 5)
1489 self.assertEqual(NEI.y.value, 2)
1490 test_pickle_dump_load(self.assertIs, NEI.y)
1491 test_pickle_dump_load(self.assertIs, NEI)
1492
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001493 def test_tuple_subclass(self):
1494 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001495 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001496 first = (1, 'for the money')
1497 second = (2, 'for the show')
1498 third = (3, 'for the music')
1499 self.assertIs(type(SomeTuple.first), SomeTuple)
1500 self.assertIsInstance(SomeTuple.second, tuple)
1501 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1502 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001503 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001504
1505 def test_duplicate_values_give_unique_enum_items(self):
1506 class AutoNumber(Enum):
1507 first = ()
1508 second = ()
1509 third = ()
1510 def __new__(cls):
1511 value = len(cls.__members__) + 1
1512 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001513 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001514 return obj
1515 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001516 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001517 self.assertEqual(
1518 list(AutoNumber),
1519 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1520 )
1521 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001522 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001523 self.assertIs(AutoNumber(1), AutoNumber.first)
1524
1525 def test_inherited_new_from_enhanced_enum(self):
1526 class AutoNumber(Enum):
1527 def __new__(cls):
1528 value = len(cls.__members__) + 1
1529 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001530 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001531 return obj
1532 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001533 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001534 class Color(AutoNumber):
1535 red = ()
1536 green = ()
1537 blue = ()
1538 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1539 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1540
1541 def test_inherited_new_from_mixed_enum(self):
1542 class AutoNumber(IntEnum):
1543 def __new__(cls):
1544 value = len(cls.__members__) + 1
1545 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001546 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547 return obj
1548 class Color(AutoNumber):
1549 red = ()
1550 green = ()
1551 blue = ()
1552 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1553 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1554
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001555 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001556 class OrdinaryEnum(Enum):
1557 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001558 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1559 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001560
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001561 def test_ordered_mixin(self):
1562 class OrderedEnum(Enum):
1563 def __ge__(self, other):
1564 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001565 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001566 return NotImplemented
1567 def __gt__(self, other):
1568 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001569 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001570 return NotImplemented
1571 def __le__(self, other):
1572 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001573 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001574 return NotImplemented
1575 def __lt__(self, other):
1576 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001577 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001578 return NotImplemented
1579 class Grade(OrderedEnum):
1580 A = 5
1581 B = 4
1582 C = 3
1583 D = 2
1584 F = 1
1585 self.assertGreater(Grade.A, Grade.B)
1586 self.assertLessEqual(Grade.F, Grade.C)
1587 self.assertLess(Grade.D, Grade.A)
1588 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001589 self.assertEqual(Grade.B, Grade.B)
1590 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001591
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001592 def test_extending2(self):
1593 class Shade(Enum):
1594 def shade(self):
1595 print(self.name)
1596 class Color(Shade):
1597 red = 1
1598 green = 2
1599 blue = 3
1600 with self.assertRaises(TypeError):
1601 class MoreColor(Color):
1602 cyan = 4
1603 magenta = 5
1604 yellow = 6
1605
1606 def test_extending3(self):
1607 class Shade(Enum):
1608 def shade(self):
1609 return self.name
1610 class Color(Shade):
1611 def hex(self):
1612 return '%s hexlified!' % self.value
1613 class MoreColor(Color):
1614 cyan = 4
1615 magenta = 5
1616 yellow = 6
1617 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1618
orlnub1230fb9fad2018-09-12 20:28:53 +03001619 def test_subclass_duplicate_name(self):
1620 class Base(Enum):
1621 def test(self):
1622 pass
1623 class Test(Base):
1624 test = 1
1625 self.assertIs(type(Test.test), Test)
1626
1627 def test_subclass_duplicate_name_dynamic(self):
1628 from types import DynamicClassAttribute
1629 class Base(Enum):
1630 @DynamicClassAttribute
1631 def test(self):
1632 return 'dynamic'
1633 class Test(Base):
1634 test = 1
1635 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001636
1637 def test_no_duplicates(self):
1638 class UniqueEnum(Enum):
1639 def __init__(self, *args):
1640 cls = self.__class__
1641 if any(self.value == e.value for e in cls):
1642 a = self.name
1643 e = cls(self.value).name
1644 raise ValueError(
1645 "aliases not allowed in UniqueEnum: %r --> %r"
1646 % (a, e)
1647 )
1648 class Color(UniqueEnum):
1649 red = 1
1650 green = 2
1651 blue = 3
1652 with self.assertRaises(ValueError):
1653 class Color(UniqueEnum):
1654 red = 1
1655 green = 2
1656 blue = 3
1657 grene = 2
1658
1659 def test_init(self):
1660 class Planet(Enum):
1661 MERCURY = (3.303e+23, 2.4397e6)
1662 VENUS = (4.869e+24, 6.0518e6)
1663 EARTH = (5.976e+24, 6.37814e6)
1664 MARS = (6.421e+23, 3.3972e6)
1665 JUPITER = (1.9e+27, 7.1492e7)
1666 SATURN = (5.688e+26, 6.0268e7)
1667 URANUS = (8.686e+25, 2.5559e7)
1668 NEPTUNE = (1.024e+26, 2.4746e7)
1669 def __init__(self, mass, radius):
1670 self.mass = mass # in kilograms
1671 self.radius = radius # in meters
1672 @property
1673 def surface_gravity(self):
1674 # universal gravitational constant (m3 kg-1 s-2)
1675 G = 6.67300E-11
1676 return G * self.mass / (self.radius * self.radius)
1677 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1678 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1679
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001680 def test_ignore(self):
1681 class Period(timedelta, Enum):
1682 '''
1683 different lengths of time
1684 '''
1685 def __new__(cls, value, period):
1686 obj = timedelta.__new__(cls, value)
1687 obj._value_ = value
1688 obj.period = period
1689 return obj
1690 _ignore_ = 'Period i'
1691 Period = vars()
1692 for i in range(13):
1693 Period['month_%d' % i] = i*30, 'month'
1694 for i in range(53):
1695 Period['week_%d' % i] = i*7, 'week'
1696 for i in range(32):
1697 Period['day_%d' % i] = i, 'day'
1698 OneDay = day_1
1699 OneWeek = week_1
1700 OneMonth = month_1
1701 self.assertFalse(hasattr(Period, '_ignore_'))
1702 self.assertFalse(hasattr(Period, 'Period'))
1703 self.assertFalse(hasattr(Period, 'i'))
1704 self.assertTrue(isinstance(Period.day_1, timedelta))
1705 self.assertTrue(Period.month_1 is Period.day_30)
1706 self.assertTrue(Period.week_4 is Period.day_28)
1707
Ethan Furman2aa27322013-07-19 19:35:56 -07001708 def test_nonhash_value(self):
1709 class AutoNumberInAList(Enum):
1710 def __new__(cls):
1711 value = [len(cls.__members__) + 1]
1712 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001713 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001714 return obj
1715 class ColorInAList(AutoNumberInAList):
1716 red = ()
1717 green = ()
1718 blue = ()
1719 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001720 for enum, value in zip(ColorInAList, range(3)):
1721 value += 1
1722 self.assertEqual(enum.value, [value])
1723 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001724
Ethan Furmanb41803e2013-07-25 13:50:45 -07001725 def test_conflicting_types_resolved_in_new(self):
1726 class LabelledIntEnum(int, Enum):
1727 def __new__(cls, *args):
1728 value, label = args
1729 obj = int.__new__(cls, value)
1730 obj.label = label
1731 obj._value_ = value
1732 return obj
1733
1734 class LabelledList(LabelledIntEnum):
1735 unprocessed = (1, "Unprocessed")
1736 payment_complete = (2, "Payment Complete")
1737
1738 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1739 self.assertEqual(LabelledList.unprocessed, 1)
1740 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001741
Ethan Furmanc16595e2016-09-10 23:36:59 -07001742 def test_auto_number(self):
1743 class Color(Enum):
1744 red = auto()
1745 blue = auto()
1746 green = auto()
1747
1748 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1749 self.assertEqual(Color.red.value, 1)
1750 self.assertEqual(Color.blue.value, 2)
1751 self.assertEqual(Color.green.value, 3)
1752
1753 def test_auto_name(self):
1754 class Color(Enum):
1755 def _generate_next_value_(name, start, count, last):
1756 return name
1757 red = auto()
1758 blue = auto()
1759 green = auto()
1760
1761 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1762 self.assertEqual(Color.red.value, 'red')
1763 self.assertEqual(Color.blue.value, 'blue')
1764 self.assertEqual(Color.green.value, 'green')
1765
1766 def test_auto_name_inherit(self):
1767 class AutoNameEnum(Enum):
1768 def _generate_next_value_(name, start, count, last):
1769 return name
1770 class Color(AutoNameEnum):
1771 red = auto()
1772 blue = auto()
1773 green = auto()
1774
1775 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1776 self.assertEqual(Color.red.value, 'red')
1777 self.assertEqual(Color.blue.value, 'blue')
1778 self.assertEqual(Color.green.value, 'green')
1779
1780 def test_auto_garbage(self):
1781 class Color(Enum):
1782 red = 'red'
1783 blue = auto()
1784 self.assertEqual(Color.blue.value, 1)
1785
1786 def test_auto_garbage_corrected(self):
1787 class Color(Enum):
1788 red = 'red'
1789 blue = 2
1790 green = auto()
1791
1792 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1793 self.assertEqual(Color.red.value, 'red')
1794 self.assertEqual(Color.blue.value, 2)
1795 self.assertEqual(Color.green.value, 3)
1796
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001797 def test_auto_order(self):
1798 with self.assertRaises(TypeError):
1799 class Color(Enum):
1800 red = auto()
1801 green = auto()
1802 blue = auto()
1803 def _generate_next_value_(name, start, count, last):
1804 return name
1805
1806
Ethan Furman3515dcc2016-09-18 13:15:41 -07001807 def test_duplicate_auto(self):
1808 class Dupes(Enum):
1809 first = primero = auto()
1810 second = auto()
1811 third = auto()
1812 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1813
Ethan Furman019f0a02018-09-12 11:43:34 -07001814 def test_missing(self):
1815 class Color(Enum):
1816 red = 1
1817 green = 2
1818 blue = 3
1819 @classmethod
1820 def _missing_(cls, item):
1821 if item == 'three':
1822 return cls.blue
1823 elif item == 'bad return':
1824 # trigger internal error
1825 return 5
1826 elif item == 'error out':
1827 raise ZeroDivisionError
1828 else:
1829 # trigger not found
1830 return None
1831 self.assertIs(Color('three'), Color.blue)
1832 self.assertRaises(ValueError, Color, 7)
1833 try:
1834 Color('bad return')
1835 except TypeError as exc:
1836 self.assertTrue(isinstance(exc.__context__, ValueError))
1837 else:
1838 raise Exception('Exception not raised.')
1839 try:
1840 Color('error out')
1841 except ZeroDivisionError as exc:
1842 self.assertTrue(isinstance(exc.__context__, ValueError))
1843 else:
1844 raise Exception('Exception not raised.')
1845
Ethan Furman5bdab642018-09-21 19:03:09 -07001846 def test_multiple_mixin(self):
1847 class MaxMixin:
1848 @classproperty
1849 def MAX(cls):
1850 max = len(cls)
1851 cls.MAX = max
1852 return max
1853 class StrMixin:
1854 def __str__(self):
1855 return self._name_.lower()
1856 class SomeEnum(Enum):
1857 def behavior(self):
1858 return 'booyah'
1859 class AnotherEnum(Enum):
1860 def behavior(self):
1861 return 'nuhuh!'
1862 def social(self):
1863 return "what's up?"
1864 class Color(MaxMixin, Enum):
1865 RED = auto()
1866 GREEN = auto()
1867 BLUE = auto()
1868 self.assertEqual(Color.RED.value, 1)
1869 self.assertEqual(Color.GREEN.value, 2)
1870 self.assertEqual(Color.BLUE.value, 3)
1871 self.assertEqual(Color.MAX, 3)
1872 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1873 class Color(MaxMixin, StrMixin, Enum):
1874 RED = auto()
1875 GREEN = auto()
1876 BLUE = auto()
1877 self.assertEqual(Color.RED.value, 1)
1878 self.assertEqual(Color.GREEN.value, 2)
1879 self.assertEqual(Color.BLUE.value, 3)
1880 self.assertEqual(Color.MAX, 3)
1881 self.assertEqual(str(Color.BLUE), 'blue')
1882 class Color(StrMixin, MaxMixin, Enum):
1883 RED = auto()
1884 GREEN = auto()
1885 BLUE = auto()
1886 self.assertEqual(Color.RED.value, 1)
1887 self.assertEqual(Color.GREEN.value, 2)
1888 self.assertEqual(Color.BLUE.value, 3)
1889 self.assertEqual(Color.MAX, 3)
1890 self.assertEqual(str(Color.BLUE), 'blue')
1891 class CoolColor(StrMixin, SomeEnum, Enum):
1892 RED = auto()
1893 GREEN = auto()
1894 BLUE = auto()
1895 self.assertEqual(CoolColor.RED.value, 1)
1896 self.assertEqual(CoolColor.GREEN.value, 2)
1897 self.assertEqual(CoolColor.BLUE.value, 3)
1898 self.assertEqual(str(CoolColor.BLUE), 'blue')
1899 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1900 class CoolerColor(StrMixin, AnotherEnum, Enum):
1901 RED = auto()
1902 GREEN = auto()
1903 BLUE = auto()
1904 self.assertEqual(CoolerColor.RED.value, 1)
1905 self.assertEqual(CoolerColor.GREEN.value, 2)
1906 self.assertEqual(CoolerColor.BLUE.value, 3)
1907 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1908 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1909 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1910 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1911 RED = auto()
1912 GREEN = auto()
1913 BLUE = auto()
1914 self.assertEqual(CoolestColor.RED.value, 1)
1915 self.assertEqual(CoolestColor.GREEN.value, 2)
1916 self.assertEqual(CoolestColor.BLUE.value, 3)
1917 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1918 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1919 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1920 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1921 RED = auto()
1922 GREEN = auto()
1923 BLUE = auto()
1924 self.assertEqual(ConfusedColor.RED.value, 1)
1925 self.assertEqual(ConfusedColor.GREEN.value, 2)
1926 self.assertEqual(ConfusedColor.BLUE.value, 3)
1927 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1928 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1929 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1930 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1931 RED = auto()
1932 GREEN = auto()
1933 BLUE = auto()
1934 self.assertEqual(ReformedColor.RED.value, 1)
1935 self.assertEqual(ReformedColor.GREEN.value, 2)
1936 self.assertEqual(ReformedColor.BLUE.value, 3)
1937 self.assertEqual(str(ReformedColor.BLUE), 'blue')
1938 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
1939 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1940 self.assertTrue(issubclass(ReformedColor, int))
1941
Ethan Furmancd453852018-10-05 23:29:36 -07001942 def test_multiple_inherited_mixin(self):
1943 class StrEnum(str, Enum):
1944 def __new__(cls, *args, **kwargs):
1945 for a in args:
1946 if not isinstance(a, str):
1947 raise TypeError("Enumeration '%s' (%s) is not"
1948 " a string" % (a, type(a).__name__))
1949 return str.__new__(cls, *args, **kwargs)
1950 @unique
1951 class Decision1(StrEnum):
1952 REVERT = "REVERT"
1953 REVERT_ALL = "REVERT_ALL"
1954 RETRY = "RETRY"
1955 class MyEnum(StrEnum):
1956 pass
1957 @unique
1958 class Decision2(MyEnum):
1959 REVERT = "REVERT"
1960 REVERT_ALL = "REVERT_ALL"
1961 RETRY = "RETRY"
1962
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01001963 def test_empty_globals(self):
1964 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
1965 # when using compile and exec because f_globals is empty
1966 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
1967 code = compile(code, "<string>", "exec")
1968 global_ns = {}
1969 local_ls = {}
1970 exec(code, global_ns, local_ls)
1971
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001972
Ethan Furmane8e61272016-08-20 07:19:31 -07001973class TestOrder(unittest.TestCase):
1974
1975 def test_same_members(self):
1976 class Color(Enum):
1977 _order_ = 'red green blue'
1978 red = 1
1979 green = 2
1980 blue = 3
1981
1982 def test_same_members_with_aliases(self):
1983 class Color(Enum):
1984 _order_ = 'red green blue'
1985 red = 1
1986 green = 2
1987 blue = 3
1988 verde = green
1989
1990 def test_same_members_wrong_order(self):
1991 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1992 class Color(Enum):
1993 _order_ = 'red green blue'
1994 red = 1
1995 blue = 3
1996 green = 2
1997
1998 def test_order_has_extra_members(self):
1999 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2000 class Color(Enum):
2001 _order_ = 'red green blue purple'
2002 red = 1
2003 green = 2
2004 blue = 3
2005
2006 def test_order_has_extra_members_with_aliases(self):
2007 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2008 class Color(Enum):
2009 _order_ = 'red green blue purple'
2010 red = 1
2011 green = 2
2012 blue = 3
2013 verde = green
2014
2015 def test_enum_has_extra_members(self):
2016 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2017 class Color(Enum):
2018 _order_ = 'red green blue'
2019 red = 1
2020 green = 2
2021 blue = 3
2022 purple = 4
2023
2024 def test_enum_has_extra_members_with_aliases(self):
2025 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2026 class Color(Enum):
2027 _order_ = 'red green blue'
2028 red = 1
2029 green = 2
2030 blue = 3
2031 purple = 4
2032 verde = green
2033
2034
Ethan Furman65a5a472016-09-01 23:55:19 -07002035class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002036 """Tests of the Flags."""
2037
Ethan Furman65a5a472016-09-01 23:55:19 -07002038 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002039 R, W, X = 4, 2, 1
2040
Ethan Furman65a5a472016-09-01 23:55:19 -07002041 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002042 RO = 0
2043 WO = 1
2044 RW = 2
2045 AC = 3
2046 CE = 1<<19
2047
Rahul Jha94306522018-09-10 23:51:04 +05302048 class Color(Flag):
2049 BLACK = 0
2050 RED = 1
2051 GREEN = 2
2052 BLUE = 4
2053 PURPLE = RED|BLUE
2054
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002055 def test_str(self):
2056 Perm = self.Perm
2057 self.assertEqual(str(Perm.R), 'Perm.R')
2058 self.assertEqual(str(Perm.W), 'Perm.W')
2059 self.assertEqual(str(Perm.X), 'Perm.X')
2060 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2061 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2062 self.assertEqual(str(Perm(0)), 'Perm.0')
2063 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2064 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2065 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2066 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2067 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2068 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2069
2070 Open = self.Open
2071 self.assertEqual(str(Open.RO), 'Open.RO')
2072 self.assertEqual(str(Open.WO), 'Open.WO')
2073 self.assertEqual(str(Open.AC), 'Open.AC')
2074 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2075 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002076 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002077 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2078 self.assertEqual(str(~Open.AC), 'Open.CE')
2079 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2080 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2081
2082 def test_repr(self):
2083 Perm = self.Perm
2084 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2085 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2086 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2087 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2088 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002089 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002090 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2091 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2092 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2093 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002094 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002095 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2096
2097 Open = self.Open
2098 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2099 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2100 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2101 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2102 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002103 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002104 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2105 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2106 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2107 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2108
2109 def test_or(self):
2110 Perm = self.Perm
2111 for i in Perm:
2112 for j in Perm:
2113 self.assertEqual((i | j), Perm(i.value | j.value))
2114 self.assertEqual((i | j).value, i.value | j.value)
2115 self.assertIs(type(i | j), Perm)
2116 for i in Perm:
2117 self.assertIs(i | i, i)
2118 Open = self.Open
2119 self.assertIs(Open.RO | Open.CE, Open.CE)
2120
2121 def test_and(self):
2122 Perm = self.Perm
2123 RW = Perm.R | Perm.W
2124 RX = Perm.R | Perm.X
2125 WX = Perm.W | Perm.X
2126 RWX = Perm.R | Perm.W | Perm.X
2127 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2128 for i in values:
2129 for j in values:
2130 self.assertEqual((i & j).value, i.value & j.value)
2131 self.assertIs(type(i & j), Perm)
2132 for i in Perm:
2133 self.assertIs(i & i, i)
2134 self.assertIs(i & RWX, i)
2135 self.assertIs(RWX & i, i)
2136 Open = self.Open
2137 self.assertIs(Open.RO & Open.CE, Open.RO)
2138
2139 def test_xor(self):
2140 Perm = self.Perm
2141 for i in Perm:
2142 for j in Perm:
2143 self.assertEqual((i ^ j).value, i.value ^ j.value)
2144 self.assertIs(type(i ^ j), Perm)
2145 for i in Perm:
2146 self.assertIs(i ^ Perm(0), i)
2147 self.assertIs(Perm(0) ^ i, i)
2148 Open = self.Open
2149 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2150 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2151
2152 def test_invert(self):
2153 Perm = self.Perm
2154 RW = Perm.R | Perm.W
2155 RX = Perm.R | Perm.X
2156 WX = Perm.W | Perm.X
2157 RWX = Perm.R | Perm.W | Perm.X
2158 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2159 for i in values:
2160 self.assertIs(type(~i), Perm)
2161 self.assertEqual(~~i, i)
2162 for i in Perm:
2163 self.assertIs(~~i, i)
2164 Open = self.Open
2165 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2166 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2167
Ethan Furman25d94bb2016-09-02 16:32:32 -07002168 def test_bool(self):
2169 Perm = self.Perm
2170 for f in Perm:
2171 self.assertTrue(f)
2172 Open = self.Open
2173 for f in Open:
2174 self.assertEqual(bool(f.value), bool(f))
2175
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002176 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002177 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002178 lst = list(Perm)
2179 self.assertEqual(len(lst), len(Perm))
2180 self.assertEqual(len(Perm), 3, Perm)
2181 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2182 for i, n in enumerate('R W X'.split()):
2183 v = 1<<i
2184 e = Perm(v)
2185 self.assertEqual(e.value, v)
2186 self.assertEqual(type(e.value), int)
2187 self.assertEqual(e.name, n)
2188 self.assertIn(e, Perm)
2189 self.assertIs(type(e), Perm)
2190
2191 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002192 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002193 lst = list(Perm)
2194 self.assertEqual(len(lst), len(Perm))
2195 self.assertEqual(len(Perm), 3, Perm)
2196 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2197 for i, n in enumerate('R W X'.split()):
2198 v = 8<<i
2199 e = Perm(v)
2200 self.assertEqual(e.value, v)
2201 self.assertEqual(type(e.value), int)
2202 self.assertEqual(e.name, n)
2203 self.assertIn(e, Perm)
2204 self.assertIs(type(e), Perm)
2205
2206 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002207 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002208 lst = list(Perm)
2209 self.assertEqual(len(lst), len(Perm))
2210 self.assertEqual(len(Perm), 3, Perm)
2211 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2212 for i, n in enumerate('R W X'.split()):
2213 v = 1<<i
2214 e = Perm(v)
2215 self.assertEqual(e.value, v)
2216 self.assertEqual(type(e.value), int)
2217 self.assertEqual(e.name, n)
2218 self.assertIn(e, Perm)
2219 self.assertIs(type(e), Perm)
2220
2221 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002222 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002223 lst = list(Perm)
2224 self.assertEqual(len(lst), len(Perm))
2225 self.assertEqual(len(Perm), 3, Perm)
2226 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2227 for i, n in enumerate('R W X'.split()):
2228 v = 1<<(2*i+1)
2229 e = Perm(v)
2230 self.assertEqual(e.value, v)
2231 self.assertEqual(type(e.value), int)
2232 self.assertEqual(e.name, n)
2233 self.assertIn(e, Perm)
2234 self.assertIs(type(e), Perm)
2235
2236 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002237 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002238 lst = list(Perm)
2239 self.assertEqual(len(lst), len(Perm))
2240 self.assertEqual(len(Perm), 3, Perm)
2241 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2242 for i, n in enumerate('R W X'.split()):
2243 v = 1<<(2*i+1)
2244 e = Perm(v)
2245 self.assertEqual(e.value, v)
2246 self.assertEqual(type(e.value), int)
2247 self.assertEqual(e.name, n)
2248 self.assertIn(e, Perm)
2249 self.assertIs(type(e), Perm)
2250
Ethan Furman65a5a472016-09-01 23:55:19 -07002251 def test_pickle(self):
2252 if isinstance(FlagStooges, Exception):
2253 raise FlagStooges
2254 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2255 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002256
Rahul Jha94306522018-09-10 23:51:04 +05302257 def test_contains(self):
2258 Open = self.Open
2259 Color = self.Color
2260 self.assertFalse(Color.BLACK in Open)
2261 self.assertFalse(Open.RO in Color)
2262 with self.assertRaises(TypeError):
2263 'BLACK' in Color
2264 with self.assertRaises(TypeError):
2265 'RO' in Open
2266 with self.assertRaises(TypeError):
2267 1 in Color
2268 with self.assertRaises(TypeError):
2269 1 in Open
2270
2271 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002272 Perm = self.Perm
2273 R, W, X = Perm
2274 RW = R | W
2275 RX = R | X
2276 WX = W | X
2277 RWX = R | W | X
2278 self.assertTrue(R in RW)
2279 self.assertTrue(R in RX)
2280 self.assertTrue(R in RWX)
2281 self.assertTrue(W in RW)
2282 self.assertTrue(W in WX)
2283 self.assertTrue(W in RWX)
2284 self.assertTrue(X in RX)
2285 self.assertTrue(X in WX)
2286 self.assertTrue(X in RWX)
2287 self.assertFalse(R in WX)
2288 self.assertFalse(W in RX)
2289 self.assertFalse(X in RW)
2290
Ethan Furmanc16595e2016-09-10 23:36:59 -07002291 def test_auto_number(self):
2292 class Color(Flag):
2293 red = auto()
2294 blue = auto()
2295 green = auto()
2296
2297 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2298 self.assertEqual(Color.red.value, 1)
2299 self.assertEqual(Color.blue.value, 2)
2300 self.assertEqual(Color.green.value, 4)
2301
2302 def test_auto_number_garbage(self):
2303 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2304 class Color(Flag):
2305 red = 'not an int'
2306 blue = auto()
2307
Ethan Furman3515dcc2016-09-18 13:15:41 -07002308 def test_cascading_failure(self):
2309 class Bizarre(Flag):
2310 c = 3
2311 d = 4
2312 f = 6
2313 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002314 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2315 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2316 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2317 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2318 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2319 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2320 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002321
2322 def test_duplicate_auto(self):
2323 class Dupes(Enum):
2324 first = primero = auto()
2325 second = auto()
2326 third = auto()
2327 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2328
2329 def test_bizarre(self):
2330 class Bizarre(Flag):
2331 b = 3
2332 c = 4
2333 d = 6
2334 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2335
Ethan Furman5bdab642018-09-21 19:03:09 -07002336 def test_multiple_mixin(self):
2337 class AllMixin:
2338 @classproperty
2339 def ALL(cls):
2340 members = list(cls)
2341 all_value = None
2342 if members:
2343 all_value = members[0]
2344 for member in members[1:]:
2345 all_value |= member
2346 cls.ALL = all_value
2347 return all_value
2348 class StrMixin:
2349 def __str__(self):
2350 return self._name_.lower()
2351 class Color(AllMixin, Flag):
2352 RED = auto()
2353 GREEN = auto()
2354 BLUE = auto()
2355 self.assertEqual(Color.RED.value, 1)
2356 self.assertEqual(Color.GREEN.value, 2)
2357 self.assertEqual(Color.BLUE.value, 4)
2358 self.assertEqual(Color.ALL.value, 7)
2359 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2360 class Color(AllMixin, StrMixin, Flag):
2361 RED = auto()
2362 GREEN = auto()
2363 BLUE = auto()
2364 self.assertEqual(Color.RED.value, 1)
2365 self.assertEqual(Color.GREEN.value, 2)
2366 self.assertEqual(Color.BLUE.value, 4)
2367 self.assertEqual(Color.ALL.value, 7)
2368 self.assertEqual(str(Color.BLUE), 'blue')
2369 class Color(StrMixin, AllMixin, Flag):
2370 RED = auto()
2371 GREEN = auto()
2372 BLUE = auto()
2373 self.assertEqual(Color.RED.value, 1)
2374 self.assertEqual(Color.GREEN.value, 2)
2375 self.assertEqual(Color.BLUE.value, 4)
2376 self.assertEqual(Color.ALL.value, 7)
2377 self.assertEqual(str(Color.BLUE), 'blue')
2378
Ethan Furman28cf6632017-01-24 12:12:06 -08002379 @support.reap_threads
2380 def test_unique_composite(self):
2381 # override __eq__ to be identity only
2382 class TestFlag(Flag):
2383 one = auto()
2384 two = auto()
2385 three = auto()
2386 four = auto()
2387 five = auto()
2388 six = auto()
2389 seven = auto()
2390 eight = auto()
2391 def __eq__(self, other):
2392 return self is other
2393 def __hash__(self):
2394 return hash(self._value_)
2395 # have multiple threads competing to complete the composite members
2396 seen = set()
2397 failed = False
2398 def cycle_enum():
2399 nonlocal failed
2400 try:
2401 for i in range(256):
2402 seen.add(TestFlag(i))
2403 except Exception:
2404 failed = True
2405 threads = [
2406 threading.Thread(target=cycle_enum)
2407 for _ in range(8)
2408 ]
2409 with support.start_threads(threads):
2410 pass
2411 # check that only 248 members were created
2412 self.assertFalse(
2413 failed,
2414 'at least one thread failed while creating composite members')
2415 self.assertEqual(256, len(seen), 'too many composite members created')
2416
Ethan Furmanc16595e2016-09-10 23:36:59 -07002417
Ethan Furman65a5a472016-09-01 23:55:19 -07002418class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002419 """Tests of the IntFlags."""
2420
Ethan Furman65a5a472016-09-01 23:55:19 -07002421 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002422 X = 1 << 0
2423 W = 1 << 1
2424 R = 1 << 2
2425
Ethan Furman65a5a472016-09-01 23:55:19 -07002426 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002427 RO = 0
2428 WO = 1
2429 RW = 2
2430 AC = 3
2431 CE = 1<<19
2432
Rahul Jha94306522018-09-10 23:51:04 +05302433 class Color(IntFlag):
2434 BLACK = 0
2435 RED = 1
2436 GREEN = 2
2437 BLUE = 4
2438 PURPLE = RED|BLUE
2439
Ethan Furman3515dcc2016-09-18 13:15:41 -07002440 def test_type(self):
2441 Perm = self.Perm
2442 Open = self.Open
2443 for f in Perm:
2444 self.assertTrue(isinstance(f, Perm))
2445 self.assertEqual(f, f.value)
2446 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2447 self.assertEqual(Perm.W | Perm.X, 3)
2448 for f in Open:
2449 self.assertTrue(isinstance(f, Open))
2450 self.assertEqual(f, f.value)
2451 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2452 self.assertEqual(Open.WO | Open.RW, 3)
2453
2454
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002455 def test_str(self):
2456 Perm = self.Perm
2457 self.assertEqual(str(Perm.R), 'Perm.R')
2458 self.assertEqual(str(Perm.W), 'Perm.W')
2459 self.assertEqual(str(Perm.X), 'Perm.X')
2460 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2461 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2462 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2463 self.assertEqual(str(Perm(0)), 'Perm.0')
2464 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002465 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2466 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2467 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2468 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002469 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002470 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2471 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2472 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002473
2474 Open = self.Open
2475 self.assertEqual(str(Open.RO), 'Open.RO')
2476 self.assertEqual(str(Open.WO), 'Open.WO')
2477 self.assertEqual(str(Open.AC), 'Open.AC')
2478 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2479 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2480 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002481 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2482 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2483 self.assertEqual(str(~Open.AC), 'Open.CE')
2484 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2485 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2486 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002487
2488 def test_repr(self):
2489 Perm = self.Perm
2490 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2491 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2492 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2493 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2494 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2495 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002496 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2497 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002498 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2499 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2500 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2501 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002502 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002503 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2504 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2505 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002506
2507 Open = self.Open
2508 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2509 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2510 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2511 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2512 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002513 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002514 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2515 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2516 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2517 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2518 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2519 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002520
2521 def test_or(self):
2522 Perm = self.Perm
2523 for i in Perm:
2524 for j in Perm:
2525 self.assertEqual(i | j, i.value | j.value)
2526 self.assertEqual((i | j).value, i.value | j.value)
2527 self.assertIs(type(i | j), Perm)
2528 for j in range(8):
2529 self.assertEqual(i | j, i.value | j)
2530 self.assertEqual((i | j).value, i.value | j)
2531 self.assertIs(type(i | j), Perm)
2532 self.assertEqual(j | i, j | i.value)
2533 self.assertEqual((j | i).value, j | i.value)
2534 self.assertIs(type(j | i), Perm)
2535 for i in Perm:
2536 self.assertIs(i | i, i)
2537 self.assertIs(i | 0, i)
2538 self.assertIs(0 | i, i)
2539 Open = self.Open
2540 self.assertIs(Open.RO | Open.CE, Open.CE)
2541
2542 def test_and(self):
2543 Perm = self.Perm
2544 RW = Perm.R | Perm.W
2545 RX = Perm.R | Perm.X
2546 WX = Perm.W | Perm.X
2547 RWX = Perm.R | Perm.W | Perm.X
2548 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2549 for i in values:
2550 for j in values:
2551 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2552 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2553 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2554 for j in range(8):
2555 self.assertEqual(i & j, i.value & j)
2556 self.assertEqual((i & j).value, i.value & j)
2557 self.assertIs(type(i & j), Perm)
2558 self.assertEqual(j & i, j & i.value)
2559 self.assertEqual((j & i).value, j & i.value)
2560 self.assertIs(type(j & i), Perm)
2561 for i in Perm:
2562 self.assertIs(i & i, i)
2563 self.assertIs(i & 7, i)
2564 self.assertIs(7 & i, i)
2565 Open = self.Open
2566 self.assertIs(Open.RO & Open.CE, Open.RO)
2567
2568 def test_xor(self):
2569 Perm = self.Perm
2570 for i in Perm:
2571 for j in Perm:
2572 self.assertEqual(i ^ j, i.value ^ j.value)
2573 self.assertEqual((i ^ j).value, i.value ^ j.value)
2574 self.assertIs(type(i ^ j), Perm)
2575 for j in range(8):
2576 self.assertEqual(i ^ j, i.value ^ j)
2577 self.assertEqual((i ^ j).value, i.value ^ j)
2578 self.assertIs(type(i ^ j), Perm)
2579 self.assertEqual(j ^ i, j ^ i.value)
2580 self.assertEqual((j ^ i).value, j ^ i.value)
2581 self.assertIs(type(j ^ i), Perm)
2582 for i in Perm:
2583 self.assertIs(i ^ 0, i)
2584 self.assertIs(0 ^ i, i)
2585 Open = self.Open
2586 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2587 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2588
2589 def test_invert(self):
2590 Perm = self.Perm
2591 RW = Perm.R | Perm.W
2592 RX = Perm.R | Perm.X
2593 WX = Perm.W | Perm.X
2594 RWX = Perm.R | Perm.W | Perm.X
2595 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2596 for i in values:
2597 self.assertEqual(~i, ~i.value)
2598 self.assertEqual((~i).value, ~i.value)
2599 self.assertIs(type(~i), Perm)
2600 self.assertEqual(~~i, i)
2601 for i in Perm:
2602 self.assertIs(~~i, i)
2603 Open = self.Open
2604 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2605 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2606
2607 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002608 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002609 lst = list(Perm)
2610 self.assertEqual(len(lst), len(Perm))
2611 self.assertEqual(len(Perm), 3, Perm)
2612 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2613 for i, n in enumerate('R W X'.split()):
2614 v = 1<<i
2615 e = Perm(v)
2616 self.assertEqual(e.value, v)
2617 self.assertEqual(type(e.value), int)
2618 self.assertEqual(e, v)
2619 self.assertEqual(e.name, n)
2620 self.assertIn(e, Perm)
2621 self.assertIs(type(e), Perm)
2622
2623 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002624 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002625 lst = list(Perm)
2626 self.assertEqual(len(lst), len(Perm))
2627 self.assertEqual(len(Perm), 3, Perm)
2628 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2629 for i, n in enumerate('R W X'.split()):
2630 v = 8<<i
2631 e = Perm(v)
2632 self.assertEqual(e.value, v)
2633 self.assertEqual(type(e.value), int)
2634 self.assertEqual(e, v)
2635 self.assertEqual(e.name, n)
2636 self.assertIn(e, Perm)
2637 self.assertIs(type(e), Perm)
2638
2639 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002640 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002641 lst = list(Perm)
2642 self.assertEqual(len(lst), len(Perm))
2643 self.assertEqual(len(Perm), 3, Perm)
2644 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2645 for i, n in enumerate('R W X'.split()):
2646 v = 1<<i
2647 e = Perm(v)
2648 self.assertEqual(e.value, v)
2649 self.assertEqual(type(e.value), int)
2650 self.assertEqual(e, v)
2651 self.assertEqual(e.name, n)
2652 self.assertIn(e, Perm)
2653 self.assertIs(type(e), Perm)
2654
2655 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002656 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002657 lst = list(Perm)
2658 self.assertEqual(len(lst), len(Perm))
2659 self.assertEqual(len(Perm), 3, Perm)
2660 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2661 for i, n in enumerate('R W X'.split()):
2662 v = 1<<(2*i+1)
2663 e = Perm(v)
2664 self.assertEqual(e.value, v)
2665 self.assertEqual(type(e.value), int)
2666 self.assertEqual(e, v)
2667 self.assertEqual(e.name, n)
2668 self.assertIn(e, Perm)
2669 self.assertIs(type(e), Perm)
2670
2671 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002672 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002673 lst = list(Perm)
2674 self.assertEqual(len(lst), len(Perm))
2675 self.assertEqual(len(Perm), 3, Perm)
2676 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2677 for i, n in enumerate('R W X'.split()):
2678 v = 1<<(2*i+1)
2679 e = Perm(v)
2680 self.assertEqual(e.value, v)
2681 self.assertEqual(type(e.value), int)
2682 self.assertEqual(e, v)
2683 self.assertEqual(e.name, n)
2684 self.assertIn(e, Perm)
2685 self.assertIs(type(e), Perm)
2686
2687
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002688 def test_programatic_function_from_empty_list(self):
2689 Perm = enum.IntFlag('Perm', [])
2690 lst = list(Perm)
2691 self.assertEqual(len(lst), len(Perm))
2692 self.assertEqual(len(Perm), 0, Perm)
2693 Thing = enum.Enum('Thing', [])
2694 lst = list(Thing)
2695 self.assertEqual(len(lst), len(Thing))
2696 self.assertEqual(len(Thing), 0, Thing)
2697
2698
2699 def test_programatic_function_from_empty_tuple(self):
2700 Perm = enum.IntFlag('Perm', ())
2701 lst = list(Perm)
2702 self.assertEqual(len(lst), len(Perm))
2703 self.assertEqual(len(Perm), 0, Perm)
2704 Thing = enum.Enum('Thing', ())
2705 self.assertEqual(len(lst), len(Thing))
2706 self.assertEqual(len(Thing), 0, Thing)
2707
Rahul Jha94306522018-09-10 23:51:04 +05302708 def test_contains(self):
2709 Open = self.Open
2710 Color = self.Color
2711 self.assertTrue(Color.GREEN in Color)
2712 self.assertTrue(Open.RW in Open)
2713 self.assertFalse(Color.GREEN in Open)
2714 self.assertFalse(Open.RW in Color)
2715 with self.assertRaises(TypeError):
2716 'GREEN' in Color
2717 with self.assertRaises(TypeError):
2718 'RW' in Open
2719 with self.assertRaises(TypeError):
2720 2 in Color
2721 with self.assertRaises(TypeError):
2722 2 in Open
2723
2724 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002725 Perm = self.Perm
2726 R, W, X = Perm
2727 RW = R | W
2728 RX = R | X
2729 WX = W | X
2730 RWX = R | W | X
2731 self.assertTrue(R in RW)
2732 self.assertTrue(R in RX)
2733 self.assertTrue(R in RWX)
2734 self.assertTrue(W in RW)
2735 self.assertTrue(W in WX)
2736 self.assertTrue(W in RWX)
2737 self.assertTrue(X in RX)
2738 self.assertTrue(X in WX)
2739 self.assertTrue(X in RWX)
2740 self.assertFalse(R in WX)
2741 self.assertFalse(W in RX)
2742 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302743 with self.assertRaises(TypeError):
2744 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002745
Ethan Furman25d94bb2016-09-02 16:32:32 -07002746 def test_bool(self):
2747 Perm = self.Perm
2748 for f in Perm:
2749 self.assertTrue(f)
2750 Open = self.Open
2751 for f in Open:
2752 self.assertEqual(bool(f.value), bool(f))
2753
Ethan Furman5bdab642018-09-21 19:03:09 -07002754 def test_multiple_mixin(self):
2755 class AllMixin:
2756 @classproperty
2757 def ALL(cls):
2758 members = list(cls)
2759 all_value = None
2760 if members:
2761 all_value = members[0]
2762 for member in members[1:]:
2763 all_value |= member
2764 cls.ALL = all_value
2765 return all_value
2766 class StrMixin:
2767 def __str__(self):
2768 return self._name_.lower()
2769 class Color(AllMixin, IntFlag):
2770 RED = auto()
2771 GREEN = auto()
2772 BLUE = auto()
2773 self.assertEqual(Color.RED.value, 1)
2774 self.assertEqual(Color.GREEN.value, 2)
2775 self.assertEqual(Color.BLUE.value, 4)
2776 self.assertEqual(Color.ALL.value, 7)
2777 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2778 class Color(AllMixin, StrMixin, IntFlag):
2779 RED = auto()
2780 GREEN = auto()
2781 BLUE = auto()
2782 self.assertEqual(Color.RED.value, 1)
2783 self.assertEqual(Color.GREEN.value, 2)
2784 self.assertEqual(Color.BLUE.value, 4)
2785 self.assertEqual(Color.ALL.value, 7)
2786 self.assertEqual(str(Color.BLUE), 'blue')
2787 class Color(StrMixin, AllMixin, IntFlag):
2788 RED = auto()
2789 GREEN = auto()
2790 BLUE = auto()
2791 self.assertEqual(Color.RED.value, 1)
2792 self.assertEqual(Color.GREEN.value, 2)
2793 self.assertEqual(Color.BLUE.value, 4)
2794 self.assertEqual(Color.ALL.value, 7)
2795 self.assertEqual(str(Color.BLUE), 'blue')
2796
Ethan Furman28cf6632017-01-24 12:12:06 -08002797 @support.reap_threads
2798 def test_unique_composite(self):
2799 # override __eq__ to be identity only
2800 class TestFlag(IntFlag):
2801 one = auto()
2802 two = auto()
2803 three = auto()
2804 four = auto()
2805 five = auto()
2806 six = auto()
2807 seven = auto()
2808 eight = auto()
2809 def __eq__(self, other):
2810 return self is other
2811 def __hash__(self):
2812 return hash(self._value_)
2813 # have multiple threads competing to complete the composite members
2814 seen = set()
2815 failed = False
2816 def cycle_enum():
2817 nonlocal failed
2818 try:
2819 for i in range(256):
2820 seen.add(TestFlag(i))
2821 except Exception:
2822 failed = True
2823 threads = [
2824 threading.Thread(target=cycle_enum)
2825 for _ in range(8)
2826 ]
2827 with support.start_threads(threads):
2828 pass
2829 # check that only 248 members were created
2830 self.assertFalse(
2831 failed,
2832 'at least one thread failed while creating composite members')
2833 self.assertEqual(256, len(seen), 'too many composite members created')
2834
2835
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002836class TestEmptyAndNonLatinStrings(unittest.TestCase):
2837
2838 def test_empty_string(self):
2839 with self.assertRaises(ValueError):
2840 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2841
2842 def test_non_latin_character_string(self):
2843 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
2844 item = getattr(greek_abc, '\u03B1')
2845 self.assertEqual(item.value, 1)
2846
2847 def test_non_latin_number_string(self):
2848 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
2849 item = getattr(hebrew_123, '\u05D0')
2850 self.assertEqual(item.value, 1)
2851
2852
Ethan Furmanf24bb352013-07-18 17:05:39 -07002853class TestUnique(unittest.TestCase):
2854
2855 def test_unique_clean(self):
2856 @unique
2857 class Clean(Enum):
2858 one = 1
2859 two = 'dos'
2860 tres = 4.0
2861 @unique
2862 class Cleaner(IntEnum):
2863 single = 1
2864 double = 2
2865 triple = 3
2866
2867 def test_unique_dirty(self):
2868 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2869 @unique
2870 class Dirty(Enum):
2871 one = 1
2872 two = 'dos'
2873 tres = 1
2874 with self.assertRaisesRegex(
2875 ValueError,
2876 'double.*single.*turkey.*triple',
2877 ):
2878 @unique
2879 class Dirtier(IntEnum):
2880 single = 1
2881 double = 1
2882 triple = 3
2883 turkey = 3
2884
Ethan Furman3803ad42016-05-01 10:03:53 -07002885 def test_unique_with_name(self):
2886 @unique
2887 class Silly(Enum):
2888 one = 1
2889 two = 'dos'
2890 name = 3
2891 @unique
2892 class Sillier(IntEnum):
2893 single = 1
2894 name = 2
2895 triple = 3
2896 value = 4
2897
Ethan Furmanf24bb352013-07-18 17:05:39 -07002898
Ethan Furman5bdab642018-09-21 19:03:09 -07002899
Ethan Furman3323da92015-04-11 09:39:59 -07002900expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002901Help on class Color in module %s:
2902
2903class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002904 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2905 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002906 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002907 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002908 | Method resolution order:
2909 | Color
2910 | enum.Enum
2911 | builtins.object
2912 |\x20\x20
2913 | Data and other attributes defined here:
2914 |\x20\x20
2915 | blue = <Color.blue: 3>
2916 |\x20\x20
2917 | green = <Color.green: 2>
2918 |\x20\x20
2919 | red = <Color.red: 1>
2920 |\x20\x20
2921 | ----------------------------------------------------------------------
2922 | Data descriptors inherited from enum.Enum:
2923 |\x20\x20
2924 | name
2925 | The name of the Enum member.
2926 |\x20\x20
2927 | value
2928 | The value of the Enum member.
2929 |\x20\x20
2930 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07002931 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07002932 |\x20\x20
2933 | __members__
2934 | Returns a mapping of member name->value.
2935 |\x20\x20\x20\x20\x20\x20
2936 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002937 | is a read-only view of the internal mapping."""
2938
2939expected_help_output_without_docs = """\
2940Help on class Color in module %s:
2941
2942class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002943 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2944 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002945 | Method resolution order:
2946 | Color
2947 | enum.Enum
2948 | builtins.object
2949 |\x20\x20
2950 | Data and other attributes defined here:
2951 |\x20\x20
2952 | blue = <Color.blue: 3>
2953 |\x20\x20
2954 | green = <Color.green: 2>
2955 |\x20\x20
2956 | red = <Color.red: 1>
2957 |\x20\x20
2958 | ----------------------------------------------------------------------
2959 | Data descriptors inherited from enum.Enum:
2960 |\x20\x20
2961 | name
2962 |\x20\x20
2963 | value
2964 |\x20\x20
2965 | ----------------------------------------------------------------------
2966 | Data descriptors inherited from enum.EnumMeta:
2967 |\x20\x20
2968 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002969
2970class TestStdLib(unittest.TestCase):
2971
Ethan Furman48a724f2015-04-11 23:23:06 -07002972 maxDiff = None
2973
Ethan Furman5875d742013-10-21 20:45:55 -07002974 class Color(Enum):
2975 red = 1
2976 green = 2
2977 blue = 3
2978
2979 def test_pydoc(self):
2980 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002981 if StrEnum.__doc__ is None:
2982 expected_text = expected_help_output_without_docs % __name__
2983 else:
2984 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002985 output = StringIO()
2986 helper = pydoc.Helper(output=output)
2987 helper(self.Color)
2988 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002989 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002990
2991 def test_inspect_getmembers(self):
2992 values = dict((
2993 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002994 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002995 ('__members__', self.Color.__members__),
2996 ('__module__', __name__),
2997 ('blue', self.Color.blue),
2998 ('green', self.Color.green),
2999 ('name', Enum.__dict__['name']),
3000 ('red', self.Color.red),
3001 ('value', Enum.__dict__['value']),
3002 ))
3003 result = dict(inspect.getmembers(self.Color))
3004 self.assertEqual(values.keys(), result.keys())
3005 failed = False
3006 for k in values.keys():
3007 if result[k] != values[k]:
3008 print()
3009 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3010 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3011 failed = True
3012 if failed:
3013 self.fail("result does not equal expected, see print above")
3014
3015 def test_inspect_classify_class_attrs(self):
3016 # indirectly test __objclass__
3017 from inspect import Attribute
3018 values = [
3019 Attribute(name='__class__', kind='data',
3020 defining_class=object, object=EnumMeta),
3021 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003022 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003023 Attribute(name='__members__', kind='property',
3024 defining_class=EnumMeta, object=EnumMeta.__members__),
3025 Attribute(name='__module__', kind='data',
3026 defining_class=self.Color, object=__name__),
3027 Attribute(name='blue', kind='data',
3028 defining_class=self.Color, object=self.Color.blue),
3029 Attribute(name='green', kind='data',
3030 defining_class=self.Color, object=self.Color.green),
3031 Attribute(name='red', kind='data',
3032 defining_class=self.Color, object=self.Color.red),
3033 Attribute(name='name', kind='data',
3034 defining_class=Enum, object=Enum.__dict__['name']),
3035 Attribute(name='value', kind='data',
3036 defining_class=Enum, object=Enum.__dict__['value']),
3037 ]
3038 values.sort(key=lambda item: item.name)
3039 result = list(inspect.classify_class_attrs(self.Color))
3040 result.sort(key=lambda item: item.name)
3041 failed = False
3042 for v, r in zip(values, result):
3043 if r != v:
3044 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3045 failed = True
3046 if failed:
3047 self.fail("result does not equal expected, see print above")
3048
Martin Panter19e69c52015-11-14 12:46:42 +00003049
3050class MiscTestCase(unittest.TestCase):
3051 def test__all__(self):
3052 support.check__all__(self, enum)
3053
3054
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003055# These are unordered here on purpose to ensure that declaration order
3056# makes no difference.
3057CONVERT_TEST_NAME_D = 5
3058CONVERT_TEST_NAME_C = 5
3059CONVERT_TEST_NAME_B = 5
3060CONVERT_TEST_NAME_A = 5 # This one should sort first.
3061CONVERT_TEST_NAME_E = 5
3062CONVERT_TEST_NAME_F = 5
3063
3064class TestIntEnumConvert(unittest.TestCase):
3065 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003066 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003067 'UnittestConvert',
3068 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003069 filter=lambda x: x.startswith('CONVERT_TEST_'))
3070 # We don't want the reverse lookup value to vary when there are
3071 # multiple possible names for a given value. It should always
3072 # report the first lexigraphical name in that case.
3073 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3074
3075 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003076 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003077 'UnittestConvert',
3078 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003079 filter=lambda x: x.startswith('CONVERT_TEST_'))
3080 # Ensure that test_type has all of the desired names and values.
3081 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3082 test_type.CONVERT_TEST_NAME_A)
3083 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3084 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3085 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3086 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3087 # Ensure that test_type only picked up names matching the filter.
3088 self.assertEqual([name for name in dir(test_type)
3089 if name[0:2] not in ('CO', '__')],
3090 [], msg='Names other than CONVERT_TEST_* found.')
3091
orlnub1230fb9fad2018-09-12 20:28:53 +03003092 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3093 '_convert was deprecated in 3.8')
3094 def test_convert_warn(self):
3095 with self.assertWarns(DeprecationWarning):
3096 enum.IntEnum._convert(
3097 'UnittestConvert',
3098 ('test.test_enum', '__main__')[__name__=='__main__'],
3099 filter=lambda x: x.startswith('CONVERT_TEST_'))
3100
3101 @unittest.skipUnless(sys.version_info >= (3, 9),
3102 '_convert was removed in 3.9')
3103 def test_convert_raise(self):
3104 with self.assertRaises(AttributeError):
3105 enum.IntEnum._convert(
3106 'UnittestConvert',
3107 ('test.test_enum', '__main__')[__name__=='__main__'],
3108 filter=lambda x: x.startswith('CONVERT_TEST_'))
3109
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003110
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003111if __name__ == '__main__':
3112 unittest.main()