blob: 19b4fa5464ce7d1df932e12d91b6e7199bc38587 [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
Ethan Furman6ec0ade2020-12-24 10:05:02 -08002122 def test_init_subclass_calling(self):
Ethan Furman6bd94de2020-12-09 16:41:22 -08002123 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 Furman6ec0ade2020-12-24 10:05:02 -08002158 def test_init_subclass_parameter(self):
2159 class multiEnum(Enum):
2160 def __init_subclass__(cls, multi):
2161 for member in cls:
2162 member._as_parameter_ = multi * member.value
2163 class E(multiEnum, multi=3):
2164 A = 1
2165 B = 2
2166 self.assertEqual(E.A._as_parameter_, 3)
2167 self.assertEqual(E.B._as_parameter_, 6)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002168
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002169 @unittest.skipUnless(
2170 sys.version_info[:2] == (3, 9),
2171 'private variables are now normal attributes',
2172 )
2173 def test_warning_for_private_variables(self):
2174 with self.assertWarns(DeprecationWarning):
2175 class Private(Enum):
2176 __corporal = 'Radar'
2177 self.assertEqual(Private._Private__corporal.value, 'Radar')
2178 try:
2179 with self.assertWarns(DeprecationWarning):
2180 class Private(Enum):
2181 __major_ = 'Hoolihan'
2182 except ValueError:
2183 pass
2184
2185 def test_private_variable_is_normal_attribute(self):
2186 class Private(Enum):
2187 __corporal = 'Radar'
2188 __major_ = 'Hoolihan'
2189 self.assertEqual(Private._Private__corporal, 'Radar')
2190 self.assertEqual(Private._Private__major_, 'Hoolihan')
2191
Ethan Furmanefb13be2020-12-10 12:20:06 -08002192 def test_strenum_auto(self):
2193 class Strings(StrEnum):
2194 ONE = auto()
2195 TWO = auto()
2196 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
2197
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002198
Ethan Furmana6582872020-12-10 13:07:00 -08002199 def test_dynamic_members_with_static_methods(self):
2200 #
2201 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
2202 class Foo(Enum):
2203 vars().update({
2204 k: v
2205 for k, v in foo_defines.items()
2206 if k.startswith('FOO_')
2207 })
2208 def upper(self):
2209 return self.value.upper()
2210 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
2211 self.assertEqual(Foo.FOO_CAT.value, 'aloof')
2212 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
2213 #
2214 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
2215 class FooBar(Enum):
2216 vars().update({
2217 k: v
2218 for k, v in foo_defines.items()
2219 if k.startswith('FOO_')
2220 },
2221 **{'FOO_CAT': 'small'},
2222 )
2223 def upper(self):
2224 return self.value.upper()
2225
2226
Ethan Furmane8e61272016-08-20 07:19:31 -07002227class TestOrder(unittest.TestCase):
2228
2229 def test_same_members(self):
2230 class Color(Enum):
2231 _order_ = 'red green blue'
2232 red = 1
2233 green = 2
2234 blue = 3
2235
2236 def test_same_members_with_aliases(self):
2237 class Color(Enum):
2238 _order_ = 'red green blue'
2239 red = 1
2240 green = 2
2241 blue = 3
2242 verde = green
2243
2244 def test_same_members_wrong_order(self):
2245 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2246 class Color(Enum):
2247 _order_ = 'red green blue'
2248 red = 1
2249 blue = 3
2250 green = 2
2251
2252 def test_order_has_extra_members(self):
2253 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2254 class Color(Enum):
2255 _order_ = 'red green blue purple'
2256 red = 1
2257 green = 2
2258 blue = 3
2259
2260 def test_order_has_extra_members_with_aliases(self):
2261 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2262 class Color(Enum):
2263 _order_ = 'red green blue purple'
2264 red = 1
2265 green = 2
2266 blue = 3
2267 verde = green
2268
2269 def test_enum_has_extra_members(self):
2270 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2271 class Color(Enum):
2272 _order_ = 'red green blue'
2273 red = 1
2274 green = 2
2275 blue = 3
2276 purple = 4
2277
2278 def test_enum_has_extra_members_with_aliases(self):
2279 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2280 class Color(Enum):
2281 _order_ = 'red green blue'
2282 red = 1
2283 green = 2
2284 blue = 3
2285 purple = 4
2286 verde = green
2287
2288
Ethan Furman65a5a472016-09-01 23:55:19 -07002289class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002290 """Tests of the Flags."""
2291
Ethan Furman65a5a472016-09-01 23:55:19 -07002292 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002293 R, W, X = 4, 2, 1
2294
Ethan Furman65a5a472016-09-01 23:55:19 -07002295 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002296 RO = 0
2297 WO = 1
2298 RW = 2
2299 AC = 3
2300 CE = 1<<19
2301
Rahul Jha94306522018-09-10 23:51:04 +05302302 class Color(Flag):
2303 BLACK = 0
2304 RED = 1
2305 GREEN = 2
2306 BLUE = 4
2307 PURPLE = RED|BLUE
2308
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002309 def test_str(self):
2310 Perm = self.Perm
2311 self.assertEqual(str(Perm.R), 'Perm.R')
2312 self.assertEqual(str(Perm.W), 'Perm.W')
2313 self.assertEqual(str(Perm.X), 'Perm.X')
2314 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2315 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2316 self.assertEqual(str(Perm(0)), 'Perm.0')
2317 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2318 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2319 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2320 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2321 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2322 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2323
2324 Open = self.Open
2325 self.assertEqual(str(Open.RO), 'Open.RO')
2326 self.assertEqual(str(Open.WO), 'Open.WO')
2327 self.assertEqual(str(Open.AC), 'Open.AC')
2328 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2329 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002330 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002331 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2332 self.assertEqual(str(~Open.AC), 'Open.CE')
2333 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2334 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2335
2336 def test_repr(self):
2337 Perm = self.Perm
2338 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2339 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2340 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2341 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2342 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002343 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002344 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2345 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2346 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2347 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002348 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002349 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2350
2351 Open = self.Open
2352 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2353 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2354 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2355 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2356 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002357 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002358 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2359 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2360 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2361 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2362
Ethan Furman37440ee2020-12-08 11:14:10 -08002363 def test_format(self):
2364 Perm = self.Perm
2365 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2366 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2367
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002368 def test_or(self):
2369 Perm = self.Perm
2370 for i in Perm:
2371 for j in Perm:
2372 self.assertEqual((i | j), Perm(i.value | j.value))
2373 self.assertEqual((i | j).value, i.value | j.value)
2374 self.assertIs(type(i | j), Perm)
2375 for i in Perm:
2376 self.assertIs(i | i, i)
2377 Open = self.Open
2378 self.assertIs(Open.RO | Open.CE, Open.CE)
2379
2380 def test_and(self):
2381 Perm = self.Perm
2382 RW = Perm.R | Perm.W
2383 RX = Perm.R | Perm.X
2384 WX = Perm.W | Perm.X
2385 RWX = Perm.R | Perm.W | Perm.X
2386 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2387 for i in values:
2388 for j in values:
2389 self.assertEqual((i & j).value, i.value & j.value)
2390 self.assertIs(type(i & j), Perm)
2391 for i in Perm:
2392 self.assertIs(i & i, i)
2393 self.assertIs(i & RWX, i)
2394 self.assertIs(RWX & i, i)
2395 Open = self.Open
2396 self.assertIs(Open.RO & Open.CE, Open.RO)
2397
2398 def test_xor(self):
2399 Perm = self.Perm
2400 for i in Perm:
2401 for j in Perm:
2402 self.assertEqual((i ^ j).value, i.value ^ j.value)
2403 self.assertIs(type(i ^ j), Perm)
2404 for i in Perm:
2405 self.assertIs(i ^ Perm(0), i)
2406 self.assertIs(Perm(0) ^ i, i)
2407 Open = self.Open
2408 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2409 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2410
2411 def test_invert(self):
2412 Perm = self.Perm
2413 RW = Perm.R | Perm.W
2414 RX = Perm.R | Perm.X
2415 WX = Perm.W | Perm.X
2416 RWX = Perm.R | Perm.W | Perm.X
2417 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2418 for i in values:
2419 self.assertIs(type(~i), Perm)
2420 self.assertEqual(~~i, i)
2421 for i in Perm:
2422 self.assertIs(~~i, i)
2423 Open = self.Open
2424 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2425 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2426
Ethan Furman25d94bb2016-09-02 16:32:32 -07002427 def test_bool(self):
2428 Perm = self.Perm
2429 for f in Perm:
2430 self.assertTrue(f)
2431 Open = self.Open
2432 for f in Open:
2433 self.assertEqual(bool(f.value), bool(f))
2434
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002435 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002436 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002437 lst = list(Perm)
2438 self.assertEqual(len(lst), len(Perm))
2439 self.assertEqual(len(Perm), 3, Perm)
2440 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2441 for i, n in enumerate('R W X'.split()):
2442 v = 1<<i
2443 e = Perm(v)
2444 self.assertEqual(e.value, v)
2445 self.assertEqual(type(e.value), int)
2446 self.assertEqual(e.name, n)
2447 self.assertIn(e, Perm)
2448 self.assertIs(type(e), Perm)
2449
2450 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002451 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002452 lst = list(Perm)
2453 self.assertEqual(len(lst), len(Perm))
2454 self.assertEqual(len(Perm), 3, Perm)
2455 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2456 for i, n in enumerate('R W X'.split()):
2457 v = 8<<i
2458 e = Perm(v)
2459 self.assertEqual(e.value, v)
2460 self.assertEqual(type(e.value), int)
2461 self.assertEqual(e.name, n)
2462 self.assertIn(e, Perm)
2463 self.assertIs(type(e), Perm)
2464
2465 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002466 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002467 lst = list(Perm)
2468 self.assertEqual(len(lst), len(Perm))
2469 self.assertEqual(len(Perm), 3, Perm)
2470 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2471 for i, n in enumerate('R W X'.split()):
2472 v = 1<<i
2473 e = Perm(v)
2474 self.assertEqual(e.value, v)
2475 self.assertEqual(type(e.value), int)
2476 self.assertEqual(e.name, n)
2477 self.assertIn(e, Perm)
2478 self.assertIs(type(e), Perm)
2479
2480 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002481 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002482 lst = list(Perm)
2483 self.assertEqual(len(lst), len(Perm))
2484 self.assertEqual(len(Perm), 3, Perm)
2485 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2486 for i, n in enumerate('R W X'.split()):
2487 v = 1<<(2*i+1)
2488 e = Perm(v)
2489 self.assertEqual(e.value, v)
2490 self.assertEqual(type(e.value), int)
2491 self.assertEqual(e.name, n)
2492 self.assertIn(e, Perm)
2493 self.assertIs(type(e), Perm)
2494
2495 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002496 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002497 lst = list(Perm)
2498 self.assertEqual(len(lst), len(Perm))
2499 self.assertEqual(len(Perm), 3, Perm)
2500 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2501 for i, n in enumerate('R W X'.split()):
2502 v = 1<<(2*i+1)
2503 e = Perm(v)
2504 self.assertEqual(e.value, v)
2505 self.assertEqual(type(e.value), int)
2506 self.assertEqual(e.name, n)
2507 self.assertIn(e, Perm)
2508 self.assertIs(type(e), Perm)
2509
Ethan Furman65a5a472016-09-01 23:55:19 -07002510 def test_pickle(self):
2511 if isinstance(FlagStooges, Exception):
2512 raise FlagStooges
2513 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2514 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002515
Rahul Jha94306522018-09-10 23:51:04 +05302516 def test_contains(self):
2517 Open = self.Open
2518 Color = self.Color
2519 self.assertFalse(Color.BLACK in Open)
2520 self.assertFalse(Open.RO in Color)
2521 with self.assertRaises(TypeError):
2522 'BLACK' in Color
2523 with self.assertRaises(TypeError):
2524 'RO' in Open
2525 with self.assertRaises(TypeError):
2526 1 in Color
2527 with self.assertRaises(TypeError):
2528 1 in Open
2529
2530 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002531 Perm = self.Perm
2532 R, W, X = Perm
2533 RW = R | W
2534 RX = R | X
2535 WX = W | X
2536 RWX = R | W | X
2537 self.assertTrue(R in RW)
2538 self.assertTrue(R in RX)
2539 self.assertTrue(R in RWX)
2540 self.assertTrue(W in RW)
2541 self.assertTrue(W in WX)
2542 self.assertTrue(W in RWX)
2543 self.assertTrue(X in RX)
2544 self.assertTrue(X in WX)
2545 self.assertTrue(X in RWX)
2546 self.assertFalse(R in WX)
2547 self.assertFalse(W in RX)
2548 self.assertFalse(X in RW)
2549
Ethan Furman7219e272020-09-16 13:01:00 -07002550 def test_member_iter(self):
2551 Color = self.Color
2552 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2553 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2554 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2555
Ethan Furmanc16595e2016-09-10 23:36:59 -07002556 def test_auto_number(self):
2557 class Color(Flag):
2558 red = auto()
2559 blue = auto()
2560 green = auto()
2561
2562 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2563 self.assertEqual(Color.red.value, 1)
2564 self.assertEqual(Color.blue.value, 2)
2565 self.assertEqual(Color.green.value, 4)
2566
2567 def test_auto_number_garbage(self):
2568 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2569 class Color(Flag):
2570 red = 'not an int'
2571 blue = auto()
2572
Ethan Furman3515dcc2016-09-18 13:15:41 -07002573 def test_cascading_failure(self):
2574 class Bizarre(Flag):
2575 c = 3
2576 d = 4
2577 f = 6
2578 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002579 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2580 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2581 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2582 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2583 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2584 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2585 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002586
2587 def test_duplicate_auto(self):
2588 class Dupes(Enum):
2589 first = primero = auto()
2590 second = auto()
2591 third = auto()
2592 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2593
2594 def test_bizarre(self):
2595 class Bizarre(Flag):
2596 b = 3
2597 c = 4
2598 d = 6
2599 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2600
Ethan Furman5bdab642018-09-21 19:03:09 -07002601 def test_multiple_mixin(self):
2602 class AllMixin:
2603 @classproperty
2604 def ALL(cls):
2605 members = list(cls)
2606 all_value = None
2607 if members:
2608 all_value = members[0]
2609 for member in members[1:]:
2610 all_value |= member
2611 cls.ALL = all_value
2612 return all_value
2613 class StrMixin:
2614 def __str__(self):
2615 return self._name_.lower()
2616 class Color(AllMixin, Flag):
2617 RED = auto()
2618 GREEN = auto()
2619 BLUE = auto()
2620 self.assertEqual(Color.RED.value, 1)
2621 self.assertEqual(Color.GREEN.value, 2)
2622 self.assertEqual(Color.BLUE.value, 4)
2623 self.assertEqual(Color.ALL.value, 7)
2624 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2625 class Color(AllMixin, StrMixin, Flag):
2626 RED = auto()
2627 GREEN = auto()
2628 BLUE = auto()
2629 self.assertEqual(Color.RED.value, 1)
2630 self.assertEqual(Color.GREEN.value, 2)
2631 self.assertEqual(Color.BLUE.value, 4)
2632 self.assertEqual(Color.ALL.value, 7)
2633 self.assertEqual(str(Color.BLUE), 'blue')
2634 class Color(StrMixin, AllMixin, Flag):
2635 RED = auto()
2636 GREEN = auto()
2637 BLUE = auto()
2638 self.assertEqual(Color.RED.value, 1)
2639 self.assertEqual(Color.GREEN.value, 2)
2640 self.assertEqual(Color.BLUE.value, 4)
2641 self.assertEqual(Color.ALL.value, 7)
2642 self.assertEqual(str(Color.BLUE), 'blue')
2643
Hai Shie80697d2020-05-28 06:10:27 +08002644 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002645 def test_unique_composite(self):
2646 # override __eq__ to be identity only
2647 class TestFlag(Flag):
2648 one = auto()
2649 two = auto()
2650 three = auto()
2651 four = auto()
2652 five = auto()
2653 six = auto()
2654 seven = auto()
2655 eight = auto()
2656 def __eq__(self, other):
2657 return self is other
2658 def __hash__(self):
2659 return hash(self._value_)
2660 # have multiple threads competing to complete the composite members
2661 seen = set()
2662 failed = False
2663 def cycle_enum():
2664 nonlocal failed
2665 try:
2666 for i in range(256):
2667 seen.add(TestFlag(i))
2668 except Exception:
2669 failed = True
2670 threads = [
2671 threading.Thread(target=cycle_enum)
2672 for _ in range(8)
2673 ]
Hai Shie80697d2020-05-28 06:10:27 +08002674 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002675 pass
2676 # check that only 248 members were created
2677 self.assertFalse(
2678 failed,
2679 'at least one thread failed while creating composite members')
2680 self.assertEqual(256, len(seen), 'too many composite members created')
2681
Ethan Furman6bd94de2020-12-09 16:41:22 -08002682 def test_init_subclass(self):
2683 class MyEnum(Flag):
2684 def __init_subclass__(cls, **kwds):
2685 super().__init_subclass__(**kwds)
2686 self.assertFalse(cls.__dict__.get('_test', False))
2687 cls._test1 = 'MyEnum'
2688 #
2689 class TheirEnum(MyEnum):
2690 def __init_subclass__(cls, **kwds):
2691 super(TheirEnum, cls).__init_subclass__(**kwds)
2692 cls._test2 = 'TheirEnum'
2693 class WhoseEnum(TheirEnum):
2694 def __init_subclass__(cls, **kwds):
2695 pass
2696 class NoEnum(WhoseEnum):
2697 ONE = 1
2698 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2699 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2700 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2701 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2702 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2703 #
2704 class OurEnum(MyEnum):
2705 def __init_subclass__(cls, **kwds):
2706 cls._test2 = 'OurEnum'
2707 class WhereEnum(OurEnum):
2708 def __init_subclass__(cls, **kwds):
2709 pass
2710 class NeverEnum(WhereEnum):
2711 ONE = 1
2712 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2713 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2714 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2715 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2716 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2717
Ethan Furmanc16595e2016-09-10 23:36:59 -07002718
Ethan Furman65a5a472016-09-01 23:55:19 -07002719class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002720 """Tests of the IntFlags."""
2721
Ethan Furman65a5a472016-09-01 23:55:19 -07002722 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002723 X = 1 << 0
2724 W = 1 << 1
2725 R = 1 << 2
2726
Ethan Furman65a5a472016-09-01 23:55:19 -07002727 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002728 RO = 0
2729 WO = 1
2730 RW = 2
2731 AC = 3
2732 CE = 1<<19
2733
Rahul Jha94306522018-09-10 23:51:04 +05302734 class Color(IntFlag):
2735 BLACK = 0
2736 RED = 1
2737 GREEN = 2
2738 BLUE = 4
2739 PURPLE = RED|BLUE
2740
Ethan Furman3515dcc2016-09-18 13:15:41 -07002741 def test_type(self):
2742 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002743 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002744 Open = self.Open
2745 for f in Perm:
2746 self.assertTrue(isinstance(f, Perm))
2747 self.assertEqual(f, f.value)
2748 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2749 self.assertEqual(Perm.W | Perm.X, 3)
2750 for f in Open:
2751 self.assertTrue(isinstance(f, Open))
2752 self.assertEqual(f, f.value)
2753 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2754 self.assertEqual(Open.WO | Open.RW, 3)
2755
2756
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002757 def test_str(self):
2758 Perm = self.Perm
2759 self.assertEqual(str(Perm.R), 'Perm.R')
2760 self.assertEqual(str(Perm.W), 'Perm.W')
2761 self.assertEqual(str(Perm.X), 'Perm.X')
2762 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2763 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2764 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2765 self.assertEqual(str(Perm(0)), 'Perm.0')
2766 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002767 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2768 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2769 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2770 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002771 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002772 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2773 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2774 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002775
2776 Open = self.Open
2777 self.assertEqual(str(Open.RO), 'Open.RO')
2778 self.assertEqual(str(Open.WO), 'Open.WO')
2779 self.assertEqual(str(Open.AC), 'Open.AC')
2780 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2781 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2782 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002783 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2784 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2785 self.assertEqual(str(~Open.AC), 'Open.CE')
2786 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2787 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2788 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002789
2790 def test_repr(self):
2791 Perm = self.Perm
2792 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2793 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2794 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2795 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2796 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2797 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002798 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2799 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002800 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2801 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2802 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2803 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002804 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002805 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2806 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2807 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002808
2809 Open = self.Open
2810 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2811 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2812 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2813 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2814 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002815 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002816 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2817 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2818 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2819 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2820 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2821 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002822
Ethan Furman37440ee2020-12-08 11:14:10 -08002823 def test_format(self):
2824 Perm = self.Perm
2825 self.assertEqual(format(Perm.R, ''), '4')
2826 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2827
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002828 def test_or(self):
2829 Perm = self.Perm
2830 for i in Perm:
2831 for j in Perm:
2832 self.assertEqual(i | j, i.value | j.value)
2833 self.assertEqual((i | j).value, i.value | j.value)
2834 self.assertIs(type(i | j), Perm)
2835 for j in range(8):
2836 self.assertEqual(i | j, i.value | j)
2837 self.assertEqual((i | j).value, i.value | j)
2838 self.assertIs(type(i | j), Perm)
2839 self.assertEqual(j | i, j | i.value)
2840 self.assertEqual((j | i).value, j | i.value)
2841 self.assertIs(type(j | i), Perm)
2842 for i in Perm:
2843 self.assertIs(i | i, i)
2844 self.assertIs(i | 0, i)
2845 self.assertIs(0 | i, i)
2846 Open = self.Open
2847 self.assertIs(Open.RO | Open.CE, Open.CE)
2848
2849 def test_and(self):
2850 Perm = self.Perm
2851 RW = Perm.R | Perm.W
2852 RX = Perm.R | Perm.X
2853 WX = Perm.W | Perm.X
2854 RWX = Perm.R | Perm.W | Perm.X
2855 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2856 for i in values:
2857 for j in values:
2858 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2859 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2860 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2861 for j in range(8):
2862 self.assertEqual(i & j, i.value & j)
2863 self.assertEqual((i & j).value, i.value & j)
2864 self.assertIs(type(i & j), Perm)
2865 self.assertEqual(j & i, j & i.value)
2866 self.assertEqual((j & i).value, j & i.value)
2867 self.assertIs(type(j & i), Perm)
2868 for i in Perm:
2869 self.assertIs(i & i, i)
2870 self.assertIs(i & 7, i)
2871 self.assertIs(7 & i, i)
2872 Open = self.Open
2873 self.assertIs(Open.RO & Open.CE, Open.RO)
2874
2875 def test_xor(self):
2876 Perm = self.Perm
2877 for i in Perm:
2878 for j in Perm:
2879 self.assertEqual(i ^ j, i.value ^ j.value)
2880 self.assertEqual((i ^ j).value, i.value ^ j.value)
2881 self.assertIs(type(i ^ j), Perm)
2882 for j in range(8):
2883 self.assertEqual(i ^ j, i.value ^ j)
2884 self.assertEqual((i ^ j).value, i.value ^ j)
2885 self.assertIs(type(i ^ j), Perm)
2886 self.assertEqual(j ^ i, j ^ i.value)
2887 self.assertEqual((j ^ i).value, j ^ i.value)
2888 self.assertIs(type(j ^ i), Perm)
2889 for i in Perm:
2890 self.assertIs(i ^ 0, i)
2891 self.assertIs(0 ^ i, i)
2892 Open = self.Open
2893 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2894 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2895
2896 def test_invert(self):
2897 Perm = self.Perm
2898 RW = Perm.R | Perm.W
2899 RX = Perm.R | Perm.X
2900 WX = Perm.W | Perm.X
2901 RWX = Perm.R | Perm.W | Perm.X
2902 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2903 for i in values:
2904 self.assertEqual(~i, ~i.value)
2905 self.assertEqual((~i).value, ~i.value)
2906 self.assertIs(type(~i), Perm)
2907 self.assertEqual(~~i, i)
2908 for i in Perm:
2909 self.assertIs(~~i, i)
2910 Open = self.Open
2911 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2912 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2913
2914 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002915 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002916 lst = list(Perm)
2917 self.assertEqual(len(lst), len(Perm))
2918 self.assertEqual(len(Perm), 3, Perm)
2919 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2920 for i, n in enumerate('R W X'.split()):
2921 v = 1<<i
2922 e = Perm(v)
2923 self.assertEqual(e.value, v)
2924 self.assertEqual(type(e.value), int)
2925 self.assertEqual(e, v)
2926 self.assertEqual(e.name, n)
2927 self.assertIn(e, Perm)
2928 self.assertIs(type(e), Perm)
2929
2930 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002931 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002932 lst = list(Perm)
2933 self.assertEqual(len(lst), len(Perm))
2934 self.assertEqual(len(Perm), 3, Perm)
2935 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2936 for i, n in enumerate('R W X'.split()):
2937 v = 8<<i
2938 e = Perm(v)
2939 self.assertEqual(e.value, v)
2940 self.assertEqual(type(e.value), int)
2941 self.assertEqual(e, v)
2942 self.assertEqual(e.name, n)
2943 self.assertIn(e, Perm)
2944 self.assertIs(type(e), Perm)
2945
2946 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002947 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002948 lst = list(Perm)
2949 self.assertEqual(len(lst), len(Perm))
2950 self.assertEqual(len(Perm), 3, Perm)
2951 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2952 for i, n in enumerate('R W X'.split()):
2953 v = 1<<i
2954 e = Perm(v)
2955 self.assertEqual(e.value, v)
2956 self.assertEqual(type(e.value), int)
2957 self.assertEqual(e, v)
2958 self.assertEqual(e.name, n)
2959 self.assertIn(e, Perm)
2960 self.assertIs(type(e), Perm)
2961
2962 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002963 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002964 lst = list(Perm)
2965 self.assertEqual(len(lst), len(Perm))
2966 self.assertEqual(len(Perm), 3, Perm)
2967 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2968 for i, n in enumerate('R W X'.split()):
2969 v = 1<<(2*i+1)
2970 e = Perm(v)
2971 self.assertEqual(e.value, v)
2972 self.assertEqual(type(e.value), int)
2973 self.assertEqual(e, v)
2974 self.assertEqual(e.name, n)
2975 self.assertIn(e, Perm)
2976 self.assertIs(type(e), Perm)
2977
2978 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002979 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002980 lst = list(Perm)
2981 self.assertEqual(len(lst), len(Perm))
2982 self.assertEqual(len(Perm), 3, Perm)
2983 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2984 for i, n in enumerate('R W X'.split()):
2985 v = 1<<(2*i+1)
2986 e = Perm(v)
2987 self.assertEqual(e.value, v)
2988 self.assertEqual(type(e.value), int)
2989 self.assertEqual(e, v)
2990 self.assertEqual(e.name, n)
2991 self.assertIn(e, Perm)
2992 self.assertIs(type(e), Perm)
2993
2994
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002995 def test_programatic_function_from_empty_list(self):
2996 Perm = enum.IntFlag('Perm', [])
2997 lst = list(Perm)
2998 self.assertEqual(len(lst), len(Perm))
2999 self.assertEqual(len(Perm), 0, Perm)
3000 Thing = enum.Enum('Thing', [])
3001 lst = list(Thing)
3002 self.assertEqual(len(lst), len(Thing))
3003 self.assertEqual(len(Thing), 0, Thing)
3004
3005
3006 def test_programatic_function_from_empty_tuple(self):
3007 Perm = enum.IntFlag('Perm', ())
3008 lst = list(Perm)
3009 self.assertEqual(len(lst), len(Perm))
3010 self.assertEqual(len(Perm), 0, Perm)
3011 Thing = enum.Enum('Thing', ())
3012 self.assertEqual(len(lst), len(Thing))
3013 self.assertEqual(len(Thing), 0, Thing)
3014
Rahul Jha94306522018-09-10 23:51:04 +05303015 def test_contains(self):
3016 Open = self.Open
3017 Color = self.Color
3018 self.assertTrue(Color.GREEN in Color)
3019 self.assertTrue(Open.RW in Open)
3020 self.assertFalse(Color.GREEN in Open)
3021 self.assertFalse(Open.RW in Color)
3022 with self.assertRaises(TypeError):
3023 'GREEN' in Color
3024 with self.assertRaises(TypeError):
3025 'RW' in Open
3026 with self.assertRaises(TypeError):
3027 2 in Color
3028 with self.assertRaises(TypeError):
3029 2 in Open
3030
3031 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07003032 Perm = self.Perm
3033 R, W, X = Perm
3034 RW = R | W
3035 RX = R | X
3036 WX = W | X
3037 RWX = R | W | X
3038 self.assertTrue(R in RW)
3039 self.assertTrue(R in RX)
3040 self.assertTrue(R in RWX)
3041 self.assertTrue(W in RW)
3042 self.assertTrue(W in WX)
3043 self.assertTrue(W in RWX)
3044 self.assertTrue(X in RX)
3045 self.assertTrue(X in WX)
3046 self.assertTrue(X in RWX)
3047 self.assertFalse(R in WX)
3048 self.assertFalse(W in RX)
3049 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05303050 with self.assertRaises(TypeError):
3051 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07003052
Ethan Furman7219e272020-09-16 13:01:00 -07003053 def test_member_iter(self):
3054 Color = self.Color
3055 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
3056 self.assertEqual(list(Color.BLUE), [Color.BLUE])
3057 self.assertEqual(list(Color.GREEN), [Color.GREEN])
3058
Ethan Furman25d94bb2016-09-02 16:32:32 -07003059 def test_bool(self):
3060 Perm = self.Perm
3061 for f in Perm:
3062 self.assertTrue(f)
3063 Open = self.Open
3064 for f in Open:
3065 self.assertEqual(bool(f.value), bool(f))
3066
Ethan Furman5bdab642018-09-21 19:03:09 -07003067 def test_multiple_mixin(self):
3068 class AllMixin:
3069 @classproperty
3070 def ALL(cls):
3071 members = list(cls)
3072 all_value = None
3073 if members:
3074 all_value = members[0]
3075 for member in members[1:]:
3076 all_value |= member
3077 cls.ALL = all_value
3078 return all_value
3079 class StrMixin:
3080 def __str__(self):
3081 return self._name_.lower()
3082 class Color(AllMixin, IntFlag):
3083 RED = auto()
3084 GREEN = auto()
3085 BLUE = auto()
3086 self.assertEqual(Color.RED.value, 1)
3087 self.assertEqual(Color.GREEN.value, 2)
3088 self.assertEqual(Color.BLUE.value, 4)
3089 self.assertEqual(Color.ALL.value, 7)
3090 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
3091 class Color(AllMixin, StrMixin, IntFlag):
3092 RED = auto()
3093 GREEN = auto()
3094 BLUE = auto()
3095 self.assertEqual(Color.RED.value, 1)
3096 self.assertEqual(Color.GREEN.value, 2)
3097 self.assertEqual(Color.BLUE.value, 4)
3098 self.assertEqual(Color.ALL.value, 7)
3099 self.assertEqual(str(Color.BLUE), 'blue')
3100 class Color(StrMixin, AllMixin, IntFlag):
3101 RED = auto()
3102 GREEN = auto()
3103 BLUE = auto()
3104 self.assertEqual(Color.RED.value, 1)
3105 self.assertEqual(Color.GREEN.value, 2)
3106 self.assertEqual(Color.BLUE.value, 4)
3107 self.assertEqual(Color.ALL.value, 7)
3108 self.assertEqual(str(Color.BLUE), 'blue')
3109
Hai Shie80697d2020-05-28 06:10:27 +08003110 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08003111 def test_unique_composite(self):
3112 # override __eq__ to be identity only
3113 class TestFlag(IntFlag):
3114 one = auto()
3115 two = auto()
3116 three = auto()
3117 four = auto()
3118 five = auto()
3119 six = auto()
3120 seven = auto()
3121 eight = auto()
3122 def __eq__(self, other):
3123 return self is other
3124 def __hash__(self):
3125 return hash(self._value_)
3126 # have multiple threads competing to complete the composite members
3127 seen = set()
3128 failed = False
3129 def cycle_enum():
3130 nonlocal failed
3131 try:
3132 for i in range(256):
3133 seen.add(TestFlag(i))
3134 except Exception:
3135 failed = True
3136 threads = [
3137 threading.Thread(target=cycle_enum)
3138 for _ in range(8)
3139 ]
Hai Shie80697d2020-05-28 06:10:27 +08003140 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003141 pass
3142 # check that only 248 members were created
3143 self.assertFalse(
3144 failed,
3145 'at least one thread failed while creating composite members')
3146 self.assertEqual(256, len(seen), 'too many composite members created')
3147
3148
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003149class TestEmptyAndNonLatinStrings(unittest.TestCase):
3150
3151 def test_empty_string(self):
3152 with self.assertRaises(ValueError):
3153 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3154
3155 def test_non_latin_character_string(self):
3156 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3157 item = getattr(greek_abc, '\u03B1')
3158 self.assertEqual(item.value, 1)
3159
3160 def test_non_latin_number_string(self):
3161 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3162 item = getattr(hebrew_123, '\u05D0')
3163 self.assertEqual(item.value, 1)
3164
3165
Ethan Furmanf24bb352013-07-18 17:05:39 -07003166class TestUnique(unittest.TestCase):
3167
3168 def test_unique_clean(self):
3169 @unique
3170 class Clean(Enum):
3171 one = 1
3172 two = 'dos'
3173 tres = 4.0
3174 @unique
3175 class Cleaner(IntEnum):
3176 single = 1
3177 double = 2
3178 triple = 3
3179
3180 def test_unique_dirty(self):
3181 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3182 @unique
3183 class Dirty(Enum):
3184 one = 1
3185 two = 'dos'
3186 tres = 1
3187 with self.assertRaisesRegex(
3188 ValueError,
3189 'double.*single.*turkey.*triple',
3190 ):
3191 @unique
3192 class Dirtier(IntEnum):
3193 single = 1
3194 double = 1
3195 triple = 3
3196 turkey = 3
3197
Ethan Furman3803ad42016-05-01 10:03:53 -07003198 def test_unique_with_name(self):
3199 @unique
3200 class Silly(Enum):
3201 one = 1
3202 two = 'dos'
3203 name = 3
3204 @unique
3205 class Sillier(IntEnum):
3206 single = 1
3207 name = 2
3208 triple = 3
3209 value = 4
3210
Ethan Furmanf24bb352013-07-18 17:05:39 -07003211
Ethan Furman5bdab642018-09-21 19:03:09 -07003212
Ethan Furman3323da92015-04-11 09:39:59 -07003213expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003214Help on class Color in module %s:
3215
3216class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003217 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3218 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003219 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003220 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003221 | Method resolution order:
3222 | Color
3223 | enum.Enum
3224 | builtins.object
3225 |\x20\x20
3226 | Data and other attributes defined here:
3227 |\x20\x20
3228 | blue = <Color.blue: 3>
3229 |\x20\x20
3230 | green = <Color.green: 2>
3231 |\x20\x20
3232 | red = <Color.red: 1>
3233 |\x20\x20
3234 | ----------------------------------------------------------------------
3235 | Data descriptors inherited from enum.Enum:
3236 |\x20\x20
3237 | name
3238 | The name of the Enum member.
3239 |\x20\x20
3240 | value
3241 | The value of the Enum member.
3242 |\x20\x20
3243 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003244 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003245 |\x20\x20
3246 | __members__
3247 | Returns a mapping of member name->value.
3248 |\x20\x20\x20\x20\x20\x20
3249 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003250 | is a read-only view of the internal mapping."""
3251
3252expected_help_output_without_docs = """\
3253Help on class Color in module %s:
3254
3255class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003256 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3257 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003258 | Method resolution order:
3259 | Color
3260 | enum.Enum
3261 | builtins.object
3262 |\x20\x20
3263 | Data and other attributes defined here:
3264 |\x20\x20
3265 | blue = <Color.blue: 3>
3266 |\x20\x20
3267 | green = <Color.green: 2>
3268 |\x20\x20
3269 | red = <Color.red: 1>
3270 |\x20\x20
3271 | ----------------------------------------------------------------------
3272 | Data descriptors inherited from enum.Enum:
3273 |\x20\x20
3274 | name
3275 |\x20\x20
3276 | value
3277 |\x20\x20
3278 | ----------------------------------------------------------------------
3279 | Data descriptors inherited from enum.EnumMeta:
3280 |\x20\x20
3281 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003282
3283class TestStdLib(unittest.TestCase):
3284
Ethan Furman48a724f2015-04-11 23:23:06 -07003285 maxDiff = None
3286
Ethan Furman5875d742013-10-21 20:45:55 -07003287 class Color(Enum):
3288 red = 1
3289 green = 2
3290 blue = 3
3291
3292 def test_pydoc(self):
3293 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003294 if StrEnum.__doc__ is None:
3295 expected_text = expected_help_output_without_docs % __name__
3296 else:
3297 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003298 output = StringIO()
3299 helper = pydoc.Helper(output=output)
3300 helper(self.Color)
3301 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003302 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003303
3304 def test_inspect_getmembers(self):
3305 values = dict((
3306 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003307 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003308 ('__members__', self.Color.__members__),
3309 ('__module__', __name__),
3310 ('blue', self.Color.blue),
3311 ('green', self.Color.green),
3312 ('name', Enum.__dict__['name']),
3313 ('red', self.Color.red),
3314 ('value', Enum.__dict__['value']),
3315 ))
3316 result = dict(inspect.getmembers(self.Color))
3317 self.assertEqual(values.keys(), result.keys())
3318 failed = False
3319 for k in values.keys():
3320 if result[k] != values[k]:
3321 print()
3322 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3323 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3324 failed = True
3325 if failed:
3326 self.fail("result does not equal expected, see print above")
3327
3328 def test_inspect_classify_class_attrs(self):
3329 # indirectly test __objclass__
3330 from inspect import Attribute
3331 values = [
3332 Attribute(name='__class__', kind='data',
3333 defining_class=object, object=EnumMeta),
3334 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003335 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003336 Attribute(name='__members__', kind='property',
3337 defining_class=EnumMeta, object=EnumMeta.__members__),
3338 Attribute(name='__module__', kind='data',
3339 defining_class=self.Color, object=__name__),
3340 Attribute(name='blue', kind='data',
3341 defining_class=self.Color, object=self.Color.blue),
3342 Attribute(name='green', kind='data',
3343 defining_class=self.Color, object=self.Color.green),
3344 Attribute(name='red', kind='data',
3345 defining_class=self.Color, object=self.Color.red),
3346 Attribute(name='name', kind='data',
3347 defining_class=Enum, object=Enum.__dict__['name']),
3348 Attribute(name='value', kind='data',
3349 defining_class=Enum, object=Enum.__dict__['value']),
3350 ]
3351 values.sort(key=lambda item: item.name)
3352 result = list(inspect.classify_class_attrs(self.Color))
3353 result.sort(key=lambda item: item.name)
3354 failed = False
3355 for v, r in zip(values, result):
3356 if r != v:
3357 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3358 failed = True
3359 if failed:
3360 self.fail("result does not equal expected, see print above")
3361
Martin Panter19e69c52015-11-14 12:46:42 +00003362
3363class MiscTestCase(unittest.TestCase):
3364 def test__all__(self):
3365 support.check__all__(self, enum)
3366
3367
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003368# These are unordered here on purpose to ensure that declaration order
3369# makes no difference.
3370CONVERT_TEST_NAME_D = 5
3371CONVERT_TEST_NAME_C = 5
3372CONVERT_TEST_NAME_B = 5
3373CONVERT_TEST_NAME_A = 5 # This one should sort first.
3374CONVERT_TEST_NAME_E = 5
3375CONVERT_TEST_NAME_F = 5
3376
3377class TestIntEnumConvert(unittest.TestCase):
3378 def test_convert_value_lookup_priority(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 # We don't want the reverse lookup value to vary when there are
3384 # multiple possible names for a given value. It should always
3385 # report the first lexigraphical name in that case.
3386 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3387
3388 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003389 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003390 'UnittestConvert',
3391 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003392 filter=lambda x: x.startswith('CONVERT_TEST_'))
3393 # Ensure that test_type has all of the desired names and values.
3394 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3395 test_type.CONVERT_TEST_NAME_A)
3396 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3397 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3398 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3399 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3400 # Ensure that test_type only picked up names matching the filter.
3401 self.assertEqual([name for name in dir(test_type)
3402 if name[0:2] not in ('CO', '__')],
3403 [], msg='Names other than CONVERT_TEST_* found.')
3404
orlnub1230fb9fad2018-09-12 20:28:53 +03003405 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3406 '_convert was deprecated in 3.8')
3407 def test_convert_warn(self):
3408 with self.assertWarns(DeprecationWarning):
3409 enum.IntEnum._convert(
3410 'UnittestConvert',
3411 ('test.test_enum', '__main__')[__name__=='__main__'],
3412 filter=lambda x: x.startswith('CONVERT_TEST_'))
3413
3414 @unittest.skipUnless(sys.version_info >= (3, 9),
3415 '_convert was removed in 3.9')
3416 def test_convert_raise(self):
3417 with self.assertRaises(AttributeError):
3418 enum.IntEnum._convert(
3419 'UnittestConvert',
3420 ('test.test_enum', '__main__')[__name__=='__main__'],
3421 filter=lambda x: x.startswith('CONVERT_TEST_'))
3422
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003423
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003424if __name__ == '__main__':
3425 unittest.main()