blob: eb1266b960440a6a6cb4c88eaf148a74ab184482 [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 Furman9bf7c2d2021-07-03 21:08:42 -07008from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Ethan Furman9bf7c2d2021-07-03 21:08:42 -070011from test.support import ALWAYS_EQ, check__all__, threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080012from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080013
Ethan Furman6b3d64a2013-06-14 16:55:46 -070014
15# for pickle tests
16try:
17 class Stooges(Enum):
18 LARRY = 1
19 CURLY = 2
20 MOE = 3
21except Exception as exc:
22 Stooges = exc
23
24try:
25 class IntStooges(int, Enum):
26 LARRY = 1
27 CURLY = 2
28 MOE = 3
29except Exception as exc:
30 IntStooges = exc
31
32try:
33 class FloatStooges(float, Enum):
34 LARRY = 1.39
35 CURLY = 2.72
36 MOE = 3.142596
37except Exception as exc:
38 FloatStooges = exc
39
Ethan Furman65a5a472016-09-01 23:55:19 -070040try:
41 class FlagStooges(Flag):
42 LARRY = 1
43 CURLY = 2
44 MOE = 3
45except Exception as exc:
46 FlagStooges = exc
47
Ethan Furman6b3d64a2013-06-14 16:55:46 -070048# for pickle test and subclass tests
Ethan Furman9bf7c2d2021-07-03 21:08:42 -070049try:
50 class StrEnum(str, Enum):
51 'accepts only string values'
52 class Name(StrEnum):
53 BDFL = 'Guido van Rossum'
54 FLUFL = 'Barry Warsaw'
55except Exception as exc:
56 Name = exc
Ethan Furman6b3d64a2013-06-14 16:55:46 -070057
58try:
59 Question = Enum('Question', 'who what when where why', module=__name__)
60except Exception as exc:
61 Question = exc
62
63try:
64 Answer = Enum('Answer', 'him this then there because')
65except Exception as exc:
66 Answer = exc
67
Ethan Furmanca1b7942014-02-08 11:36:27 -080068try:
69 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
70except Exception as exc:
71 Theory = exc
72
Ethan Furman6b3d64a2013-06-14 16:55:46 -070073# for doctests
74try:
75 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080076 TOMATO = 1
77 BANANA = 2
78 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070079except Exception:
80 pass
81
Serhiy Storchakae50e7802015-03-31 16:56:49 +030082def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080083 if target is None:
84 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080086 assertion(loads(dumps(source, protocol=protocol)), target)
87
Serhiy Storchakae50e7802015-03-31 16:56:49 +030088def test_pickle_exception(assertion, exception, obj):
89 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080090 with assertion(exception):
91 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070092
93class TestHelpers(unittest.TestCase):
94 # _is_descriptor, _is_sunder, _is_dunder
95
96 def test_is_descriptor(self):
97 class foo:
98 pass
99 for attr in ('__get__','__set__','__delete__'):
100 obj = foo()
101 self.assertFalse(enum._is_descriptor(obj))
102 setattr(obj, attr, 1)
103 self.assertTrue(enum._is_descriptor(obj))
104
105 def test_is_sunder(self):
106 for s in ('_a_', '_aa_'):
107 self.assertTrue(enum._is_sunder(s))
108
109 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
110 '__', '___', '____', '_____',):
111 self.assertFalse(enum._is_sunder(s))
112
113 def test_is_dunder(self):
114 for s in ('__a__', '__aa__'):
115 self.assertTrue(enum._is_dunder(s))
116 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
117 '__', '___', '____', '_____',):
118 self.assertFalse(enum._is_dunder(s))
119
Ethan Furman5bdab642018-09-21 19:03:09 -0700120# for subclassing tests
121
122class classproperty:
123
124 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
125 self.fget = fget
126 self.fset = fset
127 self.fdel = fdel
128 if doc is None and fget is not None:
129 doc = fget.__doc__
130 self.__doc__ = doc
131
132 def __get__(self, instance, ownerclass):
133 return self.fget(ownerclass)
134
135
Ethan Furmanc16595e2016-09-10 23:36:59 -0700136# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700137
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700138class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800139
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700140 def setUp(self):
141 class Season(Enum):
142 SPRING = 1
143 SUMMER = 2
144 AUTUMN = 3
145 WINTER = 4
146 self.Season = Season
147
Ethan Furmanec15a822013-08-31 19:17:41 -0700148 class Konstants(float, Enum):
149 E = 2.7182818
150 PI = 3.1415926
151 TAU = 2 * PI
152 self.Konstants = Konstants
153
154 class Grades(IntEnum):
155 A = 5
156 B = 4
157 C = 3
158 D = 2
159 F = 0
160 self.Grades = Grades
161
162 class Directional(str, Enum):
163 EAST = 'east'
164 WEST = 'west'
165 NORTH = 'north'
166 SOUTH = 'south'
167 self.Directional = Directional
168
169 from datetime import date
170 class Holiday(date, Enum):
171 NEW_YEAR = 2013, 1, 1
172 IDES_OF_MARCH = 2013, 3, 15
173 self.Holiday = Holiday
174
Ethan Furman388a3922013-08-12 06:51:41 -0700175 def test_dir_on_class(self):
176 Season = self.Season
177 self.assertEqual(
178 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700179 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700180 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
181 )
182
183 def test_dir_on_item(self):
184 Season = self.Season
185 self.assertEqual(
186 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700188 )
189
Ethan Furmanc850f342013-09-15 16:59:35 -0700190 def test_dir_with_added_behavior(self):
191 class Test(Enum):
192 this = 'that'
193 these = 'those'
194 def wowser(self):
195 return ("Wowser! I'm %s!" % self.name)
196 self.assertEqual(
197 set(dir(Test)),
198 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
199 )
200 self.assertEqual(
201 set(dir(Test.this)),
202 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
203 )
204
Ethan Furman0ae550b2014-10-14 08:58:32 -0700205 def test_dir_on_sub_with_behavior_on_super(self):
206 # see issue22506
207 class SuperEnum(Enum):
208 def invisible(self):
209 return "did you see me?"
210 class SubEnum(SuperEnum):
211 sample = 5
212 self.assertEqual(
213 set(dir(SubEnum.sample)),
214 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
215 )
216
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200217 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
218 # see issue40084
219 class SuperEnum(IntEnum):
220 def __new__(cls, value, description=""):
221 obj = int.__new__(cls, value)
222 obj._value_ = value
223 obj.description = description
224 return obj
225 class SubEnum(SuperEnum):
226 sample = 5
227 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
228
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700229 def test_enum_in_enum_out(self):
230 Season = self.Season
231 self.assertIs(Season(Season.WINTER), Season.WINTER)
232
233 def test_enum_value(self):
234 Season = self.Season
235 self.assertEqual(Season.SPRING.value, 1)
236
237 def test_intenum_value(self):
238 self.assertEqual(IntStooges.CURLY.value, 2)
239
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700240 def test_enum(self):
241 Season = self.Season
242 lst = list(Season)
243 self.assertEqual(len(lst), len(Season))
244 self.assertEqual(len(Season), 4, Season)
245 self.assertEqual(
246 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
247
248 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
249 e = Season(i)
250 self.assertEqual(e, getattr(Season, season))
251 self.assertEqual(e.value, i)
252 self.assertNotEqual(e, i)
253 self.assertEqual(e.name, season)
254 self.assertIn(e, Season)
255 self.assertIs(type(e), Season)
256 self.assertIsInstance(e, Season)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700257 self.assertEqual(str(e), 'Season.' + season)
258 self.assertEqual(
259 repr(e),
260 '<Season.{0}: {1}>'.format(season, i),
261 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700262
263 def test_value_name(self):
264 Season = self.Season
265 self.assertEqual(Season.SPRING.name, 'SPRING')
266 self.assertEqual(Season.SPRING.value, 1)
267 with self.assertRaises(AttributeError):
268 Season.SPRING.name = 'invierno'
269 with self.assertRaises(AttributeError):
270 Season.SPRING.value = 2
271
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700272 def test_changing_member(self):
273 Season = self.Season
274 with self.assertRaises(AttributeError):
275 Season.WINTER = 'really cold'
276
Ethan Furman64a99722013-09-22 16:18:19 -0700277 def test_attribute_deletion(self):
278 class Season(Enum):
279 SPRING = 1
280 SUMMER = 2
281 AUTUMN = 3
282 WINTER = 4
283
284 def spam(cls):
285 pass
286
287 self.assertTrue(hasattr(Season, 'spam'))
288 del Season.spam
289 self.assertFalse(hasattr(Season, 'spam'))
290
291 with self.assertRaises(AttributeError):
292 del Season.SPRING
293 with self.assertRaises(AttributeError):
294 del Season.DRY
295 with self.assertRaises(AttributeError):
296 del Season.SPRING.name
297
Ethan Furman5de67b12016-04-13 23:52:09 -0700298 def test_bool_of_class(self):
299 class Empty(Enum):
300 pass
301 self.assertTrue(bool(Empty))
302
303 def test_bool_of_member(self):
304 class Count(Enum):
305 zero = 0
306 one = 1
307 two = 2
308 for member in Count:
309 self.assertTrue(bool(member))
310
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700311 def test_invalid_names(self):
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 mro = 9
315 with self.assertRaises(ValueError):
316 class Wrong(Enum):
317 _create_= 11
318 with self.assertRaises(ValueError):
319 class Wrong(Enum):
320 _get_mixins_ = 9
321 with self.assertRaises(ValueError):
322 class Wrong(Enum):
323 _find_new_ = 1
324 with self.assertRaises(ValueError):
325 class Wrong(Enum):
326 _any_name_ = 9
327
Ethan Furman6db1fd52015-09-17 21:49:12 -0700328 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800329 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700330 class Logic(Enum):
331 true = True
332 false = False
333 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800334 self.assertTrue(Logic.false)
335 # unless overridden
336 class RealLogic(Enum):
337 true = True
338 false = False
339 def __bool__(self):
340 return bool(self._value_)
341 self.assertTrue(RealLogic.true)
342 self.assertFalse(RealLogic.false)
343 # mixed Enums depend on mixed-in type
344 class IntLogic(int, Enum):
345 true = 1
346 false = 0
347 self.assertTrue(IntLogic.true)
348 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700349
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700350 def test_contains(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700351 Season = self.Season
352 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530353 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700354 3 in Season
Rahul Jha94306522018-09-10 23:51:04 +0530355 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700356 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700357
Ethan Furman6bd92882021-04-27 13:05:08 -0700358 val = Season(3)
359 self.assertIn(val, Season)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700360
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700361 class OtherEnum(Enum):
362 one = 1; two = 2
363 self.assertNotIn(OtherEnum.two, Season)
364
365 def test_comparisons(self):
366 Season = self.Season
367 with self.assertRaises(TypeError):
368 Season.SPRING < Season.WINTER
369 with self.assertRaises(TypeError):
370 Season.SPRING > 4
371
372 self.assertNotEqual(Season.SPRING, 1)
373
374 class Part(Enum):
375 SPRING = 1
376 CLIP = 2
377 BARREL = 3
378
379 self.assertNotEqual(Season.SPRING, Part.SPRING)
380 with self.assertRaises(TypeError):
381 Season.SPRING < Part.CLIP
382
383 def test_enum_duplicates(self):
384 class Season(Enum):
385 SPRING = 1
386 SUMMER = 2
387 AUTUMN = FALL = 3
388 WINTER = 4
389 ANOTHER_SPRING = 1
390 lst = list(Season)
391 self.assertEqual(
392 lst,
393 [Season.SPRING, Season.SUMMER,
394 Season.AUTUMN, Season.WINTER,
395 ])
396 self.assertIs(Season.FALL, Season.AUTUMN)
397 self.assertEqual(Season.FALL.value, 3)
398 self.assertEqual(Season.AUTUMN.value, 3)
399 self.assertIs(Season(3), Season.AUTUMN)
400 self.assertIs(Season(1), Season.SPRING)
401 self.assertEqual(Season.FALL.name, 'AUTUMN')
402 self.assertEqual(
403 [k for k,v in Season.__members__.items() if v.name != k],
404 ['FALL', 'ANOTHER_SPRING'],
405 )
406
Ethan Furman101e0742013-09-15 12:34:36 -0700407 def test_duplicate_name(self):
408 with self.assertRaises(TypeError):
409 class Color(Enum):
410 red = 1
411 green = 2
412 blue = 3
413 red = 4
414
415 with self.assertRaises(TypeError):
416 class Color(Enum):
417 red = 1
418 green = 2
419 blue = 3
420 def red(self):
421 return 'red'
422
423 with self.assertRaises(TypeError):
424 class Color(Enum):
425 @property
426 def red(self):
427 return 'redder'
428 red = 1
429 green = 2
430 blue = 3
431
432
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700433 def test_enum_with_value_name(self):
434 class Huh(Enum):
435 name = 1
436 value = 2
437 self.assertEqual(
438 list(Huh),
439 [Huh.name, Huh.value],
440 )
441 self.assertIs(type(Huh.name), Huh)
442 self.assertEqual(Huh.name.name, 'name')
443 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700444
445 def test_format_enum(self):
446 Season = self.Season
447 self.assertEqual('{}'.format(Season.SPRING),
448 '{}'.format(str(Season.SPRING)))
449 self.assertEqual( '{:}'.format(Season.SPRING),
450 '{:}'.format(str(Season.SPRING)))
451 self.assertEqual('{:20}'.format(Season.SPRING),
452 '{:20}'.format(str(Season.SPRING)))
453 self.assertEqual('{:^20}'.format(Season.SPRING),
454 '{:^20}'.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
thatneat2f19e822019-07-04 11:28:37 -0700460 def test_str_override_enum(self):
461 class EnumWithStrOverrides(Enum):
462 one = auto()
463 two = auto()
464
465 def __str__(self):
466 return 'Str!'
467 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
468 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
469
470 def test_format_override_enum(self):
471 class EnumWithFormatOverride(Enum):
472 one = 1.0
473 two = 2.0
474 def __format__(self, spec):
475 return 'Format!!'
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700476 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
thatneat2f19e822019-07-04 11:28:37 -0700477 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
478
479 def test_str_and_format_override_enum(self):
480 class EnumWithStrFormatOverrides(Enum):
481 one = auto()
482 two = auto()
483 def __str__(self):
484 return 'Str!'
485 def __format__(self, spec):
486 return 'Format!'
487 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
488 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
489
490 def test_str_override_mixin(self):
491 class MixinEnumWithStrOverride(float, Enum):
492 one = 1.0
493 two = 2.0
494 def __str__(self):
495 return 'Overridden!'
496 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
497 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
498
499 def test_str_and_format_override_mixin(self):
500 class MixinWithStrFormatOverrides(float, Enum):
501 one = 1.0
502 two = 2.0
503 def __str__(self):
504 return 'Str!'
505 def __format__(self, spec):
506 return 'Format!'
507 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
508 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
509
510 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700511 class TestFloat(float, Enum):
512 one = 1.0
513 two = 2.0
514 def __format__(self, spec):
515 return 'TestFloat success!'
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700516 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700517 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
518
519 def assertFormatIsValue(self, spec, member):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700520 self.assertEqual(spec.format(member), spec.format(member.value))
Ethan Furmanec15a822013-08-31 19:17:41 -0700521
522 def test_format_enum_date(self):
523 Holiday = self.Holiday
524 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
525 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
526 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
527 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
528 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
529 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
530 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
531 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
532
533 def test_format_enum_float(self):
534 Konstants = self.Konstants
535 self.assertFormatIsValue('{}', Konstants.TAU)
536 self.assertFormatIsValue('{:}', Konstants.TAU)
537 self.assertFormatIsValue('{:20}', Konstants.TAU)
538 self.assertFormatIsValue('{:^20}', Konstants.TAU)
539 self.assertFormatIsValue('{:>20}', Konstants.TAU)
540 self.assertFormatIsValue('{:<20}', Konstants.TAU)
541 self.assertFormatIsValue('{:n}', Konstants.TAU)
542 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
543 self.assertFormatIsValue('{:f}', Konstants.TAU)
544
545 def test_format_enum_int(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700546 Grades = self.Grades
Ethan Furmanec15a822013-08-31 19:17:41 -0700547 self.assertFormatIsValue('{}', Grades.C)
548 self.assertFormatIsValue('{:}', Grades.C)
549 self.assertFormatIsValue('{:20}', Grades.C)
550 self.assertFormatIsValue('{:^20}', Grades.C)
551 self.assertFormatIsValue('{:>20}', Grades.C)
552 self.assertFormatIsValue('{:<20}', Grades.C)
553 self.assertFormatIsValue('{:+}', Grades.C)
554 self.assertFormatIsValue('{:08X}', Grades.C)
555 self.assertFormatIsValue('{:b}', Grades.C)
556
557 def test_format_enum_str(self):
558 Directional = self.Directional
559 self.assertFormatIsValue('{}', Directional.WEST)
560 self.assertFormatIsValue('{:}', Directional.WEST)
561 self.assertFormatIsValue('{:20}', Directional.WEST)
562 self.assertFormatIsValue('{:^20}', Directional.WEST)
563 self.assertFormatIsValue('{:>20}', Directional.WEST)
564 self.assertFormatIsValue('{:<20}', Directional.WEST)
565
Ethan Furman22415ad2020-09-15 16:28:25 -0700566 def test_object_str_override(self):
567 class Colors(Enum):
568 RED, GREEN, BLUE = 1, 2, 3
569 def __repr__(self):
570 return "test.%s" % (self._name_, )
571 __str__ = object.__str__
572 self.assertEqual(str(Colors.RED), 'test.RED')
573
Ethan Furmanbff01f32020-09-15 15:56:26 -0700574 def test_enum_str_override(self):
575 class MyStrEnum(Enum):
576 def __str__(self):
577 return 'MyStr'
578 class MyMethodEnum(Enum):
579 def hello(self):
580 return 'Hello! My name is %s' % self.name
581 class Test1Enum(MyMethodEnum, int, MyStrEnum):
582 One = 1
583 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800584 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700585 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800586 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700587 #
588 class Test2Enum(MyStrEnum, MyMethodEnum):
589 One = 1
590 Two = 2
591 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800592 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700593
594 def test_inherited_data_type(self):
595 class HexInt(int):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700596 __qualname__ = 'HexInt'
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597 def __repr__(self):
598 return hex(self)
599 class MyEnum(HexInt, enum.Enum):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700600 __qualname__ = 'MyEnum'
Ethan Furmanbff01f32020-09-15 15:56:26 -0700601 A = 1
602 B = 2
603 C = 3
604 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700605 globals()['HexInt'] = HexInt
606 globals()['MyEnum'] = MyEnum
607 test_pickle_dump_load(self.assertIs, MyEnum.A)
608 test_pickle_dump_load(self.assertIs, MyEnum)
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700609 #
610 class SillyInt(HexInt):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700611 __qualname__ = 'SillyInt'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700612 pass
613 class MyOtherEnum(SillyInt, enum.Enum):
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700614 __qualname__ = 'MyOtherEnum'
Miss Islington (bot)0f993242021-06-15 14:07:37 -0700615 D = 4
616 E = 5
617 F = 6
618 self.assertIs(MyOtherEnum._member_type_, SillyInt)
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700619 globals()['SillyInt'] = SillyInt
620 globals()['MyOtherEnum'] = MyOtherEnum
621 test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
622 test_pickle_dump_load(self.assertIs, MyOtherEnum)
623 #
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700624 class BrokenInt(int):
625 __qualname__ = 'BrokenInt'
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700626 def __new__(cls, value):
627 return int.__new__(cls, value)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700628 class MyBrokenEnum(BrokenInt, Enum):
629 __qualname__ = 'MyBrokenEnum'
Ethan Furman41c2a4a2021-06-15 18:50:59 -0700630 G = 7
631 H = 8
632 I = 9
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700633 self.assertIs(MyBrokenEnum._member_type_, BrokenInt)
634 self.assertIs(MyBrokenEnum(7), MyBrokenEnum.G)
635 globals()['BrokenInt'] = BrokenInt
636 globals()['MyBrokenEnum'] = MyBrokenEnum
637 test_pickle_exception(self.assertRaises, TypeError, MyBrokenEnum.G)
638 test_pickle_exception(self.assertRaises, PicklingError, MyBrokenEnum)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700639
640 def test_too_many_data_types(self):
641 with self.assertRaisesRegex(TypeError, 'too many data types'):
642 class Huh(str, int, Enum):
643 One = 1
644
645 class MyStr(str):
646 def hello(self):
647 return 'hello, %s' % self
648 class MyInt(int):
649 def repr(self):
650 return hex(self)
651 with self.assertRaisesRegex(TypeError, 'too many data types'):
652 class Huh(MyStr, MyInt, Enum):
653 One = 1
654
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700655 def test_hash(self):
656 Season = self.Season
657 dates = {}
658 dates[Season.WINTER] = '1225'
659 dates[Season.SPRING] = '0315'
660 dates[Season.SUMMER] = '0704'
661 dates[Season.AUTUMN] = '1031'
662 self.assertEqual(dates[Season.AUTUMN], '1031')
663
664 def test_intenum_from_scratch(self):
665 class phy(int, Enum):
666 pi = 3
667 tau = 2 * pi
668 self.assertTrue(phy.pi < phy.tau)
669
670 def test_intenum_inherited(self):
671 class IntEnum(int, Enum):
672 pass
673 class phy(IntEnum):
674 pi = 3
675 tau = 2 * pi
676 self.assertTrue(phy.pi < phy.tau)
677
678 def test_floatenum_from_scratch(self):
679 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700680 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700681 tau = 2 * pi
682 self.assertTrue(phy.pi < phy.tau)
683
684 def test_floatenum_inherited(self):
685 class FloatEnum(float, Enum):
686 pass
687 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700688 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700689 tau = 2 * pi
690 self.assertTrue(phy.pi < phy.tau)
691
692 def test_strenum_from_scratch(self):
693 class phy(str, Enum):
694 pi = 'Pi'
695 tau = 'Tau'
696 self.assertTrue(phy.pi < phy.tau)
697
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700698 def test_strenum_inherited(self):
699 class StrEnum(str, Enum):
700 pass
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700701 class phy(StrEnum):
702 pi = 'Pi'
703 tau = 'Tau'
704 self.assertTrue(phy.pi < phy.tau)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700705
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700706
707 def test_intenum(self):
708 class WeekDay(IntEnum):
709 SUNDAY = 1
710 MONDAY = 2
711 TUESDAY = 3
712 WEDNESDAY = 4
713 THURSDAY = 5
714 FRIDAY = 6
715 SATURDAY = 7
716
717 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
718 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
719
720 lst = list(WeekDay)
721 self.assertEqual(len(lst), len(WeekDay))
722 self.assertEqual(len(WeekDay), 7)
723 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
724 target = target.split()
725 for i, weekday in enumerate(target, 1):
726 e = WeekDay(i)
727 self.assertEqual(e, i)
728 self.assertEqual(int(e), i)
729 self.assertEqual(e.name, weekday)
730 self.assertIn(e, WeekDay)
731 self.assertEqual(lst.index(e)+1, i)
732 self.assertTrue(0 < e < 8)
733 self.assertIs(type(e), WeekDay)
734 self.assertIsInstance(e, int)
735 self.assertIsInstance(e, Enum)
736
737 def test_intenum_duplicates(self):
738 class WeekDay(IntEnum):
739 SUNDAY = 1
740 MONDAY = 2
741 TUESDAY = TEUSDAY = 3
742 WEDNESDAY = 4
743 THURSDAY = 5
744 FRIDAY = 6
745 SATURDAY = 7
746 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
747 self.assertEqual(WeekDay(3).name, 'TUESDAY')
748 self.assertEqual([k for k,v in WeekDay.__members__.items()
749 if v.name != k], ['TEUSDAY', ])
750
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300751 def test_intenum_from_bytes(self):
752 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
753 with self.assertRaises(ValueError):
754 IntStooges.from_bytes(b'\x00\x05', 'big')
755
756 def test_floatenum_fromhex(self):
757 h = float.hex(FloatStooges.MOE.value)
758 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
759 h = float.hex(FloatStooges.MOE.value + 0.01)
760 with self.assertRaises(ValueError):
761 FloatStooges.fromhex(h)
762
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700763 def test_pickle_enum(self):
764 if isinstance(Stooges, Exception):
765 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800766 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
767 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700768
769 def test_pickle_int(self):
770 if isinstance(IntStooges, Exception):
771 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800772 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
773 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700774
775 def test_pickle_float(self):
776 if isinstance(FloatStooges, Exception):
777 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800778 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
779 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700780
781 def test_pickle_enum_function(self):
782 if isinstance(Answer, Exception):
783 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800784 test_pickle_dump_load(self.assertIs, Answer.him)
785 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700786
787 def test_pickle_enum_function_with_module(self):
788 if isinstance(Question, Exception):
789 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800790 test_pickle_dump_load(self.assertIs, Question.who)
791 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700792
Ethan Furmanca1b7942014-02-08 11:36:27 -0800793 def test_enum_function_with_qualname(self):
794 if isinstance(Theory, Exception):
795 raise Theory
796 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
797
798 def test_class_nested_enum_and_pickle_protocol_four(self):
799 # would normally just have this directly in the class namespace
800 class NestedEnum(Enum):
801 twigs = 'common'
802 shiny = 'rare'
803
804 self.__class__.NestedEnum = NestedEnum
805 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300806 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800807
Ethan Furman24e837f2015-03-18 17:27:57 -0700808 def test_pickle_by_name(self):
809 class ReplaceGlobalInt(IntEnum):
810 ONE = 1
811 TWO = 2
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700812 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
Ethan Furman24e837f2015-03-18 17:27:57 -0700813 for proto in range(HIGHEST_PROTOCOL):
814 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
815
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700816 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800817 BadPickle = Enum(
818 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700819 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800820 # now break BadPickle to test exception raising
821 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800822 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
823 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700824
825 def test_string_enum(self):
826 class SkillLevel(str, Enum):
827 master = 'what is the sound of one hand clapping?'
828 journeyman = 'why did the chicken cross the road?'
829 apprentice = 'knock, knock!'
830 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
831
832 def test_getattr_getitem(self):
833 class Period(Enum):
834 morning = 1
835 noon = 2
836 evening = 3
837 night = 4
838 self.assertIs(Period(2), Period.noon)
839 self.assertIs(getattr(Period, 'night'), Period.night)
840 self.assertIs(Period['morning'], Period.morning)
841
842 def test_getattr_dunder(self):
843 Season = self.Season
844 self.assertTrue(getattr(Season, '__eq__'))
845
846 def test_iteration_order(self):
847 class Season(Enum):
848 SUMMER = 2
849 WINTER = 4
850 AUTUMN = 3
851 SPRING = 1
852 self.assertEqual(
853 list(Season),
854 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
855 )
856
Ethan Furman2131a4a2013-09-14 18:11:24 -0700857 def test_reversed_iteration_order(self):
858 self.assertEqual(
859 list(reversed(self.Season)),
860 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
861 self.Season.SPRING]
862 )
863
Martin Pantereb995702016-07-28 01:11:04 +0000864 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700865 SummerMonth = Enum('SummerMonth', 'june july august')
866 lst = list(SummerMonth)
867 self.assertEqual(len(lst), len(SummerMonth))
868 self.assertEqual(len(SummerMonth), 3, SummerMonth)
869 self.assertEqual(
870 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
871 lst,
872 )
873 for i, month in enumerate('june july august'.split(), 1):
874 e = SummerMonth(i)
875 self.assertEqual(int(e.value), i)
876 self.assertNotEqual(e, i)
877 self.assertEqual(e.name, month)
878 self.assertIn(e, SummerMonth)
879 self.assertIs(type(e), SummerMonth)
880
Martin Pantereb995702016-07-28 01:11:04 +0000881 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700882 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
883 lst = list(SummerMonth)
884 self.assertEqual(len(lst), len(SummerMonth))
885 self.assertEqual(len(SummerMonth), 3, SummerMonth)
886 self.assertEqual(
887 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
888 lst,
889 )
890 for i, month in enumerate('june july august'.split(), 10):
891 e = SummerMonth(i)
892 self.assertEqual(int(e.value), i)
893 self.assertNotEqual(e, i)
894 self.assertEqual(e.name, month)
895 self.assertIn(e, SummerMonth)
896 self.assertIs(type(e), SummerMonth)
897
Martin Pantereb995702016-07-28 01:11:04 +0000898 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700899 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
900 lst = list(SummerMonth)
901 self.assertEqual(len(lst), len(SummerMonth))
902 self.assertEqual(len(SummerMonth), 3, SummerMonth)
903 self.assertEqual(
904 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
905 lst,
906 )
907 for i, month in enumerate('june july august'.split(), 1):
908 e = SummerMonth(i)
909 self.assertEqual(int(e.value), i)
910 self.assertNotEqual(e, i)
911 self.assertEqual(e.name, month)
912 self.assertIn(e, SummerMonth)
913 self.assertIs(type(e), SummerMonth)
914
Martin Pantereb995702016-07-28 01:11:04 +0000915 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700916 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
917 lst = list(SummerMonth)
918 self.assertEqual(len(lst), len(SummerMonth))
919 self.assertEqual(len(SummerMonth), 3, SummerMonth)
920 self.assertEqual(
921 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
922 lst,
923 )
924 for i, month in enumerate('june july august'.split(), 20):
925 e = SummerMonth(i)
926 self.assertEqual(int(e.value), i)
927 self.assertNotEqual(e, i)
928 self.assertEqual(e.name, month)
929 self.assertIn(e, SummerMonth)
930 self.assertIs(type(e), SummerMonth)
931
Martin Pantereb995702016-07-28 01:11:04 +0000932 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700933 SummerMonth = Enum(
934 'SummerMonth',
935 (('june', 1), ('july', 2), ('august', 3))
936 )
937 lst = list(SummerMonth)
938 self.assertEqual(len(lst), len(SummerMonth))
939 self.assertEqual(len(SummerMonth), 3, SummerMonth)
940 self.assertEqual(
941 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
942 lst,
943 )
944 for i, month in enumerate('june july august'.split(), 1):
945 e = SummerMonth(i)
946 self.assertEqual(int(e.value), i)
947 self.assertNotEqual(e, i)
948 self.assertEqual(e.name, month)
949 self.assertIn(e, SummerMonth)
950 self.assertIs(type(e), SummerMonth)
951
Martin Pantereb995702016-07-28 01:11:04 +0000952 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700953 SummerMonth = Enum(
954 'SummerMonth',
955 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
956 )
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(), 1):
965 e = SummerMonth(i)
966 self.assertEqual(int(e.value), i)
967 self.assertNotEqual(e, i)
968 self.assertEqual(e.name, month)
969 self.assertIn(e, SummerMonth)
970 self.assertIs(type(e), SummerMonth)
971
Martin Pantereb995702016-07-28 01:11:04 +0000972 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700973 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
974 lst = list(SummerMonth)
975 self.assertEqual(len(lst), len(SummerMonth))
976 self.assertEqual(len(SummerMonth), 3, SummerMonth)
977 self.assertEqual(
978 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
979 lst,
980 )
981 for i, month in enumerate('june july august'.split(), 1):
982 e = SummerMonth(i)
983 self.assertEqual(e, i)
984 self.assertEqual(e.name, month)
985 self.assertIn(e, SummerMonth)
986 self.assertIs(type(e), SummerMonth)
987
Martin Pantereb995702016-07-28 01:11:04 +0000988 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700989 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
990 lst = list(SummerMonth)
991 self.assertEqual(len(lst), len(SummerMonth))
992 self.assertEqual(len(SummerMonth), 3, SummerMonth)
993 self.assertEqual(
994 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
995 lst,
996 )
997 for i, month in enumerate('june july august'.split(), 30):
998 e = SummerMonth(i)
999 self.assertEqual(e, i)
1000 self.assertEqual(e.name, month)
1001 self.assertIn(e, SummerMonth)
1002 self.assertIs(type(e), SummerMonth)
1003
Martin Pantereb995702016-07-28 01:11:04 +00001004 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001005 SummerMonth = IntEnum('SummerMonth', 'june july august')
1006 lst = list(SummerMonth)
1007 self.assertEqual(len(lst), len(SummerMonth))
1008 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1009 self.assertEqual(
1010 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1011 lst,
1012 )
1013 for i, month in enumerate('june july august'.split(), 1):
1014 e = SummerMonth(i)
1015 self.assertEqual(e, i)
1016 self.assertEqual(e.name, month)
1017 self.assertIn(e, SummerMonth)
1018 self.assertIs(type(e), SummerMonth)
1019
Martin Pantereb995702016-07-28 01:11:04 +00001020 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -07001021 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
1022 lst = list(SummerMonth)
1023 self.assertEqual(len(lst), len(SummerMonth))
1024 self.assertEqual(len(SummerMonth), 3, SummerMonth)
1025 self.assertEqual(
1026 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
1027 lst,
1028 )
1029 for i, month in enumerate('june july august'.split(), 40):
1030 e = SummerMonth(i)
1031 self.assertEqual(e, i)
1032 self.assertEqual(e.name, month)
1033 self.assertIn(e, SummerMonth)
1034 self.assertIs(type(e), SummerMonth)
1035
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001036 def test_subclassing(self):
1037 if isinstance(Name, Exception):
1038 raise Name
1039 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1040 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1041 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001042 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001043
1044 def test_extending(self):
1045 class Color(Enum):
1046 red = 1
1047 green = 2
1048 blue = 3
1049 with self.assertRaises(TypeError):
1050 class MoreColor(Color):
1051 cyan = 4
1052 magenta = 5
1053 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001054 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1055 class EvenMoreColor(Color, IntEnum):
1056 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001057
1058 def test_exclude_methods(self):
1059 class whatever(Enum):
1060 this = 'that'
1061 these = 'those'
1062 def really(self):
1063 return 'no, not %s' % self.value
1064 self.assertIsNot(type(whatever.really), whatever)
1065 self.assertEqual(whatever.this.really(), 'no, not that')
1066
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001067 def test_wrong_inheritance_order(self):
1068 with self.assertRaises(TypeError):
1069 class Wrong(Enum, str):
1070 NotHere = 'error before this point'
1071
1072 def test_intenum_transitivity(self):
1073 class number(IntEnum):
1074 one = 1
1075 two = 2
1076 three = 3
1077 class numero(IntEnum):
1078 uno = 1
1079 dos = 2
1080 tres = 3
1081 self.assertEqual(number.one, numero.uno)
1082 self.assertEqual(number.two, numero.dos)
1083 self.assertEqual(number.three, numero.tres)
1084
1085 def test_wrong_enum_in_call(self):
1086 class Monochrome(Enum):
1087 black = 0
1088 white = 1
1089 class Gender(Enum):
1090 male = 0
1091 female = 1
1092 self.assertRaises(ValueError, Monochrome, Gender.male)
1093
1094 def test_wrong_enum_in_mixed_call(self):
1095 class Monochrome(IntEnum):
1096 black = 0
1097 white = 1
1098 class Gender(Enum):
1099 male = 0
1100 female = 1
1101 self.assertRaises(ValueError, Monochrome, Gender.male)
1102
1103 def test_mixed_enum_in_call_1(self):
1104 class Monochrome(IntEnum):
1105 black = 0
1106 white = 1
1107 class Gender(IntEnum):
1108 male = 0
1109 female = 1
1110 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1111
1112 def test_mixed_enum_in_call_2(self):
1113 class Monochrome(Enum):
1114 black = 0
1115 white = 1
1116 class Gender(IntEnum):
1117 male = 0
1118 female = 1
1119 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1120
1121 def test_flufl_enum(self):
1122 class Fluflnum(Enum):
1123 def __int__(self):
1124 return int(self.value)
1125 class MailManOptions(Fluflnum):
1126 option1 = 1
1127 option2 = 2
1128 option3 = 3
1129 self.assertEqual(int(MailManOptions.option1), 1)
1130
Ethan Furman5e5a8232013-08-04 08:42:23 -07001131 def test_introspection(self):
1132 class Number(IntEnum):
1133 one = 100
1134 two = 200
1135 self.assertIs(Number.one._member_type_, int)
1136 self.assertIs(Number._member_type_, int)
1137 class String(str, Enum):
1138 yarn = 'soft'
1139 rope = 'rough'
1140 wire = 'hard'
1141 self.assertIs(String.yarn._member_type_, str)
1142 self.assertIs(String._member_type_, str)
1143 class Plain(Enum):
1144 vanilla = 'white'
1145 one = 1
1146 self.assertIs(Plain.vanilla._member_type_, object)
1147 self.assertIs(Plain._member_type_, object)
1148
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001149 def test_no_such_enum_member(self):
1150 class Color(Enum):
1151 red = 1
1152 green = 2
1153 blue = 3
1154 with self.assertRaises(ValueError):
1155 Color(4)
1156 with self.assertRaises(KeyError):
1157 Color['chartreuse']
1158
1159 def test_new_repr(self):
1160 class Color(Enum):
1161 red = 1
1162 green = 2
1163 blue = 3
1164 def __repr__(self):
1165 return "don't you just love shades of %s?" % self.name
1166 self.assertEqual(
1167 repr(Color.blue),
1168 "don't you just love shades of blue?",
1169 )
1170
1171 def test_inherited_repr(self):
1172 class MyEnum(Enum):
1173 def __repr__(self):
1174 return "My name is %s." % self.name
1175 class MyIntEnum(int, MyEnum):
1176 this = 1
1177 that = 2
1178 theother = 3
1179 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1180
1181 def test_multiple_mixin_mro(self):
1182 class auto_enum(type(Enum)):
1183 def __new__(metacls, cls, bases, classdict):
1184 temp = type(classdict)()
Ethan Furman7cf0aad2020-12-09 17:12:11 -08001185 temp._cls_name = cls
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001186 names = set(classdict._member_names)
1187 i = 0
1188 for k in classdict._member_names:
1189 v = classdict[k]
1190 if v is Ellipsis:
1191 v = i
1192 else:
1193 i = v
1194 i += 1
1195 temp[k] = v
1196 for k, v in classdict.items():
1197 if k not in names:
1198 temp[k] = v
1199 return super(auto_enum, metacls).__new__(
1200 metacls, cls, bases, temp)
1201
1202 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1203 pass
1204
1205 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1206 pass
1207
1208 class TestAutoNumber(AutoNumberedEnum):
1209 a = ...
1210 b = 3
1211 c = ...
1212
1213 class TestAutoInt(AutoIntEnum):
1214 a = ...
1215 b = 3
1216 c = ...
1217
1218 def test_subclasses_with_getnewargs(self):
1219 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001220 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001221 def __new__(cls, *args):
1222 _args = args
1223 name, *args = args
1224 if len(args) == 0:
1225 raise TypeError("name and value must be specified")
1226 self = int.__new__(cls, *args)
1227 self._intname = name
1228 self._args = _args
1229 return self
1230 def __getnewargs__(self):
1231 return self._args
1232 @property
1233 def __name__(self):
1234 return self._intname
1235 def __repr__(self):
1236 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001237 return "{}({!r}, {})".format(type(self).__name__,
1238 self.__name__,
1239 int.__repr__(self))
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240 def __str__(self):
1241 # str() is unchanged, even if it relies on the repr() fallback
1242 base = int
1243 base_str = base.__str__
1244 if base_str.__objclass__ is object:
1245 return base.__repr__(self)
1246 return base_str(self)
1247 # for simplicity, we only define one operator that
1248 # propagates expressions
1249 def __add__(self, other):
1250 temp = int(self) + int( other)
1251 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1252 return NamedInt(
1253 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001254 temp )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001255 else:
1256 return temp
1257
1258 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001259 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001260 x = ('the-x', 1)
1261 y = ('the-y', 2)
1262
Ethan Furman2aa27322013-07-19 19:35:56 -07001263
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001264 self.assertIs(NEI.__new__, Enum.__new__)
1265 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1266 globals()['NamedInt'] = NamedInt
1267 globals()['NEI'] = NEI
1268 NI5 = NamedInt('test', 5)
1269 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001270 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001271 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001272 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001273 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001274
Ethan Furmanca1b7942014-02-08 11:36:27 -08001275 def test_subclasses_with_getnewargs_ex(self):
1276 class NamedInt(int):
1277 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1278 def __new__(cls, *args):
1279 _args = args
1280 name, *args = args
1281 if len(args) == 0:
1282 raise TypeError("name and value must be specified")
1283 self = int.__new__(cls, *args)
1284 self._intname = name
1285 self._args = _args
1286 return self
1287 def __getnewargs_ex__(self):
1288 return self._args, {}
1289 @property
1290 def __name__(self):
1291 return self._intname
1292 def __repr__(self):
1293 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001294 return "{}({!r}, {})".format(type(self).__name__,
1295 self.__name__,
1296 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001297 def __str__(self):
1298 # str() is unchanged, even if it relies on the repr() fallback
1299 base = int
1300 base_str = base.__str__
1301 if base_str.__objclass__ is object:
1302 return base.__repr__(self)
1303 return base_str(self)
1304 # for simplicity, we only define one operator that
1305 # propagates expressions
1306 def __add__(self, other):
1307 temp = int(self) + int( other)
1308 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1309 return NamedInt(
1310 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001311 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001312 else:
1313 return temp
1314
1315 class NEI(NamedInt, Enum):
1316 __qualname__ = 'NEI' # needed for pickle protocol 4
1317 x = ('the-x', 1)
1318 y = ('the-y', 2)
1319
1320
1321 self.assertIs(NEI.__new__, Enum.__new__)
1322 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1323 globals()['NamedInt'] = NamedInt
1324 globals()['NEI'] = NEI
1325 NI5 = NamedInt('test', 5)
1326 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001327 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001328 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001329 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001330 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001331
1332 def test_subclasses_with_reduce(self):
1333 class NamedInt(int):
1334 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1335 def __new__(cls, *args):
1336 _args = args
1337 name, *args = args
1338 if len(args) == 0:
1339 raise TypeError("name and value must be specified")
1340 self = int.__new__(cls, *args)
1341 self._intname = name
1342 self._args = _args
1343 return self
1344 def __reduce__(self):
1345 return self.__class__, self._args
1346 @property
1347 def __name__(self):
1348 return self._intname
1349 def __repr__(self):
1350 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001351 return "{}({!r}, {})".format(type(self).__name__,
1352 self.__name__,
1353 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001354 def __str__(self):
1355 # str() is unchanged, even if it relies on the repr() fallback
1356 base = int
1357 base_str = base.__str__
1358 if base_str.__objclass__ is object:
1359 return base.__repr__(self)
1360 return base_str(self)
1361 # for simplicity, we only define one operator that
1362 # propagates expressions
1363 def __add__(self, other):
1364 temp = int(self) + int( other)
1365 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1366 return NamedInt(
1367 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001368 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001369 else:
1370 return temp
1371
1372 class NEI(NamedInt, Enum):
1373 __qualname__ = 'NEI' # needed for pickle protocol 4
1374 x = ('the-x', 1)
1375 y = ('the-y', 2)
1376
1377
1378 self.assertIs(NEI.__new__, Enum.__new__)
1379 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1380 globals()['NamedInt'] = NamedInt
1381 globals()['NEI'] = NEI
1382 NI5 = NamedInt('test', 5)
1383 self.assertEqual(NI5, 5)
1384 test_pickle_dump_load(self.assertEqual, NI5, 5)
1385 self.assertEqual(NEI.y.value, 2)
1386 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001387 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001388
1389 def test_subclasses_with_reduce_ex(self):
1390 class NamedInt(int):
1391 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1392 def __new__(cls, *args):
1393 _args = args
1394 name, *args = args
1395 if len(args) == 0:
1396 raise TypeError("name and value must be specified")
1397 self = int.__new__(cls, *args)
1398 self._intname = name
1399 self._args = _args
1400 return self
1401 def __reduce_ex__(self, proto):
1402 return self.__class__, self._args
1403 @property
1404 def __name__(self):
1405 return self._intname
1406 def __repr__(self):
1407 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001408 return "{}({!r}, {})".format(type(self).__name__,
1409 self.__name__,
1410 int.__repr__(self))
Ethan Furmanca1b7942014-02-08 11:36:27 -08001411 def __str__(self):
1412 # str() is unchanged, even if it relies on the repr() fallback
1413 base = int
1414 base_str = base.__str__
1415 if base_str.__objclass__ is object:
1416 return base.__repr__(self)
1417 return base_str(self)
1418 # for simplicity, we only define one operator that
1419 # propagates expressions
1420 def __add__(self, other):
1421 temp = int(self) + int( other)
1422 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1423 return NamedInt(
1424 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001425 temp )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001426 else:
1427 return temp
1428
1429 class NEI(NamedInt, Enum):
1430 __qualname__ = 'NEI' # needed for pickle protocol 4
1431 x = ('the-x', 1)
1432 y = ('the-y', 2)
1433
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001434
Ethan Furmanca1b7942014-02-08 11:36:27 -08001435 self.assertIs(NEI.__new__, Enum.__new__)
1436 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1437 globals()['NamedInt'] = NamedInt
1438 globals()['NEI'] = NEI
1439 NI5 = NamedInt('test', 5)
1440 self.assertEqual(NI5, 5)
1441 test_pickle_dump_load(self.assertEqual, NI5, 5)
1442 self.assertEqual(NEI.y.value, 2)
1443 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001444 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001445
Ethan Furmandc870522014-02-18 12:37:12 -08001446 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001447 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001448 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001449 def __new__(cls, *args):
1450 _args = args
1451 name, *args = args
1452 if len(args) == 0:
1453 raise TypeError("name and value must be specified")
1454 self = int.__new__(cls, *args)
1455 self._intname = name
1456 self._args = _args
1457 return self
1458 @property
1459 def __name__(self):
1460 return self._intname
1461 def __repr__(self):
1462 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001463 return "{}({!r}, {})".format(type(self).__name__,
1464 self.__name__,
1465 int.__repr__(self))
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001466 def __str__(self):
1467 # str() is unchanged, even if it relies on the repr() fallback
1468 base = int
1469 base_str = base.__str__
1470 if base_str.__objclass__ is object:
1471 return base.__repr__(self)
1472 return base_str(self)
1473 # for simplicity, we only define one operator that
1474 # propagates expressions
1475 def __add__(self, other):
1476 temp = int(self) + int( other)
1477 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1478 return NamedInt(
1479 '({0} + {1})'.format(self.__name__, other.__name__),
1480 temp )
1481 else:
1482 return temp
1483
1484 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001485 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001486 x = ('the-x', 1)
1487 y = ('the-y', 2)
1488
1489 self.assertIs(NEI.__new__, Enum.__new__)
1490 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1491 globals()['NamedInt'] = NamedInt
1492 globals()['NEI'] = NEI
1493 NI5 = NamedInt('test', 5)
1494 self.assertEqual(NI5, 5)
1495 self.assertEqual(NEI.y.value, 2)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001496 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1497 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001498
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001499 def test_subclasses_without_direct_pickle_support_using_name(self):
Ethan Furmandc870522014-02-18 12:37:12 -08001500 class NamedInt(int):
1501 __qualname__ = 'NamedInt'
1502 def __new__(cls, *args):
1503 _args = args
1504 name, *args = args
1505 if len(args) == 0:
1506 raise TypeError("name and value must be specified")
1507 self = int.__new__(cls, *args)
1508 self._intname = name
1509 self._args = _args
1510 return self
1511 @property
1512 def __name__(self):
1513 return self._intname
1514 def __repr__(self):
1515 # repr() is updated to include the name and type info
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001516 return "{}({!r}, {})".format(type(self).__name__,
1517 self.__name__,
1518 int.__repr__(self))
Ethan Furmandc870522014-02-18 12:37:12 -08001519 def __str__(self):
1520 # str() is unchanged, even if it relies on the repr() fallback
1521 base = int
1522 base_str = base.__str__
1523 if base_str.__objclass__ is object:
1524 return base.__repr__(self)
1525 return base_str(self)
1526 # for simplicity, we only define one operator that
1527 # propagates expressions
1528 def __add__(self, other):
1529 temp = int(self) + int( other)
1530 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1531 return NamedInt(
1532 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001533 temp )
Ethan Furmandc870522014-02-18 12:37:12 -08001534 else:
1535 return temp
1536
1537 class NEI(NamedInt, Enum):
1538 __qualname__ = 'NEI'
1539 x = ('the-x', 1)
1540 y = ('the-y', 2)
1541 def __reduce_ex__(self, proto):
1542 return getattr, (self.__class__, self._name_)
1543
1544 self.assertIs(NEI.__new__, Enum.__new__)
1545 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1546 globals()['NamedInt'] = NamedInt
1547 globals()['NEI'] = NEI
1548 NI5 = NamedInt('test', 5)
1549 self.assertEqual(NI5, 5)
1550 self.assertEqual(NEI.y.value, 2)
1551 test_pickle_dump_load(self.assertIs, NEI.y)
1552 test_pickle_dump_load(self.assertIs, NEI)
1553
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001554 def test_tuple_subclass(self):
1555 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001556 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 first = (1, 'for the money')
1558 second = (2, 'for the show')
1559 third = (3, 'for the music')
1560 self.assertIs(type(SomeTuple.first), SomeTuple)
1561 self.assertIsInstance(SomeTuple.second, tuple)
1562 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1563 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001564 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001565
1566 def test_duplicate_values_give_unique_enum_items(self):
1567 class AutoNumber(Enum):
1568 first = ()
1569 second = ()
1570 third = ()
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 self.assertEqual(
1579 list(AutoNumber),
1580 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1581 )
1582 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001583 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001584 self.assertIs(AutoNumber(1), AutoNumber.first)
1585
1586 def test_inherited_new_from_enhanced_enum(self):
1587 class AutoNumber(Enum):
1588 def __new__(cls):
1589 value = len(cls.__members__) + 1
1590 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001591 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001592 return obj
1593 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001594 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001595 class Color(AutoNumber):
1596 red = ()
1597 green = ()
1598 blue = ()
1599 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1600 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1601
1602 def test_inherited_new_from_mixed_enum(self):
1603 class AutoNumber(IntEnum):
1604 def __new__(cls):
1605 value = len(cls.__members__) + 1
1606 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001607 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001608 return obj
1609 class Color(AutoNumber):
1610 red = ()
1611 green = ()
1612 blue = ()
1613 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1614 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1615
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001616 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001617 class OrdinaryEnum(Enum):
1618 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001619 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1620 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001621
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001622 def test_ordered_mixin(self):
1623 class OrderedEnum(Enum):
1624 def __ge__(self, other):
1625 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001626 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001627 return NotImplemented
1628 def __gt__(self, other):
1629 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001630 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001631 return NotImplemented
1632 def __le__(self, other):
1633 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001634 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001635 return NotImplemented
1636 def __lt__(self, other):
1637 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001638 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001639 return NotImplemented
1640 class Grade(OrderedEnum):
1641 A = 5
1642 B = 4
1643 C = 3
1644 D = 2
1645 F = 1
1646 self.assertGreater(Grade.A, Grade.B)
1647 self.assertLessEqual(Grade.F, Grade.C)
1648 self.assertLess(Grade.D, Grade.A)
1649 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001650 self.assertEqual(Grade.B, Grade.B)
1651 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001652
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001653 def test_extending2(self):
1654 class Shade(Enum):
1655 def shade(self):
1656 print(self.name)
1657 class Color(Shade):
1658 red = 1
1659 green = 2
1660 blue = 3
1661 with self.assertRaises(TypeError):
1662 class MoreColor(Color):
1663 cyan = 4
1664 magenta = 5
1665 yellow = 6
1666
1667 def test_extending3(self):
1668 class Shade(Enum):
1669 def shade(self):
1670 return self.name
1671 class Color(Shade):
1672 def hex(self):
1673 return '%s hexlified!' % self.value
1674 class MoreColor(Color):
1675 cyan = 4
1676 magenta = 5
1677 yellow = 6
1678 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1679
orlnub1230fb9fad2018-09-12 20:28:53 +03001680 def test_subclass_duplicate_name(self):
1681 class Base(Enum):
1682 def test(self):
1683 pass
1684 class Test(Base):
1685 test = 1
1686 self.assertIs(type(Test.test), Test)
1687
1688 def test_subclass_duplicate_name_dynamic(self):
1689 from types import DynamicClassAttribute
1690 class Base(Enum):
1691 @DynamicClassAttribute
1692 def test(self):
1693 return 'dynamic'
1694 class Test(Base):
1695 test = 1
1696 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001697
1698 def test_no_duplicates(self):
1699 class UniqueEnum(Enum):
1700 def __init__(self, *args):
1701 cls = self.__class__
1702 if any(self.value == e.value for e in cls):
1703 a = self.name
1704 e = cls(self.value).name
1705 raise ValueError(
1706 "aliases not allowed in UniqueEnum: %r --> %r"
1707 % (a, e)
1708 )
1709 class Color(UniqueEnum):
1710 red = 1
1711 green = 2
1712 blue = 3
1713 with self.assertRaises(ValueError):
1714 class Color(UniqueEnum):
1715 red = 1
1716 green = 2
1717 blue = 3
1718 grene = 2
1719
1720 def test_init(self):
1721 class Planet(Enum):
1722 MERCURY = (3.303e+23, 2.4397e6)
1723 VENUS = (4.869e+24, 6.0518e6)
1724 EARTH = (5.976e+24, 6.37814e6)
1725 MARS = (6.421e+23, 3.3972e6)
1726 JUPITER = (1.9e+27, 7.1492e7)
1727 SATURN = (5.688e+26, 6.0268e7)
1728 URANUS = (8.686e+25, 2.5559e7)
1729 NEPTUNE = (1.024e+26, 2.4746e7)
1730 def __init__(self, mass, radius):
1731 self.mass = mass # in kilograms
1732 self.radius = radius # in meters
1733 @property
1734 def surface_gravity(self):
1735 # universal gravitational constant (m3 kg-1 s-2)
1736 G = 6.67300E-11
1737 return G * self.mass / (self.radius * self.radius)
1738 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1739 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1740
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001741 def test_ignore(self):
1742 class Period(timedelta, Enum):
1743 '''
1744 different lengths of time
1745 '''
1746 def __new__(cls, value, period):
1747 obj = timedelta.__new__(cls, value)
1748 obj._value_ = value
1749 obj.period = period
1750 return obj
1751 _ignore_ = 'Period i'
1752 Period = vars()
1753 for i in range(13):
1754 Period['month_%d' % i] = i*30, 'month'
1755 for i in range(53):
1756 Period['week_%d' % i] = i*7, 'week'
1757 for i in range(32):
1758 Period['day_%d' % i] = i, 'day'
1759 OneDay = day_1
1760 OneWeek = week_1
1761 OneMonth = month_1
1762 self.assertFalse(hasattr(Period, '_ignore_'))
1763 self.assertFalse(hasattr(Period, 'Period'))
1764 self.assertFalse(hasattr(Period, 'i'))
1765 self.assertTrue(isinstance(Period.day_1, timedelta))
1766 self.assertTrue(Period.month_1 is Period.day_30)
1767 self.assertTrue(Period.week_4 is Period.day_28)
1768
Ethan Furman2aa27322013-07-19 19:35:56 -07001769 def test_nonhash_value(self):
1770 class AutoNumberInAList(Enum):
1771 def __new__(cls):
1772 value = [len(cls.__members__) + 1]
1773 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001774 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001775 return obj
1776 class ColorInAList(AutoNumberInAList):
1777 red = ()
1778 green = ()
1779 blue = ()
1780 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001781 for enum, value in zip(ColorInAList, range(3)):
1782 value += 1
1783 self.assertEqual(enum.value, [value])
1784 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001785
Ethan Furmanb41803e2013-07-25 13:50:45 -07001786 def test_conflicting_types_resolved_in_new(self):
1787 class LabelledIntEnum(int, Enum):
1788 def __new__(cls, *args):
1789 value, label = args
1790 obj = int.__new__(cls, value)
1791 obj.label = label
1792 obj._value_ = value
1793 return obj
1794
1795 class LabelledList(LabelledIntEnum):
1796 unprocessed = (1, "Unprocessed")
1797 payment_complete = (2, "Payment Complete")
1798
1799 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1800 self.assertEqual(LabelledList.unprocessed, 1)
1801 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001802
Ethan Furmanc16595e2016-09-10 23:36:59 -07001803 def test_auto_number(self):
1804 class Color(Enum):
1805 red = auto()
1806 blue = auto()
1807 green = auto()
1808
1809 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1810 self.assertEqual(Color.red.value, 1)
1811 self.assertEqual(Color.blue.value, 2)
1812 self.assertEqual(Color.green.value, 3)
1813
1814 def test_auto_name(self):
1815 class Color(Enum):
1816 def _generate_next_value_(name, start, count, last):
1817 return name
1818 red = auto()
1819 blue = auto()
1820 green = auto()
1821
1822 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1823 self.assertEqual(Color.red.value, 'red')
1824 self.assertEqual(Color.blue.value, 'blue')
1825 self.assertEqual(Color.green.value, 'green')
1826
1827 def test_auto_name_inherit(self):
1828 class AutoNameEnum(Enum):
1829 def _generate_next_value_(name, start, count, last):
1830 return name
1831 class Color(AutoNameEnum):
1832 red = auto()
1833 blue = auto()
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, 'blue')
1839 self.assertEqual(Color.green.value, 'green')
1840
1841 def test_auto_garbage(self):
1842 class Color(Enum):
1843 red = 'red'
1844 blue = auto()
1845 self.assertEqual(Color.blue.value, 1)
1846
1847 def test_auto_garbage_corrected(self):
1848 class Color(Enum):
1849 red = 'red'
1850 blue = 2
1851 green = auto()
1852
1853 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1854 self.assertEqual(Color.red.value, 'red')
1855 self.assertEqual(Color.blue.value, 2)
1856 self.assertEqual(Color.green.value, 3)
1857
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001858 def test_auto_order(self):
1859 with self.assertRaises(TypeError):
1860 class Color(Enum):
1861 red = auto()
1862 green = auto()
1863 blue = auto()
1864 def _generate_next_value_(name, start, count, last):
1865 return name
1866
Ethan Furmanfc23a942020-09-16 12:37:54 -07001867 def test_auto_order_wierd(self):
1868 weird_auto = auto()
1869 weird_auto.value = 'pathological case'
1870 class Color(Enum):
1871 red = weird_auto
1872 def _generate_next_value_(name, start, count, last):
1873 return name
1874 blue = auto()
1875 self.assertEqual(list(Color), [Color.red, Color.blue])
1876 self.assertEqual(Color.red.value, 'pathological case')
1877 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001878
Ethan Furman3515dcc2016-09-18 13:15:41 -07001879 def test_duplicate_auto(self):
1880 class Dupes(Enum):
1881 first = primero = auto()
1882 second = auto()
1883 third = auto()
1884 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1885
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001886 def test_default_missing(self):
1887 class Color(Enum):
1888 RED = 1
1889 GREEN = 2
1890 BLUE = 3
1891 try:
1892 Color(7)
1893 except ValueError as exc:
1894 self.assertTrue(exc.__context__ is None)
1895 else:
1896 raise Exception('Exception not raised.')
1897
Ethan Furman019f0a02018-09-12 11:43:34 -07001898 def test_missing(self):
1899 class Color(Enum):
1900 red = 1
1901 green = 2
1902 blue = 3
1903 @classmethod
1904 def _missing_(cls, item):
1905 if item == 'three':
1906 return cls.blue
1907 elif item == 'bad return':
1908 # trigger internal error
1909 return 5
1910 elif item == 'error out':
1911 raise ZeroDivisionError
1912 else:
1913 # trigger not found
1914 return None
1915 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001916 try:
1917 Color(7)
1918 except ValueError as exc:
1919 self.assertTrue(exc.__context__ is None)
1920 else:
1921 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001922 try:
1923 Color('bad return')
1924 except TypeError as exc:
1925 self.assertTrue(isinstance(exc.__context__, ValueError))
1926 else:
1927 raise Exception('Exception not raised.')
1928 try:
1929 Color('error out')
1930 except ZeroDivisionError as exc:
1931 self.assertTrue(isinstance(exc.__context__, ValueError))
1932 else:
1933 raise Exception('Exception not raised.')
1934
Ethan Furman5bdab642018-09-21 19:03:09 -07001935 def test_multiple_mixin(self):
1936 class MaxMixin:
1937 @classproperty
1938 def MAX(cls):
1939 max = len(cls)
1940 cls.MAX = max
1941 return max
1942 class StrMixin:
1943 def __str__(self):
1944 return self._name_.lower()
1945 class SomeEnum(Enum):
1946 def behavior(self):
1947 return 'booyah'
1948 class AnotherEnum(Enum):
1949 def behavior(self):
1950 return 'nuhuh!'
1951 def social(self):
1952 return "what's up?"
1953 class Color(MaxMixin, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(Color.RED.value, 1)
1958 self.assertEqual(Color.GREEN.value, 2)
1959 self.assertEqual(Color.BLUE.value, 3)
1960 self.assertEqual(Color.MAX, 3)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07001961 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07001962 class Color(MaxMixin, StrMixin, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(Color.RED.value, 1)
1967 self.assertEqual(Color.GREEN.value, 2)
1968 self.assertEqual(Color.BLUE.value, 3)
1969 self.assertEqual(Color.MAX, 3)
1970 self.assertEqual(str(Color.BLUE), 'blue')
1971 class Color(StrMixin, MaxMixin, Enum):
1972 RED = auto()
1973 GREEN = auto()
1974 BLUE = auto()
1975 self.assertEqual(Color.RED.value, 1)
1976 self.assertEqual(Color.GREEN.value, 2)
1977 self.assertEqual(Color.BLUE.value, 3)
1978 self.assertEqual(Color.MAX, 3)
1979 self.assertEqual(str(Color.BLUE), 'blue')
1980 class CoolColor(StrMixin, SomeEnum, Enum):
1981 RED = auto()
1982 GREEN = auto()
1983 BLUE = auto()
1984 self.assertEqual(CoolColor.RED.value, 1)
1985 self.assertEqual(CoolColor.GREEN.value, 2)
1986 self.assertEqual(CoolColor.BLUE.value, 3)
1987 self.assertEqual(str(CoolColor.BLUE), 'blue')
1988 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1989 class CoolerColor(StrMixin, AnotherEnum, Enum):
1990 RED = auto()
1991 GREEN = auto()
1992 BLUE = auto()
1993 self.assertEqual(CoolerColor.RED.value, 1)
1994 self.assertEqual(CoolerColor.GREEN.value, 2)
1995 self.assertEqual(CoolerColor.BLUE.value, 3)
1996 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1997 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1998 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1999 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
2000 RED = auto()
2001 GREEN = auto()
2002 BLUE = auto()
2003 self.assertEqual(CoolestColor.RED.value, 1)
2004 self.assertEqual(CoolestColor.GREEN.value, 2)
2005 self.assertEqual(CoolestColor.BLUE.value, 3)
2006 self.assertEqual(str(CoolestColor.BLUE), 'blue')
2007 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
2008 self.assertEqual(CoolestColor.RED.social(), "what's up?")
2009 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
2010 RED = auto()
2011 GREEN = auto()
2012 BLUE = auto()
2013 self.assertEqual(ConfusedColor.RED.value, 1)
2014 self.assertEqual(ConfusedColor.GREEN.value, 2)
2015 self.assertEqual(ConfusedColor.BLUE.value, 3)
2016 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
2017 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2018 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2019 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2020 RED = auto()
2021 GREEN = auto()
2022 BLUE = auto()
2023 self.assertEqual(ReformedColor.RED.value, 1)
2024 self.assertEqual(ReformedColor.GREEN.value, 2)
2025 self.assertEqual(ReformedColor.BLUE.value, 3)
2026 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2027 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2028 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2029 self.assertTrue(issubclass(ReformedColor, int))
2030
Ethan Furmancd453852018-10-05 23:29:36 -07002031 def test_multiple_inherited_mixin(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002032 class StrEnum(str, Enum):
2033 def __new__(cls, *args, **kwargs):
2034 for a in args:
2035 if not isinstance(a, str):
2036 raise TypeError("Enumeration '%s' (%s) is not"
2037 " a string" % (a, type(a).__name__))
2038 return str.__new__(cls, *args, **kwargs)
Ethan Furmancd453852018-10-05 23:29:36 -07002039 @unique
2040 class Decision1(StrEnum):
2041 REVERT = "REVERT"
2042 REVERT_ALL = "REVERT_ALL"
2043 RETRY = "RETRY"
2044 class MyEnum(StrEnum):
2045 pass
2046 @unique
2047 class Decision2(MyEnum):
2048 REVERT = "REVERT"
2049 REVERT_ALL = "REVERT_ALL"
2050 RETRY = "RETRY"
2051
Ethan Furmanc2667362020-12-07 00:17:31 -08002052 def test_multiple_mixin_inherited(self):
2053 class MyInt(int):
2054 def __new__(cls, value):
2055 return super().__new__(cls, value)
2056
2057 class HexMixin:
2058 def __repr__(self):
2059 return hex(self)
2060
2061 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2062 pass
2063
2064 class Foo(MyIntEnum):
2065 TEST = 1
2066 self.assertTrue(isinstance(Foo.TEST, MyInt))
2067 self.assertEqual(repr(Foo.TEST), "0x1")
2068
2069 class Fee(MyIntEnum):
2070 TEST = 1
2071 def __new__(cls, value):
2072 value += 1
2073 member = int.__new__(cls, value)
2074 member._value_ = value
2075 return member
2076 self.assertEqual(Fee.TEST, 2)
2077
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002078 def test_empty_globals(self):
2079 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2080 # when using compile and exec because f_globals is empty
2081 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2082 code = compile(code, "<string>", "exec")
2083 global_ns = {}
2084 local_ls = {}
2085 exec(code, global_ns, local_ls)
2086
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002087 @unittest.skipUnless(
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002088 sys.version_info[:2] == (3, 9),
Ethan Furman7cf0aad2020-12-09 17:12:11 -08002089 'private variables are now normal attributes',
2090 )
2091 def test_warning_for_private_variables(self):
2092 with self.assertWarns(DeprecationWarning):
2093 class Private(Enum):
2094 __corporal = 'Radar'
2095 self.assertEqual(Private._Private__corporal.value, 'Radar')
2096 try:
2097 with self.assertWarns(DeprecationWarning):
2098 class Private(Enum):
2099 __major_ = 'Hoolihan'
2100 except ValueError:
2101 pass
2102
Ethan Furmana6582872020-12-10 13:07:00 -08002103
Ethan Furmane8e61272016-08-20 07:19:31 -07002104class TestOrder(unittest.TestCase):
2105
2106 def test_same_members(self):
2107 class Color(Enum):
2108 _order_ = 'red green blue'
2109 red = 1
2110 green = 2
2111 blue = 3
2112
2113 def test_same_members_with_aliases(self):
2114 class Color(Enum):
2115 _order_ = 'red green blue'
2116 red = 1
2117 green = 2
2118 blue = 3
2119 verde = green
2120
2121 def test_same_members_wrong_order(self):
2122 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2123 class Color(Enum):
2124 _order_ = 'red green blue'
2125 red = 1
2126 blue = 3
2127 green = 2
2128
2129 def test_order_has_extra_members(self):
2130 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2131 class Color(Enum):
2132 _order_ = 'red green blue purple'
2133 red = 1
2134 green = 2
2135 blue = 3
2136
2137 def test_order_has_extra_members_with_aliases(self):
2138 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2139 class Color(Enum):
2140 _order_ = 'red green blue purple'
2141 red = 1
2142 green = 2
2143 blue = 3
2144 verde = green
2145
2146 def test_enum_has_extra_members(self):
2147 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2148 class Color(Enum):
2149 _order_ = 'red green blue'
2150 red = 1
2151 green = 2
2152 blue = 3
2153 purple = 4
2154
2155 def test_enum_has_extra_members_with_aliases(self):
2156 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2157 class Color(Enum):
2158 _order_ = 'red green blue'
2159 red = 1
2160 green = 2
2161 blue = 3
2162 purple = 4
2163 verde = green
2164
2165
Ethan Furman65a5a472016-09-01 23:55:19 -07002166class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002167 """Tests of the Flags."""
2168
Ethan Furman65a5a472016-09-01 23:55:19 -07002169 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002170 R, W, X = 4, 2, 1
2171
Ethan Furman65a5a472016-09-01 23:55:19 -07002172 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002173 RO = 0
2174 WO = 1
2175 RW = 2
2176 AC = 3
2177 CE = 1<<19
2178
Rahul Jha94306522018-09-10 23:51:04 +05302179 class Color(Flag):
2180 BLACK = 0
2181 RED = 1
2182 GREEN = 2
2183 BLUE = 4
2184 PURPLE = RED|BLUE
2185
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002186 def test_str(self):
2187 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002188 self.assertEqual(str(Perm.R), 'Perm.R')
2189 self.assertEqual(str(Perm.W), 'Perm.W')
2190 self.assertEqual(str(Perm.X), 'Perm.X')
2191 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2192 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2193 self.assertEqual(str(Perm(0)), 'Perm.0')
2194 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2195 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2196 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2197 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2198 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2199 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002200
2201 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002202 self.assertEqual(str(Open.RO), 'Open.RO')
2203 self.assertEqual(str(Open.WO), 'Open.WO')
2204 self.assertEqual(str(Open.AC), 'Open.AC')
2205 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2206 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2207 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2208 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2209 self.assertEqual(str(~Open.AC), 'Open.CE')
2210 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2211 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002212
2213 def test_repr(self):
2214 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002215 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2216 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2217 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2218 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2219 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2220 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2221 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2222 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2223 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2224 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
2225 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
2226 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002227
2228 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002229 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2230 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2231 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2232 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2233 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2234 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
2235 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2236 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2237 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2238 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002239
Ethan Furman37440ee2020-12-08 11:14:10 -08002240 def test_format(self):
2241 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002242 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2243 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
Ethan Furman37440ee2020-12-08 11:14:10 -08002244
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002245 def test_or(self):
2246 Perm = self.Perm
2247 for i in Perm:
2248 for j in Perm:
2249 self.assertEqual((i | j), Perm(i.value | j.value))
2250 self.assertEqual((i | j).value, i.value | j.value)
2251 self.assertIs(type(i | j), Perm)
2252 for i in Perm:
2253 self.assertIs(i | i, i)
2254 Open = self.Open
2255 self.assertIs(Open.RO | Open.CE, Open.CE)
2256
2257 def test_and(self):
2258 Perm = self.Perm
2259 RW = Perm.R | Perm.W
2260 RX = Perm.R | Perm.X
2261 WX = Perm.W | Perm.X
2262 RWX = Perm.R | Perm.W | Perm.X
2263 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2264 for i in values:
2265 for j in values:
2266 self.assertEqual((i & j).value, i.value & j.value)
2267 self.assertIs(type(i & j), Perm)
2268 for i in Perm:
2269 self.assertIs(i & i, i)
2270 self.assertIs(i & RWX, i)
2271 self.assertIs(RWX & i, i)
2272 Open = self.Open
2273 self.assertIs(Open.RO & Open.CE, Open.RO)
2274
2275 def test_xor(self):
2276 Perm = self.Perm
2277 for i in Perm:
2278 for j in Perm:
2279 self.assertEqual((i ^ j).value, i.value ^ j.value)
2280 self.assertIs(type(i ^ j), Perm)
2281 for i in Perm:
2282 self.assertIs(i ^ Perm(0), i)
2283 self.assertIs(Perm(0) ^ i, i)
2284 Open = self.Open
2285 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2286 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2287
2288 def test_invert(self):
2289 Perm = self.Perm
2290 RW = Perm.R | Perm.W
2291 RX = Perm.R | Perm.X
2292 WX = Perm.W | Perm.X
2293 RWX = Perm.R | Perm.W | Perm.X
2294 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2295 for i in values:
2296 self.assertIs(type(~i), Perm)
2297 self.assertEqual(~~i, i)
2298 for i in Perm:
2299 self.assertIs(~~i, i)
2300 Open = self.Open
2301 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2302 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2303
Ethan Furman25d94bb2016-09-02 16:32:32 -07002304 def test_bool(self):
2305 Perm = self.Perm
2306 for f in Perm:
2307 self.assertTrue(f)
2308 Open = self.Open
2309 for f in Open:
2310 self.assertEqual(bool(f.value), bool(f))
2311
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002312 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002313 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002314 lst = list(Perm)
2315 self.assertEqual(len(lst), len(Perm))
2316 self.assertEqual(len(Perm), 3, Perm)
2317 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2318 for i, n in enumerate('R W X'.split()):
2319 v = 1<<i
2320 e = Perm(v)
2321 self.assertEqual(e.value, v)
2322 self.assertEqual(type(e.value), int)
2323 self.assertEqual(e.name, n)
2324 self.assertIn(e, Perm)
2325 self.assertIs(type(e), Perm)
2326
2327 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002328 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002329 lst = list(Perm)
2330 self.assertEqual(len(lst), len(Perm))
2331 self.assertEqual(len(Perm), 3, Perm)
2332 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2333 for i, n in enumerate('R W X'.split()):
2334 v = 8<<i
2335 e = Perm(v)
2336 self.assertEqual(e.value, v)
2337 self.assertEqual(type(e.value), int)
2338 self.assertEqual(e.name, n)
2339 self.assertIn(e, Perm)
2340 self.assertIs(type(e), Perm)
2341
2342 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002343 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002344 lst = list(Perm)
2345 self.assertEqual(len(lst), len(Perm))
2346 self.assertEqual(len(Perm), 3, Perm)
2347 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2348 for i, n in enumerate('R W X'.split()):
2349 v = 1<<i
2350 e = Perm(v)
2351 self.assertEqual(e.value, v)
2352 self.assertEqual(type(e.value), int)
2353 self.assertEqual(e.name, n)
2354 self.assertIn(e, Perm)
2355 self.assertIs(type(e), Perm)
2356
2357 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002358 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002359 lst = list(Perm)
2360 self.assertEqual(len(lst), len(Perm))
2361 self.assertEqual(len(Perm), 3, Perm)
2362 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2363 for i, n in enumerate('R W X'.split()):
2364 v = 1<<(2*i+1)
2365 e = Perm(v)
2366 self.assertEqual(e.value, v)
2367 self.assertEqual(type(e.value), int)
2368 self.assertEqual(e.name, n)
2369 self.assertIn(e, Perm)
2370 self.assertIs(type(e), Perm)
2371
2372 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002373 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002374 lst = list(Perm)
2375 self.assertEqual(len(lst), len(Perm))
2376 self.assertEqual(len(Perm), 3, Perm)
2377 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2378 for i, n in enumerate('R W X'.split()):
2379 v = 1<<(2*i+1)
2380 e = Perm(v)
2381 self.assertEqual(e.value, v)
2382 self.assertEqual(type(e.value), int)
2383 self.assertEqual(e.name, n)
2384 self.assertIn(e, Perm)
2385 self.assertIs(type(e), Perm)
2386
Ethan Furman65a5a472016-09-01 23:55:19 -07002387 def test_pickle(self):
2388 if isinstance(FlagStooges, Exception):
2389 raise FlagStooges
2390 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2391 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002392
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002393 def test_contains(self):
Rahul Jha94306522018-09-10 23:51:04 +05302394 Open = self.Open
2395 Color = self.Color
2396 self.assertFalse(Color.BLACK in Open)
2397 self.assertFalse(Open.RO in Color)
2398 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002399 'BLACK' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302400 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002401 'RO' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302402 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002403 1 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302404 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002405 1 in Open
Rahul Jha94306522018-09-10 23:51:04 +05302406
2407 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002408 Perm = self.Perm
2409 R, W, X = Perm
2410 RW = R | W
2411 RX = R | X
2412 WX = W | X
2413 RWX = R | W | X
2414 self.assertTrue(R in RW)
2415 self.assertTrue(R in RX)
2416 self.assertTrue(R in RWX)
2417 self.assertTrue(W in RW)
2418 self.assertTrue(W in WX)
2419 self.assertTrue(W in RWX)
2420 self.assertTrue(X in RX)
2421 self.assertTrue(X in WX)
2422 self.assertTrue(X in RWX)
2423 self.assertFalse(R in WX)
2424 self.assertFalse(W in RX)
2425 self.assertFalse(X in RW)
2426
Ethan Furmanc16595e2016-09-10 23:36:59 -07002427 def test_auto_number(self):
2428 class Color(Flag):
2429 red = auto()
2430 blue = auto()
2431 green = auto()
2432
2433 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2434 self.assertEqual(Color.red.value, 1)
2435 self.assertEqual(Color.blue.value, 2)
2436 self.assertEqual(Color.green.value, 4)
2437
2438 def test_auto_number_garbage(self):
2439 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2440 class Color(Flag):
2441 red = 'not an int'
2442 blue = auto()
2443
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002444 def test_cascading_failure(self):
2445 class Bizarre(Flag):
2446 c = 3
2447 d = 4
2448 f = 6
2449 # Bizarre.c | Bizarre.d
2450 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2451 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2452 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2453 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2454 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2455 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2456 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2457
Ethan Furman3515dcc2016-09-18 13:15:41 -07002458 def test_duplicate_auto(self):
2459 class Dupes(Enum):
2460 first = primero = auto()
2461 second = auto()
2462 third = auto()
2463 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2464
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002465 def test_bizarre(self):
2466 class Bizarre(Flag):
2467 b = 3
2468 c = 4
2469 d = 6
2470 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2471
Ethan Furman5bdab642018-09-21 19:03:09 -07002472 def test_multiple_mixin(self):
2473 class AllMixin:
2474 @classproperty
2475 def ALL(cls):
2476 members = list(cls)
2477 all_value = None
2478 if members:
2479 all_value = members[0]
2480 for member in members[1:]:
2481 all_value |= member
2482 cls.ALL = all_value
2483 return all_value
2484 class StrMixin:
2485 def __str__(self):
2486 return self._name_.lower()
2487 class Color(AllMixin, Flag):
2488 RED = auto()
2489 GREEN = auto()
2490 BLUE = auto()
2491 self.assertEqual(Color.RED.value, 1)
2492 self.assertEqual(Color.GREEN.value, 2)
2493 self.assertEqual(Color.BLUE.value, 4)
2494 self.assertEqual(Color.ALL.value, 7)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002495 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002496 class Color(AllMixin, StrMixin, Flag):
2497 RED = auto()
2498 GREEN = auto()
2499 BLUE = auto()
2500 self.assertEqual(Color.RED.value, 1)
2501 self.assertEqual(Color.GREEN.value, 2)
2502 self.assertEqual(Color.BLUE.value, 4)
2503 self.assertEqual(Color.ALL.value, 7)
2504 self.assertEqual(str(Color.BLUE), 'blue')
2505 class Color(StrMixin, AllMixin, Flag):
2506 RED = auto()
2507 GREEN = auto()
2508 BLUE = auto()
2509 self.assertEqual(Color.RED.value, 1)
2510 self.assertEqual(Color.GREEN.value, 2)
2511 self.assertEqual(Color.BLUE.value, 4)
2512 self.assertEqual(Color.ALL.value, 7)
2513 self.assertEqual(str(Color.BLUE), 'blue')
2514
Hai Shie80697d2020-05-28 06:10:27 +08002515 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002516 def test_unique_composite(self):
2517 # override __eq__ to be identity only
2518 class TestFlag(Flag):
2519 one = auto()
2520 two = auto()
2521 three = auto()
2522 four = auto()
2523 five = auto()
2524 six = auto()
2525 seven = auto()
2526 eight = auto()
2527 def __eq__(self, other):
2528 return self is other
2529 def __hash__(self):
2530 return hash(self._value_)
2531 # have multiple threads competing to complete the composite members
2532 seen = set()
2533 failed = False
2534 def cycle_enum():
2535 nonlocal failed
2536 try:
2537 for i in range(256):
2538 seen.add(TestFlag(i))
2539 except Exception:
2540 failed = True
2541 threads = [
2542 threading.Thread(target=cycle_enum)
2543 for _ in range(8)
2544 ]
Hai Shie80697d2020-05-28 06:10:27 +08002545 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002546 pass
2547 # check that only 248 members were created
2548 self.assertFalse(
2549 failed,
2550 'at least one thread failed while creating composite members')
2551 self.assertEqual(256, len(seen), 'too many composite members created')
2552
Ethan Furman6bd94de2020-12-09 16:41:22 -08002553 def test_init_subclass(self):
2554 class MyEnum(Flag):
2555 def __init_subclass__(cls, **kwds):
2556 super().__init_subclass__(**kwds)
2557 self.assertFalse(cls.__dict__.get('_test', False))
2558 cls._test1 = 'MyEnum'
2559 #
2560 class TheirEnum(MyEnum):
2561 def __init_subclass__(cls, **kwds):
2562 super(TheirEnum, cls).__init_subclass__(**kwds)
2563 cls._test2 = 'TheirEnum'
2564 class WhoseEnum(TheirEnum):
2565 def __init_subclass__(cls, **kwds):
2566 pass
2567 class NoEnum(WhoseEnum):
2568 ONE = 1
2569 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
2570 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
2571 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
2572 self.assertFalse(NoEnum.__dict__.get('_test1', False))
2573 self.assertFalse(NoEnum.__dict__.get('_test2', False))
2574 #
2575 class OurEnum(MyEnum):
2576 def __init_subclass__(cls, **kwds):
2577 cls._test2 = 'OurEnum'
2578 class WhereEnum(OurEnum):
2579 def __init_subclass__(cls, **kwds):
2580 pass
2581 class NeverEnum(WhereEnum):
2582 ONE = 1
2583 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
2584 self.assertFalse(WhereEnum.__dict__.get('_test1', False))
2585 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
2586 self.assertFalse(NeverEnum.__dict__.get('_test1', False))
2587 self.assertFalse(NeverEnum.__dict__.get('_test2', False))
2588
Ethan Furmanc16595e2016-09-10 23:36:59 -07002589
Ethan Furman65a5a472016-09-01 23:55:19 -07002590class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002591 """Tests of the IntFlags."""
2592
Ethan Furman65a5a472016-09-01 23:55:19 -07002593 class Perm(IntFlag):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002594 X = 1 << 0
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002595 W = 1 << 1
2596 R = 1 << 2
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002597
Ethan Furman65a5a472016-09-01 23:55:19 -07002598 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002599 RO = 0
2600 WO = 1
2601 RW = 2
2602 AC = 3
2603 CE = 1<<19
2604
Rahul Jha94306522018-09-10 23:51:04 +05302605 class Color(IntFlag):
2606 BLACK = 0
2607 RED = 1
2608 GREEN = 2
2609 BLUE = 4
2610 PURPLE = RED|BLUE
2611
Ethan Furman3515dcc2016-09-18 13:15:41 -07002612 def test_type(self):
2613 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002614 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002615 Open = self.Open
2616 for f in Perm:
2617 self.assertTrue(isinstance(f, Perm))
2618 self.assertEqual(f, f.value)
2619 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2620 self.assertEqual(Perm.W | Perm.X, 3)
2621 for f in Open:
2622 self.assertTrue(isinstance(f, Open))
2623 self.assertEqual(f, f.value)
2624 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2625 self.assertEqual(Open.WO | Open.RW, 3)
2626
2627
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002628 def test_str(self):
2629 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002630 self.assertEqual(str(Perm.R), 'Perm.R')
2631 self.assertEqual(str(Perm.W), 'Perm.W')
2632 self.assertEqual(str(Perm.X), 'Perm.X')
2633 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2634 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2635 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2636 self.assertEqual(str(Perm(0)), 'Perm.0')
2637 self.assertEqual(str(Perm(8)), 'Perm.8')
2638 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2639 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2640 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2641 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2642 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
2643 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2644 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2645 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002646
2647 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002648 self.assertEqual(str(Open.RO), 'Open.RO')
2649 self.assertEqual(str(Open.WO), 'Open.WO')
2650 self.assertEqual(str(Open.AC), 'Open.AC')
2651 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2652 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2653 self.assertEqual(str(Open(4)), 'Open.4')
2654 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2655 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2656 self.assertEqual(str(~Open.AC), 'Open.CE')
2657 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2658 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2659 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002660
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002661 def test_repr(self):
2662 Perm = self.Perm
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002663 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2664 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2665 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2666 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2667 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2668 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
2669 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2670 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
2671 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2672 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2673 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2674 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
2675 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
2676 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2677 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2678 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002679
2680 Open = self.Open
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002681 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2682 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2683 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2684 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2685 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
2686 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
2687 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2688 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2689 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2690 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2691 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2692 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08002693
Ethan Furman37440ee2020-12-08 11:14:10 -08002694 def test_format(self):
Ethan Furman1b4addf2021-06-18 14:25:42 -07002695 Perm = self.Perm
2696 self.assertEqual(format(Perm.R, ''), '4')
2697 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
Ethan Furman37440ee2020-12-08 11:14:10 -08002698
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002699 def test_or(self):
2700 Perm = self.Perm
2701 for i in Perm:
2702 for j in Perm:
2703 self.assertEqual(i | j, i.value | j.value)
2704 self.assertEqual((i | j).value, i.value | j.value)
2705 self.assertIs(type(i | j), Perm)
2706 for j in range(8):
2707 self.assertEqual(i | j, i.value | j)
2708 self.assertEqual((i | j).value, i.value | j)
2709 self.assertIs(type(i | j), Perm)
2710 self.assertEqual(j | i, j | i.value)
2711 self.assertEqual((j | i).value, j | i.value)
2712 self.assertIs(type(j | i), Perm)
2713 for i in Perm:
2714 self.assertIs(i | i, i)
2715 self.assertIs(i | 0, i)
2716 self.assertIs(0 | i, i)
2717 Open = self.Open
2718 self.assertIs(Open.RO | Open.CE, Open.CE)
2719
2720 def test_and(self):
2721 Perm = self.Perm
2722 RW = Perm.R | Perm.W
2723 RX = Perm.R | Perm.X
2724 WX = Perm.W | Perm.X
2725 RWX = Perm.R | Perm.W | Perm.X
2726 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2727 for i in values:
2728 for j in values:
2729 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2730 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2731 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2732 for j in range(8):
2733 self.assertEqual(i & j, i.value & j)
2734 self.assertEqual((i & j).value, i.value & j)
2735 self.assertIs(type(i & j), Perm)
2736 self.assertEqual(j & i, j & i.value)
2737 self.assertEqual((j & i).value, j & i.value)
2738 self.assertIs(type(j & i), Perm)
2739 for i in Perm:
2740 self.assertIs(i & i, i)
2741 self.assertIs(i & 7, i)
2742 self.assertIs(7 & i, i)
2743 Open = self.Open
2744 self.assertIs(Open.RO & Open.CE, Open.RO)
2745
2746 def test_xor(self):
2747 Perm = self.Perm
2748 for i in Perm:
2749 for j in Perm:
2750 self.assertEqual(i ^ j, i.value ^ j.value)
2751 self.assertEqual((i ^ j).value, i.value ^ j.value)
2752 self.assertIs(type(i ^ j), Perm)
2753 for j in range(8):
2754 self.assertEqual(i ^ j, i.value ^ j)
2755 self.assertEqual((i ^ j).value, i.value ^ j)
2756 self.assertIs(type(i ^ j), Perm)
2757 self.assertEqual(j ^ i, j ^ i.value)
2758 self.assertEqual((j ^ i).value, j ^ i.value)
2759 self.assertIs(type(j ^ i), Perm)
2760 for i in Perm:
2761 self.assertIs(i ^ 0, i)
2762 self.assertIs(0 ^ i, i)
2763 Open = self.Open
2764 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2765 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2766
2767 def test_invert(self):
2768 Perm = self.Perm
2769 RW = Perm.R | Perm.W
2770 RX = Perm.R | Perm.X
2771 WX = Perm.W | Perm.X
2772 RWX = Perm.R | Perm.W | Perm.X
2773 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2774 for i in values:
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002775 self.assertEqual(~i, ~i.value)
2776 self.assertEqual((~i).value, ~i.value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002777 self.assertIs(type(~i), Perm)
2778 self.assertEqual(~~i, i)
2779 for i in Perm:
2780 self.assertIs(~~i, i)
2781 Open = self.Open
2782 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2783 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2784
2785 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002786 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002787 lst = list(Perm)
2788 self.assertEqual(len(lst), len(Perm))
2789 self.assertEqual(len(Perm), 3, Perm)
2790 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2791 for i, n in enumerate('R W X'.split()):
2792 v = 1<<i
2793 e = Perm(v)
2794 self.assertEqual(e.value, v)
2795 self.assertEqual(type(e.value), int)
2796 self.assertEqual(e, v)
2797 self.assertEqual(e.name, n)
2798 self.assertIn(e, Perm)
2799 self.assertIs(type(e), Perm)
2800
2801 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002802 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002803 lst = list(Perm)
2804 self.assertEqual(len(lst), len(Perm))
2805 self.assertEqual(len(Perm), 3, Perm)
2806 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2807 for i, n in enumerate('R W X'.split()):
2808 v = 8<<i
2809 e = Perm(v)
2810 self.assertEqual(e.value, v)
2811 self.assertEqual(type(e.value), int)
2812 self.assertEqual(e, v)
2813 self.assertEqual(e.name, n)
2814 self.assertIn(e, Perm)
2815 self.assertIs(type(e), Perm)
2816
2817 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002818 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002819 lst = list(Perm)
2820 self.assertEqual(len(lst), len(Perm))
2821 self.assertEqual(len(Perm), 3, Perm)
2822 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2823 for i, n in enumerate('R W X'.split()):
2824 v = 1<<i
2825 e = Perm(v)
2826 self.assertEqual(e.value, v)
2827 self.assertEqual(type(e.value), int)
2828 self.assertEqual(e, v)
2829 self.assertEqual(e.name, n)
2830 self.assertIn(e, Perm)
2831 self.assertIs(type(e), Perm)
2832
2833 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002834 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002835 lst = list(Perm)
2836 self.assertEqual(len(lst), len(Perm))
2837 self.assertEqual(len(Perm), 3, Perm)
2838 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2839 for i, n in enumerate('R W X'.split()):
2840 v = 1<<(2*i+1)
2841 e = Perm(v)
2842 self.assertEqual(e.value, v)
2843 self.assertEqual(type(e.value), int)
2844 self.assertEqual(e, v)
2845 self.assertEqual(e.name, n)
2846 self.assertIn(e, Perm)
2847 self.assertIs(type(e), Perm)
2848
2849 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002850 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002851 lst = list(Perm)
2852 self.assertEqual(len(lst), len(Perm))
2853 self.assertEqual(len(Perm), 3, Perm)
2854 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2855 for i, n in enumerate('R W X'.split()):
2856 v = 1<<(2*i+1)
2857 e = Perm(v)
2858 self.assertEqual(e.value, v)
2859 self.assertEqual(type(e.value), int)
2860 self.assertEqual(e, v)
2861 self.assertEqual(e.name, n)
2862 self.assertIn(e, Perm)
2863 self.assertIs(type(e), Perm)
2864
2865
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002866 def test_programatic_function_from_empty_list(self):
2867 Perm = enum.IntFlag('Perm', [])
2868 lst = list(Perm)
2869 self.assertEqual(len(lst), len(Perm))
2870 self.assertEqual(len(Perm), 0, Perm)
2871 Thing = enum.Enum('Thing', [])
2872 lst = list(Thing)
2873 self.assertEqual(len(lst), len(Thing))
2874 self.assertEqual(len(Thing), 0, Thing)
2875
2876
2877 def test_programatic_function_from_empty_tuple(self):
2878 Perm = enum.IntFlag('Perm', ())
2879 lst = list(Perm)
2880 self.assertEqual(len(lst), len(Perm))
2881 self.assertEqual(len(Perm), 0, Perm)
2882 Thing = enum.Enum('Thing', ())
2883 self.assertEqual(len(lst), len(Thing))
2884 self.assertEqual(len(Thing), 0, Thing)
2885
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002886 def test_contains(self):
Rahul Jha94306522018-09-10 23:51:04 +05302887 Open = self.Open
2888 Color = self.Color
2889 self.assertTrue(Color.GREEN in Color)
2890 self.assertTrue(Open.RW in Open)
2891 self.assertFalse(Color.GREEN in Open)
2892 self.assertFalse(Open.RW in Color)
2893 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002894 'GREEN' in Color
Rahul Jha94306522018-09-10 23:51:04 +05302895 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002896 'RW' in Open
Rahul Jha94306522018-09-10 23:51:04 +05302897 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002898 2 in Color
Rahul Jha94306522018-09-10 23:51:04 +05302899 with self.assertRaises(TypeError):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002900 2 in Open
Rahul Jha94306522018-09-10 23:51:04 +05302901
2902 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002903 Perm = self.Perm
2904 R, W, X = Perm
2905 RW = R | W
2906 RX = R | X
2907 WX = W | X
2908 RWX = R | W | X
2909 self.assertTrue(R in RW)
2910 self.assertTrue(R in RX)
2911 self.assertTrue(R in RWX)
2912 self.assertTrue(W in RW)
2913 self.assertTrue(W in WX)
2914 self.assertTrue(W in RWX)
2915 self.assertTrue(X in RX)
2916 self.assertTrue(X in WX)
2917 self.assertTrue(X in RWX)
2918 self.assertFalse(R in WX)
2919 self.assertFalse(W in RX)
2920 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302921 with self.assertRaises(TypeError):
2922 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002923
Ethan Furman25d94bb2016-09-02 16:32:32 -07002924 def test_bool(self):
2925 Perm = self.Perm
2926 for f in Perm:
2927 self.assertTrue(f)
2928 Open = self.Open
2929 for f in Open:
2930 self.assertEqual(bool(f.value), bool(f))
2931
Ethan Furman5bdab642018-09-21 19:03:09 -07002932 def test_multiple_mixin(self):
2933 class AllMixin:
2934 @classproperty
2935 def ALL(cls):
2936 members = list(cls)
2937 all_value = None
2938 if members:
2939 all_value = members[0]
2940 for member in members[1:]:
2941 all_value |= member
2942 cls.ALL = all_value
2943 return all_value
2944 class StrMixin:
2945 def __str__(self):
2946 return self._name_.lower()
2947 class Color(AllMixin, IntFlag):
2948 RED = auto()
2949 GREEN = auto()
2950 BLUE = auto()
2951 self.assertEqual(Color.RED.value, 1)
2952 self.assertEqual(Color.GREEN.value, 2)
2953 self.assertEqual(Color.BLUE.value, 4)
2954 self.assertEqual(Color.ALL.value, 7)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07002955 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
Ethan Furman5bdab642018-09-21 19:03:09 -07002956 class Color(AllMixin, StrMixin, IntFlag):
2957 RED = auto()
2958 GREEN = auto()
2959 BLUE = auto()
2960 self.assertEqual(Color.RED.value, 1)
2961 self.assertEqual(Color.GREEN.value, 2)
2962 self.assertEqual(Color.BLUE.value, 4)
2963 self.assertEqual(Color.ALL.value, 7)
2964 self.assertEqual(str(Color.BLUE), 'blue')
2965 class Color(StrMixin, AllMixin, IntFlag):
2966 RED = auto()
2967 GREEN = auto()
2968 BLUE = auto()
2969 self.assertEqual(Color.RED.value, 1)
2970 self.assertEqual(Color.GREEN.value, 2)
2971 self.assertEqual(Color.BLUE.value, 4)
2972 self.assertEqual(Color.ALL.value, 7)
2973 self.assertEqual(str(Color.BLUE), 'blue')
2974
Hai Shie80697d2020-05-28 06:10:27 +08002975 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002976 def test_unique_composite(self):
2977 # override __eq__ to be identity only
2978 class TestFlag(IntFlag):
2979 one = auto()
2980 two = auto()
2981 three = auto()
2982 four = auto()
2983 five = auto()
2984 six = auto()
2985 seven = auto()
2986 eight = auto()
2987 def __eq__(self, other):
2988 return self is other
2989 def __hash__(self):
2990 return hash(self._value_)
2991 # have multiple threads competing to complete the composite members
2992 seen = set()
2993 failed = False
2994 def cycle_enum():
2995 nonlocal failed
2996 try:
2997 for i in range(256):
2998 seen.add(TestFlag(i))
2999 except Exception:
3000 failed = True
3001 threads = [
3002 threading.Thread(target=cycle_enum)
3003 for _ in range(8)
3004 ]
Hai Shie80697d2020-05-28 06:10:27 +08003005 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08003006 pass
3007 # check that only 248 members were created
3008 self.assertFalse(
3009 failed,
3010 'at least one thread failed while creating composite members')
3011 self.assertEqual(256, len(seen), 'too many composite members created')
3012
3013
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003014class TestEmptyAndNonLatinStrings(unittest.TestCase):
3015
3016 def test_empty_string(self):
3017 with self.assertRaises(ValueError):
3018 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3019
3020 def test_non_latin_character_string(self):
3021 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3022 item = getattr(greek_abc, '\u03B1')
3023 self.assertEqual(item.value, 1)
3024
3025 def test_non_latin_number_string(self):
3026 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3027 item = getattr(hebrew_123, '\u05D0')
3028 self.assertEqual(item.value, 1)
3029
3030
Ethan Furmanf24bb352013-07-18 17:05:39 -07003031class TestUnique(unittest.TestCase):
3032
3033 def test_unique_clean(self):
3034 @unique
3035 class Clean(Enum):
3036 one = 1
3037 two = 'dos'
3038 tres = 4.0
3039 @unique
3040 class Cleaner(IntEnum):
3041 single = 1
3042 double = 2
3043 triple = 3
3044
3045 def test_unique_dirty(self):
3046 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3047 @unique
3048 class Dirty(Enum):
3049 one = 1
3050 two = 'dos'
3051 tres = 1
3052 with self.assertRaisesRegex(
3053 ValueError,
3054 'double.*single.*turkey.*triple',
3055 ):
3056 @unique
3057 class Dirtier(IntEnum):
3058 single = 1
3059 double = 1
3060 triple = 3
3061 turkey = 3
3062
Ethan Furman3803ad42016-05-01 10:03:53 -07003063 def test_unique_with_name(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003064 @unique
Ethan Furman3803ad42016-05-01 10:03:53 -07003065 class Silly(Enum):
3066 one = 1
3067 two = 'dos'
3068 name = 3
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003069 @unique
Ethan Furman74964862021-06-10 07:24:20 -07003070 class Sillier(IntEnum):
3071 single = 1
3072 name = 2
3073 triple = 3
3074 value = 4
3075
Ethan Furman74964862021-06-10 07:24:20 -07003076
Ethan Furman5bdab642018-09-21 19:03:09 -07003077
Ethan Furman3323da92015-04-11 09:39:59 -07003078expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003079Help on class Color in module %s:
3080
3081class Color(enum.Enum)
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003082 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003083 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003084 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003085 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003086 | Method resolution order:
3087 | Color
3088 | enum.Enum
3089 | builtins.object
3090 |\x20\x20
3091 | Data and other attributes defined here:
3092 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003093 | blue = <Color.blue: 3>
Ethan Furman5875d742013-10-21 20:45:55 -07003094 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003095 | green = <Color.green: 2>
Ethan Furman5875d742013-10-21 20:45:55 -07003096 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003097 | red = <Color.red: 1>
Ethan Furman5875d742013-10-21 20:45:55 -07003098 |\x20\x20
3099 | ----------------------------------------------------------------------
3100 | Data descriptors inherited from enum.Enum:
3101 |\x20\x20
3102 | name
3103 | The name of the Enum member.
3104 |\x20\x20
3105 | value
3106 | The value of the Enum member.
3107 |\x20\x20
3108 | ----------------------------------------------------------------------
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003109 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003110 |\x20\x20
3111 | __members__
3112 | Returns a mapping of member name->value.
3113 |\x20\x20\x20\x20\x20\x20
3114 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003115 | is a read-only view of the internal mapping."""
3116
3117expected_help_output_without_docs = """\
3118Help on class Color in module %s:
3119
3120class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003121 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3122 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003123 | Method resolution order:
3124 | Color
3125 | enum.Enum
3126 | builtins.object
3127 |\x20\x20
3128 | Data and other attributes defined here:
3129 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003130 | blue = <Color.blue: 3>
Ethan Furman3323da92015-04-11 09:39:59 -07003131 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003132 | green = <Color.green: 2>
Ethan Furman3323da92015-04-11 09:39:59 -07003133 |\x20\x20
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003134 | red = <Color.red: 1>
Ethan Furman3323da92015-04-11 09:39:59 -07003135 |\x20\x20
3136 | ----------------------------------------------------------------------
3137 | Data descriptors inherited from enum.Enum:
3138 |\x20\x20
3139 | name
3140 |\x20\x20
3141 | value
3142 |\x20\x20
3143 | ----------------------------------------------------------------------
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003144 | Data descriptors inherited from enum.EnumMeta:
Ethan Furman3323da92015-04-11 09:39:59 -07003145 |\x20\x20
3146 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003147
3148class TestStdLib(unittest.TestCase):
3149
Ethan Furman48a724f2015-04-11 23:23:06 -07003150 maxDiff = None
3151
Ethan Furman5875d742013-10-21 20:45:55 -07003152 class Color(Enum):
3153 red = 1
3154 green = 2
3155 blue = 3
3156
3157 def test_pydoc(self):
3158 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003159 if StrEnum.__doc__ is None:
3160 expected_text = expected_help_output_without_docs % __name__
3161 else:
3162 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003163 output = StringIO()
3164 helper = pydoc.Helper(output=output)
3165 helper(self.Color)
3166 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003167 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003168
3169 def test_inspect_getmembers(self):
3170 values = dict((
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003171 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003172 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003173 ('__members__', self.Color.__members__),
3174 ('__module__', __name__),
3175 ('blue', self.Color.blue),
3176 ('green', self.Color.green),
3177 ('name', Enum.__dict__['name']),
3178 ('red', self.Color.red),
3179 ('value', Enum.__dict__['value']),
3180 ))
3181 result = dict(inspect.getmembers(self.Color))
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003182 self.assertEqual(values.keys(), result.keys())
Ethan Furman5875d742013-10-21 20:45:55 -07003183 failed = False
3184 for k in values.keys():
3185 if result[k] != values[k]:
3186 print()
3187 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3188 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3189 failed = True
3190 if failed:
3191 self.fail("result does not equal expected, see print above")
3192
3193 def test_inspect_classify_class_attrs(self):
3194 # indirectly test __objclass__
3195 from inspect import Attribute
3196 values = [
3197 Attribute(name='__class__', kind='data',
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003198 defining_class=object, object=EnumMeta),
Ethan Furman5875d742013-10-21 20:45:55 -07003199 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003200 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003201 Attribute(name='__members__', kind='property',
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003202 defining_class=EnumMeta, object=EnumMeta.__members__),
Ethan Furman5875d742013-10-21 20:45:55 -07003203 Attribute(name='__module__', kind='data',
3204 defining_class=self.Color, object=__name__),
3205 Attribute(name='blue', kind='data',
3206 defining_class=self.Color, object=self.Color.blue),
3207 Attribute(name='green', kind='data',
3208 defining_class=self.Color, object=self.Color.green),
3209 Attribute(name='red', kind='data',
3210 defining_class=self.Color, object=self.Color.red),
3211 Attribute(name='name', kind='data',
3212 defining_class=Enum, object=Enum.__dict__['name']),
3213 Attribute(name='value', kind='data',
3214 defining_class=Enum, object=Enum.__dict__['value']),
3215 ]
3216 values.sort(key=lambda item: item.name)
3217 result = list(inspect.classify_class_attrs(self.Color))
3218 result.sort(key=lambda item: item.name)
3219 failed = False
3220 for v, r in zip(values, result):
3221 if r != v:
3222 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3223 failed = True
3224 if failed:
3225 self.fail("result does not equal expected, see print above")
3226
Martin Panter19e69c52015-11-14 12:46:42 +00003227
3228class MiscTestCase(unittest.TestCase):
3229 def test__all__(self):
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003230 check__all__(self, enum)
Martin Panter19e69c52015-11-14 12:46:42 +00003231
3232
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003233# These are unordered here on purpose to ensure that declaration order
3234# makes no difference.
3235CONVERT_TEST_NAME_D = 5
3236CONVERT_TEST_NAME_C = 5
3237CONVERT_TEST_NAME_B = 5
3238CONVERT_TEST_NAME_A = 5 # This one should sort first.
3239CONVERT_TEST_NAME_E = 5
3240CONVERT_TEST_NAME_F = 5
3241
3242class TestIntEnumConvert(unittest.TestCase):
3243 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003244 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003245 'UnittestConvert',
3246 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003247 filter=lambda x: x.startswith('CONVERT_TEST_'))
3248 # We don't want the reverse lookup value to vary when there are
3249 # multiple possible names for a given value. It should always
3250 # report the first lexigraphical name in that case.
3251 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3252
3253 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003254 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003255 'UnittestConvert',
3256 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003257 filter=lambda x: x.startswith('CONVERT_TEST_'))
3258 # Ensure that test_type has all of the desired names and values.
3259 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3260 test_type.CONVERT_TEST_NAME_A)
3261 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3262 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3263 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3264 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3265 # Ensure that test_type only picked up names matching the filter.
3266 self.assertEqual([name for name in dir(test_type)
3267 if name[0:2] not in ('CO', '__')],
3268 [], msg='Names other than CONVERT_TEST_* found.')
3269
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003270 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
orlnub1230fb9fad2018-09-12 20:28:53 +03003271 '_convert was deprecated in 3.8')
3272 def test_convert_warn(self):
3273 with self.assertWarns(DeprecationWarning):
3274 enum.IntEnum._convert(
3275 'UnittestConvert',
3276 ('test.test_enum', '__main__')[__name__=='__main__'],
3277 filter=lambda x: x.startswith('CONVERT_TEST_'))
3278
Ethan Furman9bf7c2d2021-07-03 21:08:42 -07003279 @unittest.skipUnless(sys.version_info >= (3, 9),
orlnub1230fb9fad2018-09-12 20:28:53 +03003280 '_convert was removed in 3.9')
3281 def test_convert_raise(self):
3282 with self.assertRaises(AttributeError):
3283 enum.IntEnum._convert(
3284 'UnittestConvert',
3285 ('test.test_enum', '__main__')[__name__=='__main__'],
3286 filter=lambda x: x.startswith('CONVERT_TEST_'))
3287
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003288
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003289if __name__ == '__main__':
3290 unittest.main()