blob: 7ca54e9a649ca8568b3c79b9369feca4d59408cf [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 Furman0063ff42020-09-21 17:23:13 -07008from enum import Enum, IntEnum, StrEnum, 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
Hai Shie80697d2020-05-28 06:10:27 +080013from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080014from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080015
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016
17# for pickle tests
18try:
19 class Stooges(Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23except Exception as exc:
24 Stooges = exc
25
26try:
27 class IntStooges(int, Enum):
28 LARRY = 1
29 CURLY = 2
30 MOE = 3
31except Exception as exc:
32 IntStooges = exc
33
34try:
35 class FloatStooges(float, Enum):
36 LARRY = 1.39
37 CURLY = 2.72
38 MOE = 3.142596
39except Exception as exc:
40 FloatStooges = exc
41
Ethan Furman65a5a472016-09-01 23:55:19 -070042try:
43 class FlagStooges(Flag):
44 LARRY = 1
45 CURLY = 2
46 MOE = 3
47except Exception as exc:
48 FlagStooges = exc
49
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070051class Name(StrEnum):
52 BDFL = 'Guido van Rossum'
53 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070054
55try:
56 Question = Enum('Question', 'who what when where why', module=__name__)
57except Exception as exc:
58 Question = exc
59
60try:
61 Answer = Enum('Answer', 'him this then there because')
62except Exception as exc:
63 Answer = exc
64
Ethan Furmanca1b7942014-02-08 11:36:27 -080065try:
66 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
67except Exception as exc:
68 Theory = exc
69
Ethan Furman6b3d64a2013-06-14 16:55:46 -070070# for doctests
71try:
72 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080073 TOMATO = 1
74 BANANA = 2
75 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076except Exception:
77 pass
78
Serhiy Storchakae50e7802015-03-31 16:56:49 +030079def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080080 if target is None:
81 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030082 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080083 assertion(loads(dumps(source, protocol=protocol)), target)
84
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085def test_pickle_exception(assertion, exception, obj):
86 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 with assertion(exception):
88 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070089
90class TestHelpers(unittest.TestCase):
91 # _is_descriptor, _is_sunder, _is_dunder
92
93 def test_is_descriptor(self):
94 class foo:
95 pass
96 for attr in ('__get__','__set__','__delete__'):
97 obj = foo()
98 self.assertFalse(enum._is_descriptor(obj))
99 setattr(obj, attr, 1)
100 self.assertTrue(enum._is_descriptor(obj))
101
102 def test_is_sunder(self):
103 for s in ('_a_', '_aa_'):
104 self.assertTrue(enum._is_sunder(s))
105
106 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
107 '__', '___', '____', '_____',):
108 self.assertFalse(enum._is_sunder(s))
109
110 def test_is_dunder(self):
111 for s in ('__a__', '__aa__'):
112 self.assertTrue(enum._is_dunder(s))
113 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
114 '__', '___', '____', '_____',):
115 self.assertFalse(enum._is_dunder(s))
116
Ethan Furman5bdab642018-09-21 19:03:09 -0700117# for subclassing tests
118
119class classproperty:
120
121 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
122 self.fget = fget
123 self.fset = fset
124 self.fdel = fdel
125 if doc is None and fget is not None:
126 doc = fget.__doc__
127 self.__doc__ = doc
128
129 def __get__(self, instance, ownerclass):
130 return self.fget(ownerclass)
131
132
Ethan Furmanc16595e2016-09-10 23:36:59 -0700133# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700134
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700135class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800136
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700137 def setUp(self):
138 class Season(Enum):
139 SPRING = 1
140 SUMMER = 2
141 AUTUMN = 3
142 WINTER = 4
143 self.Season = Season
144
Ethan Furmanec15a822013-08-31 19:17:41 -0700145 class Konstants(float, Enum):
146 E = 2.7182818
147 PI = 3.1415926
148 TAU = 2 * PI
149 self.Konstants = Konstants
150
151 class Grades(IntEnum):
152 A = 5
153 B = 4
154 C = 3
155 D = 2
156 F = 0
157 self.Grades = Grades
158
159 class Directional(str, Enum):
160 EAST = 'east'
161 WEST = 'west'
162 NORTH = 'north'
163 SOUTH = 'south'
164 self.Directional = Directional
165
166 from datetime import date
167 class Holiday(date, Enum):
168 NEW_YEAR = 2013, 1, 1
169 IDES_OF_MARCH = 2013, 3, 15
170 self.Holiday = Holiday
171
Ethan Furman388a3922013-08-12 06:51:41 -0700172 def test_dir_on_class(self):
173 Season = self.Season
174 self.assertEqual(
175 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700176 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700177 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
178 )
179
180 def test_dir_on_item(self):
181 Season = self.Season
182 self.assertEqual(
183 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700184 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700185 )
186
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 def test_dir_with_added_behavior(self):
188 class Test(Enum):
189 this = 'that'
190 these = 'those'
191 def wowser(self):
192 return ("Wowser! I'm %s!" % self.name)
193 self.assertEqual(
194 set(dir(Test)),
195 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
196 )
197 self.assertEqual(
198 set(dir(Test.this)),
199 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
200 )
201
Ethan Furman0ae550b2014-10-14 08:58:32 -0700202 def test_dir_on_sub_with_behavior_on_super(self):
203 # see issue22506
204 class SuperEnum(Enum):
205 def invisible(self):
206 return "did you see me?"
207 class SubEnum(SuperEnum):
208 sample = 5
209 self.assertEqual(
210 set(dir(SubEnum.sample)),
211 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
212 )
213
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200214 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
215 # see issue40084
216 class SuperEnum(IntEnum):
217 def __new__(cls, value, description=""):
218 obj = int.__new__(cls, value)
219 obj._value_ = value
220 obj.description = description
221 return obj
222 class SubEnum(SuperEnum):
223 sample = 5
224 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
225
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700226 def test_enum_in_enum_out(self):
227 Season = self.Season
228 self.assertIs(Season(Season.WINTER), Season.WINTER)
229
230 def test_enum_value(self):
231 Season = self.Season
232 self.assertEqual(Season.SPRING.value, 1)
233
234 def test_intenum_value(self):
235 self.assertEqual(IntStooges.CURLY.value, 2)
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum(self):
238 Season = self.Season
239 lst = list(Season)
240 self.assertEqual(len(lst), len(Season))
241 self.assertEqual(len(Season), 4, Season)
242 self.assertEqual(
243 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
244
245 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
246 e = Season(i)
247 self.assertEqual(e, getattr(Season, season))
248 self.assertEqual(e.value, i)
249 self.assertNotEqual(e, i)
250 self.assertEqual(e.name, season)
251 self.assertIn(e, Season)
252 self.assertIs(type(e), Season)
253 self.assertIsInstance(e, Season)
254 self.assertEqual(str(e), 'Season.' + season)
255 self.assertEqual(
256 repr(e),
257 '<Season.{0}: {1}>'.format(season, i),
258 )
259
260 def test_value_name(self):
261 Season = self.Season
262 self.assertEqual(Season.SPRING.name, 'SPRING')
263 self.assertEqual(Season.SPRING.value, 1)
264 with self.assertRaises(AttributeError):
265 Season.SPRING.name = 'invierno'
266 with self.assertRaises(AttributeError):
267 Season.SPRING.value = 2
268
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700269 def test_changing_member(self):
270 Season = self.Season
271 with self.assertRaises(AttributeError):
272 Season.WINTER = 'really cold'
273
Ethan Furman64a99722013-09-22 16:18:19 -0700274 def test_attribute_deletion(self):
275 class Season(Enum):
276 SPRING = 1
277 SUMMER = 2
278 AUTUMN = 3
279 WINTER = 4
280
281 def spam(cls):
282 pass
283
284 self.assertTrue(hasattr(Season, 'spam'))
285 del Season.spam
286 self.assertFalse(hasattr(Season, 'spam'))
287
288 with self.assertRaises(AttributeError):
289 del Season.SPRING
290 with self.assertRaises(AttributeError):
291 del Season.DRY
292 with self.assertRaises(AttributeError):
293 del Season.SPRING.name
294
Ethan Furman5de67b12016-04-13 23:52:09 -0700295 def test_bool_of_class(self):
296 class Empty(Enum):
297 pass
298 self.assertTrue(bool(Empty))
299
300 def test_bool_of_member(self):
301 class Count(Enum):
302 zero = 0
303 one = 1
304 two = 2
305 for member in Count:
306 self.assertTrue(bool(member))
307
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700308 def test_invalid_names(self):
309 with self.assertRaises(ValueError):
310 class Wrong(Enum):
311 mro = 9
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 _create_= 11
315 with self.assertRaises(ValueError):
316 class Wrong(Enum):
317 _get_mixins_ = 9
318 with self.assertRaises(ValueError):
319 class Wrong(Enum):
320 _find_new_ = 1
321 with self.assertRaises(ValueError):
322 class Wrong(Enum):
323 _any_name_ = 9
324
Ethan Furman6db1fd52015-09-17 21:49:12 -0700325 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800326 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700327 class Logic(Enum):
328 true = True
329 false = False
330 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800331 self.assertTrue(Logic.false)
332 # unless overridden
333 class RealLogic(Enum):
334 true = True
335 false = False
336 def __bool__(self):
337 return bool(self._value_)
338 self.assertTrue(RealLogic.true)
339 self.assertFalse(RealLogic.false)
340 # mixed Enums depend on mixed-in type
341 class IntLogic(int, Enum):
342 true = 1
343 false = 0
344 self.assertTrue(IntLogic.true)
345 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700346
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347 def test_contains(self):
348 Season = self.Season
349 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530350 with self.assertRaises(TypeError):
351 3 in Season
352 with self.assertRaises(TypeError):
353 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700354
355 val = Season(3)
356 self.assertIn(val, Season)
357
358 class OtherEnum(Enum):
359 one = 1; two = 2
360 self.assertNotIn(OtherEnum.two, Season)
361
362 def test_comparisons(self):
363 Season = self.Season
364 with self.assertRaises(TypeError):
365 Season.SPRING < Season.WINTER
366 with self.assertRaises(TypeError):
367 Season.SPRING > 4
368
369 self.assertNotEqual(Season.SPRING, 1)
370
371 class Part(Enum):
372 SPRING = 1
373 CLIP = 2
374 BARREL = 3
375
376 self.assertNotEqual(Season.SPRING, Part.SPRING)
377 with self.assertRaises(TypeError):
378 Season.SPRING < Part.CLIP
379
380 def test_enum_duplicates(self):
381 class Season(Enum):
382 SPRING = 1
383 SUMMER = 2
384 AUTUMN = FALL = 3
385 WINTER = 4
386 ANOTHER_SPRING = 1
387 lst = list(Season)
388 self.assertEqual(
389 lst,
390 [Season.SPRING, Season.SUMMER,
391 Season.AUTUMN, Season.WINTER,
392 ])
393 self.assertIs(Season.FALL, Season.AUTUMN)
394 self.assertEqual(Season.FALL.value, 3)
395 self.assertEqual(Season.AUTUMN.value, 3)
396 self.assertIs(Season(3), Season.AUTUMN)
397 self.assertIs(Season(1), Season.SPRING)
398 self.assertEqual(Season.FALL.name, 'AUTUMN')
399 self.assertEqual(
400 [k for k,v in Season.__members__.items() if v.name != k],
401 ['FALL', 'ANOTHER_SPRING'],
402 )
403
Ethan Furman101e0742013-09-15 12:34:36 -0700404 def test_duplicate_name(self):
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 red = 4
411
412 with self.assertRaises(TypeError):
413 class Color(Enum):
414 red = 1
415 green = 2
416 blue = 3
417 def red(self):
418 return 'red'
419
420 with self.assertRaises(TypeError):
421 class Color(Enum):
422 @property
423 def red(self):
424 return 'redder'
425 red = 1
426 green = 2
427 blue = 3
428
Zackery Spytz2ec67522020-09-13 14:27:51 -0600429 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700430 with self.assertRaisesRegex(
431 ValueError,
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800432 "_sunder_ names, such as '_bad_', are reserved",
Ethan Furman5a565b32020-09-15 12:27:06 -0700433 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600434 class Bad(Enum):
435 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700436
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700437 def test_enum_with_value_name(self):
438 class Huh(Enum):
439 name = 1
440 value = 2
441 self.assertEqual(
442 list(Huh),
443 [Huh.name, Huh.value],
444 )
445 self.assertIs(type(Huh.name), Huh)
446 self.assertEqual(Huh.name.name, 'name')
447 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700448
449 def test_format_enum(self):
450 Season = self.Season
451 self.assertEqual('{}'.format(Season.SPRING),
452 '{}'.format(str(Season.SPRING)))
453 self.assertEqual( '{:}'.format(Season.SPRING),
454 '{:}'.format(str(Season.SPRING)))
455 self.assertEqual('{:20}'.format(Season.SPRING),
456 '{:20}'.format(str(Season.SPRING)))
457 self.assertEqual('{:^20}'.format(Season.SPRING),
458 '{:^20}'.format(str(Season.SPRING)))
459 self.assertEqual('{:>20}'.format(Season.SPRING),
460 '{:>20}'.format(str(Season.SPRING)))
461 self.assertEqual('{:<20}'.format(Season.SPRING),
462 '{:<20}'.format(str(Season.SPRING)))
463
thatneat2f19e822019-07-04 11:28:37 -0700464 def test_str_override_enum(self):
465 class EnumWithStrOverrides(Enum):
466 one = auto()
467 two = auto()
468
469 def __str__(self):
470 return 'Str!'
471 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
472 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
473
474 def test_format_override_enum(self):
475 class EnumWithFormatOverride(Enum):
476 one = 1.0
477 two = 2.0
478 def __format__(self, spec):
479 return 'Format!!'
480 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
481 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
482
483 def test_str_and_format_override_enum(self):
484 class EnumWithStrFormatOverrides(Enum):
485 one = auto()
486 two = auto()
487 def __str__(self):
488 return 'Str!'
489 def __format__(self, spec):
490 return 'Format!'
491 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
492 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
493
494 def test_str_override_mixin(self):
495 class MixinEnumWithStrOverride(float, Enum):
496 one = 1.0
497 two = 2.0
498 def __str__(self):
499 return 'Overridden!'
500 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
501 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
502
503 def test_str_and_format_override_mixin(self):
504 class MixinWithStrFormatOverrides(float, Enum):
505 one = 1.0
506 two = 2.0
507 def __str__(self):
508 return 'Str!'
509 def __format__(self, spec):
510 return 'Format!'
511 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
512 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
513
514 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700515 class TestFloat(float, Enum):
516 one = 1.0
517 two = 2.0
518 def __format__(self, spec):
519 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700520 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700521 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
522
523 def assertFormatIsValue(self, spec, member):
524 self.assertEqual(spec.format(member), spec.format(member.value))
525
526 def test_format_enum_date(self):
527 Holiday = self.Holiday
528 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
529 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
530 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
531 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
532 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
533 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
534 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
535 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
536
537 def test_format_enum_float(self):
538 Konstants = self.Konstants
539 self.assertFormatIsValue('{}', Konstants.TAU)
540 self.assertFormatIsValue('{:}', Konstants.TAU)
541 self.assertFormatIsValue('{:20}', Konstants.TAU)
542 self.assertFormatIsValue('{:^20}', Konstants.TAU)
543 self.assertFormatIsValue('{:>20}', Konstants.TAU)
544 self.assertFormatIsValue('{:<20}', Konstants.TAU)
545 self.assertFormatIsValue('{:n}', Konstants.TAU)
546 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
547 self.assertFormatIsValue('{:f}', Konstants.TAU)
548
549 def test_format_enum_int(self):
550 Grades = self.Grades
551 self.assertFormatIsValue('{}', Grades.C)
552 self.assertFormatIsValue('{:}', Grades.C)
553 self.assertFormatIsValue('{:20}', Grades.C)
554 self.assertFormatIsValue('{:^20}', Grades.C)
555 self.assertFormatIsValue('{:>20}', Grades.C)
556 self.assertFormatIsValue('{:<20}', Grades.C)
557 self.assertFormatIsValue('{:+}', Grades.C)
558 self.assertFormatIsValue('{:08X}', Grades.C)
559 self.assertFormatIsValue('{:b}', Grades.C)
560
561 def test_format_enum_str(self):
562 Directional = self.Directional
563 self.assertFormatIsValue('{}', Directional.WEST)
564 self.assertFormatIsValue('{:}', Directional.WEST)
565 self.assertFormatIsValue('{:20}', Directional.WEST)
566 self.assertFormatIsValue('{:^20}', Directional.WEST)
567 self.assertFormatIsValue('{:>20}', Directional.WEST)
568 self.assertFormatIsValue('{:<20}', Directional.WEST)
569
Ethan Furman22415ad2020-09-15 16:28:25 -0700570 def test_object_str_override(self):
571 class Colors(Enum):
572 RED, GREEN, BLUE = 1, 2, 3
573 def __repr__(self):
574 return "test.%s" % (self._name_, )
575 __str__ = object.__str__
576 self.assertEqual(str(Colors.RED), 'test.RED')
577
Ethan Furmanbff01f32020-09-15 15:56:26 -0700578 def test_enum_str_override(self):
579 class MyStrEnum(Enum):
580 def __str__(self):
581 return 'MyStr'
582 class MyMethodEnum(Enum):
583 def hello(self):
584 return 'Hello! My name is %s' % self.name
585 class Test1Enum(MyMethodEnum, int, MyStrEnum):
586 One = 1
587 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800588 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700589 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800590 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700591 #
592 class Test2Enum(MyStrEnum, MyMethodEnum):
593 One = 1
594 Two = 2
595 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800596 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597
598 def test_inherited_data_type(self):
599 class HexInt(int):
600 def __repr__(self):
601 return hex(self)
602 class MyEnum(HexInt, enum.Enum):
603 A = 1
604 B = 2
605 C = 3
606 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
607
608 def test_too_many_data_types(self):
609 with self.assertRaisesRegex(TypeError, 'too many data types'):
610 class Huh(str, int, Enum):
611 One = 1
612
613 class MyStr(str):
614 def hello(self):
615 return 'hello, %s' % self
616 class MyInt(int):
617 def repr(self):
618 return hex(self)
619 with self.assertRaisesRegex(TypeError, 'too many data types'):
620 class Huh(MyStr, MyInt, Enum):
621 One = 1
622
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700623 def test_hash(self):
624 Season = self.Season
625 dates = {}
626 dates[Season.WINTER] = '1225'
627 dates[Season.SPRING] = '0315'
628 dates[Season.SUMMER] = '0704'
629 dates[Season.AUTUMN] = '1031'
630 self.assertEqual(dates[Season.AUTUMN], '1031')
631
632 def test_intenum_from_scratch(self):
633 class phy(int, Enum):
634 pi = 3
635 tau = 2 * pi
636 self.assertTrue(phy.pi < phy.tau)
637
638 def test_intenum_inherited(self):
639 class IntEnum(int, Enum):
640 pass
641 class phy(IntEnum):
642 pi = 3
643 tau = 2 * pi
644 self.assertTrue(phy.pi < phy.tau)
645
646 def test_floatenum_from_scratch(self):
647 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700648 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700649 tau = 2 * pi
650 self.assertTrue(phy.pi < phy.tau)
651
652 def test_floatenum_inherited(self):
653 class FloatEnum(float, Enum):
654 pass
655 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700656 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700657 tau = 2 * pi
658 self.assertTrue(phy.pi < phy.tau)
659
660 def test_strenum_from_scratch(self):
661 class phy(str, Enum):
662 pi = 'Pi'
663 tau = 'Tau'
664 self.assertTrue(phy.pi < phy.tau)
665
Ethan Furman0063ff42020-09-21 17:23:13 -0700666 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 class phy(StrEnum):
668 pi = 'Pi'
669 tau = 'Tau'
670 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700671 self.assertEqual(phy.pi.upper(), 'PI')
672 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700673
674 def test_intenum(self):
675 class WeekDay(IntEnum):
676 SUNDAY = 1
677 MONDAY = 2
678 TUESDAY = 3
679 WEDNESDAY = 4
680 THURSDAY = 5
681 FRIDAY = 6
682 SATURDAY = 7
683
684 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
685 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
686
687 lst = list(WeekDay)
688 self.assertEqual(len(lst), len(WeekDay))
689 self.assertEqual(len(WeekDay), 7)
690 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
691 target = target.split()
692 for i, weekday in enumerate(target, 1):
693 e = WeekDay(i)
694 self.assertEqual(e, i)
695 self.assertEqual(int(e), i)
696 self.assertEqual(e.name, weekday)
697 self.assertIn(e, WeekDay)
698 self.assertEqual(lst.index(e)+1, i)
699 self.assertTrue(0 < e < 8)
700 self.assertIs(type(e), WeekDay)
701 self.assertIsInstance(e, int)
702 self.assertIsInstance(e, Enum)
703
704 def test_intenum_duplicates(self):
705 class WeekDay(IntEnum):
706 SUNDAY = 1
707 MONDAY = 2
708 TUESDAY = TEUSDAY = 3
709 WEDNESDAY = 4
710 THURSDAY = 5
711 FRIDAY = 6
712 SATURDAY = 7
713 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
714 self.assertEqual(WeekDay(3).name, 'TUESDAY')
715 self.assertEqual([k for k,v in WeekDay.__members__.items()
716 if v.name != k], ['TEUSDAY', ])
717
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300718 def test_intenum_from_bytes(self):
719 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
720 with self.assertRaises(ValueError):
721 IntStooges.from_bytes(b'\x00\x05', 'big')
722
723 def test_floatenum_fromhex(self):
724 h = float.hex(FloatStooges.MOE.value)
725 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
726 h = float.hex(FloatStooges.MOE.value + 0.01)
727 with self.assertRaises(ValueError):
728 FloatStooges.fromhex(h)
729
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700730 def test_pickle_enum(self):
731 if isinstance(Stooges, Exception):
732 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800733 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
734 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700735
736 def test_pickle_int(self):
737 if isinstance(IntStooges, Exception):
738 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800739 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
740 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700741
742 def test_pickle_float(self):
743 if isinstance(FloatStooges, Exception):
744 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800745 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
746 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700747
748 def test_pickle_enum_function(self):
749 if isinstance(Answer, Exception):
750 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800751 test_pickle_dump_load(self.assertIs, Answer.him)
752 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700753
754 def test_pickle_enum_function_with_module(self):
755 if isinstance(Question, Exception):
756 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800757 test_pickle_dump_load(self.assertIs, Question.who)
758 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700759
Ethan Furmanca1b7942014-02-08 11:36:27 -0800760 def test_enum_function_with_qualname(self):
761 if isinstance(Theory, Exception):
762 raise Theory
763 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
764
765 def test_class_nested_enum_and_pickle_protocol_four(self):
766 # would normally just have this directly in the class namespace
767 class NestedEnum(Enum):
768 twigs = 'common'
769 shiny = 'rare'
770
771 self.__class__.NestedEnum = NestedEnum
772 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300773 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800774
Ethan Furman24e837f2015-03-18 17:27:57 -0700775 def test_pickle_by_name(self):
776 class ReplaceGlobalInt(IntEnum):
777 ONE = 1
778 TWO = 2
779 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
780 for proto in range(HIGHEST_PROTOCOL):
781 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
782
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784 BadPickle = Enum(
785 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700786 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800787 # now break BadPickle to test exception raising
788 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800789 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
790 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700791
792 def test_string_enum(self):
793 class SkillLevel(str, Enum):
794 master = 'what is the sound of one hand clapping?'
795 journeyman = 'why did the chicken cross the road?'
796 apprentice = 'knock, knock!'
797 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
798
799 def test_getattr_getitem(self):
800 class Period(Enum):
801 morning = 1
802 noon = 2
803 evening = 3
804 night = 4
805 self.assertIs(Period(2), Period.noon)
806 self.assertIs(getattr(Period, 'night'), Period.night)
807 self.assertIs(Period['morning'], Period.morning)
808
809 def test_getattr_dunder(self):
810 Season = self.Season
811 self.assertTrue(getattr(Season, '__eq__'))
812
813 def test_iteration_order(self):
814 class Season(Enum):
815 SUMMER = 2
816 WINTER = 4
817 AUTUMN = 3
818 SPRING = 1
819 self.assertEqual(
820 list(Season),
821 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
822 )
823
Ethan Furman2131a4a2013-09-14 18:11:24 -0700824 def test_reversed_iteration_order(self):
825 self.assertEqual(
826 list(reversed(self.Season)),
827 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
828 self.Season.SPRING]
829 )
830
Martin Pantereb995702016-07-28 01:11:04 +0000831 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832 SummerMonth = Enum('SummerMonth', 'june july august')
833 lst = list(SummerMonth)
834 self.assertEqual(len(lst), len(SummerMonth))
835 self.assertEqual(len(SummerMonth), 3, SummerMonth)
836 self.assertEqual(
837 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
838 lst,
839 )
840 for i, month in enumerate('june july august'.split(), 1):
841 e = SummerMonth(i)
842 self.assertEqual(int(e.value), i)
843 self.assertNotEqual(e, i)
844 self.assertEqual(e.name, month)
845 self.assertIn(e, SummerMonth)
846 self.assertIs(type(e), SummerMonth)
847
Martin Pantereb995702016-07-28 01:11:04 +0000848 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700849 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
850 lst = list(SummerMonth)
851 self.assertEqual(len(lst), len(SummerMonth))
852 self.assertEqual(len(SummerMonth), 3, SummerMonth)
853 self.assertEqual(
854 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
855 lst,
856 )
857 for i, month in enumerate('june july august'.split(), 10):
858 e = SummerMonth(i)
859 self.assertEqual(int(e.value), i)
860 self.assertNotEqual(e, i)
861 self.assertEqual(e.name, month)
862 self.assertIn(e, SummerMonth)
863 self.assertIs(type(e), SummerMonth)
864
Martin Pantereb995702016-07-28 01:11:04 +0000865 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700866 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
867 lst = list(SummerMonth)
868 self.assertEqual(len(lst), len(SummerMonth))
869 self.assertEqual(len(SummerMonth), 3, SummerMonth)
870 self.assertEqual(
871 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
872 lst,
873 )
874 for i, month in enumerate('june july august'.split(), 1):
875 e = SummerMonth(i)
876 self.assertEqual(int(e.value), i)
877 self.assertNotEqual(e, i)
878 self.assertEqual(e.name, month)
879 self.assertIn(e, SummerMonth)
880 self.assertIs(type(e), SummerMonth)
881
Martin Pantereb995702016-07-28 01:11:04 +0000882 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700883 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
884 lst = list(SummerMonth)
885 self.assertEqual(len(lst), len(SummerMonth))
886 self.assertEqual(len(SummerMonth), 3, SummerMonth)
887 self.assertEqual(
888 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
889 lst,
890 )
891 for i, month in enumerate('june july august'.split(), 20):
892 e = SummerMonth(i)
893 self.assertEqual(int(e.value), i)
894 self.assertNotEqual(e, i)
895 self.assertEqual(e.name, month)
896 self.assertIn(e, SummerMonth)
897 self.assertIs(type(e), SummerMonth)
898
Martin Pantereb995702016-07-28 01:11:04 +0000899 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700900 SummerMonth = Enum(
901 'SummerMonth',
902 (('june', 1), ('july', 2), ('august', 3))
903 )
904 lst = list(SummerMonth)
905 self.assertEqual(len(lst), len(SummerMonth))
906 self.assertEqual(len(SummerMonth), 3, SummerMonth)
907 self.assertEqual(
908 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
909 lst,
910 )
911 for i, month in enumerate('june july august'.split(), 1):
912 e = SummerMonth(i)
913 self.assertEqual(int(e.value), i)
914 self.assertNotEqual(e, i)
915 self.assertEqual(e.name, month)
916 self.assertIn(e, SummerMonth)
917 self.assertIs(type(e), SummerMonth)
918
Martin Pantereb995702016-07-28 01:11:04 +0000919 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700920 SummerMonth = Enum(
921 'SummerMonth',
922 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
923 )
924 lst = list(SummerMonth)
925 self.assertEqual(len(lst), len(SummerMonth))
926 self.assertEqual(len(SummerMonth), 3, SummerMonth)
927 self.assertEqual(
928 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
929 lst,
930 )
931 for i, month in enumerate('june july august'.split(), 1):
932 e = SummerMonth(i)
933 self.assertEqual(int(e.value), i)
934 self.assertNotEqual(e, i)
935 self.assertEqual(e.name, month)
936 self.assertIn(e, SummerMonth)
937 self.assertIs(type(e), SummerMonth)
938
Martin Pantereb995702016-07-28 01:11:04 +0000939 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700940 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
941 lst = list(SummerMonth)
942 self.assertEqual(len(lst), len(SummerMonth))
943 self.assertEqual(len(SummerMonth), 3, SummerMonth)
944 self.assertEqual(
945 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
946 lst,
947 )
948 for i, month in enumerate('june july august'.split(), 1):
949 e = SummerMonth(i)
950 self.assertEqual(e, i)
951 self.assertEqual(e.name, month)
952 self.assertIn(e, SummerMonth)
953 self.assertIs(type(e), SummerMonth)
954
Martin Pantereb995702016-07-28 01:11:04 +0000955 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700956 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
957 lst = list(SummerMonth)
958 self.assertEqual(len(lst), len(SummerMonth))
959 self.assertEqual(len(SummerMonth), 3, SummerMonth)
960 self.assertEqual(
961 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
962 lst,
963 )
964 for i, month in enumerate('june july august'.split(), 30):
965 e = SummerMonth(i)
966 self.assertEqual(e, i)
967 self.assertEqual(e.name, month)
968 self.assertIn(e, SummerMonth)
969 self.assertIs(type(e), SummerMonth)
970
Martin Pantereb995702016-07-28 01:11:04 +0000971 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700972 SummerMonth = IntEnum('SummerMonth', 'june july august')
973 lst = list(SummerMonth)
974 self.assertEqual(len(lst), len(SummerMonth))
975 self.assertEqual(len(SummerMonth), 3, SummerMonth)
976 self.assertEqual(
977 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
978 lst,
979 )
980 for i, month in enumerate('june july august'.split(), 1):
981 e = SummerMonth(i)
982 self.assertEqual(e, i)
983 self.assertEqual(e.name, month)
984 self.assertIn(e, SummerMonth)
985 self.assertIs(type(e), SummerMonth)
986
Martin Pantereb995702016-07-28 01:11:04 +0000987 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700988 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
989 lst = list(SummerMonth)
990 self.assertEqual(len(lst), len(SummerMonth))
991 self.assertEqual(len(SummerMonth), 3, SummerMonth)
992 self.assertEqual(
993 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
994 lst,
995 )
996 for i, month in enumerate('june july august'.split(), 40):
997 e = SummerMonth(i)
998 self.assertEqual(e, i)
999 self.assertEqual(e.name, month)
1000 self.assertIn(e, SummerMonth)
1001 self.assertIs(type(e), SummerMonth)
1002
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001003 def test_subclassing(self):
1004 if isinstance(Name, Exception):
1005 raise Name
1006 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1007 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1008 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001009 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001010
1011 def test_extending(self):
1012 class Color(Enum):
1013 red = 1
1014 green = 2
1015 blue = 3
1016 with self.assertRaises(TypeError):
1017 class MoreColor(Color):
1018 cyan = 4
1019 magenta = 5
1020 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001021 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1022 class EvenMoreColor(Color, IntEnum):
1023 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001024
1025 def test_exclude_methods(self):
1026 class whatever(Enum):
1027 this = 'that'
1028 these = 'those'
1029 def really(self):
1030 return 'no, not %s' % self.value
1031 self.assertIsNot(type(whatever.really), whatever)
1032 self.assertEqual(whatever.this.really(), 'no, not that')
1033
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034 def test_wrong_inheritance_order(self):
1035 with self.assertRaises(TypeError):
1036 class Wrong(Enum, str):
1037 NotHere = 'error before this point'
1038
1039 def test_intenum_transitivity(self):
1040 class number(IntEnum):
1041 one = 1
1042 two = 2
1043 three = 3
1044 class numero(IntEnum):
1045 uno = 1
1046 dos = 2
1047 tres = 3
1048 self.assertEqual(number.one, numero.uno)
1049 self.assertEqual(number.two, numero.dos)
1050 self.assertEqual(number.three, numero.tres)
1051
1052 def test_wrong_enum_in_call(self):
1053 class Monochrome(Enum):
1054 black = 0
1055 white = 1
1056 class Gender(Enum):
1057 male = 0
1058 female = 1
1059 self.assertRaises(ValueError, Monochrome, Gender.male)
1060
1061 def test_wrong_enum_in_mixed_call(self):
1062 class Monochrome(IntEnum):
1063 black = 0
1064 white = 1
1065 class Gender(Enum):
1066 male = 0
1067 female = 1
1068 self.assertRaises(ValueError, Monochrome, Gender.male)
1069
1070 def test_mixed_enum_in_call_1(self):
1071 class Monochrome(IntEnum):
1072 black = 0
1073 white = 1
1074 class Gender(IntEnum):
1075 male = 0
1076 female = 1
1077 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1078
1079 def test_mixed_enum_in_call_2(self):
1080 class Monochrome(Enum):
1081 black = 0
1082 white = 1
1083 class Gender(IntEnum):
1084 male = 0
1085 female = 1
1086 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1087
1088 def test_flufl_enum(self):
1089 class Fluflnum(Enum):
1090 def __int__(self):
1091 return int(self.value)
1092 class MailManOptions(Fluflnum):
1093 option1 = 1
1094 option2 = 2
1095 option3 = 3
1096 self.assertEqual(int(MailManOptions.option1), 1)
1097
Ethan Furman5e5a8232013-08-04 08:42:23 -07001098 def test_introspection(self):
1099 class Number(IntEnum):
1100 one = 100
1101 two = 200
1102 self.assertIs(Number.one._member_type_, int)
1103 self.assertIs(Number._member_type_, int)
1104 class String(str, Enum):
1105 yarn = 'soft'
1106 rope = 'rough'
1107 wire = 'hard'
1108 self.assertIs(String.yarn._member_type_, str)
1109 self.assertIs(String._member_type_, str)
1110 class Plain(Enum):
1111 vanilla = 'white'
1112 one = 1
1113 self.assertIs(Plain.vanilla._member_type_, object)
1114 self.assertIs(Plain._member_type_, object)
1115
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001116 def test_no_such_enum_member(self):
1117 class Color(Enum):
1118 red = 1
1119 green = 2
1120 blue = 3
1121 with self.assertRaises(ValueError):
1122 Color(4)
1123 with self.assertRaises(KeyError):
1124 Color['chartreuse']
1125
1126 def test_new_repr(self):
1127 class Color(Enum):
1128 red = 1
1129 green = 2
1130 blue = 3
1131 def __repr__(self):
1132 return "don't you just love shades of %s?" % self.name
1133 self.assertEqual(
1134 repr(Color.blue),
1135 "don't you just love shades of blue?",
1136 )
1137
1138 def test_inherited_repr(self):
1139 class MyEnum(Enum):
1140 def __repr__(self):
1141 return "My name is %s." % self.name
1142 class MyIntEnum(int, MyEnum):
1143 this = 1
1144 that = 2
1145 theother = 3
1146 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1147
1148 def test_multiple_mixin_mro(self):
1149 class auto_enum(type(Enum)):
1150 def __new__(metacls, cls, bases, classdict):
1151 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001152 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001153 names = set(classdict._member_names)
1154 i = 0
1155 for k in classdict._member_names:
1156 v = classdict[k]
1157 if v is Ellipsis:
1158 v = i
1159 else:
1160 i = v
1161 i += 1
1162 temp[k] = v
1163 for k, v in classdict.items():
1164 if k not in names:
1165 temp[k] = v
1166 return super(auto_enum, metacls).__new__(
1167 metacls, cls, bases, temp)
1168
1169 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1170 pass
1171
1172 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1173 pass
1174
1175 class TestAutoNumber(AutoNumberedEnum):
1176 a = ...
1177 b = 3
1178 c = ...
1179
1180 class TestAutoInt(AutoIntEnum):
1181 a = ...
1182 b = 3
1183 c = ...
1184
1185 def test_subclasses_with_getnewargs(self):
1186 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001187 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001188 def __new__(cls, *args):
1189 _args = args
1190 name, *args = args
1191 if len(args) == 0:
1192 raise TypeError("name and value must be specified")
1193 self = int.__new__(cls, *args)
1194 self._intname = name
1195 self._args = _args
1196 return self
1197 def __getnewargs__(self):
1198 return self._args
1199 @property
1200 def __name__(self):
1201 return self._intname
1202 def __repr__(self):
1203 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001204 return "{}({!r}, {})".format(
1205 type(self).__name__,
1206 self.__name__,
1207 int.__repr__(self),
1208 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001209 def __str__(self):
1210 # str() is unchanged, even if it relies on the repr() fallback
1211 base = int
1212 base_str = base.__str__
1213 if base_str.__objclass__ is object:
1214 return base.__repr__(self)
1215 return base_str(self)
1216 # for simplicity, we only define one operator that
1217 # propagates expressions
1218 def __add__(self, other):
1219 temp = int(self) + int( other)
1220 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1221 return NamedInt(
1222 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001223 temp,
1224 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001225 else:
1226 return temp
1227
1228 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001229 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001230 x = ('the-x', 1)
1231 y = ('the-y', 2)
1232
Ethan Furman2aa27322013-07-19 19:35:56 -07001233
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001234 self.assertIs(NEI.__new__, Enum.__new__)
1235 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1236 globals()['NamedInt'] = NamedInt
1237 globals()['NEI'] = NEI
1238 NI5 = NamedInt('test', 5)
1239 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001240 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001241 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001242 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001243 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001244
Ethan Furmanca1b7942014-02-08 11:36:27 -08001245 def test_subclasses_with_getnewargs_ex(self):
1246 class NamedInt(int):
1247 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1248 def __new__(cls, *args):
1249 _args = args
1250 name, *args = args
1251 if len(args) == 0:
1252 raise TypeError("name and value must be specified")
1253 self = int.__new__(cls, *args)
1254 self._intname = name
1255 self._args = _args
1256 return self
1257 def __getnewargs_ex__(self):
1258 return self._args, {}
1259 @property
1260 def __name__(self):
1261 return self._intname
1262 def __repr__(self):
1263 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001264 return "{}({!r}, {})".format(
1265 type(self).__name__,
1266 self.__name__,
1267 int.__repr__(self),
1268 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001269 def __str__(self):
1270 # str() is unchanged, even if it relies on the repr() fallback
1271 base = int
1272 base_str = base.__str__
1273 if base_str.__objclass__ is object:
1274 return base.__repr__(self)
1275 return base_str(self)
1276 # for simplicity, we only define one operator that
1277 # propagates expressions
1278 def __add__(self, other):
1279 temp = int(self) + int( other)
1280 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1281 return NamedInt(
1282 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001283 temp,
1284 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001285 else:
1286 return temp
1287
1288 class NEI(NamedInt, Enum):
1289 __qualname__ = 'NEI' # needed for pickle protocol 4
1290 x = ('the-x', 1)
1291 y = ('the-y', 2)
1292
1293
1294 self.assertIs(NEI.__new__, Enum.__new__)
1295 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1296 globals()['NamedInt'] = NamedInt
1297 globals()['NEI'] = NEI
1298 NI5 = NamedInt('test', 5)
1299 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001300 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001301 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001302 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001303 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001304
1305 def test_subclasses_with_reduce(self):
1306 class NamedInt(int):
1307 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1308 def __new__(cls, *args):
1309 _args = args
1310 name, *args = args
1311 if len(args) == 0:
1312 raise TypeError("name and value must be specified")
1313 self = int.__new__(cls, *args)
1314 self._intname = name
1315 self._args = _args
1316 return self
1317 def __reduce__(self):
1318 return self.__class__, self._args
1319 @property
1320 def __name__(self):
1321 return self._intname
1322 def __repr__(self):
1323 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001324 return "{}({!r}, {})".format(
1325 type(self).__name__,
1326 self.__name__,
1327 int.__repr__(self),
1328 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001329 def __str__(self):
1330 # str() is unchanged, even if it relies on the repr() fallback
1331 base = int
1332 base_str = base.__str__
1333 if base_str.__objclass__ is object:
1334 return base.__repr__(self)
1335 return base_str(self)
1336 # for simplicity, we only define one operator that
1337 # propagates expressions
1338 def __add__(self, other):
1339 temp = int(self) + int( other)
1340 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1341 return NamedInt(
1342 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001343 temp,
1344 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001345 else:
1346 return temp
1347
1348 class NEI(NamedInt, Enum):
1349 __qualname__ = 'NEI' # needed for pickle protocol 4
1350 x = ('the-x', 1)
1351 y = ('the-y', 2)
1352
1353
1354 self.assertIs(NEI.__new__, Enum.__new__)
1355 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1356 globals()['NamedInt'] = NamedInt
1357 globals()['NEI'] = NEI
1358 NI5 = NamedInt('test', 5)
1359 self.assertEqual(NI5, 5)
1360 test_pickle_dump_load(self.assertEqual, NI5, 5)
1361 self.assertEqual(NEI.y.value, 2)
1362 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001363 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001364
1365 def test_subclasses_with_reduce_ex(self):
1366 class NamedInt(int):
1367 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1368 def __new__(cls, *args):
1369 _args = args
1370 name, *args = args
1371 if len(args) == 0:
1372 raise TypeError("name and value must be specified")
1373 self = int.__new__(cls, *args)
1374 self._intname = name
1375 self._args = _args
1376 return self
1377 def __reduce_ex__(self, proto):
1378 return self.__class__, self._args
1379 @property
1380 def __name__(self):
1381 return self._intname
1382 def __repr__(self):
1383 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001384 return "{}({!r}, {})".format(
1385 type(self).__name__,
1386 self.__name__,
1387 int.__repr__(self),
1388 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001389 def __str__(self):
1390 # str() is unchanged, even if it relies on the repr() fallback
1391 base = int
1392 base_str = base.__str__
1393 if base_str.__objclass__ is object:
1394 return base.__repr__(self)
1395 return base_str(self)
1396 # for simplicity, we only define one operator that
1397 # propagates expressions
1398 def __add__(self, other):
1399 temp = int(self) + int( other)
1400 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1401 return NamedInt(
1402 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001403 temp,
1404 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001405 else:
1406 return temp
1407
1408 class NEI(NamedInt, Enum):
1409 __qualname__ = 'NEI' # needed for pickle protocol 4
1410 x = ('the-x', 1)
1411 y = ('the-y', 2)
1412
Ethan Furmanca1b7942014-02-08 11:36:27 -08001413 self.assertIs(NEI.__new__, Enum.__new__)
1414 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1415 globals()['NamedInt'] = NamedInt
1416 globals()['NEI'] = NEI
1417 NI5 = NamedInt('test', 5)
1418 self.assertEqual(NI5, 5)
1419 test_pickle_dump_load(self.assertEqual, NI5, 5)
1420 self.assertEqual(NEI.y.value, 2)
1421 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001422 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001423
Ethan Furmandc870522014-02-18 12:37:12 -08001424 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001425 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001426 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001427 def __new__(cls, *args):
1428 _args = args
1429 name, *args = args
1430 if len(args) == 0:
1431 raise TypeError("name and value must be specified")
1432 self = int.__new__(cls, *args)
1433 self._intname = name
1434 self._args = _args
1435 return self
1436 @property
1437 def __name__(self):
1438 return self._intname
1439 def __repr__(self):
1440 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001441 return "{}({!r}, {})".format(
1442 type(self).__name__,
1443 self.__name__,
1444 int.__repr__(self),
1445 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001446 def __str__(self):
1447 # str() is unchanged, even if it relies on the repr() fallback
1448 base = int
1449 base_str = base.__str__
1450 if base_str.__objclass__ is object:
1451 return base.__repr__(self)
1452 return base_str(self)
1453 # for simplicity, we only define one operator that
1454 # propagates expressions
1455 def __add__(self, other):
1456 temp = int(self) + int( other)
1457 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1458 return NamedInt(
1459 '({0} + {1})'.format(self.__name__, other.__name__),
1460 temp )
1461 else:
1462 return temp
1463
1464 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001465 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001466 x = ('the-x', 1)
1467 y = ('the-y', 2)
1468
1469 self.assertIs(NEI.__new__, Enum.__new__)
1470 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1471 globals()['NamedInt'] = NamedInt
1472 globals()['NEI'] = NEI
1473 NI5 = NamedInt('test', 5)
1474 self.assertEqual(NI5, 5)
1475 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001476 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1477 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001478
Ethan Furmandc870522014-02-18 12:37:12 -08001479 def test_subclasses_without_direct_pickle_support_using_name(self):
1480 class NamedInt(int):
1481 __qualname__ = 'NamedInt'
1482 def __new__(cls, *args):
1483 _args = args
1484 name, *args = args
1485 if len(args) == 0:
1486 raise TypeError("name and value must be specified")
1487 self = int.__new__(cls, *args)
1488 self._intname = name
1489 self._args = _args
1490 return self
1491 @property
1492 def __name__(self):
1493 return self._intname
1494 def __repr__(self):
1495 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001496 return "{}({!r}, {})".format(
1497 type(self).__name__,
1498 self.__name__,
1499 int.__repr__(self),
1500 )
Ethan Furmandc870522014-02-18 12:37:12 -08001501 def __str__(self):
1502 # str() is unchanged, even if it relies on the repr() fallback
1503 base = int
1504 base_str = base.__str__
1505 if base_str.__objclass__ is object:
1506 return base.__repr__(self)
1507 return base_str(self)
1508 # for simplicity, we only define one operator that
1509 # propagates expressions
1510 def __add__(self, other):
1511 temp = int(self) + int( other)
1512 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1513 return NamedInt(
1514 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001515 temp,
1516 )
Ethan Furmandc870522014-02-18 12:37:12 -08001517 else:
1518 return temp
1519
1520 class NEI(NamedInt, Enum):
1521 __qualname__ = 'NEI'
1522 x = ('the-x', 1)
1523 y = ('the-y', 2)
1524 def __reduce_ex__(self, proto):
1525 return getattr, (self.__class__, self._name_)
1526
1527 self.assertIs(NEI.__new__, Enum.__new__)
1528 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1529 globals()['NamedInt'] = NamedInt
1530 globals()['NEI'] = NEI
1531 NI5 = NamedInt('test', 5)
1532 self.assertEqual(NI5, 5)
1533 self.assertEqual(NEI.y.value, 2)
1534 test_pickle_dump_load(self.assertIs, NEI.y)
1535 test_pickle_dump_load(self.assertIs, NEI)
1536
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001537 def test_tuple_subclass(self):
1538 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001539 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001540 first = (1, 'for the money')
1541 second = (2, 'for the show')
1542 third = (3, 'for the music')
1543 self.assertIs(type(SomeTuple.first), SomeTuple)
1544 self.assertIsInstance(SomeTuple.second, tuple)
1545 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1546 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001547 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001548
1549 def test_duplicate_values_give_unique_enum_items(self):
1550 class AutoNumber(Enum):
1551 first = ()
1552 second = ()
1553 third = ()
1554 def __new__(cls):
1555 value = len(cls.__members__) + 1
1556 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001557 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001558 return obj
1559 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001560 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001561 self.assertEqual(
1562 list(AutoNumber),
1563 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1564 )
1565 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001566 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001567 self.assertIs(AutoNumber(1), AutoNumber.first)
1568
1569 def test_inherited_new_from_enhanced_enum(self):
1570 class AutoNumber(Enum):
1571 def __new__(cls):
1572 value = len(cls.__members__) + 1
1573 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001574 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001575 return obj
1576 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001577 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001578 class Color(AutoNumber):
1579 red = ()
1580 green = ()
1581 blue = ()
1582 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1583 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1584
1585 def test_inherited_new_from_mixed_enum(self):
1586 class AutoNumber(IntEnum):
1587 def __new__(cls):
1588 value = len(cls.__members__) + 1
1589 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001590 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001591 return obj
1592 class Color(AutoNumber):
1593 red = ()
1594 green = ()
1595 blue = ()
1596 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1597 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1598
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001599 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001600 class OrdinaryEnum(Enum):
1601 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001602 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1603 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001604
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001605 def test_ordered_mixin(self):
1606 class OrderedEnum(Enum):
1607 def __ge__(self, other):
1608 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001609 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001610 return NotImplemented
1611 def __gt__(self, other):
1612 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001613 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 return NotImplemented
1615 def __le__(self, other):
1616 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001617 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001618 return NotImplemented
1619 def __lt__(self, other):
1620 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001621 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001622 return NotImplemented
1623 class Grade(OrderedEnum):
1624 A = 5
1625 B = 4
1626 C = 3
1627 D = 2
1628 F = 1
1629 self.assertGreater(Grade.A, Grade.B)
1630 self.assertLessEqual(Grade.F, Grade.C)
1631 self.assertLess(Grade.D, Grade.A)
1632 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001633 self.assertEqual(Grade.B, Grade.B)
1634 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001635
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001636 def test_extending2(self):
1637 class Shade(Enum):
1638 def shade(self):
1639 print(self.name)
1640 class Color(Shade):
1641 red = 1
1642 green = 2
1643 blue = 3
1644 with self.assertRaises(TypeError):
1645 class MoreColor(Color):
1646 cyan = 4
1647 magenta = 5
1648 yellow = 6
1649
1650 def test_extending3(self):
1651 class Shade(Enum):
1652 def shade(self):
1653 return self.name
1654 class Color(Shade):
1655 def hex(self):
1656 return '%s hexlified!' % self.value
1657 class MoreColor(Color):
1658 cyan = 4
1659 magenta = 5
1660 yellow = 6
1661 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1662
orlnub1230fb9fad2018-09-12 20:28:53 +03001663 def test_subclass_duplicate_name(self):
1664 class Base(Enum):
1665 def test(self):
1666 pass
1667 class Test(Base):
1668 test = 1
1669 self.assertIs(type(Test.test), Test)
1670
1671 def test_subclass_duplicate_name_dynamic(self):
1672 from types import DynamicClassAttribute
1673 class Base(Enum):
1674 @DynamicClassAttribute
1675 def test(self):
1676 return 'dynamic'
1677 class Test(Base):
1678 test = 1
1679 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001680
1681 def test_no_duplicates(self):
1682 class UniqueEnum(Enum):
1683 def __init__(self, *args):
1684 cls = self.__class__
1685 if any(self.value == e.value for e in cls):
1686 a = self.name
1687 e = cls(self.value).name
1688 raise ValueError(
1689 "aliases not allowed in UniqueEnum: %r --> %r"
1690 % (a, e)
1691 )
1692 class Color(UniqueEnum):
1693 red = 1
1694 green = 2
1695 blue = 3
1696 with self.assertRaises(ValueError):
1697 class Color(UniqueEnum):
1698 red = 1
1699 green = 2
1700 blue = 3
1701 grene = 2
1702
1703 def test_init(self):
1704 class Planet(Enum):
1705 MERCURY = (3.303e+23, 2.4397e6)
1706 VENUS = (4.869e+24, 6.0518e6)
1707 EARTH = (5.976e+24, 6.37814e6)
1708 MARS = (6.421e+23, 3.3972e6)
1709 JUPITER = (1.9e+27, 7.1492e7)
1710 SATURN = (5.688e+26, 6.0268e7)
1711 URANUS = (8.686e+25, 2.5559e7)
1712 NEPTUNE = (1.024e+26, 2.4746e7)
1713 def __init__(self, mass, radius):
1714 self.mass = mass # in kilograms
1715 self.radius = radius # in meters
1716 @property
1717 def surface_gravity(self):
1718 # universal gravitational constant (m3 kg-1 s-2)
1719 G = 6.67300E-11
1720 return G * self.mass / (self.radius * self.radius)
1721 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1722 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1723
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001724 def test_ignore(self):
1725 class Period(timedelta, Enum):
1726 '''
1727 different lengths of time
1728 '''
1729 def __new__(cls, value, period):
1730 obj = timedelta.__new__(cls, value)
1731 obj._value_ = value
1732 obj.period = period
1733 return obj
1734 _ignore_ = 'Period i'
1735 Period = vars()
1736 for i in range(13):
1737 Period['month_%d' % i] = i*30, 'month'
1738 for i in range(53):
1739 Period['week_%d' % i] = i*7, 'week'
1740 for i in range(32):
1741 Period['day_%d' % i] = i, 'day'
1742 OneDay = day_1
1743 OneWeek = week_1
1744 OneMonth = month_1
1745 self.assertFalse(hasattr(Period, '_ignore_'))
1746 self.assertFalse(hasattr(Period, 'Period'))
1747 self.assertFalse(hasattr(Period, 'i'))
1748 self.assertTrue(isinstance(Period.day_1, timedelta))
1749 self.assertTrue(Period.month_1 is Period.day_30)
1750 self.assertTrue(Period.week_4 is Period.day_28)
1751
Ethan Furman2aa27322013-07-19 19:35:56 -07001752 def test_nonhash_value(self):
1753 class AutoNumberInAList(Enum):
1754 def __new__(cls):
1755 value = [len(cls.__members__) + 1]
1756 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001757 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001758 return obj
1759 class ColorInAList(AutoNumberInAList):
1760 red = ()
1761 green = ()
1762 blue = ()
1763 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001764 for enum, value in zip(ColorInAList, range(3)):
1765 value += 1
1766 self.assertEqual(enum.value, [value])
1767 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001768
Ethan Furmanb41803e2013-07-25 13:50:45 -07001769 def test_conflicting_types_resolved_in_new(self):
1770 class LabelledIntEnum(int, Enum):
1771 def __new__(cls, *args):
1772 value, label = args
1773 obj = int.__new__(cls, value)
1774 obj.label = label
1775 obj._value_ = value
1776 return obj
1777
1778 class LabelledList(LabelledIntEnum):
1779 unprocessed = (1, "Unprocessed")
1780 payment_complete = (2, "Payment Complete")
1781
1782 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1783 self.assertEqual(LabelledList.unprocessed, 1)
1784 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001785
Ethan Furmanc16595e2016-09-10 23:36:59 -07001786 def test_auto_number(self):
1787 class Color(Enum):
1788 red = auto()
1789 blue = auto()
1790 green = auto()
1791
1792 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1793 self.assertEqual(Color.red.value, 1)
1794 self.assertEqual(Color.blue.value, 2)
1795 self.assertEqual(Color.green.value, 3)
1796
1797 def test_auto_name(self):
1798 class Color(Enum):
1799 def _generate_next_value_(name, start, count, last):
1800 return name
1801 red = auto()
1802 blue = auto()
1803 green = auto()
1804
1805 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1806 self.assertEqual(Color.red.value, 'red')
1807 self.assertEqual(Color.blue.value, 'blue')
1808 self.assertEqual(Color.green.value, 'green')
1809
1810 def test_auto_name_inherit(self):
1811 class AutoNameEnum(Enum):
1812 def _generate_next_value_(name, start, count, last):
1813 return name
1814 class Color(AutoNameEnum):
1815 red = auto()
1816 blue = auto()
1817 green = auto()
1818
1819 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1820 self.assertEqual(Color.red.value, 'red')
1821 self.assertEqual(Color.blue.value, 'blue')
1822 self.assertEqual(Color.green.value, 'green')
1823
1824 def test_auto_garbage(self):
1825 class Color(Enum):
1826 red = 'red'
1827 blue = auto()
1828 self.assertEqual(Color.blue.value, 1)
1829
1830 def test_auto_garbage_corrected(self):
1831 class Color(Enum):
1832 red = 'red'
1833 blue = 2
1834 green = auto()
1835
1836 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1837 self.assertEqual(Color.red.value, 'red')
1838 self.assertEqual(Color.blue.value, 2)
1839 self.assertEqual(Color.green.value, 3)
1840
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001841 def test_auto_order(self):
1842 with self.assertRaises(TypeError):
1843 class Color(Enum):
1844 red = auto()
1845 green = auto()
1846 blue = auto()
1847 def _generate_next_value_(name, start, count, last):
1848 return name
1849
Ethan Furmanfc23a942020-09-16 12:37:54 -07001850 def test_auto_order_wierd(self):
1851 weird_auto = auto()
1852 weird_auto.value = 'pathological case'
1853 class Color(Enum):
1854 red = weird_auto
1855 def _generate_next_value_(name, start, count, last):
1856 return name
1857 blue = auto()
1858 self.assertEqual(list(Color), [Color.red, Color.blue])
1859 self.assertEqual(Color.red.value, 'pathological case')
1860 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001861
Ethan Furman3515dcc2016-09-18 13:15:41 -07001862 def test_duplicate_auto(self):
1863 class Dupes(Enum):
1864 first = primero = auto()
1865 second = auto()
1866 third = auto()
1867 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1868
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001869 def test_default_missing(self):
1870 class Color(Enum):
1871 RED = 1
1872 GREEN = 2
1873 BLUE = 3
1874 try:
1875 Color(7)
1876 except ValueError as exc:
1877 self.assertTrue(exc.__context__ is None)
1878 else:
1879 raise Exception('Exception not raised.')
1880
Ethan Furman019f0a02018-09-12 11:43:34 -07001881 def test_missing(self):
1882 class Color(Enum):
1883 red = 1
1884 green = 2
1885 blue = 3
1886 @classmethod
1887 def _missing_(cls, item):
1888 if item == 'three':
1889 return cls.blue
1890 elif item == 'bad return':
1891 # trigger internal error
1892 return 5
1893 elif item == 'error out':
1894 raise ZeroDivisionError
1895 else:
1896 # trigger not found
1897 return None
1898 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001899 try:
1900 Color(7)
1901 except ValueError as exc:
1902 self.assertTrue(exc.__context__ is None)
1903 else:
1904 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001905 try:
1906 Color('bad return')
1907 except TypeError as exc:
1908 self.assertTrue(isinstance(exc.__context__, ValueError))
1909 else:
1910 raise Exception('Exception not raised.')
1911 try:
1912 Color('error out')
1913 except ZeroDivisionError as exc:
1914 self.assertTrue(isinstance(exc.__context__, ValueError))
1915 else:
1916 raise Exception('Exception not raised.')
1917
Ethan Furman5bdab642018-09-21 19:03:09 -07001918 def test_multiple_mixin(self):
1919 class MaxMixin:
1920 @classproperty
1921 def MAX(cls):
1922 max = len(cls)
1923 cls.MAX = max
1924 return max
1925 class StrMixin:
1926 def __str__(self):
1927 return self._name_.lower()
1928 class SomeEnum(Enum):
1929 def behavior(self):
1930 return 'booyah'
1931 class AnotherEnum(Enum):
1932 def behavior(self):
1933 return 'nuhuh!'
1934 def social(self):
1935 return "what's up?"
1936 class Color(MaxMixin, Enum):
1937 RED = auto()
1938 GREEN = auto()
1939 BLUE = auto()
1940 self.assertEqual(Color.RED.value, 1)
1941 self.assertEqual(Color.GREEN.value, 2)
1942 self.assertEqual(Color.BLUE.value, 3)
1943 self.assertEqual(Color.MAX, 3)
1944 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1945 class Color(MaxMixin, StrMixin, Enum):
1946 RED = auto()
1947 GREEN = auto()
1948 BLUE = auto()
1949 self.assertEqual(Color.RED.value, 1)
1950 self.assertEqual(Color.GREEN.value, 2)
1951 self.assertEqual(Color.BLUE.value, 3)
1952 self.assertEqual(Color.MAX, 3)
1953 self.assertEqual(str(Color.BLUE), 'blue')
1954 class Color(StrMixin, MaxMixin, Enum):
1955 RED = auto()
1956 GREEN = auto()
1957 BLUE = auto()
1958 self.assertEqual(Color.RED.value, 1)
1959 self.assertEqual(Color.GREEN.value, 2)
1960 self.assertEqual(Color.BLUE.value, 3)
1961 self.assertEqual(Color.MAX, 3)
1962 self.assertEqual(str(Color.BLUE), 'blue')
1963 class CoolColor(StrMixin, SomeEnum, Enum):
1964 RED = auto()
1965 GREEN = auto()
1966 BLUE = auto()
1967 self.assertEqual(CoolColor.RED.value, 1)
1968 self.assertEqual(CoolColor.GREEN.value, 2)
1969 self.assertEqual(CoolColor.BLUE.value, 3)
1970 self.assertEqual(str(CoolColor.BLUE), 'blue')
1971 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1972 class CoolerColor(StrMixin, AnotherEnum, Enum):
1973 RED = auto()
1974 GREEN = auto()
1975 BLUE = auto()
1976 self.assertEqual(CoolerColor.RED.value, 1)
1977 self.assertEqual(CoolerColor.GREEN.value, 2)
1978 self.assertEqual(CoolerColor.BLUE.value, 3)
1979 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1980 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1981 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1982 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1983 RED = auto()
1984 GREEN = auto()
1985 BLUE = auto()
1986 self.assertEqual(CoolestColor.RED.value, 1)
1987 self.assertEqual(CoolestColor.GREEN.value, 2)
1988 self.assertEqual(CoolestColor.BLUE.value, 3)
1989 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1990 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1991 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1992 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1993 RED = auto()
1994 GREEN = auto()
1995 BLUE = auto()
1996 self.assertEqual(ConfusedColor.RED.value, 1)
1997 self.assertEqual(ConfusedColor.GREEN.value, 2)
1998 self.assertEqual(ConfusedColor.BLUE.value, 3)
1999 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2000 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2001 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2002 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2003 RED = auto()
2004 GREEN = auto()
2005 BLUE = auto()
2006 self.assertEqual(ReformedColor.RED.value, 1)
2007 self.assertEqual(ReformedColor.GREEN.value, 2)
2008 self.assertEqual(ReformedColor.BLUE.value, 3)
2009 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2010 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2011 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2012 self.assertTrue(issubclass(ReformedColor, int))
2013
Ethan Furmancd453852018-10-05 23:29:36 -07002014 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002015 @unique
2016 class Decision1(StrEnum):
2017 REVERT = "REVERT"
2018 REVERT_ALL = "REVERT_ALL"
2019 RETRY = "RETRY"
2020 class MyEnum(StrEnum):
2021 pass
2022 @unique
2023 class Decision2(MyEnum):
2024 REVERT = "REVERT"
2025 REVERT_ALL = "REVERT_ALL"
2026 RETRY = "RETRY"
2027
Ethan Furmanc2667362020-12-07 00:17:31 -08002028 def test_multiple_mixin_inherited(self):
2029 class MyInt(int):
2030 def __new__(cls, value):
2031 return super().__new__(cls, value)
2032
2033 class HexMixin:
2034 def __repr__(self):
2035 return hex(self)
2036
2037 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2038 pass
2039
2040 class Foo(MyIntEnum):
2041 TEST = 1
2042 self.assertTrue(isinstance(Foo.TEST, MyInt))
2043 self.assertEqual(repr(Foo.TEST), "0x1")
2044
2045 class Fee(MyIntEnum):
2046 TEST = 1
2047 def __new__(cls, value):
2048 value += 1
2049 member = int.__new__(cls, value)
2050 member._value_ = value
2051 return member
2052 self.assertEqual(Fee.TEST, 2)
2053
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002054 def test_empty_globals(self):
2055 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2056 # when using compile and exec because f_globals is empty
2057 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2058 code = compile(code, "<string>", "exec")
2059 global_ns = {}
2060 local_ls = {}
2061 exec(code, global_ns, local_ls)
2062
Ethan Furman0063ff42020-09-21 17:23:13 -07002063 def test_strenum(self):
2064 class GoodStrEnum(StrEnum):
2065 one = '1'
2066 two = '2'
2067 three = b'3', 'ascii'
2068 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002069 self.assertEqual(GoodStrEnum.one, '1')
2070 self.assertEqual(str(GoodStrEnum.one), '1')
2071 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2072 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2073 #
2074 class DumbMixin:
2075 def __str__(self):
2076 return "don't do this"
2077 class DumbStrEnum(DumbMixin, StrEnum):
2078 five = '5'
2079 six = '6'
2080 seven = '7'
2081 self.assertEqual(DumbStrEnum.seven, '7')
2082 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2083 #
2084 class EnumMixin(Enum):
2085 def hello(self):
2086 print('hello from %s' % (self, ))
2087 class HelloEnum(EnumMixin, StrEnum):
2088 eight = '8'
2089 self.assertEqual(HelloEnum.eight, '8')
2090 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2091 #
2092 class GoodbyeMixin:
2093 def goodbye(self):
2094 print('%s wishes you a fond farewell')
2095 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2096 nine = '9'
2097 self.assertEqual(GoodbyeEnum.nine, '9')
2098 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2099 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002100 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2101 class FirstFailedStrEnum(StrEnum):
2102 one = 1
2103 two = '2'
2104 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2105 class SecondFailedStrEnum(StrEnum):
2106 one = '1'
2107 two = 2,
2108 three = '3'
2109 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2110 class ThirdFailedStrEnum(StrEnum):
2111 one = '1'
2112 two = 2
2113 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2114 class ThirdFailedStrEnum(StrEnum):
2115 one = '1'
2116 two = b'2', sys.getdefaultencoding
2117 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2118 class ThirdFailedStrEnum(StrEnum):
2119 one = '1'
2120 two = b'2', 'ascii', 9
Ethan Furman6bd94de2020-12-09 16:41:22 -08002121
2122 def test_init_subclass(self):
2123 class MyEnum(Enum):
2124 def __init_subclass__(cls, **kwds):
2125 super(MyEnum, cls).__init_subclass__(**kwds)
2126 self.assertFalse(cls.__dict__.get('_test', False))
2127 cls._test1 = 'MyEnum'
2128 #
2129 class TheirEnum(MyEnum):
2130 def __init_subclass__(cls, **kwds):
2131 super().__init_subclass__(**kwds)
2132 cls._test2 = 'TheirEnum'
2133 class WhoseEnum(TheirEnum):
2134 def __init_subclass__(cls, **kwds):
2135 pass
2136 class NoEnum(WhoseEnum):
2137 ONE = 1
2138 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2139 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2140 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2141 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2142 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2143 #
2144 class OurEnum(MyEnum):
2145 def __init_subclass__(cls, **kwds):
2146 cls._test2 = 'OurEnum'
2147 class WhereEnum(OurEnum):
2148 def __init_subclass__(cls, **kwds):
2149 pass
2150 class NeverEnum(WhereEnum):
2151 ONE = 'one'
2152 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2153 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2154 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2155 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2156 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2157
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002158
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002159 @unittest.skipUnless(
2160 sys.version_info[:2] == (3, 9),
2161 'private variables are now normal attributes',
2162 )
2163 def test_warning_for_private_variables(self):
2164 with self.assertWarns(DeprecationWarning):
2165 class Private(Enum):
2166 __corporal = 'Radar'
2167 self.assertEqual(Private._Private__corporal.value, 'Radar')
2168 try:
2169 with self.assertWarns(DeprecationWarning):
2170 class Private(Enum):
2171 __major_ = 'Hoolihan'
2172 except ValueError:
2173 pass
2174
2175 def test_private_variable_is_normal_attribute(self):
2176 class Private(Enum):
2177 __corporal = 'Radar'
2178 __major_ = 'Hoolihan'
2179 self.assertEqual(Private._Private__corporal, 'Radar')
2180 self.assertEqual(Private._Private__major_, 'Hoolihan')
2181
2182
Ethan Furmane8e61272016-08-20 07:19:31 -07002183class TestOrder(unittest.TestCase):
2184
2185 def test_same_members(self):
2186 class Color(Enum):
2187 _order_ = 'red green blue'
2188 red = 1
2189 green = 2
2190 blue = 3
2191
2192 def test_same_members_with_aliases(self):
2193 class Color(Enum):
2194 _order_ = 'red green blue'
2195 red = 1
2196 green = 2
2197 blue = 3
2198 verde = green
2199
2200 def test_same_members_wrong_order(self):
2201 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2202 class Color(Enum):
2203 _order_ = 'red green blue'
2204 red = 1
2205 blue = 3
2206 green = 2
2207
2208 def test_order_has_extra_members(self):
2209 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2210 class Color(Enum):
2211 _order_ = 'red green blue purple'
2212 red = 1
2213 green = 2
2214 blue = 3
2215
2216 def test_order_has_extra_members_with_aliases(self):
2217 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2218 class Color(Enum):
2219 _order_ = 'red green blue purple'
2220 red = 1
2221 green = 2
2222 blue = 3
2223 verde = green
2224
2225 def test_enum_has_extra_members(self):
2226 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2227 class Color(Enum):
2228 _order_ = 'red green blue'
2229 red = 1
2230 green = 2
2231 blue = 3
2232 purple = 4
2233
2234 def test_enum_has_extra_members_with_aliases(self):
2235 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2236 class Color(Enum):
2237 _order_ = 'red green blue'
2238 red = 1
2239 green = 2
2240 blue = 3
2241 purple = 4
2242 verde = green
2243
2244
Ethan Furman65a5a472016-09-01 23:55:19 -07002245class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002246 """Tests of the Flags."""
2247
Ethan Furman65a5a472016-09-01 23:55:19 -07002248 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002249 R, W, X = 4, 2, 1
2250
Ethan Furman65a5a472016-09-01 23:55:19 -07002251 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002252 RO = 0
2253 WO = 1
2254 RW = 2
2255 AC = 3
2256 CE = 1<<19
2257
Rahul Jha94306522018-09-10 23:51:04 +05302258 class Color(Flag):
2259 BLACK = 0
2260 RED = 1
2261 GREEN = 2
2262 BLUE = 4
2263 PURPLE = RED|BLUE
2264
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002265 def test_str(self):
2266 Perm = self.Perm
2267 self.assertEqual(str(Perm.R), 'Perm.R')
2268 self.assertEqual(str(Perm.W), 'Perm.W')
2269 self.assertEqual(str(Perm.X), 'Perm.X')
2270 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2271 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2272 self.assertEqual(str(Perm(0)), 'Perm.0')
2273 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2274 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2275 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2276 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2277 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2278 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2279
2280 Open = self.Open
2281 self.assertEqual(str(Open.RO), 'Open.RO')
2282 self.assertEqual(str(Open.WO), 'Open.WO')
2283 self.assertEqual(str(Open.AC), 'Open.AC')
2284 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2285 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002286 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002287 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2288 self.assertEqual(str(~Open.AC), 'Open.CE')
2289 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2290 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2291
2292 def test_repr(self):
2293 Perm = self.Perm
2294 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2295 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2296 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2297 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2298 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002299 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002300 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2301 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2302 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2303 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002304 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002305 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2306
2307 Open = self.Open
2308 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2309 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2310 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2311 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2312 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002313 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002314 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2315 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2316 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2317 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2318
Ethan Furman37440ee2020-12-08 11:14:10 -08002319 def test_format(self):
2320 Perm = self.Perm
2321 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2322 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2323
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002324 def test_or(self):
2325 Perm = self.Perm
2326 for i in Perm:
2327 for j in Perm:
2328 self.assertEqual((i | j), Perm(i.value | j.value))
2329 self.assertEqual((i | j).value, i.value | j.value)
2330 self.assertIs(type(i | j), Perm)
2331 for i in Perm:
2332 self.assertIs(i | i, i)
2333 Open = self.Open
2334 self.assertIs(Open.RO | Open.CE, Open.CE)
2335
2336 def test_and(self):
2337 Perm = self.Perm
2338 RW = Perm.R | Perm.W
2339 RX = Perm.R | Perm.X
2340 WX = Perm.W | Perm.X
2341 RWX = Perm.R | Perm.W | Perm.X
2342 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2343 for i in values:
2344 for j in values:
2345 self.assertEqual((i & j).value, i.value & j.value)
2346 self.assertIs(type(i & j), Perm)
2347 for i in Perm:
2348 self.assertIs(i & i, i)
2349 self.assertIs(i & RWX, i)
2350 self.assertIs(RWX & i, i)
2351 Open = self.Open
2352 self.assertIs(Open.RO & Open.CE, Open.RO)
2353
2354 def test_xor(self):
2355 Perm = self.Perm
2356 for i in Perm:
2357 for j in Perm:
2358 self.assertEqual((i ^ j).value, i.value ^ j.value)
2359 self.assertIs(type(i ^ j), Perm)
2360 for i in Perm:
2361 self.assertIs(i ^ Perm(0), i)
2362 self.assertIs(Perm(0) ^ i, i)
2363 Open = self.Open
2364 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2365 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2366
2367 def test_invert(self):
2368 Perm = self.Perm
2369 RW = Perm.R | Perm.W
2370 RX = Perm.R | Perm.X
2371 WX = Perm.W | Perm.X
2372 RWX = Perm.R | Perm.W | Perm.X
2373 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2374 for i in values:
2375 self.assertIs(type(~i), Perm)
2376 self.assertEqual(~~i, i)
2377 for i in Perm:
2378 self.assertIs(~~i, i)
2379 Open = self.Open
2380 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2381 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2382
Ethan Furman25d94bb2016-09-02 16:32:32 -07002383 def test_bool(self):
2384 Perm = self.Perm
2385 for f in Perm:
2386 self.assertTrue(f)
2387 Open = self.Open
2388 for f in Open:
2389 self.assertEqual(bool(f.value), bool(f))
2390
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002391 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002392 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002393 lst = list(Perm)
2394 self.assertEqual(len(lst), len(Perm))
2395 self.assertEqual(len(Perm), 3, Perm)
2396 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2397 for i, n in enumerate('R W X'.split()):
2398 v = 1<<i
2399 e = Perm(v)
2400 self.assertEqual(e.value, v)
2401 self.assertEqual(type(e.value), int)
2402 self.assertEqual(e.name, n)
2403 self.assertIn(e, Perm)
2404 self.assertIs(type(e), Perm)
2405
2406 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002407 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002408 lst = list(Perm)
2409 self.assertEqual(len(lst), len(Perm))
2410 self.assertEqual(len(Perm), 3, Perm)
2411 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2412 for i, n in enumerate('R W X'.split()):
2413 v = 8<<i
2414 e = Perm(v)
2415 self.assertEqual(e.value, v)
2416 self.assertEqual(type(e.value), int)
2417 self.assertEqual(e.name, n)
2418 self.assertIn(e, Perm)
2419 self.assertIs(type(e), Perm)
2420
2421 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002422 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002423 lst = list(Perm)
2424 self.assertEqual(len(lst), len(Perm))
2425 self.assertEqual(len(Perm), 3, Perm)
2426 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2427 for i, n in enumerate('R W X'.split()):
2428 v = 1<<i
2429 e = Perm(v)
2430 self.assertEqual(e.value, v)
2431 self.assertEqual(type(e.value), int)
2432 self.assertEqual(e.name, n)
2433 self.assertIn(e, Perm)
2434 self.assertIs(type(e), Perm)
2435
2436 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002437 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002438 lst = list(Perm)
2439 self.assertEqual(len(lst), len(Perm))
2440 self.assertEqual(len(Perm), 3, Perm)
2441 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2442 for i, n in enumerate('R W X'.split()):
2443 v = 1<<(2*i+1)
2444 e = Perm(v)
2445 self.assertEqual(e.value, v)
2446 self.assertEqual(type(e.value), int)
2447 self.assertEqual(e.name, n)
2448 self.assertIn(e, Perm)
2449 self.assertIs(type(e), Perm)
2450
2451 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002452 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002453 lst = list(Perm)
2454 self.assertEqual(len(lst), len(Perm))
2455 self.assertEqual(len(Perm), 3, Perm)
2456 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2457 for i, n in enumerate('R W X'.split()):
2458 v = 1<<(2*i+1)
2459 e = Perm(v)
2460 self.assertEqual(e.value, v)
2461 self.assertEqual(type(e.value), int)
2462 self.assertEqual(e.name, n)
2463 self.assertIn(e, Perm)
2464 self.assertIs(type(e), Perm)
2465
Ethan Furman65a5a472016-09-01 23:55:19 -07002466 def test_pickle(self):
2467 if isinstance(FlagStooges, Exception):
2468 raise FlagStooges
2469 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2470 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002471
Rahul Jha94306522018-09-10 23:51:04 +05302472 def test_contains(self):
2473 Open = self.Open
2474 Color = self.Color
2475 self.assertFalse(Color.BLACK in Open)
2476 self.assertFalse(Open.RO in Color)
2477 with self.assertRaises(TypeError):
2478 'BLACK' in Color
2479 with self.assertRaises(TypeError):
2480 'RO' in Open
2481 with self.assertRaises(TypeError):
2482 1 in Color
2483 with self.assertRaises(TypeError):
2484 1 in Open
2485
2486 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002487 Perm = self.Perm
2488 R, W, X = Perm
2489 RW = R | W
2490 RX = R | X
2491 WX = W | X
2492 RWX = R | W | X
2493 self.assertTrue(R in RW)
2494 self.assertTrue(R in RX)
2495 self.assertTrue(R in RWX)
2496 self.assertTrue(W in RW)
2497 self.assertTrue(W in WX)
2498 self.assertTrue(W in RWX)
2499 self.assertTrue(X in RX)
2500 self.assertTrue(X in WX)
2501 self.assertTrue(X in RWX)
2502 self.assertFalse(R in WX)
2503 self.assertFalse(W in RX)
2504 self.assertFalse(X in RW)
2505
Ethan Furman7219e272020-09-16 13:01:00 -07002506 def test_member_iter(self):
2507 Color = self.Color
2508 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2509 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2510 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2511
Ethan Furmanc16595e2016-09-10 23:36:59 -07002512 def test_auto_number(self):
2513 class Color(Flag):
2514 red = auto()
2515 blue = auto()
2516 green = auto()
2517
2518 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2519 self.assertEqual(Color.red.value, 1)
2520 self.assertEqual(Color.blue.value, 2)
2521 self.assertEqual(Color.green.value, 4)
2522
2523 def test_auto_number_garbage(self):
2524 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2525 class Color(Flag):
2526 red = 'not an int'
2527 blue = auto()
2528
Ethan Furman3515dcc2016-09-18 13:15:41 -07002529 def test_cascading_failure(self):
2530 class Bizarre(Flag):
2531 c = 3
2532 d = 4
2533 f = 6
2534 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002535 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2536 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2537 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2538 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2539 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2540 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2541 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002542
2543 def test_duplicate_auto(self):
2544 class Dupes(Enum):
2545 first = primero = auto()
2546 second = auto()
2547 third = auto()
2548 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2549
2550 def test_bizarre(self):
2551 class Bizarre(Flag):
2552 b = 3
2553 c = 4
2554 d = 6
2555 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2556
Ethan Furman5bdab642018-09-21 19:03:09 -07002557 def test_multiple_mixin(self):
2558 class AllMixin:
2559 @classproperty
2560 def ALL(cls):
2561 members = list(cls)
2562 all_value = None
2563 if members:
2564 all_value = members[0]
2565 for member in members[1:]:
2566 all_value |= member
2567 cls.ALL = all_value
2568 return all_value
2569 class StrMixin:
2570 def __str__(self):
2571 return self._name_.lower()
2572 class Color(AllMixin, Flag):
2573 RED = auto()
2574 GREEN = auto()
2575 BLUE = auto()
2576 self.assertEqual(Color.RED.value, 1)
2577 self.assertEqual(Color.GREEN.value, 2)
2578 self.assertEqual(Color.BLUE.value, 4)
2579 self.assertEqual(Color.ALL.value, 7)
2580 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2581 class Color(AllMixin, StrMixin, Flag):
2582 RED = auto()
2583 GREEN = auto()
2584 BLUE = auto()
2585 self.assertEqual(Color.RED.value, 1)
2586 self.assertEqual(Color.GREEN.value, 2)
2587 self.assertEqual(Color.BLUE.value, 4)
2588 self.assertEqual(Color.ALL.value, 7)
2589 self.assertEqual(str(Color.BLUE), 'blue')
2590 class Color(StrMixin, AllMixin, Flag):
2591 RED = auto()
2592 GREEN = auto()
2593 BLUE = auto()
2594 self.assertEqual(Color.RED.value, 1)
2595 self.assertEqual(Color.GREEN.value, 2)
2596 self.assertEqual(Color.BLUE.value, 4)
2597 self.assertEqual(Color.ALL.value, 7)
2598 self.assertEqual(str(Color.BLUE), 'blue')
2599
Hai Shie80697d2020-05-28 06:10:27 +08002600 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002601 def test_unique_composite(self):
2602 # override __eq__ to be identity only
2603 class TestFlag(Flag):
2604 one = auto()
2605 two = auto()
2606 three = auto()
2607 four = auto()
2608 five = auto()
2609 six = auto()
2610 seven = auto()
2611 eight = auto()
2612 def __eq__(self, other):
2613 return self is other
2614 def __hash__(self):
2615 return hash(self._value_)
2616 # have multiple threads competing to complete the composite members
2617 seen = set()
2618 failed = False
2619 def cycle_enum():
2620 nonlocal failed
2621 try:
2622 for i in range(256):
2623 seen.add(TestFlag(i))
2624 except Exception:
2625 failed = True
2626 threads = [
2627 threading.Thread(target=cycle_enum)
2628 for _ in range(8)
2629 ]
Hai Shie80697d2020-05-28 06:10:27 +08002630 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002631 pass
2632 # check that only 248 members were created
2633 self.assertFalse(
2634 failed,
2635 'at least one thread failed while creating composite members')
2636 self.assertEqual(256, len(seen), 'too many composite members created')
2637
Ethan Furman6bd94de2020-12-09 16:41:22 -08002638 def test_init_subclass(self):
2639 class MyEnum(Flag):
2640 def __init_subclass__(cls, **kwds):
2641 super().__init_subclass__(**kwds)
2642 self.assertFalse(cls.__dict__.get('_test', False))
2643 cls._test1 = 'MyEnum'
2644 #
2645 class TheirEnum(MyEnum):
2646 def __init_subclass__(cls, **kwds):
2647 super(TheirEnum, cls).__init_subclass__(**kwds)
2648 cls._test2 = 'TheirEnum'
2649 class WhoseEnum(TheirEnum):
2650 def __init_subclass__(cls, **kwds):
2651 pass
2652 class NoEnum(WhoseEnum):
2653 ONE = 1
2654 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2655 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2656 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2657 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2658 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2659 #
2660 class OurEnum(MyEnum):
2661 def __init_subclass__(cls, **kwds):
2662 cls._test2 = 'OurEnum'
2663 class WhereEnum(OurEnum):
2664 def __init_subclass__(cls, **kwds):
2665 pass
2666 class NeverEnum(WhereEnum):
2667 ONE = 1
2668 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2669 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2670 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2671 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2672 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2673
Ethan Furmanc16595e2016-09-10 23:36:59 -07002674
Ethan Furman65a5a472016-09-01 23:55:19 -07002675class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002676 """Tests of the IntFlags."""
2677
Ethan Furman65a5a472016-09-01 23:55:19 -07002678 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002679 X = 1 << 0
2680 W = 1 << 1
2681 R = 1 << 2
2682
Ethan Furman65a5a472016-09-01 23:55:19 -07002683 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002684 RO = 0
2685 WO = 1
2686 RW = 2
2687 AC = 3
2688 CE = 1<<19
2689
Rahul Jha94306522018-09-10 23:51:04 +05302690 class Color(IntFlag):
2691 BLACK = 0
2692 RED = 1
2693 GREEN = 2
2694 BLUE = 4
2695 PURPLE = RED|BLUE
2696
Ethan Furman3515dcc2016-09-18 13:15:41 -07002697 def test_type(self):
2698 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002699 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002700 Open = self.Open
2701 for f in Perm:
2702 self.assertTrue(isinstance(f, Perm))
2703 self.assertEqual(f, f.value)
2704 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2705 self.assertEqual(Perm.W | Perm.X, 3)
2706 for f in Open:
2707 self.assertTrue(isinstance(f, Open))
2708 self.assertEqual(f, f.value)
2709 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2710 self.assertEqual(Open.WO | Open.RW, 3)
2711
2712
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002713 def test_str(self):
2714 Perm = self.Perm
2715 self.assertEqual(str(Perm.R), 'Perm.R')
2716 self.assertEqual(str(Perm.W), 'Perm.W')
2717 self.assertEqual(str(Perm.X), 'Perm.X')
2718 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2719 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2720 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2721 self.assertEqual(str(Perm(0)), 'Perm.0')
2722 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002723 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2724 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2725 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2726 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002727 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002728 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2729 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2730 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002731
2732 Open = self.Open
2733 self.assertEqual(str(Open.RO), 'Open.RO')
2734 self.assertEqual(str(Open.WO), 'Open.WO')
2735 self.assertEqual(str(Open.AC), 'Open.AC')
2736 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2737 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2738 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002739 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2740 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2741 self.assertEqual(str(~Open.AC), 'Open.CE')
2742 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2743 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2744 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002745
2746 def test_repr(self):
2747 Perm = self.Perm
2748 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2749 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2750 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2751 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2752 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2753 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002754 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2755 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002756 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2757 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2758 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2759 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002760 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002761 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2762 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2763 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002764
2765 Open = self.Open
2766 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2767 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2768 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2769 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2770 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002771 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002772 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2773 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2774 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2775 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2776 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2777 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002778
Ethan Furman37440ee2020-12-08 11:14:10 -08002779 def test_format(self):
2780 Perm = self.Perm
2781 self.assertEqual(format(Perm.R, ''), '4')
2782 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2783
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002784 def test_or(self):
2785 Perm = self.Perm
2786 for i in Perm:
2787 for j in Perm:
2788 self.assertEqual(i | j, i.value | j.value)
2789 self.assertEqual((i | j).value, i.value | j.value)
2790 self.assertIs(type(i | j), Perm)
2791 for j in range(8):
2792 self.assertEqual(i | j, i.value | j)
2793 self.assertEqual((i | j).value, i.value | j)
2794 self.assertIs(type(i | j), Perm)
2795 self.assertEqual(j | i, j | i.value)
2796 self.assertEqual((j | i).value, j | i.value)
2797 self.assertIs(type(j | i), Perm)
2798 for i in Perm:
2799 self.assertIs(i | i, i)
2800 self.assertIs(i | 0, i)
2801 self.assertIs(0 | i, i)
2802 Open = self.Open
2803 self.assertIs(Open.RO | Open.CE, Open.CE)
2804
2805 def test_and(self):
2806 Perm = self.Perm
2807 RW = Perm.R | Perm.W
2808 RX = Perm.R | Perm.X
2809 WX = Perm.W | Perm.X
2810 RWX = Perm.R | Perm.W | Perm.X
2811 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2812 for i in values:
2813 for j in values:
2814 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2815 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2816 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2817 for j in range(8):
2818 self.assertEqual(i & j, i.value & j)
2819 self.assertEqual((i & j).value, i.value & j)
2820 self.assertIs(type(i & j), Perm)
2821 self.assertEqual(j & i, j & i.value)
2822 self.assertEqual((j & i).value, j & i.value)
2823 self.assertIs(type(j & i), Perm)
2824 for i in Perm:
2825 self.assertIs(i & i, i)
2826 self.assertIs(i & 7, i)
2827 self.assertIs(7 & i, i)
2828 Open = self.Open
2829 self.assertIs(Open.RO & Open.CE, Open.RO)
2830
2831 def test_xor(self):
2832 Perm = self.Perm
2833 for i in Perm:
2834 for j in Perm:
2835 self.assertEqual(i ^ j, i.value ^ j.value)
2836 self.assertEqual((i ^ j).value, i.value ^ j.value)
2837 self.assertIs(type(i ^ j), Perm)
2838 for j in range(8):
2839 self.assertEqual(i ^ j, i.value ^ j)
2840 self.assertEqual((i ^ j).value, i.value ^ j)
2841 self.assertIs(type(i ^ j), Perm)
2842 self.assertEqual(j ^ i, j ^ i.value)
2843 self.assertEqual((j ^ i).value, j ^ i.value)
2844 self.assertIs(type(j ^ i), Perm)
2845 for i in Perm:
2846 self.assertIs(i ^ 0, i)
2847 self.assertIs(0 ^ i, i)
2848 Open = self.Open
2849 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2850 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2851
2852 def test_invert(self):
2853 Perm = self.Perm
2854 RW = Perm.R | Perm.W
2855 RX = Perm.R | Perm.X
2856 WX = Perm.W | Perm.X
2857 RWX = Perm.R | Perm.W | Perm.X
2858 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2859 for i in values:
2860 self.assertEqual(~i, ~i.value)
2861 self.assertEqual((~i).value, ~i.value)
2862 self.assertIs(type(~i), Perm)
2863 self.assertEqual(~~i, i)
2864 for i in Perm:
2865 self.assertIs(~~i, i)
2866 Open = self.Open
2867 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2868 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2869
2870 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002871 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002872 lst = list(Perm)
2873 self.assertEqual(len(lst), len(Perm))
2874 self.assertEqual(len(Perm), 3, Perm)
2875 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2876 for i, n in enumerate('R W X'.split()):
2877 v = 1<<i
2878 e = Perm(v)
2879 self.assertEqual(e.value, v)
2880 self.assertEqual(type(e.value), int)
2881 self.assertEqual(e, v)
2882 self.assertEqual(e.name, n)
2883 self.assertIn(e, Perm)
2884 self.assertIs(type(e), Perm)
2885
2886 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002887 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002888 lst = list(Perm)
2889 self.assertEqual(len(lst), len(Perm))
2890 self.assertEqual(len(Perm), 3, Perm)
2891 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2892 for i, n in enumerate('R W X'.split()):
2893 v = 8<<i
2894 e = Perm(v)
2895 self.assertEqual(e.value, v)
2896 self.assertEqual(type(e.value), int)
2897 self.assertEqual(e, v)
2898 self.assertEqual(e.name, n)
2899 self.assertIn(e, Perm)
2900 self.assertIs(type(e), Perm)
2901
2902 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002903 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002904 lst = list(Perm)
2905 self.assertEqual(len(lst), len(Perm))
2906 self.assertEqual(len(Perm), 3, Perm)
2907 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2908 for i, n in enumerate('R W X'.split()):
2909 v = 1<<i
2910 e = Perm(v)
2911 self.assertEqual(e.value, v)
2912 self.assertEqual(type(e.value), int)
2913 self.assertEqual(e, v)
2914 self.assertEqual(e.name, n)
2915 self.assertIn(e, Perm)
2916 self.assertIs(type(e), Perm)
2917
2918 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002919 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002920 lst = list(Perm)
2921 self.assertEqual(len(lst), len(Perm))
2922 self.assertEqual(len(Perm), 3, Perm)
2923 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2924 for i, n in enumerate('R W X'.split()):
2925 v = 1<<(2*i+1)
2926 e = Perm(v)
2927 self.assertEqual(e.value, v)
2928 self.assertEqual(type(e.value), int)
2929 self.assertEqual(e, v)
2930 self.assertEqual(e.name, n)
2931 self.assertIn(e, Perm)
2932 self.assertIs(type(e), Perm)
2933
2934 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002935 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002936 lst = list(Perm)
2937 self.assertEqual(len(lst), len(Perm))
2938 self.assertEqual(len(Perm), 3, Perm)
2939 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2940 for i, n in enumerate('R W X'.split()):
2941 v = 1<<(2*i+1)
2942 e = Perm(v)
2943 self.assertEqual(e.value, v)
2944 self.assertEqual(type(e.value), int)
2945 self.assertEqual(e, v)
2946 self.assertEqual(e.name, n)
2947 self.assertIn(e, Perm)
2948 self.assertIs(type(e), Perm)
2949
2950
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002951 def test_programatic_function_from_empty_list(self):
2952 Perm = enum.IntFlag('Perm', [])
2953 lst = list(Perm)
2954 self.assertEqual(len(lst), len(Perm))
2955 self.assertEqual(len(Perm), 0, Perm)
2956 Thing = enum.Enum('Thing', [])
2957 lst = list(Thing)
2958 self.assertEqual(len(lst), len(Thing))
2959 self.assertEqual(len(Thing), 0, Thing)
2960
2961
2962 def test_programatic_function_from_empty_tuple(self):
2963 Perm = enum.IntFlag('Perm', ())
2964 lst = list(Perm)
2965 self.assertEqual(len(lst), len(Perm))
2966 self.assertEqual(len(Perm), 0, Perm)
2967 Thing = enum.Enum('Thing', ())
2968 self.assertEqual(len(lst), len(Thing))
2969 self.assertEqual(len(Thing), 0, Thing)
2970
Rahul Jha94306522018-09-10 23:51:04 +05302971 def test_contains(self):
2972 Open = self.Open
2973 Color = self.Color
2974 self.assertTrue(Color.GREEN in Color)
2975 self.assertTrue(Open.RW in Open)
2976 self.assertFalse(Color.GREEN in Open)
2977 self.assertFalse(Open.RW in Color)
2978 with self.assertRaises(TypeError):
2979 'GREEN' in Color
2980 with self.assertRaises(TypeError):
2981 'RW' in Open
2982 with self.assertRaises(TypeError):
2983 2 in Color
2984 with self.assertRaises(TypeError):
2985 2 in Open
2986
2987 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002988 Perm = self.Perm
2989 R, W, X = Perm
2990 RW = R | W
2991 RX = R | X
2992 WX = W | X
2993 RWX = R | W | X
2994 self.assertTrue(R in RW)
2995 self.assertTrue(R in RX)
2996 self.assertTrue(R in RWX)
2997 self.assertTrue(W in RW)
2998 self.assertTrue(W in WX)
2999 self.assertTrue(W in RWX)
3000 self.assertTrue(X in RX)
3001 self.assertTrue(X in WX)
3002 self.assertTrue(X in RWX)
3003 self.assertFalse(R in WX)
3004 self.assertFalse(W in RX)
3005 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303006 with self.assertRaises(TypeError):
3007 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003008
Ethan Furman7219e272020-09-16 13:01:00 -07003009 def test_member_iter(self):
3010 Color = self.Color
3011 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
3012 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3013 self.assertEqual(list(Color.GREEN), [Color.GREEN])
3014
Ethan Furman25d94bb2016-09-02 16:32:32 -07003015 def test_bool(self):
3016 Perm = self.Perm
3017 for f in Perm:
3018 self.assertTrue(f)
3019 Open = self.Open
3020 for f in Open:
3021 self.assertEqual(bool(f.value), bool(f))
3022
Ethan Furman5bdab642018-09-21 19:03:09 -07003023 def test_multiple_mixin(self):
3024 class AllMixin:
3025 @classproperty
3026 def ALL(cls):
3027 members = list(cls)
3028 all_value = None
3029 if members:
3030 all_value = members[0]
3031 for member in members[1:]:
3032 all_value |= member
3033 cls.ALL = all_value
3034 return all_value
3035 class StrMixin:
3036 def __str__(self):
3037 return self._name_.lower()
3038 class Color(AllMixin, IntFlag):
3039 RED = auto()
3040 GREEN = auto()
3041 BLUE = auto()
3042 self.assertEqual(Color.RED.value, 1)
3043 self.assertEqual(Color.GREEN.value, 2)
3044 self.assertEqual(Color.BLUE.value, 4)
3045 self.assertEqual(Color.ALL.value, 7)
3046 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3047 class Color(AllMixin, StrMixin, IntFlag):
3048 RED = auto()
3049 GREEN = auto()
3050 BLUE = auto()
3051 self.assertEqual(Color.RED.value, 1)
3052 self.assertEqual(Color.GREEN.value, 2)
3053 self.assertEqual(Color.BLUE.value, 4)
3054 self.assertEqual(Color.ALL.value, 7)
3055 self.assertEqual(str(Color.BLUE), 'blue')
3056 class Color(StrMixin, AllMixin, IntFlag):
3057 RED = auto()
3058 GREEN = auto()
3059 BLUE = auto()
3060 self.assertEqual(Color.RED.value, 1)
3061 self.assertEqual(Color.GREEN.value, 2)
3062 self.assertEqual(Color.BLUE.value, 4)
3063 self.assertEqual(Color.ALL.value, 7)
3064 self.assertEqual(str(Color.BLUE), 'blue')
3065
Hai Shie80697d2020-05-28 06:10:27 +08003066 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003067 def test_unique_composite(self):
3068 # override __eq__ to be identity only
3069 class TestFlag(IntFlag):
3070 one = auto()
3071 two = auto()
3072 three = auto()
3073 four = auto()
3074 five = auto()
3075 six = auto()
3076 seven = auto()
3077 eight = auto()
3078 def __eq__(self, other):
3079 return self is other
3080 def __hash__(self):
3081 return hash(self._value_)
3082 # have multiple threads competing to complete the composite members
3083 seen = set()
3084 failed = False
3085 def cycle_enum():
3086 nonlocal failed
3087 try:
3088 for i in range(256):
3089 seen.add(TestFlag(i))
3090 except Exception:
3091 failed = True
3092 threads = [
3093 threading.Thread(target=cycle_enum)
3094 for _ in range(8)
3095 ]
Hai Shie80697d2020-05-28 06:10:27 +08003096 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003097 pass
3098 # check that only 248 members were created
3099 self.assertFalse(
3100 failed,
3101 'at least one thread failed while creating composite members')
3102 self.assertEqual(256, len(seen), 'too many composite members created')
3103
3104
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003105class TestEmptyAndNonLatinStrings(unittest.TestCase):
3106
3107 def test_empty_string(self):
3108 with self.assertRaises(ValueError):
3109 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3110
3111 def test_non_latin_character_string(self):
3112 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3113 item = getattr(greek_abc, '\u03B1')
3114 self.assertEqual(item.value, 1)
3115
3116 def test_non_latin_number_string(self):
3117 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3118 item = getattr(hebrew_123, '\u05D0')
3119 self.assertEqual(item.value, 1)
3120
3121
Ethan Furmanf24bb352013-07-18 17:05:39 -07003122class TestUnique(unittest.TestCase):
3123
3124 def test_unique_clean(self):
3125 @unique
3126 class Clean(Enum):
3127 one = 1
3128 two = 'dos'
3129 tres = 4.0
3130 @unique
3131 class Cleaner(IntEnum):
3132 single = 1
3133 double = 2
3134 triple = 3
3135
3136 def test_unique_dirty(self):
3137 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3138 @unique
3139 class Dirty(Enum):
3140 one = 1
3141 two = 'dos'
3142 tres = 1
3143 with self.assertRaisesRegex(
3144 ValueError,
3145 'double.*single.*turkey.*triple',
3146 ):
3147 @unique
3148 class Dirtier(IntEnum):
3149 single = 1
3150 double = 1
3151 triple = 3
3152 turkey = 3
3153
Ethan Furman3803ad42016-05-01 10:03:53 -07003154 def test_unique_with_name(self):
3155 @unique
3156 class Silly(Enum):
3157 one = 1
3158 two = 'dos'
3159 name = 3
3160 @unique
3161 class Sillier(IntEnum):
3162 single = 1
3163 name = 2
3164 triple = 3
3165 value = 4
3166
Ethan Furmanf24bb352013-07-18 17:05:39 -07003167
Ethan Furman5bdab642018-09-21 19:03:09 -07003168
Ethan Furman3323da92015-04-11 09:39:59 -07003169expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003170Help on class Color in module %s:
3171
3172class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003173 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3174 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003175 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003176 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003177 | Method resolution order:
3178 | Color
3179 | enum.Enum
3180 | builtins.object
3181 |\x20\x20
3182 | Data and other attributes defined here:
3183 |\x20\x20
3184 | blue = <Color.blue: 3>
3185 |\x20\x20
3186 | green = <Color.green: 2>
3187 |\x20\x20
3188 | red = <Color.red: 1>
3189 |\x20\x20
3190 | ----------------------------------------------------------------------
3191 | Data descriptors inherited from enum.Enum:
3192 |\x20\x20
3193 | name
3194 | The name of the Enum member.
3195 |\x20\x20
3196 | value
3197 | The value of the Enum member.
3198 |\x20\x20
3199 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003200 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003201 |\x20\x20
3202 | __members__
3203 | Returns a mapping of member name->value.
3204 |\x20\x20\x20\x20\x20\x20
3205 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003206 | is a read-only view of the internal mapping."""
3207
3208expected_help_output_without_docs = """\
3209Help on class Color in module %s:
3210
3211class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003212 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3213 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003214 | Method resolution order:
3215 | Color
3216 | enum.Enum
3217 | builtins.object
3218 |\x20\x20
3219 | Data and other attributes defined here:
3220 |\x20\x20
3221 | blue = <Color.blue: 3>
3222 |\x20\x20
3223 | green = <Color.green: 2>
3224 |\x20\x20
3225 | red = <Color.red: 1>
3226 |\x20\x20
3227 | ----------------------------------------------------------------------
3228 | Data descriptors inherited from enum.Enum:
3229 |\x20\x20
3230 | name
3231 |\x20\x20
3232 | value
3233 |\x20\x20
3234 | ----------------------------------------------------------------------
3235 | Data descriptors inherited from enum.EnumMeta:
3236 |\x20\x20
3237 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003238
3239class TestStdLib(unittest.TestCase):
3240
Ethan Furman48a724f2015-04-11 23:23:06 -07003241 maxDiff = None
3242
Ethan Furman5875d742013-10-21 20:45:55 -07003243 class Color(Enum):
3244 red = 1
3245 green = 2
3246 blue = 3
3247
3248 def test_pydoc(self):
3249 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003250 if StrEnum.__doc__ is None:
3251 expected_text = expected_help_output_without_docs % __name__
3252 else:
3253 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003254 output = StringIO()
3255 helper = pydoc.Helper(output=output)
3256 helper(self.Color)
3257 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003258 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003259
3260 def test_inspect_getmembers(self):
3261 values = dict((
3262 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003263 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003264 ('__members__', self.Color.__members__),
3265 ('__module__', __name__),
3266 ('blue', self.Color.blue),
3267 ('green', self.Color.green),
3268 ('name', Enum.__dict__['name']),
3269 ('red', self.Color.red),
3270 ('value', Enum.__dict__['value']),
3271 ))
3272 result = dict(inspect.getmembers(self.Color))
3273 self.assertEqual(values.keys(), result.keys())
3274 failed = False
3275 for k in values.keys():
3276 if result[k] != values[k]:
3277 print()
3278 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3279 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3280 failed = True
3281 if failed:
3282 self.fail("result does not equal expected, see print above")
3283
3284 def test_inspect_classify_class_attrs(self):
3285 # indirectly test __objclass__
3286 from inspect import Attribute
3287 values = [
3288 Attribute(name='__class__', kind='data',
3289 defining_class=object, object=EnumMeta),
3290 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003291 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003292 Attribute(name='__members__', kind='property',
3293 defining_class=EnumMeta, object=EnumMeta.__members__),
3294 Attribute(name='__module__', kind='data',
3295 defining_class=self.Color, object=__name__),
3296 Attribute(name='blue', kind='data',
3297 defining_class=self.Color, object=self.Color.blue),
3298 Attribute(name='green', kind='data',
3299 defining_class=self.Color, object=self.Color.green),
3300 Attribute(name='red', kind='data',
3301 defining_class=self.Color, object=self.Color.red),
3302 Attribute(name='name', kind='data',
3303 defining_class=Enum, object=Enum.__dict__['name']),
3304 Attribute(name='value', kind='data',
3305 defining_class=Enum, object=Enum.__dict__['value']),
3306 ]
3307 values.sort(key=lambda item: item.name)
3308 result = list(inspect.classify_class_attrs(self.Color))
3309 result.sort(key=lambda item: item.name)
3310 failed = False
3311 for v, r in zip(values, result):
3312 if r != v:
3313 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3314 failed = True
3315 if failed:
3316 self.fail("result does not equal expected, see print above")
3317
Martin Panter19e69c52015-11-14 12:46:42 +00003318
3319class MiscTestCase(unittest.TestCase):
3320 def test__all__(self):
3321 support.check__all__(self, enum)
3322
3323
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003324# These are unordered here on purpose to ensure that declaration order
3325# makes no difference.
3326CONVERT_TEST_NAME_D = 5
3327CONVERT_TEST_NAME_C = 5
3328CONVERT_TEST_NAME_B = 5
3329CONVERT_TEST_NAME_A = 5 # This one should sort first.
3330CONVERT_TEST_NAME_E = 5
3331CONVERT_TEST_NAME_F = 5
3332
3333class TestIntEnumConvert(unittest.TestCase):
3334 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003335 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003336 'UnittestConvert',
3337 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003338 filter=lambda x: x.startswith('CONVERT_TEST_'))
3339 # We don't want the reverse lookup value to vary when there are
3340 # multiple possible names for a given value. It should always
3341 # report the first lexigraphical name in that case.
3342 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3343
3344 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003345 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003346 'UnittestConvert',
3347 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003348 filter=lambda x: x.startswith('CONVERT_TEST_'))
3349 # Ensure that test_type has all of the desired names and values.
3350 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3351 test_type.CONVERT_TEST_NAME_A)
3352 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3353 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3354 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3355 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3356 # Ensure that test_type only picked up names matching the filter.
3357 self.assertEqual([name for name in dir(test_type)
3358 if name[0:2] not in ('CO', '__')],
3359 [], msg='Names other than CONVERT_TEST_* found.')
3360
orlnub1230fb9fad2018-09-12 20:28:53 +03003361 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3362 '_convert was deprecated in 3.8')
3363 def test_convert_warn(self):
3364 with self.assertWarns(DeprecationWarning):
3365 enum.IntEnum._convert(
3366 'UnittestConvert',
3367 ('test.test_enum', '__main__')[__name__=='__main__'],
3368 filter=lambda x: x.startswith('CONVERT_TEST_'))
3369
3370 @unittest.skipUnless(sys.version_info >= (3, 9),
3371 '_convert was removed in 3.9')
3372 def test_convert_raise(self):
3373 with self.assertRaises(AttributeError):
3374 enum.IntEnum._convert(
3375 'UnittestConvert',
3376 ('test.test_enum', '__main__')[__name__=='__main__'],
3377 filter=lambda x: x.startswith('CONVERT_TEST_'))
3378
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003379
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003380if __name__ == '__main__':
3381 unittest.main()