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