blob: f2171b53946b99e0c6dcc6a515a3eaa6384441bc [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,
432 '_sunder_ names, such as "_bad_", are reserved',
433 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600434 class Bad(Enum):
435 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700436
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700437 def test_enum_with_value_name(self):
438 class Huh(Enum):
439 name = 1
440 value = 2
441 self.assertEqual(
442 list(Huh),
443 [Huh.name, Huh.value],
444 )
445 self.assertIs(type(Huh.name), Huh)
446 self.assertEqual(Huh.name.name, 'name')
447 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700448
449 def test_format_enum(self):
450 Season = self.Season
451 self.assertEqual('{}'.format(Season.SPRING),
452 '{}'.format(str(Season.SPRING)))
453 self.assertEqual( '{:}'.format(Season.SPRING),
454 '{:}'.format(str(Season.SPRING)))
455 self.assertEqual('{:20}'.format(Season.SPRING),
456 '{:20}'.format(str(Season.SPRING)))
457 self.assertEqual('{:^20}'.format(Season.SPRING),
458 '{:^20}'.format(str(Season.SPRING)))
459 self.assertEqual('{:>20}'.format(Season.SPRING),
460 '{:>20}'.format(str(Season.SPRING)))
461 self.assertEqual('{:<20}'.format(Season.SPRING),
462 '{:<20}'.format(str(Season.SPRING)))
463
thatneat2f19e822019-07-04 11:28:37 -0700464 def test_str_override_enum(self):
465 class EnumWithStrOverrides(Enum):
466 one = auto()
467 two = auto()
468
469 def __str__(self):
470 return 'Str!'
471 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
472 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
473
474 def test_format_override_enum(self):
475 class EnumWithFormatOverride(Enum):
476 one = 1.0
477 two = 2.0
478 def __format__(self, spec):
479 return 'Format!!'
480 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
481 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
482
483 def test_str_and_format_override_enum(self):
484 class EnumWithStrFormatOverrides(Enum):
485 one = auto()
486 two = auto()
487 def __str__(self):
488 return 'Str!'
489 def __format__(self, spec):
490 return 'Format!'
491 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
492 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
493
494 def test_str_override_mixin(self):
495 class MixinEnumWithStrOverride(float, Enum):
496 one = 1.0
497 two = 2.0
498 def __str__(self):
499 return 'Overridden!'
500 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
501 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
502
503 def test_str_and_format_override_mixin(self):
504 class MixinWithStrFormatOverrides(float, Enum):
505 one = 1.0
506 two = 2.0
507 def __str__(self):
508 return 'Str!'
509 def __format__(self, spec):
510 return 'Format!'
511 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
512 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
513
514 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700515 class TestFloat(float, Enum):
516 one = 1.0
517 two = 2.0
518 def __format__(self, spec):
519 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700520 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700521 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
522
523 def assertFormatIsValue(self, spec, member):
524 self.assertEqual(spec.format(member), spec.format(member.value))
525
526 def test_format_enum_date(self):
527 Holiday = self.Holiday
528 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
529 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
530 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
531 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
532 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
533 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
534 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
535 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
536
537 def test_format_enum_float(self):
538 Konstants = self.Konstants
539 self.assertFormatIsValue('{}', Konstants.TAU)
540 self.assertFormatIsValue('{:}', Konstants.TAU)
541 self.assertFormatIsValue('{:20}', Konstants.TAU)
542 self.assertFormatIsValue('{:^20}', Konstants.TAU)
543 self.assertFormatIsValue('{:>20}', Konstants.TAU)
544 self.assertFormatIsValue('{:<20}', Konstants.TAU)
545 self.assertFormatIsValue('{:n}', Konstants.TAU)
546 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
547 self.assertFormatIsValue('{:f}', Konstants.TAU)
548
549 def test_format_enum_int(self):
550 Grades = self.Grades
551 self.assertFormatIsValue('{}', Grades.C)
552 self.assertFormatIsValue('{:}', Grades.C)
553 self.assertFormatIsValue('{:20}', Grades.C)
554 self.assertFormatIsValue('{:^20}', Grades.C)
555 self.assertFormatIsValue('{:>20}', Grades.C)
556 self.assertFormatIsValue('{:<20}', Grades.C)
557 self.assertFormatIsValue('{:+}', Grades.C)
558 self.assertFormatIsValue('{:08X}', Grades.C)
559 self.assertFormatIsValue('{:b}', Grades.C)
560
561 def test_format_enum_str(self):
562 Directional = self.Directional
563 self.assertFormatIsValue('{}', Directional.WEST)
564 self.assertFormatIsValue('{:}', Directional.WEST)
565 self.assertFormatIsValue('{:20}', Directional.WEST)
566 self.assertFormatIsValue('{:^20}', Directional.WEST)
567 self.assertFormatIsValue('{:>20}', Directional.WEST)
568 self.assertFormatIsValue('{:<20}', Directional.WEST)
569
Ethan Furman22415ad2020-09-15 16:28:25 -0700570 def test_object_str_override(self):
571 class Colors(Enum):
572 RED, GREEN, BLUE = 1, 2, 3
573 def __repr__(self):
574 return "test.%s" % (self._name_, )
575 __str__ = object.__str__
576 self.assertEqual(str(Colors.RED), 'test.RED')
577
Ethan Furmanbff01f32020-09-15 15:56:26 -0700578 def test_enum_str_override(self):
579 class MyStrEnum(Enum):
580 def __str__(self):
581 return 'MyStr'
582 class MyMethodEnum(Enum):
583 def hello(self):
584 return 'Hello! My name is %s' % self.name
585 class Test1Enum(MyMethodEnum, int, MyStrEnum):
586 One = 1
587 Two = 2
Ethan Furman37440ee2020-12-08 11:14:10 -0800588 self.assertTrue(Test1Enum._member_type_ is int)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700589 self.assertEqual(str(Test1Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800590 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700591 #
592 class Test2Enum(MyStrEnum, MyMethodEnum):
593 One = 1
594 Two = 2
595 self.assertEqual(str(Test2Enum.One), 'MyStr')
Ethan Furman37440ee2020-12-08 11:14:10 -0800596 self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
Ethan Furmanbff01f32020-09-15 15:56:26 -0700597
598 def test_inherited_data_type(self):
599 class HexInt(int):
600 def __repr__(self):
601 return hex(self)
602 class MyEnum(HexInt, enum.Enum):
603 A = 1
604 B = 2
605 C = 3
606 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
607
608 def test_too_many_data_types(self):
609 with self.assertRaisesRegex(TypeError, 'too many data types'):
610 class Huh(str, int, Enum):
611 One = 1
612
613 class MyStr(str):
614 def hello(self):
615 return 'hello, %s' % self
616 class MyInt(int):
617 def repr(self):
618 return hex(self)
619 with self.assertRaisesRegex(TypeError, 'too many data types'):
620 class Huh(MyStr, MyInt, Enum):
621 One = 1
622
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700623 def test_hash(self):
624 Season = self.Season
625 dates = {}
626 dates[Season.WINTER] = '1225'
627 dates[Season.SPRING] = '0315'
628 dates[Season.SUMMER] = '0704'
629 dates[Season.AUTUMN] = '1031'
630 self.assertEqual(dates[Season.AUTUMN], '1031')
631
632 def test_intenum_from_scratch(self):
633 class phy(int, Enum):
634 pi = 3
635 tau = 2 * pi
636 self.assertTrue(phy.pi < phy.tau)
637
638 def test_intenum_inherited(self):
639 class IntEnum(int, Enum):
640 pass
641 class phy(IntEnum):
642 pi = 3
643 tau = 2 * pi
644 self.assertTrue(phy.pi < phy.tau)
645
646 def test_floatenum_from_scratch(self):
647 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700648 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700649 tau = 2 * pi
650 self.assertTrue(phy.pi < phy.tau)
651
652 def test_floatenum_inherited(self):
653 class FloatEnum(float, Enum):
654 pass
655 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700656 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700657 tau = 2 * pi
658 self.assertTrue(phy.pi < phy.tau)
659
660 def test_strenum_from_scratch(self):
661 class phy(str, Enum):
662 pi = 'Pi'
663 tau = 'Tau'
664 self.assertTrue(phy.pi < phy.tau)
665
Ethan Furman0063ff42020-09-21 17:23:13 -0700666 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700667 class phy(StrEnum):
668 pi = 'Pi'
669 tau = 'Tau'
670 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700671 self.assertEqual(phy.pi.upper(), 'PI')
672 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700673
674 def test_intenum(self):
675 class WeekDay(IntEnum):
676 SUNDAY = 1
677 MONDAY = 2
678 TUESDAY = 3
679 WEDNESDAY = 4
680 THURSDAY = 5
681 FRIDAY = 6
682 SATURDAY = 7
683
684 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
685 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
686
687 lst = list(WeekDay)
688 self.assertEqual(len(lst), len(WeekDay))
689 self.assertEqual(len(WeekDay), 7)
690 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
691 target = target.split()
692 for i, weekday in enumerate(target, 1):
693 e = WeekDay(i)
694 self.assertEqual(e, i)
695 self.assertEqual(int(e), i)
696 self.assertEqual(e.name, weekday)
697 self.assertIn(e, WeekDay)
698 self.assertEqual(lst.index(e)+1, i)
699 self.assertTrue(0 < e < 8)
700 self.assertIs(type(e), WeekDay)
701 self.assertIsInstance(e, int)
702 self.assertIsInstance(e, Enum)
703
704 def test_intenum_duplicates(self):
705 class WeekDay(IntEnum):
706 SUNDAY = 1
707 MONDAY = 2
708 TUESDAY = TEUSDAY = 3
709 WEDNESDAY = 4
710 THURSDAY = 5
711 FRIDAY = 6
712 SATURDAY = 7
713 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
714 self.assertEqual(WeekDay(3).name, 'TUESDAY')
715 self.assertEqual([k for k,v in WeekDay.__members__.items()
716 if v.name != k], ['TEUSDAY', ])
717
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300718 def test_intenum_from_bytes(self):
719 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
720 with self.assertRaises(ValueError):
721 IntStooges.from_bytes(b'\x00\x05', 'big')
722
723 def test_floatenum_fromhex(self):
724 h = float.hex(FloatStooges.MOE.value)
725 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
726 h = float.hex(FloatStooges.MOE.value + 0.01)
727 with self.assertRaises(ValueError):
728 FloatStooges.fromhex(h)
729
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700730 def test_pickle_enum(self):
731 if isinstance(Stooges, Exception):
732 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800733 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
734 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700735
736 def test_pickle_int(self):
737 if isinstance(IntStooges, Exception):
738 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800739 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
740 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700741
742 def test_pickle_float(self):
743 if isinstance(FloatStooges, Exception):
744 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800745 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
746 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700747
748 def test_pickle_enum_function(self):
749 if isinstance(Answer, Exception):
750 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800751 test_pickle_dump_load(self.assertIs, Answer.him)
752 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700753
754 def test_pickle_enum_function_with_module(self):
755 if isinstance(Question, Exception):
756 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800757 test_pickle_dump_load(self.assertIs, Question.who)
758 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700759
Ethan Furmanca1b7942014-02-08 11:36:27 -0800760 def test_enum_function_with_qualname(self):
761 if isinstance(Theory, Exception):
762 raise Theory
763 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
764
765 def test_class_nested_enum_and_pickle_protocol_four(self):
766 # would normally just have this directly in the class namespace
767 class NestedEnum(Enum):
768 twigs = 'common'
769 shiny = 'rare'
770
771 self.__class__.NestedEnum = NestedEnum
772 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300773 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800774
Ethan Furman24e837f2015-03-18 17:27:57 -0700775 def test_pickle_by_name(self):
776 class ReplaceGlobalInt(IntEnum):
777 ONE = 1
778 TWO = 2
779 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
780 for proto in range(HIGHEST_PROTOCOL):
781 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
782
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784 BadPickle = Enum(
785 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700786 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800787 # now break BadPickle to test exception raising
788 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800789 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
790 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700791
792 def test_string_enum(self):
793 class SkillLevel(str, Enum):
794 master = 'what is the sound of one hand clapping?'
795 journeyman = 'why did the chicken cross the road?'
796 apprentice = 'knock, knock!'
797 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
798
799 def test_getattr_getitem(self):
800 class Period(Enum):
801 morning = 1
802 noon = 2
803 evening = 3
804 night = 4
805 self.assertIs(Period(2), Period.noon)
806 self.assertIs(getattr(Period, 'night'), Period.night)
807 self.assertIs(Period['morning'], Period.morning)
808
809 def test_getattr_dunder(self):
810 Season = self.Season
811 self.assertTrue(getattr(Season, '__eq__'))
812
813 def test_iteration_order(self):
814 class Season(Enum):
815 SUMMER = 2
816 WINTER = 4
817 AUTUMN = 3
818 SPRING = 1
819 self.assertEqual(
820 list(Season),
821 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
822 )
823
Ethan Furman2131a4a2013-09-14 18:11:24 -0700824 def test_reversed_iteration_order(self):
825 self.assertEqual(
826 list(reversed(self.Season)),
827 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
828 self.Season.SPRING]
829 )
830
Martin Pantereb995702016-07-28 01:11:04 +0000831 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832 SummerMonth = Enum('SummerMonth', 'june july august')
833 lst = list(SummerMonth)
834 self.assertEqual(len(lst), len(SummerMonth))
835 self.assertEqual(len(SummerMonth), 3, SummerMonth)
836 self.assertEqual(
837 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
838 lst,
839 )
840 for i, month in enumerate('june july august'.split(), 1):
841 e = SummerMonth(i)
842 self.assertEqual(int(e.value), i)
843 self.assertNotEqual(e, i)
844 self.assertEqual(e.name, month)
845 self.assertIn(e, SummerMonth)
846 self.assertIs(type(e), SummerMonth)
847
Martin Pantereb995702016-07-28 01:11:04 +0000848 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700849 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
850 lst = list(SummerMonth)
851 self.assertEqual(len(lst), len(SummerMonth))
852 self.assertEqual(len(SummerMonth), 3, SummerMonth)
853 self.assertEqual(
854 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
855 lst,
856 )
857 for i, month in enumerate('june july august'.split(), 10):
858 e = SummerMonth(i)
859 self.assertEqual(int(e.value), i)
860 self.assertNotEqual(e, i)
861 self.assertEqual(e.name, month)
862 self.assertIn(e, SummerMonth)
863 self.assertIs(type(e), SummerMonth)
864
Martin Pantereb995702016-07-28 01:11:04 +0000865 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700866 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
867 lst = list(SummerMonth)
868 self.assertEqual(len(lst), len(SummerMonth))
869 self.assertEqual(len(SummerMonth), 3, SummerMonth)
870 self.assertEqual(
871 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
872 lst,
873 )
874 for i, month in enumerate('june july august'.split(), 1):
875 e = SummerMonth(i)
876 self.assertEqual(int(e.value), i)
877 self.assertNotEqual(e, i)
878 self.assertEqual(e.name, month)
879 self.assertIn(e, SummerMonth)
880 self.assertIs(type(e), SummerMonth)
881
Martin Pantereb995702016-07-28 01:11:04 +0000882 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700883 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
884 lst = list(SummerMonth)
885 self.assertEqual(len(lst), len(SummerMonth))
886 self.assertEqual(len(SummerMonth), 3, SummerMonth)
887 self.assertEqual(
888 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
889 lst,
890 )
891 for i, month in enumerate('june july august'.split(), 20):
892 e = SummerMonth(i)
893 self.assertEqual(int(e.value), i)
894 self.assertNotEqual(e, i)
895 self.assertEqual(e.name, month)
896 self.assertIn(e, SummerMonth)
897 self.assertIs(type(e), SummerMonth)
898
Martin Pantereb995702016-07-28 01:11:04 +0000899 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700900 SummerMonth = Enum(
901 'SummerMonth',
902 (('june', 1), ('july', 2), ('august', 3))
903 )
904 lst = list(SummerMonth)
905 self.assertEqual(len(lst), len(SummerMonth))
906 self.assertEqual(len(SummerMonth), 3, SummerMonth)
907 self.assertEqual(
908 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
909 lst,
910 )
911 for i, month in enumerate('june july august'.split(), 1):
912 e = SummerMonth(i)
913 self.assertEqual(int(e.value), i)
914 self.assertNotEqual(e, i)
915 self.assertEqual(e.name, month)
916 self.assertIn(e, SummerMonth)
917 self.assertIs(type(e), SummerMonth)
918
Martin Pantereb995702016-07-28 01:11:04 +0000919 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700920 SummerMonth = Enum(
921 'SummerMonth',
922 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
923 )
924 lst = list(SummerMonth)
925 self.assertEqual(len(lst), len(SummerMonth))
926 self.assertEqual(len(SummerMonth), 3, SummerMonth)
927 self.assertEqual(
928 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
929 lst,
930 )
931 for i, month in enumerate('june july august'.split(), 1):
932 e = SummerMonth(i)
933 self.assertEqual(int(e.value), i)
934 self.assertNotEqual(e, i)
935 self.assertEqual(e.name, month)
936 self.assertIn(e, SummerMonth)
937 self.assertIs(type(e), SummerMonth)
938
Martin Pantereb995702016-07-28 01:11:04 +0000939 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700940 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
941 lst = list(SummerMonth)
942 self.assertEqual(len(lst), len(SummerMonth))
943 self.assertEqual(len(SummerMonth), 3, SummerMonth)
944 self.assertEqual(
945 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
946 lst,
947 )
948 for i, month in enumerate('june july august'.split(), 1):
949 e = SummerMonth(i)
950 self.assertEqual(e, i)
951 self.assertEqual(e.name, month)
952 self.assertIn(e, SummerMonth)
953 self.assertIs(type(e), SummerMonth)
954
Martin Pantereb995702016-07-28 01:11:04 +0000955 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700956 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
957 lst = list(SummerMonth)
958 self.assertEqual(len(lst), len(SummerMonth))
959 self.assertEqual(len(SummerMonth), 3, SummerMonth)
960 self.assertEqual(
961 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
962 lst,
963 )
964 for i, month in enumerate('june july august'.split(), 30):
965 e = SummerMonth(i)
966 self.assertEqual(e, i)
967 self.assertEqual(e.name, month)
968 self.assertIn(e, SummerMonth)
969 self.assertIs(type(e), SummerMonth)
970
Martin Pantereb995702016-07-28 01:11:04 +0000971 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700972 SummerMonth = IntEnum('SummerMonth', 'june july august')
973 lst = list(SummerMonth)
974 self.assertEqual(len(lst), len(SummerMonth))
975 self.assertEqual(len(SummerMonth), 3, SummerMonth)
976 self.assertEqual(
977 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
978 lst,
979 )
980 for i, month in enumerate('june july august'.split(), 1):
981 e = SummerMonth(i)
982 self.assertEqual(e, i)
983 self.assertEqual(e.name, month)
984 self.assertIn(e, SummerMonth)
985 self.assertIs(type(e), SummerMonth)
986
Martin Pantereb995702016-07-28 01:11:04 +0000987 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700988 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
989 lst = list(SummerMonth)
990 self.assertEqual(len(lst), len(SummerMonth))
991 self.assertEqual(len(SummerMonth), 3, SummerMonth)
992 self.assertEqual(
993 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
994 lst,
995 )
996 for i, month in enumerate('june july august'.split(), 40):
997 e = SummerMonth(i)
998 self.assertEqual(e, i)
999 self.assertEqual(e.name, month)
1000 self.assertIn(e, SummerMonth)
1001 self.assertIs(type(e), SummerMonth)
1002
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001003 def test_subclassing(self):
1004 if isinstance(Name, Exception):
1005 raise Name
1006 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1007 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1008 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001009 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001010
1011 def test_extending(self):
1012 class Color(Enum):
1013 red = 1
1014 green = 2
1015 blue = 3
1016 with self.assertRaises(TypeError):
1017 class MoreColor(Color):
1018 cyan = 4
1019 magenta = 5
1020 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001021 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1022 class EvenMoreColor(Color, IntEnum):
1023 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001024
1025 def test_exclude_methods(self):
1026 class whatever(Enum):
1027 this = 'that'
1028 these = 'those'
1029 def really(self):
1030 return 'no, not %s' % self.value
1031 self.assertIsNot(type(whatever.really), whatever)
1032 self.assertEqual(whatever.this.really(), 'no, not that')
1033
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001034 def test_wrong_inheritance_order(self):
1035 with self.assertRaises(TypeError):
1036 class Wrong(Enum, str):
1037 NotHere = 'error before this point'
1038
1039 def test_intenum_transitivity(self):
1040 class number(IntEnum):
1041 one = 1
1042 two = 2
1043 three = 3
1044 class numero(IntEnum):
1045 uno = 1
1046 dos = 2
1047 tres = 3
1048 self.assertEqual(number.one, numero.uno)
1049 self.assertEqual(number.two, numero.dos)
1050 self.assertEqual(number.three, numero.tres)
1051
1052 def test_wrong_enum_in_call(self):
1053 class Monochrome(Enum):
1054 black = 0
1055 white = 1
1056 class Gender(Enum):
1057 male = 0
1058 female = 1
1059 self.assertRaises(ValueError, Monochrome, Gender.male)
1060
1061 def test_wrong_enum_in_mixed_call(self):
1062 class Monochrome(IntEnum):
1063 black = 0
1064 white = 1
1065 class Gender(Enum):
1066 male = 0
1067 female = 1
1068 self.assertRaises(ValueError, Monochrome, Gender.male)
1069
1070 def test_mixed_enum_in_call_1(self):
1071 class Monochrome(IntEnum):
1072 black = 0
1073 white = 1
1074 class Gender(IntEnum):
1075 male = 0
1076 female = 1
1077 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1078
1079 def test_mixed_enum_in_call_2(self):
1080 class Monochrome(Enum):
1081 black = 0
1082 white = 1
1083 class Gender(IntEnum):
1084 male = 0
1085 female = 1
1086 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1087
1088 def test_flufl_enum(self):
1089 class Fluflnum(Enum):
1090 def __int__(self):
1091 return int(self.value)
1092 class MailManOptions(Fluflnum):
1093 option1 = 1
1094 option2 = 2
1095 option3 = 3
1096 self.assertEqual(int(MailManOptions.option1), 1)
1097
Ethan Furman5e5a8232013-08-04 08:42:23 -07001098 def test_introspection(self):
1099 class Number(IntEnum):
1100 one = 100
1101 two = 200
1102 self.assertIs(Number.one._member_type_, int)
1103 self.assertIs(Number._member_type_, int)
1104 class String(str, Enum):
1105 yarn = 'soft'
1106 rope = 'rough'
1107 wire = 'hard'
1108 self.assertIs(String.yarn._member_type_, str)
1109 self.assertIs(String._member_type_, str)
1110 class Plain(Enum):
1111 vanilla = 'white'
1112 one = 1
1113 self.assertIs(Plain.vanilla._member_type_, object)
1114 self.assertIs(Plain._member_type_, object)
1115
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001116 def test_no_such_enum_member(self):
1117 class Color(Enum):
1118 red = 1
1119 green = 2
1120 blue = 3
1121 with self.assertRaises(ValueError):
1122 Color(4)
1123 with self.assertRaises(KeyError):
1124 Color['chartreuse']
1125
1126 def test_new_repr(self):
1127 class Color(Enum):
1128 red = 1
1129 green = 2
1130 blue = 3
1131 def __repr__(self):
1132 return "don't you just love shades of %s?" % self.name
1133 self.assertEqual(
1134 repr(Color.blue),
1135 "don't you just love shades of blue?",
1136 )
1137
1138 def test_inherited_repr(self):
1139 class MyEnum(Enum):
1140 def __repr__(self):
1141 return "My name is %s." % self.name
1142 class MyIntEnum(int, MyEnum):
1143 this = 1
1144 that = 2
1145 theother = 3
1146 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1147
1148 def test_multiple_mixin_mro(self):
1149 class auto_enum(type(Enum)):
1150 def __new__(metacls, cls, bases, classdict):
1151 temp = type(classdict)()
1152 names = set(classdict._member_names)
1153 i = 0
1154 for k in classdict._member_names:
1155 v = classdict[k]
1156 if v is Ellipsis:
1157 v = i
1158 else:
1159 i = v
1160 i += 1
1161 temp[k] = v
1162 for k, v in classdict.items():
1163 if k not in names:
1164 temp[k] = v
1165 return super(auto_enum, metacls).__new__(
1166 metacls, cls, bases, temp)
1167
1168 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1169 pass
1170
1171 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1172 pass
1173
1174 class TestAutoNumber(AutoNumberedEnum):
1175 a = ...
1176 b = 3
1177 c = ...
1178
1179 class TestAutoInt(AutoIntEnum):
1180 a = ...
1181 b = 3
1182 c = ...
1183
1184 def test_subclasses_with_getnewargs(self):
1185 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001186 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001187 def __new__(cls, *args):
1188 _args = args
1189 name, *args = args
1190 if len(args) == 0:
1191 raise TypeError("name and value must be specified")
1192 self = int.__new__(cls, *args)
1193 self._intname = name
1194 self._args = _args
1195 return self
1196 def __getnewargs__(self):
1197 return self._args
1198 @property
1199 def __name__(self):
1200 return self._intname
1201 def __repr__(self):
1202 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001203 return "{}({!r}, {})".format(
1204 type(self).__name__,
1205 self.__name__,
1206 int.__repr__(self),
1207 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001208 def __str__(self):
1209 # str() is unchanged, even if it relies on the repr() fallback
1210 base = int
1211 base_str = base.__str__
1212 if base_str.__objclass__ is object:
1213 return base.__repr__(self)
1214 return base_str(self)
1215 # for simplicity, we only define one operator that
1216 # propagates expressions
1217 def __add__(self, other):
1218 temp = int(self) + int( other)
1219 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1220 return NamedInt(
1221 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001222 temp,
1223 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001224 else:
1225 return temp
1226
1227 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001228 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001229 x = ('the-x', 1)
1230 y = ('the-y', 2)
1231
Ethan Furman2aa27322013-07-19 19:35:56 -07001232
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001233 self.assertIs(NEI.__new__, Enum.__new__)
1234 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1235 globals()['NamedInt'] = NamedInt
1236 globals()['NEI'] = NEI
1237 NI5 = NamedInt('test', 5)
1238 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001239 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001241 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001242 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001243
Ethan Furmanca1b7942014-02-08 11:36:27 -08001244 def test_subclasses_with_getnewargs_ex(self):
1245 class NamedInt(int):
1246 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1247 def __new__(cls, *args):
1248 _args = args
1249 name, *args = args
1250 if len(args) == 0:
1251 raise TypeError("name and value must be specified")
1252 self = int.__new__(cls, *args)
1253 self._intname = name
1254 self._args = _args
1255 return self
1256 def __getnewargs_ex__(self):
1257 return self._args, {}
1258 @property
1259 def __name__(self):
1260 return self._intname
1261 def __repr__(self):
1262 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001263 return "{}({!r}, {})".format(
1264 type(self).__name__,
1265 self.__name__,
1266 int.__repr__(self),
1267 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001268 def __str__(self):
1269 # str() is unchanged, even if it relies on the repr() fallback
1270 base = int
1271 base_str = base.__str__
1272 if base_str.__objclass__ is object:
1273 return base.__repr__(self)
1274 return base_str(self)
1275 # for simplicity, we only define one operator that
1276 # propagates expressions
1277 def __add__(self, other):
1278 temp = int(self) + int( other)
1279 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1280 return NamedInt(
1281 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001282 temp,
1283 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001284 else:
1285 return temp
1286
1287 class NEI(NamedInt, Enum):
1288 __qualname__ = 'NEI' # needed for pickle protocol 4
1289 x = ('the-x', 1)
1290 y = ('the-y', 2)
1291
1292
1293 self.assertIs(NEI.__new__, Enum.__new__)
1294 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1295 globals()['NamedInt'] = NamedInt
1296 globals()['NEI'] = NEI
1297 NI5 = NamedInt('test', 5)
1298 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001299 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001300 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001301 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001302 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001303
1304 def test_subclasses_with_reduce(self):
1305 class NamedInt(int):
1306 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1307 def __new__(cls, *args):
1308 _args = args
1309 name, *args = args
1310 if len(args) == 0:
1311 raise TypeError("name and value must be specified")
1312 self = int.__new__(cls, *args)
1313 self._intname = name
1314 self._args = _args
1315 return self
1316 def __reduce__(self):
1317 return self.__class__, self._args
1318 @property
1319 def __name__(self):
1320 return self._intname
1321 def __repr__(self):
1322 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001323 return "{}({!r}, {})".format(
1324 type(self).__name__,
1325 self.__name__,
1326 int.__repr__(self),
1327 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001328 def __str__(self):
1329 # str() is unchanged, even if it relies on the repr() fallback
1330 base = int
1331 base_str = base.__str__
1332 if base_str.__objclass__ is object:
1333 return base.__repr__(self)
1334 return base_str(self)
1335 # for simplicity, we only define one operator that
1336 # propagates expressions
1337 def __add__(self, other):
1338 temp = int(self) + int( other)
1339 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1340 return NamedInt(
1341 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001342 temp,
1343 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001344 else:
1345 return temp
1346
1347 class NEI(NamedInt, Enum):
1348 __qualname__ = 'NEI' # needed for pickle protocol 4
1349 x = ('the-x', 1)
1350 y = ('the-y', 2)
1351
1352
1353 self.assertIs(NEI.__new__, Enum.__new__)
1354 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1355 globals()['NamedInt'] = NamedInt
1356 globals()['NEI'] = NEI
1357 NI5 = NamedInt('test', 5)
1358 self.assertEqual(NI5, 5)
1359 test_pickle_dump_load(self.assertEqual, NI5, 5)
1360 self.assertEqual(NEI.y.value, 2)
1361 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001362 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001363
1364 def test_subclasses_with_reduce_ex(self):
1365 class NamedInt(int):
1366 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1367 def __new__(cls, *args):
1368 _args = args
1369 name, *args = args
1370 if len(args) == 0:
1371 raise TypeError("name and value must be specified")
1372 self = int.__new__(cls, *args)
1373 self._intname = name
1374 self._args = _args
1375 return self
1376 def __reduce_ex__(self, proto):
1377 return self.__class__, self._args
1378 @property
1379 def __name__(self):
1380 return self._intname
1381 def __repr__(self):
1382 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001383 return "{}({!r}, {})".format(
1384 type(self).__name__,
1385 self.__name__,
1386 int.__repr__(self),
1387 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001388 def __str__(self):
1389 # str() is unchanged, even if it relies on the repr() fallback
1390 base = int
1391 base_str = base.__str__
1392 if base_str.__objclass__ is object:
1393 return base.__repr__(self)
1394 return base_str(self)
1395 # for simplicity, we only define one operator that
1396 # propagates expressions
1397 def __add__(self, other):
1398 temp = int(self) + int( other)
1399 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1400 return NamedInt(
1401 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001402 temp,
1403 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001404 else:
1405 return temp
1406
1407 class NEI(NamedInt, Enum):
1408 __qualname__ = 'NEI' # needed for pickle protocol 4
1409 x = ('the-x', 1)
1410 y = ('the-y', 2)
1411
Ethan Furmanca1b7942014-02-08 11:36:27 -08001412 self.assertIs(NEI.__new__, Enum.__new__)
1413 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1414 globals()['NamedInt'] = NamedInt
1415 globals()['NEI'] = NEI
1416 NI5 = NamedInt('test', 5)
1417 self.assertEqual(NI5, 5)
1418 test_pickle_dump_load(self.assertEqual, NI5, 5)
1419 self.assertEqual(NEI.y.value, 2)
1420 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001421 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001422
Ethan Furmandc870522014-02-18 12:37:12 -08001423 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001424 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001425 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001426 def __new__(cls, *args):
1427 _args = args
1428 name, *args = args
1429 if len(args) == 0:
1430 raise TypeError("name and value must be specified")
1431 self = int.__new__(cls, *args)
1432 self._intname = name
1433 self._args = _args
1434 return self
1435 @property
1436 def __name__(self):
1437 return self._intname
1438 def __repr__(self):
1439 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001440 return "{}({!r}, {})".format(
1441 type(self).__name__,
1442 self.__name__,
1443 int.__repr__(self),
1444 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001445 def __str__(self):
1446 # str() is unchanged, even if it relies on the repr() fallback
1447 base = int
1448 base_str = base.__str__
1449 if base_str.__objclass__ is object:
1450 return base.__repr__(self)
1451 return base_str(self)
1452 # for simplicity, we only define one operator that
1453 # propagates expressions
1454 def __add__(self, other):
1455 temp = int(self) + int( other)
1456 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1457 return NamedInt(
1458 '({0} + {1})'.format(self.__name__, other.__name__),
1459 temp )
1460 else:
1461 return temp
1462
1463 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001464 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001465 x = ('the-x', 1)
1466 y = ('the-y', 2)
1467
1468 self.assertIs(NEI.__new__, Enum.__new__)
1469 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1470 globals()['NamedInt'] = NamedInt
1471 globals()['NEI'] = NEI
1472 NI5 = NamedInt('test', 5)
1473 self.assertEqual(NI5, 5)
1474 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001475 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1476 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477
Ethan Furmandc870522014-02-18 12:37:12 -08001478 def test_subclasses_without_direct_pickle_support_using_name(self):
1479 class NamedInt(int):
1480 __qualname__ = 'NamedInt'
1481 def __new__(cls, *args):
1482 _args = args
1483 name, *args = args
1484 if len(args) == 0:
1485 raise TypeError("name and value must be specified")
1486 self = int.__new__(cls, *args)
1487 self._intname = name
1488 self._args = _args
1489 return self
1490 @property
1491 def __name__(self):
1492 return self._intname
1493 def __repr__(self):
1494 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001495 return "{}({!r}, {})".format(
1496 type(self).__name__,
1497 self.__name__,
1498 int.__repr__(self),
1499 )
Ethan Furmandc870522014-02-18 12:37:12 -08001500 def __str__(self):
1501 # str() is unchanged, even if it relies on the repr() fallback
1502 base = int
1503 base_str = base.__str__
1504 if base_str.__objclass__ is object:
1505 return base.__repr__(self)
1506 return base_str(self)
1507 # for simplicity, we only define one operator that
1508 # propagates expressions
1509 def __add__(self, other):
1510 temp = int(self) + int( other)
1511 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1512 return NamedInt(
1513 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001514 temp,
1515 )
Ethan Furmandc870522014-02-18 12:37:12 -08001516 else:
1517 return temp
1518
1519 class NEI(NamedInt, Enum):
1520 __qualname__ = 'NEI'
1521 x = ('the-x', 1)
1522 y = ('the-y', 2)
1523 def __reduce_ex__(self, proto):
1524 return getattr, (self.__class__, self._name_)
1525
1526 self.assertIs(NEI.__new__, Enum.__new__)
1527 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1528 globals()['NamedInt'] = NamedInt
1529 globals()['NEI'] = NEI
1530 NI5 = NamedInt('test', 5)
1531 self.assertEqual(NI5, 5)
1532 self.assertEqual(NEI.y.value, 2)
1533 test_pickle_dump_load(self.assertIs, NEI.y)
1534 test_pickle_dump_load(self.assertIs, NEI)
1535
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001536 def test_tuple_subclass(self):
1537 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001538 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001539 first = (1, 'for the money')
1540 second = (2, 'for the show')
1541 third = (3, 'for the music')
1542 self.assertIs(type(SomeTuple.first), SomeTuple)
1543 self.assertIsInstance(SomeTuple.second, tuple)
1544 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1545 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001546 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001547
1548 def test_duplicate_values_give_unique_enum_items(self):
1549 class AutoNumber(Enum):
1550 first = ()
1551 second = ()
1552 third = ()
1553 def __new__(cls):
1554 value = len(cls.__members__) + 1
1555 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001556 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 return obj
1558 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001559 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001560 self.assertEqual(
1561 list(AutoNumber),
1562 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1563 )
1564 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001565 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001566 self.assertIs(AutoNumber(1), AutoNumber.first)
1567
1568 def test_inherited_new_from_enhanced_enum(self):
1569 class AutoNumber(Enum):
1570 def __new__(cls):
1571 value = len(cls.__members__) + 1
1572 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001573 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001574 return obj
1575 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001576 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001577 class Color(AutoNumber):
1578 red = ()
1579 green = ()
1580 blue = ()
1581 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1582 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1583
1584 def test_inherited_new_from_mixed_enum(self):
1585 class AutoNumber(IntEnum):
1586 def __new__(cls):
1587 value = len(cls.__members__) + 1
1588 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001589 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001590 return obj
1591 class Color(AutoNumber):
1592 red = ()
1593 green = ()
1594 blue = ()
1595 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1596 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1597
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001598 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001599 class OrdinaryEnum(Enum):
1600 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001601 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1602 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001603
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001604 def test_ordered_mixin(self):
1605 class OrderedEnum(Enum):
1606 def __ge__(self, other):
1607 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001608 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001609 return NotImplemented
1610 def __gt__(self, other):
1611 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001612 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001613 return NotImplemented
1614 def __le__(self, other):
1615 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001616 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001617 return NotImplemented
1618 def __lt__(self, other):
1619 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001620 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001621 return NotImplemented
1622 class Grade(OrderedEnum):
1623 A = 5
1624 B = 4
1625 C = 3
1626 D = 2
1627 F = 1
1628 self.assertGreater(Grade.A, Grade.B)
1629 self.assertLessEqual(Grade.F, Grade.C)
1630 self.assertLess(Grade.D, Grade.A)
1631 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001632 self.assertEqual(Grade.B, Grade.B)
1633 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001634
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001635 def test_extending2(self):
1636 class Shade(Enum):
1637 def shade(self):
1638 print(self.name)
1639 class Color(Shade):
1640 red = 1
1641 green = 2
1642 blue = 3
1643 with self.assertRaises(TypeError):
1644 class MoreColor(Color):
1645 cyan = 4
1646 magenta = 5
1647 yellow = 6
1648
1649 def test_extending3(self):
1650 class Shade(Enum):
1651 def shade(self):
1652 return self.name
1653 class Color(Shade):
1654 def hex(self):
1655 return '%s hexlified!' % self.value
1656 class MoreColor(Color):
1657 cyan = 4
1658 magenta = 5
1659 yellow = 6
1660 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1661
orlnub1230fb9fad2018-09-12 20:28:53 +03001662 def test_subclass_duplicate_name(self):
1663 class Base(Enum):
1664 def test(self):
1665 pass
1666 class Test(Base):
1667 test = 1
1668 self.assertIs(type(Test.test), Test)
1669
1670 def test_subclass_duplicate_name_dynamic(self):
1671 from types import DynamicClassAttribute
1672 class Base(Enum):
1673 @DynamicClassAttribute
1674 def test(self):
1675 return 'dynamic'
1676 class Test(Base):
1677 test = 1
1678 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001679
1680 def test_no_duplicates(self):
1681 class UniqueEnum(Enum):
1682 def __init__(self, *args):
1683 cls = self.__class__
1684 if any(self.value == e.value for e in cls):
1685 a = self.name
1686 e = cls(self.value).name
1687 raise ValueError(
1688 "aliases not allowed in UniqueEnum: %r --> %r"
1689 % (a, e)
1690 )
1691 class Color(UniqueEnum):
1692 red = 1
1693 green = 2
1694 blue = 3
1695 with self.assertRaises(ValueError):
1696 class Color(UniqueEnum):
1697 red = 1
1698 green = 2
1699 blue = 3
1700 grene = 2
1701
1702 def test_init(self):
1703 class Planet(Enum):
1704 MERCURY = (3.303e+23, 2.4397e6)
1705 VENUS = (4.869e+24, 6.0518e6)
1706 EARTH = (5.976e+24, 6.37814e6)
1707 MARS = (6.421e+23, 3.3972e6)
1708 JUPITER = (1.9e+27, 7.1492e7)
1709 SATURN = (5.688e+26, 6.0268e7)
1710 URANUS = (8.686e+25, 2.5559e7)
1711 NEPTUNE = (1.024e+26, 2.4746e7)
1712 def __init__(self, mass, radius):
1713 self.mass = mass # in kilograms
1714 self.radius = radius # in meters
1715 @property
1716 def surface_gravity(self):
1717 # universal gravitational constant (m3 kg-1 s-2)
1718 G = 6.67300E-11
1719 return G * self.mass / (self.radius * self.radius)
1720 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1721 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1722
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001723 def test_ignore(self):
1724 class Period(timedelta, Enum):
1725 '''
1726 different lengths of time
1727 '''
1728 def __new__(cls, value, period):
1729 obj = timedelta.__new__(cls, value)
1730 obj._value_ = value
1731 obj.period = period
1732 return obj
1733 _ignore_ = 'Period i'
1734 Period = vars()
1735 for i in range(13):
1736 Period['month_%d' % i] = i*30, 'month'
1737 for i in range(53):
1738 Period['week_%d' % i] = i*7, 'week'
1739 for i in range(32):
1740 Period['day_%d' % i] = i, 'day'
1741 OneDay = day_1
1742 OneWeek = week_1
1743 OneMonth = month_1
1744 self.assertFalse(hasattr(Period, '_ignore_'))
1745 self.assertFalse(hasattr(Period, 'Period'))
1746 self.assertFalse(hasattr(Period, 'i'))
1747 self.assertTrue(isinstance(Period.day_1, timedelta))
1748 self.assertTrue(Period.month_1 is Period.day_30)
1749 self.assertTrue(Period.week_4 is Period.day_28)
1750
Ethan Furman2aa27322013-07-19 19:35:56 -07001751 def test_nonhash_value(self):
1752 class AutoNumberInAList(Enum):
1753 def __new__(cls):
1754 value = [len(cls.__members__) + 1]
1755 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001756 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001757 return obj
1758 class ColorInAList(AutoNumberInAList):
1759 red = ()
1760 green = ()
1761 blue = ()
1762 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001763 for enum, value in zip(ColorInAList, range(3)):
1764 value += 1
1765 self.assertEqual(enum.value, [value])
1766 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001767
Ethan Furmanb41803e2013-07-25 13:50:45 -07001768 def test_conflicting_types_resolved_in_new(self):
1769 class LabelledIntEnum(int, Enum):
1770 def __new__(cls, *args):
1771 value, label = args
1772 obj = int.__new__(cls, value)
1773 obj.label = label
1774 obj._value_ = value
1775 return obj
1776
1777 class LabelledList(LabelledIntEnum):
1778 unprocessed = (1, "Unprocessed")
1779 payment_complete = (2, "Payment Complete")
1780
1781 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1782 self.assertEqual(LabelledList.unprocessed, 1)
1783 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001784
Ethan Furmanc16595e2016-09-10 23:36:59 -07001785 def test_auto_number(self):
1786 class Color(Enum):
1787 red = auto()
1788 blue = auto()
1789 green = auto()
1790
1791 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1792 self.assertEqual(Color.red.value, 1)
1793 self.assertEqual(Color.blue.value, 2)
1794 self.assertEqual(Color.green.value, 3)
1795
1796 def test_auto_name(self):
1797 class Color(Enum):
1798 def _generate_next_value_(name, start, count, last):
1799 return name
1800 red = auto()
1801 blue = auto()
1802 green = auto()
1803
1804 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1805 self.assertEqual(Color.red.value, 'red')
1806 self.assertEqual(Color.blue.value, 'blue')
1807 self.assertEqual(Color.green.value, 'green')
1808
1809 def test_auto_name_inherit(self):
1810 class AutoNameEnum(Enum):
1811 def _generate_next_value_(name, start, count, last):
1812 return name
1813 class Color(AutoNameEnum):
1814 red = auto()
1815 blue = auto()
1816 green = auto()
1817
1818 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1819 self.assertEqual(Color.red.value, 'red')
1820 self.assertEqual(Color.blue.value, 'blue')
1821 self.assertEqual(Color.green.value, 'green')
1822
1823 def test_auto_garbage(self):
1824 class Color(Enum):
1825 red = 'red'
1826 blue = auto()
1827 self.assertEqual(Color.blue.value, 1)
1828
1829 def test_auto_garbage_corrected(self):
1830 class Color(Enum):
1831 red = 'red'
1832 blue = 2
1833 green = auto()
1834
1835 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1836 self.assertEqual(Color.red.value, 'red')
1837 self.assertEqual(Color.blue.value, 2)
1838 self.assertEqual(Color.green.value, 3)
1839
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001840 def test_auto_order(self):
1841 with self.assertRaises(TypeError):
1842 class Color(Enum):
1843 red = auto()
1844 green = auto()
1845 blue = auto()
1846 def _generate_next_value_(name, start, count, last):
1847 return name
1848
Ethan Furmanfc23a942020-09-16 12:37:54 -07001849 def test_auto_order_wierd(self):
1850 weird_auto = auto()
1851 weird_auto.value = 'pathological case'
1852 class Color(Enum):
1853 red = weird_auto
1854 def _generate_next_value_(name, start, count, last):
1855 return name
1856 blue = auto()
1857 self.assertEqual(list(Color), [Color.red, Color.blue])
1858 self.assertEqual(Color.red.value, 'pathological case')
1859 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001860
Ethan Furman3515dcc2016-09-18 13:15:41 -07001861 def test_duplicate_auto(self):
1862 class Dupes(Enum):
1863 first = primero = auto()
1864 second = auto()
1865 third = auto()
1866 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1867
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001868 def test_default_missing(self):
1869 class Color(Enum):
1870 RED = 1
1871 GREEN = 2
1872 BLUE = 3
1873 try:
1874 Color(7)
1875 except ValueError as exc:
1876 self.assertTrue(exc.__context__ is None)
1877 else:
1878 raise Exception('Exception not raised.')
1879
Ethan Furman019f0a02018-09-12 11:43:34 -07001880 def test_missing(self):
1881 class Color(Enum):
1882 red = 1
1883 green = 2
1884 blue = 3
1885 @classmethod
1886 def _missing_(cls, item):
1887 if item == 'three':
1888 return cls.blue
1889 elif item == 'bad return':
1890 # trigger internal error
1891 return 5
1892 elif item == 'error out':
1893 raise ZeroDivisionError
1894 else:
1895 # trigger not found
1896 return None
1897 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001898 try:
1899 Color(7)
1900 except ValueError as exc:
1901 self.assertTrue(exc.__context__ is None)
1902 else:
1903 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001904 try:
1905 Color('bad return')
1906 except TypeError as exc:
1907 self.assertTrue(isinstance(exc.__context__, ValueError))
1908 else:
1909 raise Exception('Exception not raised.')
1910 try:
1911 Color('error out')
1912 except ZeroDivisionError as exc:
1913 self.assertTrue(isinstance(exc.__context__, ValueError))
1914 else:
1915 raise Exception('Exception not raised.')
1916
Ethan Furman5bdab642018-09-21 19:03:09 -07001917 def test_multiple_mixin(self):
1918 class MaxMixin:
1919 @classproperty
1920 def MAX(cls):
1921 max = len(cls)
1922 cls.MAX = max
1923 return max
1924 class StrMixin:
1925 def __str__(self):
1926 return self._name_.lower()
1927 class SomeEnum(Enum):
1928 def behavior(self):
1929 return 'booyah'
1930 class AnotherEnum(Enum):
1931 def behavior(self):
1932 return 'nuhuh!'
1933 def social(self):
1934 return "what's up?"
1935 class Color(MaxMixin, Enum):
1936 RED = auto()
1937 GREEN = auto()
1938 BLUE = auto()
1939 self.assertEqual(Color.RED.value, 1)
1940 self.assertEqual(Color.GREEN.value, 2)
1941 self.assertEqual(Color.BLUE.value, 3)
1942 self.assertEqual(Color.MAX, 3)
1943 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1944 class Color(MaxMixin, StrMixin, Enum):
1945 RED = auto()
1946 GREEN = auto()
1947 BLUE = auto()
1948 self.assertEqual(Color.RED.value, 1)
1949 self.assertEqual(Color.GREEN.value, 2)
1950 self.assertEqual(Color.BLUE.value, 3)
1951 self.assertEqual(Color.MAX, 3)
1952 self.assertEqual(str(Color.BLUE), 'blue')
1953 class Color(StrMixin, MaxMixin, Enum):
1954 RED = auto()
1955 GREEN = auto()
1956 BLUE = auto()
1957 self.assertEqual(Color.RED.value, 1)
1958 self.assertEqual(Color.GREEN.value, 2)
1959 self.assertEqual(Color.BLUE.value, 3)
1960 self.assertEqual(Color.MAX, 3)
1961 self.assertEqual(str(Color.BLUE), 'blue')
1962 class CoolColor(StrMixin, SomeEnum, Enum):
1963 RED = auto()
1964 GREEN = auto()
1965 BLUE = auto()
1966 self.assertEqual(CoolColor.RED.value, 1)
1967 self.assertEqual(CoolColor.GREEN.value, 2)
1968 self.assertEqual(CoolColor.BLUE.value, 3)
1969 self.assertEqual(str(CoolColor.BLUE), 'blue')
1970 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1971 class CoolerColor(StrMixin, AnotherEnum, Enum):
1972 RED = auto()
1973 GREEN = auto()
1974 BLUE = auto()
1975 self.assertEqual(CoolerColor.RED.value, 1)
1976 self.assertEqual(CoolerColor.GREEN.value, 2)
1977 self.assertEqual(CoolerColor.BLUE.value, 3)
1978 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1979 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1980 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1981 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1982 RED = auto()
1983 GREEN = auto()
1984 BLUE = auto()
1985 self.assertEqual(CoolestColor.RED.value, 1)
1986 self.assertEqual(CoolestColor.GREEN.value, 2)
1987 self.assertEqual(CoolestColor.BLUE.value, 3)
1988 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1989 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1990 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1991 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1992 RED = auto()
1993 GREEN = auto()
1994 BLUE = auto()
1995 self.assertEqual(ConfusedColor.RED.value, 1)
1996 self.assertEqual(ConfusedColor.GREEN.value, 2)
1997 self.assertEqual(ConfusedColor.BLUE.value, 3)
1998 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1999 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
2000 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2001 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
2002 RED = auto()
2003 GREEN = auto()
2004 BLUE = auto()
2005 self.assertEqual(ReformedColor.RED.value, 1)
2006 self.assertEqual(ReformedColor.GREEN.value, 2)
2007 self.assertEqual(ReformedColor.BLUE.value, 3)
2008 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2009 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2010 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2011 self.assertTrue(issubclass(ReformedColor, int))
2012
Ethan Furmancd453852018-10-05 23:29:36 -07002013 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002014 @unique
2015 class Decision1(StrEnum):
2016 REVERT = "REVERT"
2017 REVERT_ALL = "REVERT_ALL"
2018 RETRY = "RETRY"
2019 class MyEnum(StrEnum):
2020 pass
2021 @unique
2022 class Decision2(MyEnum):
2023 REVERT = "REVERT"
2024 REVERT_ALL = "REVERT_ALL"
2025 RETRY = "RETRY"
2026
Ethan Furmanc2667362020-12-07 00:17:31 -08002027 def test_multiple_mixin_inherited(self):
2028 class MyInt(int):
2029 def __new__(cls, value):
2030 return super().__new__(cls, value)
2031
2032 class HexMixin:
2033 def __repr__(self):
2034 return hex(self)
2035
2036 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2037 pass
2038
2039 class Foo(MyIntEnum):
2040 TEST = 1
2041 self.assertTrue(isinstance(Foo.TEST, MyInt))
2042 self.assertEqual(repr(Foo.TEST), "0x1")
2043
2044 class Fee(MyIntEnum):
2045 TEST = 1
2046 def __new__(cls, value):
2047 value += 1
2048 member = int.__new__(cls, value)
2049 member._value_ = value
2050 return member
2051 self.assertEqual(Fee.TEST, 2)
2052
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002053 def test_empty_globals(self):
2054 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2055 # when using compile and exec because f_globals is empty
2056 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2057 code = compile(code, "<string>", "exec")
2058 global_ns = {}
2059 local_ls = {}
2060 exec(code, global_ns, local_ls)
2061
Ethan Furman0063ff42020-09-21 17:23:13 -07002062 def test_strenum(self):
2063 class GoodStrEnum(StrEnum):
2064 one = '1'
2065 two = '2'
2066 three = b'3', 'ascii'
2067 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002068 self.assertEqual(GoodStrEnum.one, '1')
2069 self.assertEqual(str(GoodStrEnum.one), '1')
2070 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2071 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2072 #
2073 class DumbMixin:
2074 def __str__(self):
2075 return "don't do this"
2076 class DumbStrEnum(DumbMixin, StrEnum):
2077 five = '5'
2078 six = '6'
2079 seven = '7'
2080 self.assertEqual(DumbStrEnum.seven, '7')
2081 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2082 #
2083 class EnumMixin(Enum):
2084 def hello(self):
2085 print('hello from %s' % (self, ))
2086 class HelloEnum(EnumMixin, StrEnum):
2087 eight = '8'
2088 self.assertEqual(HelloEnum.eight, '8')
2089 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2090 #
2091 class GoodbyeMixin:
2092 def goodbye(self):
2093 print('%s wishes you a fond farewell')
2094 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2095 nine = '9'
2096 self.assertEqual(GoodbyeEnum.nine, '9')
2097 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2098 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002099 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2100 class FirstFailedStrEnum(StrEnum):
2101 one = 1
2102 two = '2'
2103 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2104 class SecondFailedStrEnum(StrEnum):
2105 one = '1'
2106 two = 2,
2107 three = '3'
2108 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2109 class ThirdFailedStrEnum(StrEnum):
2110 one = '1'
2111 two = 2
2112 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2113 class ThirdFailedStrEnum(StrEnum):
2114 one = '1'
2115 two = b'2', sys.getdefaultencoding
2116 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2117 class ThirdFailedStrEnum(StrEnum):
2118 one = '1'
2119 two = b'2', 'ascii', 9
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002120
Ethan Furmane8e61272016-08-20 07:19:31 -07002121class TestOrder(unittest.TestCase):
2122
2123 def test_same_members(self):
2124 class Color(Enum):
2125 _order_ = 'red green blue'
2126 red = 1
2127 green = 2
2128 blue = 3
2129
2130 def test_same_members_with_aliases(self):
2131 class Color(Enum):
2132 _order_ = 'red green blue'
2133 red = 1
2134 green = 2
2135 blue = 3
2136 verde = green
2137
2138 def test_same_members_wrong_order(self):
2139 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2140 class Color(Enum):
2141 _order_ = 'red green blue'
2142 red = 1
2143 blue = 3
2144 green = 2
2145
2146 def test_order_has_extra_members(self):
2147 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2148 class Color(Enum):
2149 _order_ = 'red green blue purple'
2150 red = 1
2151 green = 2
2152 blue = 3
2153
2154 def test_order_has_extra_members_with_aliases(self):
2155 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2156 class Color(Enum):
2157 _order_ = 'red green blue purple'
2158 red = 1
2159 green = 2
2160 blue = 3
2161 verde = green
2162
2163 def test_enum_has_extra_members(self):
2164 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2165 class Color(Enum):
2166 _order_ = 'red green blue'
2167 red = 1
2168 green = 2
2169 blue = 3
2170 purple = 4
2171
2172 def test_enum_has_extra_members_with_aliases(self):
2173 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2174 class Color(Enum):
2175 _order_ = 'red green blue'
2176 red = 1
2177 green = 2
2178 blue = 3
2179 purple = 4
2180 verde = green
2181
2182
Ethan Furman65a5a472016-09-01 23:55:19 -07002183class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002184 """Tests of the Flags."""
2185
Ethan Furman65a5a472016-09-01 23:55:19 -07002186 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002187 R, W, X = 4, 2, 1
2188
Ethan Furman65a5a472016-09-01 23:55:19 -07002189 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002190 RO = 0
2191 WO = 1
2192 RW = 2
2193 AC = 3
2194 CE = 1<<19
2195
Rahul Jha94306522018-09-10 23:51:04 +05302196 class Color(Flag):
2197 BLACK = 0
2198 RED = 1
2199 GREEN = 2
2200 BLUE = 4
2201 PURPLE = RED|BLUE
2202
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002203 def test_str(self):
2204 Perm = self.Perm
2205 self.assertEqual(str(Perm.R), 'Perm.R')
2206 self.assertEqual(str(Perm.W), 'Perm.W')
2207 self.assertEqual(str(Perm.X), 'Perm.X')
2208 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2209 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2210 self.assertEqual(str(Perm(0)), 'Perm.0')
2211 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2212 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2213 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2214 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2215 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2216 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2217
2218 Open = self.Open
2219 self.assertEqual(str(Open.RO), 'Open.RO')
2220 self.assertEqual(str(Open.WO), 'Open.WO')
2221 self.assertEqual(str(Open.AC), 'Open.AC')
2222 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2223 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002224 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002225 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2226 self.assertEqual(str(~Open.AC), 'Open.CE')
2227 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2228 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2229
2230 def test_repr(self):
2231 Perm = self.Perm
2232 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2233 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2234 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2235 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2236 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002237 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002238 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2239 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2240 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2241 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002242 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002243 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2244
2245 Open = self.Open
2246 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2247 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2248 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2249 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2250 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002251 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002252 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2253 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2254 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2255 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2256
Ethan Furman37440ee2020-12-08 11:14:10 -08002257 def test_format(self):
2258 Perm = self.Perm
2259 self.assertEqual(format(Perm.R, ''), 'Perm.R')
2260 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
2261
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002262 def test_or(self):
2263 Perm = self.Perm
2264 for i in Perm:
2265 for j in Perm:
2266 self.assertEqual((i | j), Perm(i.value | j.value))
2267 self.assertEqual((i | j).value, i.value | j.value)
2268 self.assertIs(type(i | j), Perm)
2269 for i in Perm:
2270 self.assertIs(i | i, i)
2271 Open = self.Open
2272 self.assertIs(Open.RO | Open.CE, Open.CE)
2273
2274 def test_and(self):
2275 Perm = self.Perm
2276 RW = Perm.R | Perm.W
2277 RX = Perm.R | Perm.X
2278 WX = Perm.W | Perm.X
2279 RWX = Perm.R | Perm.W | Perm.X
2280 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2281 for i in values:
2282 for j in values:
2283 self.assertEqual((i & j).value, i.value & j.value)
2284 self.assertIs(type(i & j), Perm)
2285 for i in Perm:
2286 self.assertIs(i & i, i)
2287 self.assertIs(i & RWX, i)
2288 self.assertIs(RWX & i, i)
2289 Open = self.Open
2290 self.assertIs(Open.RO & Open.CE, Open.RO)
2291
2292 def test_xor(self):
2293 Perm = self.Perm
2294 for i in Perm:
2295 for j in Perm:
2296 self.assertEqual((i ^ j).value, i.value ^ j.value)
2297 self.assertIs(type(i ^ j), Perm)
2298 for i in Perm:
2299 self.assertIs(i ^ Perm(0), i)
2300 self.assertIs(Perm(0) ^ i, i)
2301 Open = self.Open
2302 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2303 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2304
2305 def test_invert(self):
2306 Perm = self.Perm
2307 RW = Perm.R | Perm.W
2308 RX = Perm.R | Perm.X
2309 WX = Perm.W | Perm.X
2310 RWX = Perm.R | Perm.W | Perm.X
2311 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2312 for i in values:
2313 self.assertIs(type(~i), Perm)
2314 self.assertEqual(~~i, i)
2315 for i in Perm:
2316 self.assertIs(~~i, i)
2317 Open = self.Open
2318 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2319 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2320
Ethan Furman25d94bb2016-09-02 16:32:32 -07002321 def test_bool(self):
2322 Perm = self.Perm
2323 for f in Perm:
2324 self.assertTrue(f)
2325 Open = self.Open
2326 for f in Open:
2327 self.assertEqual(bool(f.value), bool(f))
2328
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002329 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002330 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002331 lst = list(Perm)
2332 self.assertEqual(len(lst), len(Perm))
2333 self.assertEqual(len(Perm), 3, Perm)
2334 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2335 for i, n in enumerate('R W X'.split()):
2336 v = 1<<i
2337 e = Perm(v)
2338 self.assertEqual(e.value, v)
2339 self.assertEqual(type(e.value), int)
2340 self.assertEqual(e.name, n)
2341 self.assertIn(e, Perm)
2342 self.assertIs(type(e), Perm)
2343
2344 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002345 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002346 lst = list(Perm)
2347 self.assertEqual(len(lst), len(Perm))
2348 self.assertEqual(len(Perm), 3, Perm)
2349 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2350 for i, n in enumerate('R W X'.split()):
2351 v = 8<<i
2352 e = Perm(v)
2353 self.assertEqual(e.value, v)
2354 self.assertEqual(type(e.value), int)
2355 self.assertEqual(e.name, n)
2356 self.assertIn(e, Perm)
2357 self.assertIs(type(e), Perm)
2358
2359 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002360 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002361 lst = list(Perm)
2362 self.assertEqual(len(lst), len(Perm))
2363 self.assertEqual(len(Perm), 3, Perm)
2364 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2365 for i, n in enumerate('R W X'.split()):
2366 v = 1<<i
2367 e = Perm(v)
2368 self.assertEqual(e.value, v)
2369 self.assertEqual(type(e.value), int)
2370 self.assertEqual(e.name, n)
2371 self.assertIn(e, Perm)
2372 self.assertIs(type(e), Perm)
2373
2374 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002375 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002376 lst = list(Perm)
2377 self.assertEqual(len(lst), len(Perm))
2378 self.assertEqual(len(Perm), 3, Perm)
2379 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2380 for i, n in enumerate('R W X'.split()):
2381 v = 1<<(2*i+1)
2382 e = Perm(v)
2383 self.assertEqual(e.value, v)
2384 self.assertEqual(type(e.value), int)
2385 self.assertEqual(e.name, n)
2386 self.assertIn(e, Perm)
2387 self.assertIs(type(e), Perm)
2388
2389 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002390 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002391 lst = list(Perm)
2392 self.assertEqual(len(lst), len(Perm))
2393 self.assertEqual(len(Perm), 3, Perm)
2394 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2395 for i, n in enumerate('R W X'.split()):
2396 v = 1<<(2*i+1)
2397 e = Perm(v)
2398 self.assertEqual(e.value, v)
2399 self.assertEqual(type(e.value), int)
2400 self.assertEqual(e.name, n)
2401 self.assertIn(e, Perm)
2402 self.assertIs(type(e), Perm)
2403
Ethan Furman65a5a472016-09-01 23:55:19 -07002404 def test_pickle(self):
2405 if isinstance(FlagStooges, Exception):
2406 raise FlagStooges
2407 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2408 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002409
Rahul Jha94306522018-09-10 23:51:04 +05302410 def test_contains(self):
2411 Open = self.Open
2412 Color = self.Color
2413 self.assertFalse(Color.BLACK in Open)
2414 self.assertFalse(Open.RO in Color)
2415 with self.assertRaises(TypeError):
2416 'BLACK' in Color
2417 with self.assertRaises(TypeError):
2418 'RO' in Open
2419 with self.assertRaises(TypeError):
2420 1 in Color
2421 with self.assertRaises(TypeError):
2422 1 in Open
2423
2424 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002425 Perm = self.Perm
2426 R, W, X = Perm
2427 RW = R | W
2428 RX = R | X
2429 WX = W | X
2430 RWX = R | W | X
2431 self.assertTrue(R in RW)
2432 self.assertTrue(R in RX)
2433 self.assertTrue(R in RWX)
2434 self.assertTrue(W in RW)
2435 self.assertTrue(W in WX)
2436 self.assertTrue(W in RWX)
2437 self.assertTrue(X in RX)
2438 self.assertTrue(X in WX)
2439 self.assertTrue(X in RWX)
2440 self.assertFalse(R in WX)
2441 self.assertFalse(W in RX)
2442 self.assertFalse(X in RW)
2443
Ethan Furman7219e272020-09-16 13:01:00 -07002444 def test_member_iter(self):
2445 Color = self.Color
2446 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2447 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2448 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2449
Ethan Furmanc16595e2016-09-10 23:36:59 -07002450 def test_auto_number(self):
2451 class Color(Flag):
2452 red = auto()
2453 blue = auto()
2454 green = auto()
2455
2456 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2457 self.assertEqual(Color.red.value, 1)
2458 self.assertEqual(Color.blue.value, 2)
2459 self.assertEqual(Color.green.value, 4)
2460
2461 def test_auto_number_garbage(self):
2462 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2463 class Color(Flag):
2464 red = 'not an int'
2465 blue = auto()
2466
Ethan Furman3515dcc2016-09-18 13:15:41 -07002467 def test_cascading_failure(self):
2468 class Bizarre(Flag):
2469 c = 3
2470 d = 4
2471 f = 6
2472 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002473 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2474 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2475 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2476 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2477 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2478 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2479 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002480
2481 def test_duplicate_auto(self):
2482 class Dupes(Enum):
2483 first = primero = auto()
2484 second = auto()
2485 third = auto()
2486 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2487
2488 def test_bizarre(self):
2489 class Bizarre(Flag):
2490 b = 3
2491 c = 4
2492 d = 6
2493 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2494
Ethan Furman5bdab642018-09-21 19:03:09 -07002495 def test_multiple_mixin(self):
2496 class AllMixin:
2497 @classproperty
2498 def ALL(cls):
2499 members = list(cls)
2500 all_value = None
2501 if members:
2502 all_value = members[0]
2503 for member in members[1:]:
2504 all_value |= member
2505 cls.ALL = all_value
2506 return all_value
2507 class StrMixin:
2508 def __str__(self):
2509 return self._name_.lower()
2510 class Color(AllMixin, Flag):
2511 RED = auto()
2512 GREEN = auto()
2513 BLUE = auto()
2514 self.assertEqual(Color.RED.value, 1)
2515 self.assertEqual(Color.GREEN.value, 2)
2516 self.assertEqual(Color.BLUE.value, 4)
2517 self.assertEqual(Color.ALL.value, 7)
2518 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2519 class Color(AllMixin, StrMixin, Flag):
2520 RED = auto()
2521 GREEN = auto()
2522 BLUE = auto()
2523 self.assertEqual(Color.RED.value, 1)
2524 self.assertEqual(Color.GREEN.value, 2)
2525 self.assertEqual(Color.BLUE.value, 4)
2526 self.assertEqual(Color.ALL.value, 7)
2527 self.assertEqual(str(Color.BLUE), 'blue')
2528 class Color(StrMixin, AllMixin, Flag):
2529 RED = auto()
2530 GREEN = auto()
2531 BLUE = auto()
2532 self.assertEqual(Color.RED.value, 1)
2533 self.assertEqual(Color.GREEN.value, 2)
2534 self.assertEqual(Color.BLUE.value, 4)
2535 self.assertEqual(Color.ALL.value, 7)
2536 self.assertEqual(str(Color.BLUE), 'blue')
2537
Hai Shie80697d2020-05-28 06:10:27 +08002538 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002539 def test_unique_composite(self):
2540 # override __eq__ to be identity only
2541 class TestFlag(Flag):
2542 one = auto()
2543 two = auto()
2544 three = auto()
2545 four = auto()
2546 five = auto()
2547 six = auto()
2548 seven = auto()
2549 eight = auto()
2550 def __eq__(self, other):
2551 return self is other
2552 def __hash__(self):
2553 return hash(self._value_)
2554 # have multiple threads competing to complete the composite members
2555 seen = set()
2556 failed = False
2557 def cycle_enum():
2558 nonlocal failed
2559 try:
2560 for i in range(256):
2561 seen.add(TestFlag(i))
2562 except Exception:
2563 failed = True
2564 threads = [
2565 threading.Thread(target=cycle_enum)
2566 for _ in range(8)
2567 ]
Hai Shie80697d2020-05-28 06:10:27 +08002568 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002569 pass
2570 # check that only 248 members were created
2571 self.assertFalse(
2572 failed,
2573 'at least one thread failed while creating composite members')
2574 self.assertEqual(256, len(seen), 'too many composite members created')
2575
Ethan Furmanc16595e2016-09-10 23:36:59 -07002576
Ethan Furman65a5a472016-09-01 23:55:19 -07002577class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002578 """Tests of the IntFlags."""
2579
Ethan Furman65a5a472016-09-01 23:55:19 -07002580 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002581 X = 1 << 0
2582 W = 1 << 1
2583 R = 1 << 2
2584
Ethan Furman65a5a472016-09-01 23:55:19 -07002585 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002586 RO = 0
2587 WO = 1
2588 RW = 2
2589 AC = 3
2590 CE = 1<<19
2591
Rahul Jha94306522018-09-10 23:51:04 +05302592 class Color(IntFlag):
2593 BLACK = 0
2594 RED = 1
2595 GREEN = 2
2596 BLUE = 4
2597 PURPLE = RED|BLUE
2598
Ethan Furman3515dcc2016-09-18 13:15:41 -07002599 def test_type(self):
2600 Perm = self.Perm
Ethan Furman37440ee2020-12-08 11:14:10 -08002601 self.assertTrue(Perm._member_type_ is int)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002602 Open = self.Open
2603 for f in Perm:
2604 self.assertTrue(isinstance(f, Perm))
2605 self.assertEqual(f, f.value)
2606 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2607 self.assertEqual(Perm.W | Perm.X, 3)
2608 for f in Open:
2609 self.assertTrue(isinstance(f, Open))
2610 self.assertEqual(f, f.value)
2611 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2612 self.assertEqual(Open.WO | Open.RW, 3)
2613
2614
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002615 def test_str(self):
2616 Perm = self.Perm
2617 self.assertEqual(str(Perm.R), 'Perm.R')
2618 self.assertEqual(str(Perm.W), 'Perm.W')
2619 self.assertEqual(str(Perm.X), 'Perm.X')
2620 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2621 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2622 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2623 self.assertEqual(str(Perm(0)), 'Perm.0')
2624 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002625 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2626 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2627 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2628 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002629 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002630 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2631 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2632 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002633
2634 Open = self.Open
2635 self.assertEqual(str(Open.RO), 'Open.RO')
2636 self.assertEqual(str(Open.WO), 'Open.WO')
2637 self.assertEqual(str(Open.AC), 'Open.AC')
2638 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2639 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2640 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002641 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2642 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2643 self.assertEqual(str(~Open.AC), 'Open.CE')
2644 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2645 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2646 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002647
2648 def test_repr(self):
2649 Perm = self.Perm
2650 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2651 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2652 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2653 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2654 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2655 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002656 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2657 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002658 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2659 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2660 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2661 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002662 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002663 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2664 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2665 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002666
2667 Open = self.Open
2668 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2669 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2670 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2671 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2672 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002673 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002674 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2675 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2676 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2677 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2678 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2679 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002680
Ethan Furman37440ee2020-12-08 11:14:10 -08002681 def test_format(self):
2682 Perm = self.Perm
2683 self.assertEqual(format(Perm.R, ''), '4')
2684 self.assertEqual(format(Perm.R | Perm.X, ''), '5')
2685
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002686 def test_or(self):
2687 Perm = self.Perm
2688 for i in Perm:
2689 for j in Perm:
2690 self.assertEqual(i | j, i.value | j.value)
2691 self.assertEqual((i | j).value, i.value | j.value)
2692 self.assertIs(type(i | j), Perm)
2693 for j in range(8):
2694 self.assertEqual(i | j, i.value | j)
2695 self.assertEqual((i | j).value, i.value | j)
2696 self.assertIs(type(i | j), Perm)
2697 self.assertEqual(j | i, j | i.value)
2698 self.assertEqual((j | i).value, j | i.value)
2699 self.assertIs(type(j | i), Perm)
2700 for i in Perm:
2701 self.assertIs(i | i, i)
2702 self.assertIs(i | 0, i)
2703 self.assertIs(0 | i, i)
2704 Open = self.Open
2705 self.assertIs(Open.RO | Open.CE, Open.CE)
2706
2707 def test_and(self):
2708 Perm = self.Perm
2709 RW = Perm.R | Perm.W
2710 RX = Perm.R | Perm.X
2711 WX = Perm.W | Perm.X
2712 RWX = Perm.R | Perm.W | Perm.X
2713 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2714 for i in values:
2715 for j in values:
2716 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2717 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2718 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2719 for j in range(8):
2720 self.assertEqual(i & j, i.value & j)
2721 self.assertEqual((i & j).value, i.value & j)
2722 self.assertIs(type(i & j), Perm)
2723 self.assertEqual(j & i, j & i.value)
2724 self.assertEqual((j & i).value, j & i.value)
2725 self.assertIs(type(j & i), Perm)
2726 for i in Perm:
2727 self.assertIs(i & i, i)
2728 self.assertIs(i & 7, i)
2729 self.assertIs(7 & i, i)
2730 Open = self.Open
2731 self.assertIs(Open.RO & Open.CE, Open.RO)
2732
2733 def test_xor(self):
2734 Perm = self.Perm
2735 for i in Perm:
2736 for j in Perm:
2737 self.assertEqual(i ^ j, i.value ^ j.value)
2738 self.assertEqual((i ^ j).value, i.value ^ j.value)
2739 self.assertIs(type(i ^ j), Perm)
2740 for j in range(8):
2741 self.assertEqual(i ^ j, i.value ^ j)
2742 self.assertEqual((i ^ j).value, i.value ^ j)
2743 self.assertIs(type(i ^ j), Perm)
2744 self.assertEqual(j ^ i, j ^ i.value)
2745 self.assertEqual((j ^ i).value, j ^ i.value)
2746 self.assertIs(type(j ^ i), Perm)
2747 for i in Perm:
2748 self.assertIs(i ^ 0, i)
2749 self.assertIs(0 ^ i, i)
2750 Open = self.Open
2751 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2752 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2753
2754 def test_invert(self):
2755 Perm = self.Perm
2756 RW = Perm.R | Perm.W
2757 RX = Perm.R | Perm.X
2758 WX = Perm.W | Perm.X
2759 RWX = Perm.R | Perm.W | Perm.X
2760 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2761 for i in values:
2762 self.assertEqual(~i, ~i.value)
2763 self.assertEqual((~i).value, ~i.value)
2764 self.assertIs(type(~i), Perm)
2765 self.assertEqual(~~i, i)
2766 for i in Perm:
2767 self.assertIs(~~i, i)
2768 Open = self.Open
2769 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2770 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2771
2772 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002773 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002774 lst = list(Perm)
2775 self.assertEqual(len(lst), len(Perm))
2776 self.assertEqual(len(Perm), 3, Perm)
2777 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2778 for i, n in enumerate('R W X'.split()):
2779 v = 1<<i
2780 e = Perm(v)
2781 self.assertEqual(e.value, v)
2782 self.assertEqual(type(e.value), int)
2783 self.assertEqual(e, v)
2784 self.assertEqual(e.name, n)
2785 self.assertIn(e, Perm)
2786 self.assertIs(type(e), Perm)
2787
2788 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002789 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002790 lst = list(Perm)
2791 self.assertEqual(len(lst), len(Perm))
2792 self.assertEqual(len(Perm), 3, Perm)
2793 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2794 for i, n in enumerate('R W X'.split()):
2795 v = 8<<i
2796 e = Perm(v)
2797 self.assertEqual(e.value, v)
2798 self.assertEqual(type(e.value), int)
2799 self.assertEqual(e, v)
2800 self.assertEqual(e.name, n)
2801 self.assertIn(e, Perm)
2802 self.assertIs(type(e), Perm)
2803
2804 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002805 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002806 lst = list(Perm)
2807 self.assertEqual(len(lst), len(Perm))
2808 self.assertEqual(len(Perm), 3, Perm)
2809 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2810 for i, n in enumerate('R W X'.split()):
2811 v = 1<<i
2812 e = Perm(v)
2813 self.assertEqual(e.value, v)
2814 self.assertEqual(type(e.value), int)
2815 self.assertEqual(e, v)
2816 self.assertEqual(e.name, n)
2817 self.assertIn(e, Perm)
2818 self.assertIs(type(e), Perm)
2819
2820 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002821 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002822 lst = list(Perm)
2823 self.assertEqual(len(lst), len(Perm))
2824 self.assertEqual(len(Perm), 3, Perm)
2825 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2826 for i, n in enumerate('R W X'.split()):
2827 v = 1<<(2*i+1)
2828 e = Perm(v)
2829 self.assertEqual(e.value, v)
2830 self.assertEqual(type(e.value), int)
2831 self.assertEqual(e, v)
2832 self.assertEqual(e.name, n)
2833 self.assertIn(e, Perm)
2834 self.assertIs(type(e), Perm)
2835
2836 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002837 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002838 lst = list(Perm)
2839 self.assertEqual(len(lst), len(Perm))
2840 self.assertEqual(len(Perm), 3, Perm)
2841 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2842 for i, n in enumerate('R W X'.split()):
2843 v = 1<<(2*i+1)
2844 e = Perm(v)
2845 self.assertEqual(e.value, v)
2846 self.assertEqual(type(e.value), int)
2847 self.assertEqual(e, v)
2848 self.assertEqual(e.name, n)
2849 self.assertIn(e, Perm)
2850 self.assertIs(type(e), Perm)
2851
2852
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002853 def test_programatic_function_from_empty_list(self):
2854 Perm = enum.IntFlag('Perm', [])
2855 lst = list(Perm)
2856 self.assertEqual(len(lst), len(Perm))
2857 self.assertEqual(len(Perm), 0, Perm)
2858 Thing = enum.Enum('Thing', [])
2859 lst = list(Thing)
2860 self.assertEqual(len(lst), len(Thing))
2861 self.assertEqual(len(Thing), 0, Thing)
2862
2863
2864 def test_programatic_function_from_empty_tuple(self):
2865 Perm = enum.IntFlag('Perm', ())
2866 lst = list(Perm)
2867 self.assertEqual(len(lst), len(Perm))
2868 self.assertEqual(len(Perm), 0, Perm)
2869 Thing = enum.Enum('Thing', ())
2870 self.assertEqual(len(lst), len(Thing))
2871 self.assertEqual(len(Thing), 0, Thing)
2872
Rahul Jha94306522018-09-10 23:51:04 +05302873 def test_contains(self):
2874 Open = self.Open
2875 Color = self.Color
2876 self.assertTrue(Color.GREEN in Color)
2877 self.assertTrue(Open.RW in Open)
2878 self.assertFalse(Color.GREEN in Open)
2879 self.assertFalse(Open.RW in Color)
2880 with self.assertRaises(TypeError):
2881 'GREEN' in Color
2882 with self.assertRaises(TypeError):
2883 'RW' in Open
2884 with self.assertRaises(TypeError):
2885 2 in Color
2886 with self.assertRaises(TypeError):
2887 2 in Open
2888
2889 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002890 Perm = self.Perm
2891 R, W, X = Perm
2892 RW = R | W
2893 RX = R | X
2894 WX = W | X
2895 RWX = R | W | X
2896 self.assertTrue(R in RW)
2897 self.assertTrue(R in RX)
2898 self.assertTrue(R in RWX)
2899 self.assertTrue(W in RW)
2900 self.assertTrue(W in WX)
2901 self.assertTrue(W in RWX)
2902 self.assertTrue(X in RX)
2903 self.assertTrue(X in WX)
2904 self.assertTrue(X in RWX)
2905 self.assertFalse(R in WX)
2906 self.assertFalse(W in RX)
2907 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302908 with self.assertRaises(TypeError):
2909 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002910
Ethan Furman7219e272020-09-16 13:01:00 -07002911 def test_member_iter(self):
2912 Color = self.Color
2913 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2914 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2915 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2916
Ethan Furman25d94bb2016-09-02 16:32:32 -07002917 def test_bool(self):
2918 Perm = self.Perm
2919 for f in Perm:
2920 self.assertTrue(f)
2921 Open = self.Open
2922 for f in Open:
2923 self.assertEqual(bool(f.value), bool(f))
2924
Ethan Furman5bdab642018-09-21 19:03:09 -07002925 def test_multiple_mixin(self):
2926 class AllMixin:
2927 @classproperty
2928 def ALL(cls):
2929 members = list(cls)
2930 all_value = None
2931 if members:
2932 all_value = members[0]
2933 for member in members[1:]:
2934 all_value |= member
2935 cls.ALL = all_value
2936 return all_value
2937 class StrMixin:
2938 def __str__(self):
2939 return self._name_.lower()
2940 class Color(AllMixin, IntFlag):
2941 RED = auto()
2942 GREEN = auto()
2943 BLUE = auto()
2944 self.assertEqual(Color.RED.value, 1)
2945 self.assertEqual(Color.GREEN.value, 2)
2946 self.assertEqual(Color.BLUE.value, 4)
2947 self.assertEqual(Color.ALL.value, 7)
2948 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2949 class Color(AllMixin, StrMixin, IntFlag):
2950 RED = auto()
2951 GREEN = auto()
2952 BLUE = auto()
2953 self.assertEqual(Color.RED.value, 1)
2954 self.assertEqual(Color.GREEN.value, 2)
2955 self.assertEqual(Color.BLUE.value, 4)
2956 self.assertEqual(Color.ALL.value, 7)
2957 self.assertEqual(str(Color.BLUE), 'blue')
2958 class Color(StrMixin, AllMixin, IntFlag):
2959 RED = auto()
2960 GREEN = auto()
2961 BLUE = auto()
2962 self.assertEqual(Color.RED.value, 1)
2963 self.assertEqual(Color.GREEN.value, 2)
2964 self.assertEqual(Color.BLUE.value, 4)
2965 self.assertEqual(Color.ALL.value, 7)
2966 self.assertEqual(str(Color.BLUE), 'blue')
2967
Hai Shie80697d2020-05-28 06:10:27 +08002968 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002969 def test_unique_composite(self):
2970 # override __eq__ to be identity only
2971 class TestFlag(IntFlag):
2972 one = auto()
2973 two = auto()
2974 three = auto()
2975 four = auto()
2976 five = auto()
2977 six = auto()
2978 seven = auto()
2979 eight = auto()
2980 def __eq__(self, other):
2981 return self is other
2982 def __hash__(self):
2983 return hash(self._value_)
2984 # have multiple threads competing to complete the composite members
2985 seen = set()
2986 failed = False
2987 def cycle_enum():
2988 nonlocal failed
2989 try:
2990 for i in range(256):
2991 seen.add(TestFlag(i))
2992 except Exception:
2993 failed = True
2994 threads = [
2995 threading.Thread(target=cycle_enum)
2996 for _ in range(8)
2997 ]
Hai Shie80697d2020-05-28 06:10:27 +08002998 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002999 pass
3000 # check that only 248 members were created
3001 self.assertFalse(
3002 failed,
3003 'at least one thread failed while creating composite members')
3004 self.assertEqual(256, len(seen), 'too many composite members created')
3005
3006
Brennan D Baraban8b914d22019-03-03 14:09:11 -08003007class TestEmptyAndNonLatinStrings(unittest.TestCase):
3008
3009 def test_empty_string(self):
3010 with self.assertRaises(ValueError):
3011 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
3012
3013 def test_non_latin_character_string(self):
3014 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3015 item = getattr(greek_abc, '\u03B1')
3016 self.assertEqual(item.value, 1)
3017
3018 def test_non_latin_number_string(self):
3019 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3020 item = getattr(hebrew_123, '\u05D0')
3021 self.assertEqual(item.value, 1)
3022
3023
Ethan Furmanf24bb352013-07-18 17:05:39 -07003024class TestUnique(unittest.TestCase):
3025
3026 def test_unique_clean(self):
3027 @unique
3028 class Clean(Enum):
3029 one = 1
3030 two = 'dos'
3031 tres = 4.0
3032 @unique
3033 class Cleaner(IntEnum):
3034 single = 1
3035 double = 2
3036 triple = 3
3037
3038 def test_unique_dirty(self):
3039 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3040 @unique
3041 class Dirty(Enum):
3042 one = 1
3043 two = 'dos'
3044 tres = 1
3045 with self.assertRaisesRegex(
3046 ValueError,
3047 'double.*single.*turkey.*triple',
3048 ):
3049 @unique
3050 class Dirtier(IntEnum):
3051 single = 1
3052 double = 1
3053 triple = 3
3054 turkey = 3
3055
Ethan Furman3803ad42016-05-01 10:03:53 -07003056 def test_unique_with_name(self):
3057 @unique
3058 class Silly(Enum):
3059 one = 1
3060 two = 'dos'
3061 name = 3
3062 @unique
3063 class Sillier(IntEnum):
3064 single = 1
3065 name = 2
3066 triple = 3
3067 value = 4
3068
Ethan Furmanf24bb352013-07-18 17:05:39 -07003069
Ethan Furman5bdab642018-09-21 19:03:09 -07003070
Ethan Furman3323da92015-04-11 09:39:59 -07003071expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003072Help on class Color in module %s:
3073
3074class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003075 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3076 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003077 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003078 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003079 | Method resolution order:
3080 | Color
3081 | enum.Enum
3082 | builtins.object
3083 |\x20\x20
3084 | Data and other attributes defined here:
3085 |\x20\x20
3086 | blue = <Color.blue: 3>
3087 |\x20\x20
3088 | green = <Color.green: 2>
3089 |\x20\x20
3090 | red = <Color.red: 1>
3091 |\x20\x20
3092 | ----------------------------------------------------------------------
3093 | Data descriptors inherited from enum.Enum:
3094 |\x20\x20
3095 | name
3096 | The name of the Enum member.
3097 |\x20\x20
3098 | value
3099 | The value of the Enum member.
3100 |\x20\x20
3101 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003102 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003103 |\x20\x20
3104 | __members__
3105 | Returns a mapping of member name->value.
3106 |\x20\x20\x20\x20\x20\x20
3107 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003108 | is a read-only view of the internal mapping."""
3109
3110expected_help_output_without_docs = """\
3111Help on class Color in module %s:
3112
3113class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003114 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3115 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003116 | Method resolution order:
3117 | Color
3118 | enum.Enum
3119 | builtins.object
3120 |\x20\x20
3121 | Data and other attributes defined here:
3122 |\x20\x20
3123 | blue = <Color.blue: 3>
3124 |\x20\x20
3125 | green = <Color.green: 2>
3126 |\x20\x20
3127 | red = <Color.red: 1>
3128 |\x20\x20
3129 | ----------------------------------------------------------------------
3130 | Data descriptors inherited from enum.Enum:
3131 |\x20\x20
3132 | name
3133 |\x20\x20
3134 | value
3135 |\x20\x20
3136 | ----------------------------------------------------------------------
3137 | Data descriptors inherited from enum.EnumMeta:
3138 |\x20\x20
3139 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003140
3141class TestStdLib(unittest.TestCase):
3142
Ethan Furman48a724f2015-04-11 23:23:06 -07003143 maxDiff = None
3144
Ethan Furman5875d742013-10-21 20:45:55 -07003145 class Color(Enum):
3146 red = 1
3147 green = 2
3148 blue = 3
3149
3150 def test_pydoc(self):
3151 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003152 if StrEnum.__doc__ is None:
3153 expected_text = expected_help_output_without_docs % __name__
3154 else:
3155 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003156 output = StringIO()
3157 helper = pydoc.Helper(output=output)
3158 helper(self.Color)
3159 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003160 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003161
3162 def test_inspect_getmembers(self):
3163 values = dict((
3164 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003165 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003166 ('__members__', self.Color.__members__),
3167 ('__module__', __name__),
3168 ('blue', self.Color.blue),
3169 ('green', self.Color.green),
3170 ('name', Enum.__dict__['name']),
3171 ('red', self.Color.red),
3172 ('value', Enum.__dict__['value']),
3173 ))
3174 result = dict(inspect.getmembers(self.Color))
3175 self.assertEqual(values.keys(), result.keys())
3176 failed = False
3177 for k in values.keys():
3178 if result[k] != values[k]:
3179 print()
3180 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3181 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3182 failed = True
3183 if failed:
3184 self.fail("result does not equal expected, see print above")
3185
3186 def test_inspect_classify_class_attrs(self):
3187 # indirectly test __objclass__
3188 from inspect import Attribute
3189 values = [
3190 Attribute(name='__class__', kind='data',
3191 defining_class=object, object=EnumMeta),
3192 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003193 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003194 Attribute(name='__members__', kind='property',
3195 defining_class=EnumMeta, object=EnumMeta.__members__),
3196 Attribute(name='__module__', kind='data',
3197 defining_class=self.Color, object=__name__),
3198 Attribute(name='blue', kind='data',
3199 defining_class=self.Color, object=self.Color.blue),
3200 Attribute(name='green', kind='data',
3201 defining_class=self.Color, object=self.Color.green),
3202 Attribute(name='red', kind='data',
3203 defining_class=self.Color, object=self.Color.red),
3204 Attribute(name='name', kind='data',
3205 defining_class=Enum, object=Enum.__dict__['name']),
3206 Attribute(name='value', kind='data',
3207 defining_class=Enum, object=Enum.__dict__['value']),
3208 ]
3209 values.sort(key=lambda item: item.name)
3210 result = list(inspect.classify_class_attrs(self.Color))
3211 result.sort(key=lambda item: item.name)
3212 failed = False
3213 for v, r in zip(values, result):
3214 if r != v:
3215 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3216 failed = True
3217 if failed:
3218 self.fail("result does not equal expected, see print above")
3219
Martin Panter19e69c52015-11-14 12:46:42 +00003220
3221class MiscTestCase(unittest.TestCase):
3222 def test__all__(self):
3223 support.check__all__(self, enum)
3224
3225
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003226# These are unordered here on purpose to ensure that declaration order
3227# makes no difference.
3228CONVERT_TEST_NAME_D = 5
3229CONVERT_TEST_NAME_C = 5
3230CONVERT_TEST_NAME_B = 5
3231CONVERT_TEST_NAME_A = 5 # This one should sort first.
3232CONVERT_TEST_NAME_E = 5
3233CONVERT_TEST_NAME_F = 5
3234
3235class TestIntEnumConvert(unittest.TestCase):
3236 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003237 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003238 'UnittestConvert',
3239 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003240 filter=lambda x: x.startswith('CONVERT_TEST_'))
3241 # We don't want the reverse lookup value to vary when there are
3242 # multiple possible names for a given value. It should always
3243 # report the first lexigraphical name in that case.
3244 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3245
3246 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003247 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003248 'UnittestConvert',
3249 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003250 filter=lambda x: x.startswith('CONVERT_TEST_'))
3251 # Ensure that test_type has all of the desired names and values.
3252 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3253 test_type.CONVERT_TEST_NAME_A)
3254 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3255 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3256 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3257 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3258 # Ensure that test_type only picked up names matching the filter.
3259 self.assertEqual([name for name in dir(test_type)
3260 if name[0:2] not in ('CO', '__')],
3261 [], msg='Names other than CONVERT_TEST_* found.')
3262
orlnub1230fb9fad2018-09-12 20:28:53 +03003263 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3264 '_convert was deprecated in 3.8')
3265 def test_convert_warn(self):
3266 with self.assertWarns(DeprecationWarning):
3267 enum.IntEnum._convert(
3268 'UnittestConvert',
3269 ('test.test_enum', '__main__')[__name__=='__main__'],
3270 filter=lambda x: x.startswith('CONVERT_TEST_'))
3271
3272 @unittest.skipUnless(sys.version_info >= (3, 9),
3273 '_convert was removed in 3.9')
3274 def test_convert_raise(self):
3275 with self.assertRaises(AttributeError):
3276 enum.IntEnum._convert(
3277 'UnittestConvert',
3278 ('test.test_enum', '__main__')[__name__=='__main__'],
3279 filter=lambda x: x.startswith('CONVERT_TEST_'))
3280
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003281
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003282if __name__ == '__main__':
3283 unittest.main()