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