blob: 20bc5b3c750d61960223298f885956835700a26a [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)()
1152 names = set(classdict._member_names)
1153 i = 0
1154 for k in classdict._member_names:
1155 v = classdict[k]
1156 if v is Ellipsis:
1157 v = i
1158 else:
1159 i = v
1160 i += 1
1161 temp[k] = v
1162 for k, v in classdict.items():
1163 if k not in names:
1164 temp[k] = v
1165 return super(auto_enum, metacls).__new__(
1166 metacls, cls, bases, temp)
1167
1168 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1169 pass
1170
1171 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1172 pass
1173
1174 class TestAutoNumber(AutoNumberedEnum):
1175 a = ...
1176 b = 3
1177 c = ...
1178
1179 class TestAutoInt(AutoIntEnum):
1180 a = ...
1181 b = 3
1182 c = ...
1183
1184 def test_subclasses_with_getnewargs(self):
1185 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001186 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001187 def __new__(cls, *args):
1188 _args = args
1189 name, *args = args
1190 if len(args) == 0:
1191 raise TypeError("name and value must be specified")
1192 self = int.__new__(cls, *args)
1193 self._intname = name
1194 self._args = _args
1195 return self
1196 def __getnewargs__(self):
1197 return self._args
1198 @property
1199 def __name__(self):
1200 return self._intname
1201 def __repr__(self):
1202 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001203 return "{}({!r}, {})".format(
1204 type(self).__name__,
1205 self.__name__,
1206 int.__repr__(self),
1207 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001208 def __str__(self):
1209 # str() is unchanged, even if it relies on the repr() fallback
1210 base = int
1211 base_str = base.__str__
1212 if base_str.__objclass__ is object:
1213 return base.__repr__(self)
1214 return base_str(self)
1215 # for simplicity, we only define one operator that
1216 # propagates expressions
1217 def __add__(self, other):
1218 temp = int(self) + int( other)
1219 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1220 return NamedInt(
1221 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001222 temp,
1223 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001224 else:
1225 return temp
1226
1227 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001228 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001229 x = ('the-x', 1)
1230 y = ('the-y', 2)
1231
Ethan Furman2aa27322013-07-19 19:35:56 -07001232
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001233 self.assertIs(NEI.__new__, Enum.__new__)
1234 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1235 globals()['NamedInt'] = NamedInt
1236 globals()['NEI'] = NEI
1237 NI5 = NamedInt('test', 5)
1238 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001239 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001241 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001242 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243
Ethan Furmanca1b7942014-02-08 11:36:27 -08001244 def test_subclasses_with_getnewargs_ex(self):
1245 class NamedInt(int):
1246 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1247 def __new__(cls, *args):
1248 _args = args
1249 name, *args = args
1250 if len(args) == 0:
1251 raise TypeError("name and value must be specified")
1252 self = int.__new__(cls, *args)
1253 self._intname = name
1254 self._args = _args
1255 return self
1256 def __getnewargs_ex__(self):
1257 return self._args, {}
1258 @property
1259 def __name__(self):
1260 return self._intname
1261 def __repr__(self):
1262 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001263 return "{}({!r}, {})".format(
1264 type(self).__name__,
1265 self.__name__,
1266 int.__repr__(self),
1267 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001268 def __str__(self):
1269 # str() is unchanged, even if it relies on the repr() fallback
1270 base = int
1271 base_str = base.__str__
1272 if base_str.__objclass__ is object:
1273 return base.__repr__(self)
1274 return base_str(self)
1275 # for simplicity, we only define one operator that
1276 # propagates expressions
1277 def __add__(self, other):
1278 temp = int(self) + int( other)
1279 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1280 return NamedInt(
1281 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001282 temp,
1283 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001284 else:
1285 return temp
1286
1287 class NEI(NamedInt, Enum):
1288 __qualname__ = 'NEI' # needed for pickle protocol 4
1289 x = ('the-x', 1)
1290 y = ('the-y', 2)
1291
1292
1293 self.assertIs(NEI.__new__, Enum.__new__)
1294 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1295 globals()['NamedInt'] = NamedInt
1296 globals()['NEI'] = NEI
1297 NI5 = NamedInt('test', 5)
1298 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001299 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001300 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001301 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001302 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001303
1304 def test_subclasses_with_reduce(self):
1305 class NamedInt(int):
1306 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1307 def __new__(cls, *args):
1308 _args = args
1309 name, *args = args
1310 if len(args) == 0:
1311 raise TypeError("name and value must be specified")
1312 self = int.__new__(cls, *args)
1313 self._intname = name
1314 self._args = _args
1315 return self
1316 def __reduce__(self):
1317 return self.__class__, self._args
1318 @property
1319 def __name__(self):
1320 return self._intname
1321 def __repr__(self):
1322 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001323 return "{}({!r}, {})".format(
1324 type(self).__name__,
1325 self.__name__,
1326 int.__repr__(self),
1327 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001328 def __str__(self):
1329 # str() is unchanged, even if it relies on the repr() fallback
1330 base = int
1331 base_str = base.__str__
1332 if base_str.__objclass__ is object:
1333 return base.__repr__(self)
1334 return base_str(self)
1335 # for simplicity, we only define one operator that
1336 # propagates expressions
1337 def __add__(self, other):
1338 temp = int(self) + int( other)
1339 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1340 return NamedInt(
1341 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001342 temp,
1343 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001344 else:
1345 return temp
1346
1347 class NEI(NamedInt, Enum):
1348 __qualname__ = 'NEI' # needed for pickle protocol 4
1349 x = ('the-x', 1)
1350 y = ('the-y', 2)
1351
1352
1353 self.assertIs(NEI.__new__, Enum.__new__)
1354 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1355 globals()['NamedInt'] = NamedInt
1356 globals()['NEI'] = NEI
1357 NI5 = NamedInt('test', 5)
1358 self.assertEqual(NI5, 5)
1359 test_pickle_dump_load(self.assertEqual, NI5, 5)
1360 self.assertEqual(NEI.y.value, 2)
1361 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001362 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001363
1364 def test_subclasses_with_reduce_ex(self):
1365 class NamedInt(int):
1366 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1367 def __new__(cls, *args):
1368 _args = args
1369 name, *args = args
1370 if len(args) == 0:
1371 raise TypeError("name and value must be specified")
1372 self = int.__new__(cls, *args)
1373 self._intname = name
1374 self._args = _args
1375 return self
1376 def __reduce_ex__(self, proto):
1377 return self.__class__, self._args
1378 @property
1379 def __name__(self):
1380 return self._intname
1381 def __repr__(self):
1382 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001383 return "{}({!r}, {})".format(
1384 type(self).__name__,
1385 self.__name__,
1386 int.__repr__(self),
1387 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001388 def __str__(self):
1389 # str() is unchanged, even if it relies on the repr() fallback
1390 base = int
1391 base_str = base.__str__
1392 if base_str.__objclass__ is object:
1393 return base.__repr__(self)
1394 return base_str(self)
1395 # for simplicity, we only define one operator that
1396 # propagates expressions
1397 def __add__(self, other):
1398 temp = int(self) + int( other)
1399 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1400 return NamedInt(
1401 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001402 temp,
1403 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001404 else:
1405 return temp
1406
1407 class NEI(NamedInt, Enum):
1408 __qualname__ = 'NEI' # needed for pickle protocol 4
1409 x = ('the-x', 1)
1410 y = ('the-y', 2)
1411
Ethan Furmanca1b7942014-02-08 11:36:27 -08001412 self.assertIs(NEI.__new__, Enum.__new__)
1413 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1414 globals()['NamedInt'] = NamedInt
1415 globals()['NEI'] = NEI
1416 NI5 = NamedInt('test', 5)
1417 self.assertEqual(NI5, 5)
1418 test_pickle_dump_load(self.assertEqual, NI5, 5)
1419 self.assertEqual(NEI.y.value, 2)
1420 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001421 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001422
Ethan Furmandc870522014-02-18 12:37:12 -08001423 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001424 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001425 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001426 def __new__(cls, *args):
1427 _args = args
1428 name, *args = args
1429 if len(args) == 0:
1430 raise TypeError("name and value must be specified")
1431 self = int.__new__(cls, *args)
1432 self._intname = name
1433 self._args = _args
1434 return self
1435 @property
1436 def __name__(self):
1437 return self._intname
1438 def __repr__(self):
1439 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001440 return "{}({!r}, {})".format(
1441 type(self).__name__,
1442 self.__name__,
1443 int.__repr__(self),
1444 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001445 def __str__(self):
1446 # str() is unchanged, even if it relies on the repr() fallback
1447 base = int
1448 base_str = base.__str__
1449 if base_str.__objclass__ is object:
1450 return base.__repr__(self)
1451 return base_str(self)
1452 # for simplicity, we only define one operator that
1453 # propagates expressions
1454 def __add__(self, other):
1455 temp = int(self) + int( other)
1456 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1457 return NamedInt(
1458 '({0} + {1})'.format(self.__name__, other.__name__),
1459 temp )
1460 else:
1461 return temp
1462
1463 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001464 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001465 x = ('the-x', 1)
1466 y = ('the-y', 2)
1467
1468 self.assertIs(NEI.__new__, Enum.__new__)
1469 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1470 globals()['NamedInt'] = NamedInt
1471 globals()['NEI'] = NEI
1472 NI5 = NamedInt('test', 5)
1473 self.assertEqual(NI5, 5)
1474 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001475 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1476 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477
Ethan Furmandc870522014-02-18 12:37:12 -08001478 def test_subclasses_without_direct_pickle_support_using_name(self):
1479 class NamedInt(int):
1480 __qualname__ = 'NamedInt'
1481 def __new__(cls, *args):
1482 _args = args
1483 name, *args = args
1484 if len(args) == 0:
1485 raise TypeError("name and value must be specified")
1486 self = int.__new__(cls, *args)
1487 self._intname = name
1488 self._args = _args
1489 return self
1490 @property
1491 def __name__(self):
1492 return self._intname
1493 def __repr__(self):
1494 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001495 return "{}({!r}, {})".format(
1496 type(self).__name__,
1497 self.__name__,
1498 int.__repr__(self),
1499 )
Ethan Furmandc870522014-02-18 12:37:12 -08001500 def __str__(self):
1501 # str() is unchanged, even if it relies on the repr() fallback
1502 base = int
1503 base_str = base.__str__
1504 if base_str.__objclass__ is object:
1505 return base.__repr__(self)
1506 return base_str(self)
1507 # for simplicity, we only define one operator that
1508 # propagates expressions
1509 def __add__(self, other):
1510 temp = int(self) + int( other)
1511 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1512 return NamedInt(
1513 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001514 temp,
1515 )
Ethan Furmandc870522014-02-18 12:37:12 -08001516 else:
1517 return temp
1518
1519 class NEI(NamedInt, Enum):
1520 __qualname__ = 'NEI'
1521 x = ('the-x', 1)
1522 y = ('the-y', 2)
1523 def __reduce_ex__(self, proto):
1524 return getattr, (self.__class__, self._name_)
1525
1526 self.assertIs(NEI.__new__, Enum.__new__)
1527 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1528 globals()['NamedInt'] = NamedInt
1529 globals()['NEI'] = NEI
1530 NI5 = NamedInt('test', 5)
1531 self.assertEqual(NI5, 5)
1532 self.assertEqual(NEI.y.value, 2)
1533 test_pickle_dump_load(self.assertIs, NEI.y)
1534 test_pickle_dump_load(self.assertIs, NEI)
1535
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001536 def test_tuple_subclass(self):
1537 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001538 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001539 first = (1, 'for the money')
1540 second = (2, 'for the show')
1541 third = (3, 'for the music')
1542 self.assertIs(type(SomeTuple.first), SomeTuple)
1543 self.assertIsInstance(SomeTuple.second, tuple)
1544 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1545 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001546 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547
1548 def test_duplicate_values_give_unique_enum_items(self):
1549 class AutoNumber(Enum):
1550 first = ()
1551 second = ()
1552 third = ()
1553 def __new__(cls):
1554 value = len(cls.__members__) + 1
1555 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001556 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 return obj
1558 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001559 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001560 self.assertEqual(
1561 list(AutoNumber),
1562 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1563 )
1564 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001565 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001566 self.assertIs(AutoNumber(1), AutoNumber.first)
1567
1568 def test_inherited_new_from_enhanced_enum(self):
1569 class AutoNumber(Enum):
1570 def __new__(cls):
1571 value = len(cls.__members__) + 1
1572 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001573 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001574 return obj
1575 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001576 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 class Color(AutoNumber):
1578 red = ()
1579 green = ()
1580 blue = ()
1581 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1582 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1583
1584 def test_inherited_new_from_mixed_enum(self):
1585 class AutoNumber(IntEnum):
1586 def __new__(cls):
1587 value = len(cls.__members__) + 1
1588 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001589 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001590 return obj
1591 class Color(AutoNumber):
1592 red = ()
1593 green = ()
1594 blue = ()
1595 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1596 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1597
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001598 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001599 class OrdinaryEnum(Enum):
1600 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001601 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1602 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001603
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001604 def test_ordered_mixin(self):
1605 class OrderedEnum(Enum):
1606 def __ge__(self, other):
1607 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001608 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001609 return NotImplemented
1610 def __gt__(self, other):
1611 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001612 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001613 return NotImplemented
1614 def __le__(self, other):
1615 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001616 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001617 return NotImplemented
1618 def __lt__(self, other):
1619 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001620 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001621 return NotImplemented
1622 class Grade(OrderedEnum):
1623 A = 5
1624 B = 4
1625 C = 3
1626 D = 2
1627 F = 1
1628 self.assertGreater(Grade.A, Grade.B)
1629 self.assertLessEqual(Grade.F, Grade.C)
1630 self.assertLess(Grade.D, Grade.A)
1631 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001632 self.assertEqual(Grade.B, Grade.B)
1633 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001634
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001635 def test_extending2(self):
1636 class Shade(Enum):
1637 def shade(self):
1638 print(self.name)
1639 class Color(Shade):
1640 red = 1
1641 green = 2
1642 blue = 3
1643 with self.assertRaises(TypeError):
1644 class MoreColor(Color):
1645 cyan = 4
1646 magenta = 5
1647 yellow = 6
1648
1649 def test_extending3(self):
1650 class Shade(Enum):
1651 def shade(self):
1652 return self.name
1653 class Color(Shade):
1654 def hex(self):
1655 return '%s hexlified!' % self.value
1656 class MoreColor(Color):
1657 cyan = 4
1658 magenta = 5
1659 yellow = 6
1660 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1661
orlnub1230fb9fad2018-09-12 20:28:53 +03001662 def test_subclass_duplicate_name(self):
1663 class Base(Enum):
1664 def test(self):
1665 pass
1666 class Test(Base):
1667 test = 1
1668 self.assertIs(type(Test.test), Test)
1669
1670 def test_subclass_duplicate_name_dynamic(self):
1671 from types import DynamicClassAttribute
1672 class Base(Enum):
1673 @DynamicClassAttribute
1674 def test(self):
1675 return 'dynamic'
1676 class Test(Base):
1677 test = 1
1678 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001679
1680 def test_no_duplicates(self):
1681 class UniqueEnum(Enum):
1682 def __init__(self, *args):
1683 cls = self.__class__
1684 if any(self.value == e.value for e in cls):
1685 a = self.name
1686 e = cls(self.value).name
1687 raise ValueError(
1688 "aliases not allowed in UniqueEnum: %r --> %r"
1689 % (a, e)
1690 )
1691 class Color(UniqueEnum):
1692 red = 1
1693 green = 2
1694 blue = 3
1695 with self.assertRaises(ValueError):
1696 class Color(UniqueEnum):
1697 red = 1
1698 green = 2
1699 blue = 3
1700 grene = 2
1701
1702 def test_init(self):
1703 class Planet(Enum):
1704 MERCURY = (3.303e+23, 2.4397e6)
1705 VENUS = (4.869e+24, 6.0518e6)
1706 EARTH = (5.976e+24, 6.37814e6)
1707 MARS = (6.421e+23, 3.3972e6)
1708 JUPITER = (1.9e+27, 7.1492e7)
1709 SATURN = (5.688e+26, 6.0268e7)
1710 URANUS = (8.686e+25, 2.5559e7)
1711 NEPTUNE = (1.024e+26, 2.4746e7)
1712 def __init__(self, mass, radius):
1713 self.mass = mass # in kilograms
1714 self.radius = radius # in meters
1715 @property
1716 def surface_gravity(self):
1717 # universal gravitational constant (m3 kg-1 s-2)
1718 G = 6.67300E-11
1719 return G * self.mass / (self.radius * self.radius)
1720 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1721 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1722
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001723 def test_ignore(self):
1724 class Period(timedelta, Enum):
1725 '''
1726 different lengths of time
1727 '''
1728 def __new__(cls, value, period):
1729 obj = timedelta.__new__(cls, value)
1730 obj._value_ = value
1731 obj.period = period
1732 return obj
1733 _ignore_ = 'Period i'
1734 Period = vars()
1735 for i in range(13):
1736 Period['month_%d' % i] = i*30, 'month'
1737 for i in range(53):
1738 Period['week_%d' % i] = i*7, 'week'
1739 for i in range(32):
1740 Period['day_%d' % i] = i, 'day'
1741 OneDay = day_1
1742 OneWeek = week_1
1743 OneMonth = month_1
1744 self.assertFalse(hasattr(Period, '_ignore_'))
1745 self.assertFalse(hasattr(Period, 'Period'))
1746 self.assertFalse(hasattr(Period, 'i'))
1747 self.assertTrue(isinstance(Period.day_1, timedelta))
1748 self.assertTrue(Period.month_1 is Period.day_30)
1749 self.assertTrue(Period.week_4 is Period.day_28)
1750
Ethan Furman2aa27322013-07-19 19:35:56 -07001751 def test_nonhash_value(self):
1752 class AutoNumberInAList(Enum):
1753 def __new__(cls):
1754 value = [len(cls.__members__) + 1]
1755 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001756 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001757 return obj
1758 class ColorInAList(AutoNumberInAList):
1759 red = ()
1760 green = ()
1761 blue = ()
1762 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001763 for enum, value in zip(ColorInAList, range(3)):
1764 value += 1
1765 self.assertEqual(enum.value, [value])
1766 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001767
Ethan Furmanb41803e2013-07-25 13:50:45 -07001768 def test_conflicting_types_resolved_in_new(self):
1769 class LabelledIntEnum(int, Enum):
1770 def __new__(cls, *args):
1771 value, label = args
1772 obj = int.__new__(cls, value)
1773 obj.label = label
1774 obj._value_ = value
1775 return obj
1776
1777 class LabelledList(LabelledIntEnum):
1778 unprocessed = (1, "Unprocessed")
1779 payment_complete = (2, "Payment Complete")
1780
1781 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1782 self.assertEqual(LabelledList.unprocessed, 1)
1783 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001784
Ethan Furmanc16595e2016-09-10 23:36:59 -07001785 def test_auto_number(self):
1786 class Color(Enum):
1787 red = auto()
1788 blue = auto()
1789 green = auto()
1790
1791 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1792 self.assertEqual(Color.red.value, 1)
1793 self.assertEqual(Color.blue.value, 2)
1794 self.assertEqual(Color.green.value, 3)
1795
1796 def test_auto_name(self):
1797 class Color(Enum):
1798 def _generate_next_value_(name, start, count, last):
1799 return name
1800 red = auto()
1801 blue = auto()
1802 green = auto()
1803
1804 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1805 self.assertEqual(Color.red.value, 'red')
1806 self.assertEqual(Color.blue.value, 'blue')
1807 self.assertEqual(Color.green.value, 'green')
1808
1809 def test_auto_name_inherit(self):
1810 class AutoNameEnum(Enum):
1811 def _generate_next_value_(name, start, count, last):
1812 return name
1813 class Color(AutoNameEnum):
1814 red = auto()
1815 blue = auto()
1816 green = auto()
1817
1818 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1819 self.assertEqual(Color.red.value, 'red')
1820 self.assertEqual(Color.blue.value, 'blue')
1821 self.assertEqual(Color.green.value, 'green')
1822
1823 def test_auto_garbage(self):
1824 class Color(Enum):
1825 red = 'red'
1826 blue = auto()
1827 self.assertEqual(Color.blue.value, 1)
1828
1829 def test_auto_garbage_corrected(self):
1830 class Color(Enum):
1831 red = 'red'
1832 blue = 2
1833 green = auto()
1834
1835 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1836 self.assertEqual(Color.red.value, 'red')
1837 self.assertEqual(Color.blue.value, 2)
1838 self.assertEqual(Color.green.value, 3)
1839
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001840 def test_auto_order(self):
1841 with self.assertRaises(TypeError):
1842 class Color(Enum):
1843 red = auto()
1844 green = auto()
1845 blue = auto()
1846 def _generate_next_value_(name, start, count, last):
1847 return name
1848
Ethan Furmanfc23a942020-09-16 12:37:54 -07001849 def test_auto_order_wierd(self):
1850 weird_auto = auto()
1851 weird_auto.value = 'pathological case'
1852 class Color(Enum):
1853 red = weird_auto
1854 def _generate_next_value_(name, start, count, last):
1855 return name
1856 blue = auto()
1857 self.assertEqual(list(Color), [Color.red, Color.blue])
1858 self.assertEqual(Color.red.value, 'pathological case')
1859 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001860
Ethan Furman3515dcc2016-09-18 13:15:41 -07001861 def test_duplicate_auto(self):
1862 class Dupes(Enum):
1863 first = primero = auto()
1864 second = auto()
1865 third = auto()
1866 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1867
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001868 def test_default_missing(self):
1869 class Color(Enum):
1870 RED = 1
1871 GREEN = 2
1872 BLUE = 3
1873 try:
1874 Color(7)
1875 except ValueError as exc:
1876 self.assertTrue(exc.__context__ is None)
1877 else:
1878 raise Exception('Exception not raised.')
1879
Ethan Furman019f0a02018-09-12 11:43:34 -07001880 def test_missing(self):
1881 class Color(Enum):
1882 red = 1
1883 green = 2
1884 blue = 3
1885 @classmethod
1886 def _missing_(cls, item):
1887 if item == 'three':
1888 return cls.blue
1889 elif item == 'bad return':
1890 # trigger internal error
1891 return 5
1892 elif item == 'error out':
1893 raise ZeroDivisionError
1894 else:
1895 # trigger not found
1896 return None
1897 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001898 try:
1899 Color(7)
1900 except ValueError as exc:
1901 self.assertTrue(exc.__context__ is None)
1902 else:
1903 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001904 try:
1905 Color('bad return')
1906 except TypeError as exc:
1907 self.assertTrue(isinstance(exc.__context__, ValueError))
1908 else:
1909 raise Exception('Exception not raised.')
1910 try:
1911 Color('error out')
1912 except ZeroDivisionError as exc:
1913 self.assertTrue(isinstance(exc.__context__, ValueError))
1914 else:
1915 raise Exception('Exception not raised.')
1916
Ethan Furman5bdab642018-09-21 19:03:09 -07001917 def test_multiple_mixin(self):
1918 class MaxMixin:
1919 @classproperty
1920 def MAX(cls):
1921 max = len(cls)
1922 cls.MAX = max
1923 return max
1924 class StrMixin:
1925 def __str__(self):
1926 return self._name_.lower()
1927 class SomeEnum(Enum):
1928 def behavior(self):
1929 return 'booyah'
1930 class AnotherEnum(Enum):
1931 def behavior(self):
1932 return 'nuhuh!'
1933 def social(self):
1934 return "what's up?"
1935 class Color(MaxMixin, Enum):
1936 RED = auto()
1937 GREEN = auto()
1938 BLUE = auto()
1939 self.assertEqual(Color.RED.value, 1)
1940 self.assertEqual(Color.GREEN.value, 2)
1941 self.assertEqual(Color.BLUE.value, 3)
1942 self.assertEqual(Color.MAX, 3)
1943 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1944 class Color(MaxMixin, StrMixin, Enum):
1945 RED = auto()
1946 GREEN = auto()
1947 BLUE = auto()
1948 self.assertEqual(Color.RED.value, 1)
1949 self.assertEqual(Color.GREEN.value, 2)
1950 self.assertEqual(Color.BLUE.value, 3)
1951 self.assertEqual(Color.MAX, 3)
1952 self.assertEqual(str(Color.BLUE), 'blue')
1953 class Color(StrMixin, MaxMixin, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(Color.RED.value, 1)
1958 self.assertEqual(Color.GREEN.value, 2)
1959 self.assertEqual(Color.BLUE.value, 3)
1960 self.assertEqual(Color.MAX, 3)
1961 self.assertEqual(str(Color.BLUE), 'blue')
1962 class CoolColor(StrMixin, SomeEnum, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(CoolColor.RED.value, 1)
1967 self.assertEqual(CoolColor.GREEN.value, 2)
1968 self.assertEqual(CoolColor.BLUE.value, 3)
1969 self.assertEqual(str(CoolColor.BLUE), 'blue')
1970 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1971 class CoolerColor(StrMixin, AnotherEnum, Enum):
1972 RED = auto()
1973 GREEN = auto()
1974 BLUE = auto()
1975 self.assertEqual(CoolerColor.RED.value, 1)
1976 self.assertEqual(CoolerColor.GREEN.value, 2)
1977 self.assertEqual(CoolerColor.BLUE.value, 3)
1978 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1979 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1980 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1981 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1982 RED = auto()
1983 GREEN = auto()
1984 BLUE = auto()
1985 self.assertEqual(CoolestColor.RED.value, 1)
1986 self.assertEqual(CoolestColor.GREEN.value, 2)
1987 self.assertEqual(CoolestColor.BLUE.value, 3)
1988 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1989 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1990 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1991 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1992 RED = auto()
1993 GREEN = auto()
1994 BLUE = auto()
1995 self.assertEqual(ConfusedColor.RED.value, 1)
1996 self.assertEqual(ConfusedColor.GREEN.value, 2)
1997 self.assertEqual(ConfusedColor.BLUE.value, 3)
1998 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1999 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2000 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2001 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2002 RED = auto()
2003 GREEN = auto()
2004 BLUE = auto()
2005 self.assertEqual(ReformedColor.RED.value, 1)
2006 self.assertEqual(ReformedColor.GREEN.value, 2)
2007 self.assertEqual(ReformedColor.BLUE.value, 3)
2008 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2009 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2010 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2011 self.assertTrue(issubclass(ReformedColor, int))
2012
Ethan Furmancd453852018-10-05 23:29:36 -07002013 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002014 @unique
2015 class Decision1(StrEnum):
2016 REVERT = "REVERT"
2017 REVERT_ALL = "REVERT_ALL"
2018 RETRY = "RETRY"
2019 class MyEnum(StrEnum):
2020 pass
2021 @unique
2022 class Decision2(MyEnum):
2023 REVERT = "REVERT"
2024 REVERT_ALL = "REVERT_ALL"
2025 RETRY = "RETRY"
2026
Ethan Furmanc2667362020-12-07 00:17:31 -08002027 def test_multiple_mixin_inherited(self):
2028 class MyInt(int):
2029 def __new__(cls, value):
2030 return super().__new__(cls, value)
2031
2032 class HexMixin:
2033 def __repr__(self):
2034 return hex(self)
2035
2036 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2037 pass
2038
2039 class Foo(MyIntEnum):
2040 TEST = 1
2041 self.assertTrue(isinstance(Foo.TEST, MyInt))
2042 self.assertEqual(repr(Foo.TEST), "0x1")
2043
2044 class Fee(MyIntEnum):
2045 TEST = 1
2046 def __new__(cls, value):
2047 value += 1
2048 member = int.__new__(cls, value)
2049 member._value_ = value
2050 return member
2051 self.assertEqual(Fee.TEST, 2)
2052
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002053 def test_empty_globals(self):
2054 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2055 # when using compile and exec because f_globals is empty
2056 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2057 code = compile(code, "<string>", "exec")
2058 global_ns = {}
2059 local_ls = {}
2060 exec(code, global_ns, local_ls)
2061
Ethan Furman0063ff42020-09-21 17:23:13 -07002062 def test_strenum(self):
2063 class GoodStrEnum(StrEnum):
2064 one = '1'
2065 two = '2'
2066 three = b'3', 'ascii'
2067 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002068 self.assertEqual(GoodStrEnum.one, '1')
2069 self.assertEqual(str(GoodStrEnum.one), '1')
2070 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2071 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2072 #
2073 class DumbMixin:
2074 def __str__(self):
2075 return "don't do this"
2076 class DumbStrEnum(DumbMixin, StrEnum):
2077 five = '5'
2078 six = '6'
2079 seven = '7'
2080 self.assertEqual(DumbStrEnum.seven, '7')
2081 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2082 #
2083 class EnumMixin(Enum):
2084 def hello(self):
2085 print('hello from %s' % (self, ))
2086 class HelloEnum(EnumMixin, StrEnum):
2087 eight = '8'
2088 self.assertEqual(HelloEnum.eight, '8')
2089 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2090 #
2091 class GoodbyeMixin:
2092 def goodbye(self):
2093 print('%s wishes you a fond farewell')
2094 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2095 nine = '9'
2096 self.assertEqual(GoodbyeEnum.nine, '9')
2097 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2098 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002099 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2100 class FirstFailedStrEnum(StrEnum):
2101 one = 1
2102 two = '2'
2103 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2104 class SecondFailedStrEnum(StrEnum):
2105 one = '1'
2106 two = 2,
2107 three = '3'
2108 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2109 class ThirdFailedStrEnum(StrEnum):
2110 one = '1'
2111 two = 2
2112 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2113 class ThirdFailedStrEnum(StrEnum):
2114 one = '1'
2115 two = b'2', sys.getdefaultencoding
2116 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2117 class ThirdFailedStrEnum(StrEnum):
2118 one = '1'
2119 two = b'2', 'ascii', 9
Ethan Furman6bd94de2020-12-09 16:41:22 -08002120
2121 def test_init_subclass(self):
2122 class MyEnum(Enum):
2123 def __init_subclass__(cls, **kwds):
2124 super(MyEnum, cls).__init_subclass__(**kwds)
2125 self.assertFalse(cls.__dict__.get('_test', False))
2126 cls._test1 = 'MyEnum'
2127 #
2128 class TheirEnum(MyEnum):
2129 def __init_subclass__(cls, **kwds):
2130 super().__init_subclass__(**kwds)
2131 cls._test2 = 'TheirEnum'
2132 class WhoseEnum(TheirEnum):
2133 def __init_subclass__(cls, **kwds):
2134 pass
2135 class NoEnum(WhoseEnum):
2136 ONE = 1
2137 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2138 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2139 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2140 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2141 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2142 #
2143 class OurEnum(MyEnum):
2144 def __init_subclass__(cls, **kwds):
2145 cls._test2 = 'OurEnum'
2146 class WhereEnum(OurEnum):
2147 def __init_subclass__(cls, **kwds):
2148 pass
2149 class NeverEnum(WhereEnum):
2150 ONE = 'one'
2151 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2152 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2153 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2154 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2155 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2156
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002157
Ethan Furmane8e61272016-08-20 07:19:31 -07002158class TestOrder(unittest.TestCase):
2159
2160 def test_same_members(self):
2161 class Color(Enum):
2162 _order_ = 'red green blue'
2163 red = 1
2164 green = 2
2165 blue = 3
2166
2167 def test_same_members_with_aliases(self):
2168 class Color(Enum):
2169 _order_ = 'red green blue'
2170 red = 1
2171 green = 2
2172 blue = 3
2173 verde = green
2174
2175 def test_same_members_wrong_order(self):
2176 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2177 class Color(Enum):
2178 _order_ = 'red green blue'
2179 red = 1
2180 blue = 3
2181 green = 2
2182
2183 def test_order_has_extra_members(self):
2184 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2185 class Color(Enum):
2186 _order_ = 'red green blue purple'
2187 red = 1
2188 green = 2
2189 blue = 3
2190
2191 def test_order_has_extra_members_with_aliases(self):
2192 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2193 class Color(Enum):
2194 _order_ = 'red green blue purple'
2195 red = 1
2196 green = 2
2197 blue = 3
2198 verde = green
2199
2200 def test_enum_has_extra_members(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 green = 2
2206 blue = 3
2207 purple = 4
2208
2209 def test_enum_has_extra_members_with_aliases(self):
2210 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2211 class Color(Enum):
2212 _order_ = 'red green blue'
2213 red = 1
2214 green = 2
2215 blue = 3
2216 purple = 4
2217 verde = green
2218
2219
Ethan Furman65a5a472016-09-01 23:55:19 -07002220class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002221 """Tests of the Flags."""
2222
Ethan Furman65a5a472016-09-01 23:55:19 -07002223 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002224 R, W, X = 4, 2, 1
2225
Ethan Furman65a5a472016-09-01 23:55:19 -07002226 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002227 RO = 0
2228 WO = 1
2229 RW = 2
2230 AC = 3
2231 CE = 1<<19
2232
Rahul Jha94306522018-09-10 23:51:04 +05302233 class Color(Flag):
2234 BLACK = 0
2235 RED = 1
2236 GREEN = 2
2237 BLUE = 4
2238 PURPLE = RED|BLUE
2239
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002240 def test_str(self):
2241 Perm = self.Perm
2242 self.assertEqual(str(Perm.R), 'Perm.R')
2243 self.assertEqual(str(Perm.W), 'Perm.W')
2244 self.assertEqual(str(Perm.X), 'Perm.X')
2245 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2246 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2247 self.assertEqual(str(Perm(0)), 'Perm.0')
2248 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2249 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2250 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2251 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2252 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2253 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2254
2255 Open = self.Open
2256 self.assertEqual(str(Open.RO), 'Open.RO')
2257 self.assertEqual(str(Open.WO), 'Open.WO')
2258 self.assertEqual(str(Open.AC), 'Open.AC')
2259 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2260 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002261 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002262 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2263 self.assertEqual(str(~Open.AC), 'Open.CE')
2264 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2265 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2266
2267 def test_repr(self):
2268 Perm = self.Perm
2269 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2270 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2271 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2272 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2273 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002274 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002275 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2276 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2277 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2278 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002279 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002280 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2281
2282 Open = self.Open
2283 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2284 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2285 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2286 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2287 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002288 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002289 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2290 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2291 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2292 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2293
Ethan Furman37440ee2020-12-08 11:14:10 -08002294 def test_format(self):
2295 Perm = self.Perm
2296 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2297 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2298
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002299 def test_or(self):
2300 Perm = self.Perm
2301 for i in Perm:
2302 for j in Perm:
2303 self.assertEqual((i | j), Perm(i.value | j.value))
2304 self.assertEqual((i | j).value, i.value | j.value)
2305 self.assertIs(type(i | j), Perm)
2306 for i in Perm:
2307 self.assertIs(i | i, i)
2308 Open = self.Open
2309 self.assertIs(Open.RO | Open.CE, Open.CE)
2310
2311 def test_and(self):
2312 Perm = self.Perm
2313 RW = Perm.R | Perm.W
2314 RX = Perm.R | Perm.X
2315 WX = Perm.W | Perm.X
2316 RWX = Perm.R | Perm.W | Perm.X
2317 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2318 for i in values:
2319 for j in values:
2320 self.assertEqual((i & j).value, i.value & j.value)
2321 self.assertIs(type(i & j), Perm)
2322 for i in Perm:
2323 self.assertIs(i & i, i)
2324 self.assertIs(i & RWX, i)
2325 self.assertIs(RWX & i, i)
2326 Open = self.Open
2327 self.assertIs(Open.RO & Open.CE, Open.RO)
2328
2329 def test_xor(self):
2330 Perm = self.Perm
2331 for i in Perm:
2332 for j in Perm:
2333 self.assertEqual((i ^ j).value, i.value ^ j.value)
2334 self.assertIs(type(i ^ j), Perm)
2335 for i in Perm:
2336 self.assertIs(i ^ Perm(0), i)
2337 self.assertIs(Perm(0) ^ i, i)
2338 Open = self.Open
2339 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2340 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2341
2342 def test_invert(self):
2343 Perm = self.Perm
2344 RW = Perm.R | Perm.W
2345 RX = Perm.R | Perm.X
2346 WX = Perm.W | Perm.X
2347 RWX = Perm.R | Perm.W | Perm.X
2348 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2349 for i in values:
2350 self.assertIs(type(~i), Perm)
2351 self.assertEqual(~~i, i)
2352 for i in Perm:
2353 self.assertIs(~~i, i)
2354 Open = self.Open
2355 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2356 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2357
Ethan Furman25d94bb2016-09-02 16:32:32 -07002358 def test_bool(self):
2359 Perm = self.Perm
2360 for f in Perm:
2361 self.assertTrue(f)
2362 Open = self.Open
2363 for f in Open:
2364 self.assertEqual(bool(f.value), bool(f))
2365
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002366 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002367 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002368 lst = list(Perm)
2369 self.assertEqual(len(lst), len(Perm))
2370 self.assertEqual(len(Perm), 3, Perm)
2371 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2372 for i, n in enumerate('R W X'.split()):
2373 v = 1<<i
2374 e = Perm(v)
2375 self.assertEqual(e.value, v)
2376 self.assertEqual(type(e.value), int)
2377 self.assertEqual(e.name, n)
2378 self.assertIn(e, Perm)
2379 self.assertIs(type(e), Perm)
2380
2381 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002382 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383 lst = list(Perm)
2384 self.assertEqual(len(lst), len(Perm))
2385 self.assertEqual(len(Perm), 3, Perm)
2386 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2387 for i, n in enumerate('R W X'.split()):
2388 v = 8<<i
2389 e = Perm(v)
2390 self.assertEqual(e.value, v)
2391 self.assertEqual(type(e.value), int)
2392 self.assertEqual(e.name, n)
2393 self.assertIn(e, Perm)
2394 self.assertIs(type(e), Perm)
2395
2396 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002397 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002398 lst = list(Perm)
2399 self.assertEqual(len(lst), len(Perm))
2400 self.assertEqual(len(Perm), 3, Perm)
2401 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2402 for i, n in enumerate('R W X'.split()):
2403 v = 1<<i
2404 e = Perm(v)
2405 self.assertEqual(e.value, v)
2406 self.assertEqual(type(e.value), int)
2407 self.assertEqual(e.name, n)
2408 self.assertIn(e, Perm)
2409 self.assertIs(type(e), Perm)
2410
2411 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002412 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002413 lst = list(Perm)
2414 self.assertEqual(len(lst), len(Perm))
2415 self.assertEqual(len(Perm), 3, Perm)
2416 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2417 for i, n in enumerate('R W X'.split()):
2418 v = 1<<(2*i+1)
2419 e = Perm(v)
2420 self.assertEqual(e.value, v)
2421 self.assertEqual(type(e.value), int)
2422 self.assertEqual(e.name, n)
2423 self.assertIn(e, Perm)
2424 self.assertIs(type(e), Perm)
2425
2426 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002427 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002428 lst = list(Perm)
2429 self.assertEqual(len(lst), len(Perm))
2430 self.assertEqual(len(Perm), 3, Perm)
2431 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2432 for i, n in enumerate('R W X'.split()):
2433 v = 1<<(2*i+1)
2434 e = Perm(v)
2435 self.assertEqual(e.value, v)
2436 self.assertEqual(type(e.value), int)
2437 self.assertEqual(e.name, n)
2438 self.assertIn(e, Perm)
2439 self.assertIs(type(e), Perm)
2440
Ethan Furman65a5a472016-09-01 23:55:19 -07002441 def test_pickle(self):
2442 if isinstance(FlagStooges, Exception):
2443 raise FlagStooges
2444 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2445 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002446
Rahul Jha94306522018-09-10 23:51:04 +05302447 def test_contains(self):
2448 Open = self.Open
2449 Color = self.Color
2450 self.assertFalse(Color.BLACK in Open)
2451 self.assertFalse(Open.RO in Color)
2452 with self.assertRaises(TypeError):
2453 'BLACK' in Color
2454 with self.assertRaises(TypeError):
2455 'RO' in Open
2456 with self.assertRaises(TypeError):
2457 1 in Color
2458 with self.assertRaises(TypeError):
2459 1 in Open
2460
2461 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002462 Perm = self.Perm
2463 R, W, X = Perm
2464 RW = R | W
2465 RX = R | X
2466 WX = W | X
2467 RWX = R | W | X
2468 self.assertTrue(R in RW)
2469 self.assertTrue(R in RX)
2470 self.assertTrue(R in RWX)
2471 self.assertTrue(W in RW)
2472 self.assertTrue(W in WX)
2473 self.assertTrue(W in RWX)
2474 self.assertTrue(X in RX)
2475 self.assertTrue(X in WX)
2476 self.assertTrue(X in RWX)
2477 self.assertFalse(R in WX)
2478 self.assertFalse(W in RX)
2479 self.assertFalse(X in RW)
2480
Ethan Furman7219e272020-09-16 13:01:00 -07002481 def test_member_iter(self):
2482 Color = self.Color
2483 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2484 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2485 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2486
Ethan Furmanc16595e2016-09-10 23:36:59 -07002487 def test_auto_number(self):
2488 class Color(Flag):
2489 red = auto()
2490 blue = auto()
2491 green = auto()
2492
2493 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2494 self.assertEqual(Color.red.value, 1)
2495 self.assertEqual(Color.blue.value, 2)
2496 self.assertEqual(Color.green.value, 4)
2497
2498 def test_auto_number_garbage(self):
2499 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2500 class Color(Flag):
2501 red = 'not an int'
2502 blue = auto()
2503
Ethan Furman3515dcc2016-09-18 13:15:41 -07002504 def test_cascading_failure(self):
2505 class Bizarre(Flag):
2506 c = 3
2507 d = 4
2508 f = 6
2509 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002510 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2511 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2512 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2513 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2514 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2515 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2516 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002517
2518 def test_duplicate_auto(self):
2519 class Dupes(Enum):
2520 first = primero = auto()
2521 second = auto()
2522 third = auto()
2523 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2524
2525 def test_bizarre(self):
2526 class Bizarre(Flag):
2527 b = 3
2528 c = 4
2529 d = 6
2530 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2531
Ethan Furman5bdab642018-09-21 19:03:09 -07002532 def test_multiple_mixin(self):
2533 class AllMixin:
2534 @classproperty
2535 def ALL(cls):
2536 members = list(cls)
2537 all_value = None
2538 if members:
2539 all_value = members[0]
2540 for member in members[1:]:
2541 all_value |= member
2542 cls.ALL = all_value
2543 return all_value
2544 class StrMixin:
2545 def __str__(self):
2546 return self._name_.lower()
2547 class Color(AllMixin, Flag):
2548 RED = auto()
2549 GREEN = auto()
2550 BLUE = auto()
2551 self.assertEqual(Color.RED.value, 1)
2552 self.assertEqual(Color.GREEN.value, 2)
2553 self.assertEqual(Color.BLUE.value, 4)
2554 self.assertEqual(Color.ALL.value, 7)
2555 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2556 class Color(AllMixin, StrMixin, Flag):
2557 RED = auto()
2558 GREEN = auto()
2559 BLUE = auto()
2560 self.assertEqual(Color.RED.value, 1)
2561 self.assertEqual(Color.GREEN.value, 2)
2562 self.assertEqual(Color.BLUE.value, 4)
2563 self.assertEqual(Color.ALL.value, 7)
2564 self.assertEqual(str(Color.BLUE), 'blue')
2565 class Color(StrMixin, AllMixin, Flag):
2566 RED = auto()
2567 GREEN = auto()
2568 BLUE = auto()
2569 self.assertEqual(Color.RED.value, 1)
2570 self.assertEqual(Color.GREEN.value, 2)
2571 self.assertEqual(Color.BLUE.value, 4)
2572 self.assertEqual(Color.ALL.value, 7)
2573 self.assertEqual(str(Color.BLUE), 'blue')
2574
Hai Shie80697d2020-05-28 06:10:27 +08002575 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002576 def test_unique_composite(self):
2577 # override __eq__ to be identity only
2578 class TestFlag(Flag):
2579 one = auto()
2580 two = auto()
2581 three = auto()
2582 four = auto()
2583 five = auto()
2584 six = auto()
2585 seven = auto()
2586 eight = auto()
2587 def __eq__(self, other):
2588 return self is other
2589 def __hash__(self):
2590 return hash(self._value_)
2591 # have multiple threads competing to complete the composite members
2592 seen = set()
2593 failed = False
2594 def cycle_enum():
2595 nonlocal failed
2596 try:
2597 for i in range(256):
2598 seen.add(TestFlag(i))
2599 except Exception:
2600 failed = True
2601 threads = [
2602 threading.Thread(target=cycle_enum)
2603 for _ in range(8)
2604 ]
Hai Shie80697d2020-05-28 06:10:27 +08002605 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002606 pass
2607 # check that only 248 members were created
2608 self.assertFalse(
2609 failed,
2610 'at least one thread failed while creating composite members')
2611 self.assertEqual(256, len(seen), 'too many composite members created')
2612
Ethan Furman6bd94de2020-12-09 16:41:22 -08002613 def test_init_subclass(self):
2614 class MyEnum(Flag):
2615 def __init_subclass__(cls, **kwds):
2616 super().__init_subclass__(**kwds)
2617 self.assertFalse(cls.__dict__.get('_test', False))
2618 cls._test1 = 'MyEnum'
2619 #
2620 class TheirEnum(MyEnum):
2621 def __init_subclass__(cls, **kwds):
2622 super(TheirEnum, cls).__init_subclass__(**kwds)
2623 cls._test2 = 'TheirEnum'
2624 class WhoseEnum(TheirEnum):
2625 def __init_subclass__(cls, **kwds):
2626 pass
2627 class NoEnum(WhoseEnum):
2628 ONE = 1
2629 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2630 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2631 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2632 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2633 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2634 #
2635 class OurEnum(MyEnum):
2636 def __init_subclass__(cls, **kwds):
2637 cls._test2 = 'OurEnum'
2638 class WhereEnum(OurEnum):
2639 def __init_subclass__(cls, **kwds):
2640 pass
2641 class NeverEnum(WhereEnum):
2642 ONE = 1
2643 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2644 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2645 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2646 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2647 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2648
Ethan Furmanc16595e2016-09-10 23:36:59 -07002649
Ethan Furman65a5a472016-09-01 23:55:19 -07002650class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002651 """Tests of the IntFlags."""
2652
Ethan Furman65a5a472016-09-01 23:55:19 -07002653 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002654 X = 1 << 0
2655 W = 1 << 1
2656 R = 1 << 2
2657
Ethan Furman65a5a472016-09-01 23:55:19 -07002658 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002659 RO = 0
2660 WO = 1
2661 RW = 2
2662 AC = 3
2663 CE = 1<<19
2664
Rahul Jha94306522018-09-10 23:51:04 +05302665 class Color(IntFlag):
2666 BLACK = 0
2667 RED = 1
2668 GREEN = 2
2669 BLUE = 4
2670 PURPLE = RED|BLUE
2671
Ethan Furman3515dcc2016-09-18 13:15:41 -07002672 def test_type(self):
2673 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002674 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002675 Open = self.Open
2676 for f in Perm:
2677 self.assertTrue(isinstance(f, Perm))
2678 self.assertEqual(f, f.value)
2679 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2680 self.assertEqual(Perm.W | Perm.X, 3)
2681 for f in Open:
2682 self.assertTrue(isinstance(f, Open))
2683 self.assertEqual(f, f.value)
2684 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2685 self.assertEqual(Open.WO | Open.RW, 3)
2686
2687
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002688 def test_str(self):
2689 Perm = self.Perm
2690 self.assertEqual(str(Perm.R), 'Perm.R')
2691 self.assertEqual(str(Perm.W), 'Perm.W')
2692 self.assertEqual(str(Perm.X), 'Perm.X')
2693 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2694 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2695 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2696 self.assertEqual(str(Perm(0)), 'Perm.0')
2697 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002698 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2699 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2700 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2701 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002702 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002703 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2704 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2705 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002706
2707 Open = self.Open
2708 self.assertEqual(str(Open.RO), 'Open.RO')
2709 self.assertEqual(str(Open.WO), 'Open.WO')
2710 self.assertEqual(str(Open.AC), 'Open.AC')
2711 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2712 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2713 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002714 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2715 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2716 self.assertEqual(str(~Open.AC), 'Open.CE')
2717 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2718 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2719 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002720
2721 def test_repr(self):
2722 Perm = self.Perm
2723 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2724 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2725 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2726 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2727 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2728 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002729 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2730 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002731 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2732 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2733 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2734 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002735 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002736 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2737 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2738 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002739
2740 Open = self.Open
2741 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2742 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2743 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2744 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2745 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002746 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002747 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2748 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2749 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2750 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2751 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2752 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002753
Ethan Furman37440ee2020-12-08 11:14:10 -08002754 def test_format(self):
2755 Perm = self.Perm
2756 self.assertEqual(format(Perm.R, ''), '4')
2757 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2758
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002759 def test_or(self):
2760 Perm = self.Perm
2761 for i in Perm:
2762 for j in Perm:
2763 self.assertEqual(i | j, i.value | j.value)
2764 self.assertEqual((i | j).value, i.value | j.value)
2765 self.assertIs(type(i | j), Perm)
2766 for j in range(8):
2767 self.assertEqual(i | j, i.value | j)
2768 self.assertEqual((i | j).value, i.value | j)
2769 self.assertIs(type(i | j), Perm)
2770 self.assertEqual(j | i, j | i.value)
2771 self.assertEqual((j | i).value, j | i.value)
2772 self.assertIs(type(j | i), Perm)
2773 for i in Perm:
2774 self.assertIs(i | i, i)
2775 self.assertIs(i | 0, i)
2776 self.assertIs(0 | i, i)
2777 Open = self.Open
2778 self.assertIs(Open.RO | Open.CE, Open.CE)
2779
2780 def test_and(self):
2781 Perm = self.Perm
2782 RW = Perm.R | Perm.W
2783 RX = Perm.R | Perm.X
2784 WX = Perm.W | Perm.X
2785 RWX = Perm.R | Perm.W | Perm.X
2786 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2787 for i in values:
2788 for j in values:
2789 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2790 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2791 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2792 for j in range(8):
2793 self.assertEqual(i & j, i.value & j)
2794 self.assertEqual((i & j).value, i.value & j)
2795 self.assertIs(type(i & j), Perm)
2796 self.assertEqual(j & i, j & i.value)
2797 self.assertEqual((j & i).value, j & i.value)
2798 self.assertIs(type(j & i), Perm)
2799 for i in Perm:
2800 self.assertIs(i & i, i)
2801 self.assertIs(i & 7, i)
2802 self.assertIs(7 & i, i)
2803 Open = self.Open
2804 self.assertIs(Open.RO & Open.CE, Open.RO)
2805
2806 def test_xor(self):
2807 Perm = self.Perm
2808 for i in Perm:
2809 for j in Perm:
2810 self.assertEqual(i ^ j, i.value ^ j.value)
2811 self.assertEqual((i ^ j).value, i.value ^ j.value)
2812 self.assertIs(type(i ^ j), Perm)
2813 for j in range(8):
2814 self.assertEqual(i ^ j, i.value ^ j)
2815 self.assertEqual((i ^ j).value, i.value ^ j)
2816 self.assertIs(type(i ^ j), Perm)
2817 self.assertEqual(j ^ i, j ^ i.value)
2818 self.assertEqual((j ^ i).value, j ^ i.value)
2819 self.assertIs(type(j ^ i), Perm)
2820 for i in Perm:
2821 self.assertIs(i ^ 0, i)
2822 self.assertIs(0 ^ i, i)
2823 Open = self.Open
2824 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2825 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2826
2827 def test_invert(self):
2828 Perm = self.Perm
2829 RW = Perm.R | Perm.W
2830 RX = Perm.R | Perm.X
2831 WX = Perm.W | Perm.X
2832 RWX = Perm.R | Perm.W | Perm.X
2833 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2834 for i in values:
2835 self.assertEqual(~i, ~i.value)
2836 self.assertEqual((~i).value, ~i.value)
2837 self.assertIs(type(~i), Perm)
2838 self.assertEqual(~~i, i)
2839 for i in Perm:
2840 self.assertIs(~~i, i)
2841 Open = self.Open
2842 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2843 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2844
2845 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002846 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002847 lst = list(Perm)
2848 self.assertEqual(len(lst), len(Perm))
2849 self.assertEqual(len(Perm), 3, Perm)
2850 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2851 for i, n in enumerate('R W X'.split()):
2852 v = 1<<i
2853 e = Perm(v)
2854 self.assertEqual(e.value, v)
2855 self.assertEqual(type(e.value), int)
2856 self.assertEqual(e, v)
2857 self.assertEqual(e.name, n)
2858 self.assertIn(e, Perm)
2859 self.assertIs(type(e), Perm)
2860
2861 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002862 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002863 lst = list(Perm)
2864 self.assertEqual(len(lst), len(Perm))
2865 self.assertEqual(len(Perm), 3, Perm)
2866 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2867 for i, n in enumerate('R W X'.split()):
2868 v = 8<<i
2869 e = Perm(v)
2870 self.assertEqual(e.value, v)
2871 self.assertEqual(type(e.value), int)
2872 self.assertEqual(e, v)
2873 self.assertEqual(e.name, n)
2874 self.assertIn(e, Perm)
2875 self.assertIs(type(e), Perm)
2876
2877 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002878 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002879 lst = list(Perm)
2880 self.assertEqual(len(lst), len(Perm))
2881 self.assertEqual(len(Perm), 3, Perm)
2882 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2883 for i, n in enumerate('R W X'.split()):
2884 v = 1<<i
2885 e = Perm(v)
2886 self.assertEqual(e.value, v)
2887 self.assertEqual(type(e.value), int)
2888 self.assertEqual(e, v)
2889 self.assertEqual(e.name, n)
2890 self.assertIn(e, Perm)
2891 self.assertIs(type(e), Perm)
2892
2893 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002894 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002895 lst = list(Perm)
2896 self.assertEqual(len(lst), len(Perm))
2897 self.assertEqual(len(Perm), 3, Perm)
2898 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2899 for i, n in enumerate('R W X'.split()):
2900 v = 1<<(2*i+1)
2901 e = Perm(v)
2902 self.assertEqual(e.value, v)
2903 self.assertEqual(type(e.value), int)
2904 self.assertEqual(e, v)
2905 self.assertEqual(e.name, n)
2906 self.assertIn(e, Perm)
2907 self.assertIs(type(e), Perm)
2908
2909 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002910 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002911 lst = list(Perm)
2912 self.assertEqual(len(lst), len(Perm))
2913 self.assertEqual(len(Perm), 3, Perm)
2914 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2915 for i, n in enumerate('R W X'.split()):
2916 v = 1<<(2*i+1)
2917 e = Perm(v)
2918 self.assertEqual(e.value, v)
2919 self.assertEqual(type(e.value), int)
2920 self.assertEqual(e, v)
2921 self.assertEqual(e.name, n)
2922 self.assertIn(e, Perm)
2923 self.assertIs(type(e), Perm)
2924
2925
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002926 def test_programatic_function_from_empty_list(self):
2927 Perm = enum.IntFlag('Perm', [])
2928 lst = list(Perm)
2929 self.assertEqual(len(lst), len(Perm))
2930 self.assertEqual(len(Perm), 0, Perm)
2931 Thing = enum.Enum('Thing', [])
2932 lst = list(Thing)
2933 self.assertEqual(len(lst), len(Thing))
2934 self.assertEqual(len(Thing), 0, Thing)
2935
2936
2937 def test_programatic_function_from_empty_tuple(self):
2938 Perm = enum.IntFlag('Perm', ())
2939 lst = list(Perm)
2940 self.assertEqual(len(lst), len(Perm))
2941 self.assertEqual(len(Perm), 0, Perm)
2942 Thing = enum.Enum('Thing', ())
2943 self.assertEqual(len(lst), len(Thing))
2944 self.assertEqual(len(Thing), 0, Thing)
2945
Rahul Jha94306522018-09-10 23:51:04 +05302946 def test_contains(self):
2947 Open = self.Open
2948 Color = self.Color
2949 self.assertTrue(Color.GREEN in Color)
2950 self.assertTrue(Open.RW in Open)
2951 self.assertFalse(Color.GREEN in Open)
2952 self.assertFalse(Open.RW in Color)
2953 with self.assertRaises(TypeError):
2954 'GREEN' in Color
2955 with self.assertRaises(TypeError):
2956 'RW' in Open
2957 with self.assertRaises(TypeError):
2958 2 in Color
2959 with self.assertRaises(TypeError):
2960 2 in Open
2961
2962 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002963 Perm = self.Perm
2964 R, W, X = Perm
2965 RW = R | W
2966 RX = R | X
2967 WX = W | X
2968 RWX = R | W | X
2969 self.assertTrue(R in RW)
2970 self.assertTrue(R in RX)
2971 self.assertTrue(R in RWX)
2972 self.assertTrue(W in RW)
2973 self.assertTrue(W in WX)
2974 self.assertTrue(W in RWX)
2975 self.assertTrue(X in RX)
2976 self.assertTrue(X in WX)
2977 self.assertTrue(X in RWX)
2978 self.assertFalse(R in WX)
2979 self.assertFalse(W in RX)
2980 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302981 with self.assertRaises(TypeError):
2982 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002983
Ethan Furman7219e272020-09-16 13:01:00 -07002984 def test_member_iter(self):
2985 Color = self.Color
2986 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2987 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2988 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2989
Ethan Furman25d94bb2016-09-02 16:32:32 -07002990 def test_bool(self):
2991 Perm = self.Perm
2992 for f in Perm:
2993 self.assertTrue(f)
2994 Open = self.Open
2995 for f in Open:
2996 self.assertEqual(bool(f.value), bool(f))
2997
Ethan Furman5bdab642018-09-21 19:03:09 -07002998 def test_multiple_mixin(self):
2999 class AllMixin:
3000 @classproperty
3001 def ALL(cls):
3002 members = list(cls)
3003 all_value = None
3004 if members:
3005 all_value = members[0]
3006 for member in members[1:]:
3007 all_value |= member
3008 cls.ALL = all_value
3009 return all_value
3010 class StrMixin:
3011 def __str__(self):
3012 return self._name_.lower()
3013 class Color(AllMixin, IntFlag):
3014 RED = auto()
3015 GREEN = auto()
3016 BLUE = auto()
3017 self.assertEqual(Color.RED.value, 1)
3018 self.assertEqual(Color.GREEN.value, 2)
3019 self.assertEqual(Color.BLUE.value, 4)
3020 self.assertEqual(Color.ALL.value, 7)
3021 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3022 class Color(AllMixin, StrMixin, IntFlag):
3023 RED = auto()
3024 GREEN = auto()
3025 BLUE = auto()
3026 self.assertEqual(Color.RED.value, 1)
3027 self.assertEqual(Color.GREEN.value, 2)
3028 self.assertEqual(Color.BLUE.value, 4)
3029 self.assertEqual(Color.ALL.value, 7)
3030 self.assertEqual(str(Color.BLUE), 'blue')
3031 class Color(StrMixin, AllMixin, IntFlag):
3032 RED = auto()
3033 GREEN = auto()
3034 BLUE = auto()
3035 self.assertEqual(Color.RED.value, 1)
3036 self.assertEqual(Color.GREEN.value, 2)
3037 self.assertEqual(Color.BLUE.value, 4)
3038 self.assertEqual(Color.ALL.value, 7)
3039 self.assertEqual(str(Color.BLUE), 'blue')
3040
Hai Shie80697d2020-05-28 06:10:27 +08003041 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003042 def test_unique_composite(self):
3043 # override __eq__ to be identity only
3044 class TestFlag(IntFlag):
3045 one = auto()
3046 two = auto()
3047 three = auto()
3048 four = auto()
3049 five = auto()
3050 six = auto()
3051 seven = auto()
3052 eight = auto()
3053 def __eq__(self, other):
3054 return self is other
3055 def __hash__(self):
3056 return hash(self._value_)
3057 # have multiple threads competing to complete the composite members
3058 seen = set()
3059 failed = False
3060 def cycle_enum():
3061 nonlocal failed
3062 try:
3063 for i in range(256):
3064 seen.add(TestFlag(i))
3065 except Exception:
3066 failed = True
3067 threads = [
3068 threading.Thread(target=cycle_enum)
3069 for _ in range(8)
3070 ]
Hai Shie80697d2020-05-28 06:10:27 +08003071 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003072 pass
3073 # check that only 248 members were created
3074 self.assertFalse(
3075 failed,
3076 'at least one thread failed while creating composite members')
3077 self.assertEqual(256, len(seen), 'too many composite members created')
3078
3079
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003080class TestEmptyAndNonLatinStrings(unittest.TestCase):
3081
3082 def test_empty_string(self):
3083 with self.assertRaises(ValueError):
3084 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3085
3086 def test_non_latin_character_string(self):
3087 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3088 item = getattr(greek_abc, '\u03B1')
3089 self.assertEqual(item.value, 1)
3090
3091 def test_non_latin_number_string(self):
3092 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3093 item = getattr(hebrew_123, '\u05D0')
3094 self.assertEqual(item.value, 1)
3095
3096
Ethan Furmanf24bb352013-07-18 17:05:39 -07003097class TestUnique(unittest.TestCase):
3098
3099 def test_unique_clean(self):
3100 @unique
3101 class Clean(Enum):
3102 one = 1
3103 two = 'dos'
3104 tres = 4.0
3105 @unique
3106 class Cleaner(IntEnum):
3107 single = 1
3108 double = 2
3109 triple = 3
3110
3111 def test_unique_dirty(self):
3112 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3113 @unique
3114 class Dirty(Enum):
3115 one = 1
3116 two = 'dos'
3117 tres = 1
3118 with self.assertRaisesRegex(
3119 ValueError,
3120 'double.*single.*turkey.*triple',
3121 ):
3122 @unique
3123 class Dirtier(IntEnum):
3124 single = 1
3125 double = 1
3126 triple = 3
3127 turkey = 3
3128
Ethan Furman3803ad42016-05-01 10:03:53 -07003129 def test_unique_with_name(self):
3130 @unique
3131 class Silly(Enum):
3132 one = 1
3133 two = 'dos'
3134 name = 3
3135 @unique
3136 class Sillier(IntEnum):
3137 single = 1
3138 name = 2
3139 triple = 3
3140 value = 4
3141
Ethan Furmanf24bb352013-07-18 17:05:39 -07003142
Ethan Furman5bdab642018-09-21 19:03:09 -07003143
Ethan Furman3323da92015-04-11 09:39:59 -07003144expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003145Help on class Color in module %s:
3146
3147class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003148 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3149 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003150 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003151 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003152 | Method resolution order:
3153 | Color
3154 | enum.Enum
3155 | builtins.object
3156 |\x20\x20
3157 | Data and other attributes defined here:
3158 |\x20\x20
3159 | blue = <Color.blue: 3>
3160 |\x20\x20
3161 | green = <Color.green: 2>
3162 |\x20\x20
3163 | red = <Color.red: 1>
3164 |\x20\x20
3165 | ----------------------------------------------------------------------
3166 | Data descriptors inherited from enum.Enum:
3167 |\x20\x20
3168 | name
3169 | The name of the Enum member.
3170 |\x20\x20
3171 | value
3172 | The value of the Enum member.
3173 |\x20\x20
3174 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003175 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003176 |\x20\x20
3177 | __members__
3178 | Returns a mapping of member name->value.
3179 |\x20\x20\x20\x20\x20\x20
3180 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003181 | is a read-only view of the internal mapping."""
3182
3183expected_help_output_without_docs = """\
3184Help on class Color in module %s:
3185
3186class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003187 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3188 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003189 | Method resolution order:
3190 | Color
3191 | enum.Enum
3192 | builtins.object
3193 |\x20\x20
3194 | Data and other attributes defined here:
3195 |\x20\x20
3196 | blue = <Color.blue: 3>
3197 |\x20\x20
3198 | green = <Color.green: 2>
3199 |\x20\x20
3200 | red = <Color.red: 1>
3201 |\x20\x20
3202 | ----------------------------------------------------------------------
3203 | Data descriptors inherited from enum.Enum:
3204 |\x20\x20
3205 | name
3206 |\x20\x20
3207 | value
3208 |\x20\x20
3209 | ----------------------------------------------------------------------
3210 | Data descriptors inherited from enum.EnumMeta:
3211 |\x20\x20
3212 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003213
3214class TestStdLib(unittest.TestCase):
3215
Ethan Furman48a724f2015-04-11 23:23:06 -07003216 maxDiff = None
3217
Ethan Furman5875d742013-10-21 20:45:55 -07003218 class Color(Enum):
3219 red = 1
3220 green = 2
3221 blue = 3
3222
3223 def test_pydoc(self):
3224 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003225 if StrEnum.__doc__ is None:
3226 expected_text = expected_help_output_without_docs % __name__
3227 else:
3228 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003229 output = StringIO()
3230 helper = pydoc.Helper(output=output)
3231 helper(self.Color)
3232 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003233 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003234
3235 def test_inspect_getmembers(self):
3236 values = dict((
3237 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003238 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003239 ('__members__', self.Color.__members__),
3240 ('__module__', __name__),
3241 ('blue', self.Color.blue),
3242 ('green', self.Color.green),
3243 ('name', Enum.__dict__['name']),
3244 ('red', self.Color.red),
3245 ('value', Enum.__dict__['value']),
3246 ))
3247 result = dict(inspect.getmembers(self.Color))
3248 self.assertEqual(values.keys(), result.keys())
3249 failed = False
3250 for k in values.keys():
3251 if result[k] != values[k]:
3252 print()
3253 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3254 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3255 failed = True
3256 if failed:
3257 self.fail("result does not equal expected, see print above")
3258
3259 def test_inspect_classify_class_attrs(self):
3260 # indirectly test __objclass__
3261 from inspect import Attribute
3262 values = [
3263 Attribute(name='__class__', kind='data',
3264 defining_class=object, object=EnumMeta),
3265 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003266 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003267 Attribute(name='__members__', kind='property',
3268 defining_class=EnumMeta, object=EnumMeta.__members__),
3269 Attribute(name='__module__', kind='data',
3270 defining_class=self.Color, object=__name__),
3271 Attribute(name='blue', kind='data',
3272 defining_class=self.Color, object=self.Color.blue),
3273 Attribute(name='green', kind='data',
3274 defining_class=self.Color, object=self.Color.green),
3275 Attribute(name='red', kind='data',
3276 defining_class=self.Color, object=self.Color.red),
3277 Attribute(name='name', kind='data',
3278 defining_class=Enum, object=Enum.__dict__['name']),
3279 Attribute(name='value', kind='data',
3280 defining_class=Enum, object=Enum.__dict__['value']),
3281 ]
3282 values.sort(key=lambda item: item.name)
3283 result = list(inspect.classify_class_attrs(self.Color))
3284 result.sort(key=lambda item: item.name)
3285 failed = False
3286 for v, r in zip(values, result):
3287 if r != v:
3288 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3289 failed = True
3290 if failed:
3291 self.fail("result does not equal expected, see print above")
3292
Martin Panter19e69c52015-11-14 12:46:42 +00003293
3294class MiscTestCase(unittest.TestCase):
3295 def test__all__(self):
3296 support.check__all__(self, enum)
3297
3298
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003299# These are unordered here on purpose to ensure that declaration order
3300# makes no difference.
3301CONVERT_TEST_NAME_D = 5
3302CONVERT_TEST_NAME_C = 5
3303CONVERT_TEST_NAME_B = 5
3304CONVERT_TEST_NAME_A = 5 # This one should sort first.
3305CONVERT_TEST_NAME_E = 5
3306CONVERT_TEST_NAME_F = 5
3307
3308class TestIntEnumConvert(unittest.TestCase):
3309 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003310 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003311 'UnittestConvert',
3312 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003313 filter=lambda x: x.startswith('CONVERT_TEST_'))
3314 # We don't want the reverse lookup value to vary when there are
3315 # multiple possible names for a given value. It should always
3316 # report the first lexigraphical name in that case.
3317 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3318
3319 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003320 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003321 'UnittestConvert',
3322 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003323 filter=lambda x: x.startswith('CONVERT_TEST_'))
3324 # Ensure that test_type has all of the desired names and values.
3325 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3326 test_type.CONVERT_TEST_NAME_A)
3327 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3328 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3329 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3330 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3331 # Ensure that test_type only picked up names matching the filter.
3332 self.assertEqual([name for name in dir(test_type)
3333 if name[0:2] not in ('CO', '__')],
3334 [], msg='Names other than CONVERT_TEST_* found.')
3335
orlnub1230fb9fad2018-09-12 20:28:53 +03003336 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3337 '_convert was deprecated in 3.8')
3338 def test_convert_warn(self):
3339 with self.assertWarns(DeprecationWarning):
3340 enum.IntEnum._convert(
3341 'UnittestConvert',
3342 ('test.test_enum', '__main__')[__name__=='__main__'],
3343 filter=lambda x: x.startswith('CONVERT_TEST_'))
3344
3345 @unittest.skipUnless(sys.version_info >= (3, 9),
3346 '_convert was removed in 3.9')
3347 def test_convert_raise(self):
3348 with self.assertRaises(AttributeError):
3349 enum.IntEnum._convert(
3350 'UnittestConvert',
3351 ('test.test_enum', '__main__')[__name__=='__main__'],
3352 filter=lambda x: x.startswith('CONVERT_TEST_'))
3353
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003354
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003355if __name__ == '__main__':
3356 unittest.main()