blob: 4b5d0d07bc09f1e7c6a2b570efd0d2a6dbcc7e6a [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004import unittest
5from collections import OrderedDict
Ethan Furman5875d742013-10-21 20:45:55 -07006from enum import Enum, IntEnum, EnumMeta, unique
7from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -08008from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Ethan Furman6b3d64a2013-06-14 16:55:46 -07009
10# for pickle tests
11try:
12 class Stooges(Enum):
13 LARRY = 1
14 CURLY = 2
15 MOE = 3
16except Exception as exc:
17 Stooges = exc
18
19try:
20 class IntStooges(int, Enum):
21 LARRY = 1
22 CURLY = 2
23 MOE = 3
24except Exception as exc:
25 IntStooges = exc
26
27try:
28 class FloatStooges(float, Enum):
29 LARRY = 1.39
30 CURLY = 2.72
31 MOE = 3.142596
32except Exception as exc:
33 FloatStooges = exc
34
35# for pickle test and subclass tests
36try:
37 class StrEnum(str, Enum):
38 'accepts only string values'
39 class Name(StrEnum):
40 BDFL = 'Guido van Rossum'
41 FLUFL = 'Barry Warsaw'
42except Exception as exc:
43 Name = exc
44
45try:
46 Question = Enum('Question', 'who what when where why', module=__name__)
47except Exception as exc:
48 Question = exc
49
50try:
51 Answer = Enum('Answer', 'him this then there because')
52except Exception as exc:
53 Answer = exc
54
Ethan Furmanca1b7942014-02-08 11:36:27 -080055try:
56 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
57except Exception as exc:
58 Theory = exc
59
Ethan Furman6b3d64a2013-06-14 16:55:46 -070060# for doctests
61try:
62 class Fruit(Enum):
63 tomato = 1
64 banana = 2
65 cherry = 3
66except Exception:
67 pass
68
Serhiy Storchakae50e7802015-03-31 16:56:49 +030069def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080070 if target is None:
71 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030072 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080073 assertion(loads(dumps(source, protocol=protocol)), target)
74
Serhiy Storchakae50e7802015-03-31 16:56:49 +030075def test_pickle_exception(assertion, exception, obj):
76 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080077 with assertion(exception):
78 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070079
80class TestHelpers(unittest.TestCase):
81 # _is_descriptor, _is_sunder, _is_dunder
82
83 def test_is_descriptor(self):
84 class foo:
85 pass
86 for attr in ('__get__','__set__','__delete__'):
87 obj = foo()
88 self.assertFalse(enum._is_descriptor(obj))
89 setattr(obj, attr, 1)
90 self.assertTrue(enum._is_descriptor(obj))
91
92 def test_is_sunder(self):
93 for s in ('_a_', '_aa_'):
94 self.assertTrue(enum._is_sunder(s))
95
96 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
97 '__', '___', '____', '_____',):
98 self.assertFalse(enum._is_sunder(s))
99
100 def test_is_dunder(self):
101 for s in ('__a__', '__aa__'):
102 self.assertTrue(enum._is_dunder(s))
103 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
104 '__', '___', '____', '_____',):
105 self.assertFalse(enum._is_dunder(s))
106
107
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700108class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800109
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700110 def setUp(self):
111 class Season(Enum):
112 SPRING = 1
113 SUMMER = 2
114 AUTUMN = 3
115 WINTER = 4
116 self.Season = Season
117
Ethan Furmanec15a822013-08-31 19:17:41 -0700118 class Konstants(float, Enum):
119 E = 2.7182818
120 PI = 3.1415926
121 TAU = 2 * PI
122 self.Konstants = Konstants
123
124 class Grades(IntEnum):
125 A = 5
126 B = 4
127 C = 3
128 D = 2
129 F = 0
130 self.Grades = Grades
131
132 class Directional(str, Enum):
133 EAST = 'east'
134 WEST = 'west'
135 NORTH = 'north'
136 SOUTH = 'south'
137 self.Directional = Directional
138
139 from datetime import date
140 class Holiday(date, Enum):
141 NEW_YEAR = 2013, 1, 1
142 IDES_OF_MARCH = 2013, 3, 15
143 self.Holiday = Holiday
144
Ethan Furman388a3922013-08-12 06:51:41 -0700145 def test_dir_on_class(self):
146 Season = self.Season
147 self.assertEqual(
148 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700149 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700150 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
151 )
152
153 def test_dir_on_item(self):
154 Season = self.Season
155 self.assertEqual(
156 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700157 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700158 )
159
Ethan Furmanc850f342013-09-15 16:59:35 -0700160 def test_dir_with_added_behavior(self):
161 class Test(Enum):
162 this = 'that'
163 these = 'those'
164 def wowser(self):
165 return ("Wowser! I'm %s!" % self.name)
166 self.assertEqual(
167 set(dir(Test)),
168 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
169 )
170 self.assertEqual(
171 set(dir(Test.this)),
172 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
173 )
174
Ethan Furman0ae550b2014-10-14 08:58:32 -0700175 def test_dir_on_sub_with_behavior_on_super(self):
176 # see issue22506
177 class SuperEnum(Enum):
178 def invisible(self):
179 return "did you see me?"
180 class SubEnum(SuperEnum):
181 sample = 5
182 self.assertEqual(
183 set(dir(SubEnum.sample)),
184 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
185 )
186
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700187 def test_enum_in_enum_out(self):
188 Season = self.Season
189 self.assertIs(Season(Season.WINTER), Season.WINTER)
190
191 def test_enum_value(self):
192 Season = self.Season
193 self.assertEqual(Season.SPRING.value, 1)
194
195 def test_intenum_value(self):
196 self.assertEqual(IntStooges.CURLY.value, 2)
197
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700198 def test_enum(self):
199 Season = self.Season
200 lst = list(Season)
201 self.assertEqual(len(lst), len(Season))
202 self.assertEqual(len(Season), 4, Season)
203 self.assertEqual(
204 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
205
206 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
207 e = Season(i)
208 self.assertEqual(e, getattr(Season, season))
209 self.assertEqual(e.value, i)
210 self.assertNotEqual(e, i)
211 self.assertEqual(e.name, season)
212 self.assertIn(e, Season)
213 self.assertIs(type(e), Season)
214 self.assertIsInstance(e, Season)
215 self.assertEqual(str(e), 'Season.' + season)
216 self.assertEqual(
217 repr(e),
218 '<Season.{0}: {1}>'.format(season, i),
219 )
220
221 def test_value_name(self):
222 Season = self.Season
223 self.assertEqual(Season.SPRING.name, 'SPRING')
224 self.assertEqual(Season.SPRING.value, 1)
225 with self.assertRaises(AttributeError):
226 Season.SPRING.name = 'invierno'
227 with self.assertRaises(AttributeError):
228 Season.SPRING.value = 2
229
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700230 def test_changing_member(self):
231 Season = self.Season
232 with self.assertRaises(AttributeError):
233 Season.WINTER = 'really cold'
234
Ethan Furman64a99722013-09-22 16:18:19 -0700235 def test_attribute_deletion(self):
236 class Season(Enum):
237 SPRING = 1
238 SUMMER = 2
239 AUTUMN = 3
240 WINTER = 4
241
242 def spam(cls):
243 pass
244
245 self.assertTrue(hasattr(Season, 'spam'))
246 del Season.spam
247 self.assertFalse(hasattr(Season, 'spam'))
248
249 with self.assertRaises(AttributeError):
250 del Season.SPRING
251 with self.assertRaises(AttributeError):
252 del Season.DRY
253 with self.assertRaises(AttributeError):
254 del Season.SPRING.name
255
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700256 def test_invalid_names(self):
257 with self.assertRaises(ValueError):
258 class Wrong(Enum):
259 mro = 9
260 with self.assertRaises(ValueError):
261 class Wrong(Enum):
262 _create_= 11
263 with self.assertRaises(ValueError):
264 class Wrong(Enum):
265 _get_mixins_ = 9
266 with self.assertRaises(ValueError):
267 class Wrong(Enum):
268 _find_new_ = 1
269 with self.assertRaises(ValueError):
270 class Wrong(Enum):
271 _any_name_ = 9
272
273 def test_contains(self):
274 Season = self.Season
275 self.assertIn(Season.AUTUMN, Season)
276 self.assertNotIn(3, Season)
277
278 val = Season(3)
279 self.assertIn(val, Season)
280
281 class OtherEnum(Enum):
282 one = 1; two = 2
283 self.assertNotIn(OtherEnum.two, Season)
284
285 def test_comparisons(self):
286 Season = self.Season
287 with self.assertRaises(TypeError):
288 Season.SPRING < Season.WINTER
289 with self.assertRaises(TypeError):
290 Season.SPRING > 4
291
292 self.assertNotEqual(Season.SPRING, 1)
293
294 class Part(Enum):
295 SPRING = 1
296 CLIP = 2
297 BARREL = 3
298
299 self.assertNotEqual(Season.SPRING, Part.SPRING)
300 with self.assertRaises(TypeError):
301 Season.SPRING < Part.CLIP
302
303 def test_enum_duplicates(self):
304 class Season(Enum):
305 SPRING = 1
306 SUMMER = 2
307 AUTUMN = FALL = 3
308 WINTER = 4
309 ANOTHER_SPRING = 1
310 lst = list(Season)
311 self.assertEqual(
312 lst,
313 [Season.SPRING, Season.SUMMER,
314 Season.AUTUMN, Season.WINTER,
315 ])
316 self.assertIs(Season.FALL, Season.AUTUMN)
317 self.assertEqual(Season.FALL.value, 3)
318 self.assertEqual(Season.AUTUMN.value, 3)
319 self.assertIs(Season(3), Season.AUTUMN)
320 self.assertIs(Season(1), Season.SPRING)
321 self.assertEqual(Season.FALL.name, 'AUTUMN')
322 self.assertEqual(
323 [k for k,v in Season.__members__.items() if v.name != k],
324 ['FALL', 'ANOTHER_SPRING'],
325 )
326
Ethan Furman101e0742013-09-15 12:34:36 -0700327 def test_duplicate_name(self):
328 with self.assertRaises(TypeError):
329 class Color(Enum):
330 red = 1
331 green = 2
332 blue = 3
333 red = 4
334
335 with self.assertRaises(TypeError):
336 class Color(Enum):
337 red = 1
338 green = 2
339 blue = 3
340 def red(self):
341 return 'red'
342
343 with self.assertRaises(TypeError):
344 class Color(Enum):
345 @property
346 def red(self):
347 return 'redder'
348 red = 1
349 green = 2
350 blue = 3
351
352
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700353 def test_enum_with_value_name(self):
354 class Huh(Enum):
355 name = 1
356 value = 2
357 self.assertEqual(
358 list(Huh),
359 [Huh.name, Huh.value],
360 )
361 self.assertIs(type(Huh.name), Huh)
362 self.assertEqual(Huh.name.name, 'name')
363 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700364
365 def test_format_enum(self):
366 Season = self.Season
367 self.assertEqual('{}'.format(Season.SPRING),
368 '{}'.format(str(Season.SPRING)))
369 self.assertEqual( '{:}'.format(Season.SPRING),
370 '{:}'.format(str(Season.SPRING)))
371 self.assertEqual('{:20}'.format(Season.SPRING),
372 '{:20}'.format(str(Season.SPRING)))
373 self.assertEqual('{:^20}'.format(Season.SPRING),
374 '{:^20}'.format(str(Season.SPRING)))
375 self.assertEqual('{:>20}'.format(Season.SPRING),
376 '{:>20}'.format(str(Season.SPRING)))
377 self.assertEqual('{:<20}'.format(Season.SPRING),
378 '{:<20}'.format(str(Season.SPRING)))
379
380 def test_format_enum_custom(self):
381 class TestFloat(float, Enum):
382 one = 1.0
383 two = 2.0
384 def __format__(self, spec):
385 return 'TestFloat success!'
386 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
387
388 def assertFormatIsValue(self, spec, member):
389 self.assertEqual(spec.format(member), spec.format(member.value))
390
391 def test_format_enum_date(self):
392 Holiday = self.Holiday
393 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
394 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
395 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
396 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
397 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
398 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
399 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
400 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
401
402 def test_format_enum_float(self):
403 Konstants = self.Konstants
404 self.assertFormatIsValue('{}', Konstants.TAU)
405 self.assertFormatIsValue('{:}', Konstants.TAU)
406 self.assertFormatIsValue('{:20}', Konstants.TAU)
407 self.assertFormatIsValue('{:^20}', Konstants.TAU)
408 self.assertFormatIsValue('{:>20}', Konstants.TAU)
409 self.assertFormatIsValue('{:<20}', Konstants.TAU)
410 self.assertFormatIsValue('{:n}', Konstants.TAU)
411 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
412 self.assertFormatIsValue('{:f}', Konstants.TAU)
413
414 def test_format_enum_int(self):
415 Grades = self.Grades
416 self.assertFormatIsValue('{}', Grades.C)
417 self.assertFormatIsValue('{:}', Grades.C)
418 self.assertFormatIsValue('{:20}', Grades.C)
419 self.assertFormatIsValue('{:^20}', Grades.C)
420 self.assertFormatIsValue('{:>20}', Grades.C)
421 self.assertFormatIsValue('{:<20}', Grades.C)
422 self.assertFormatIsValue('{:+}', Grades.C)
423 self.assertFormatIsValue('{:08X}', Grades.C)
424 self.assertFormatIsValue('{:b}', Grades.C)
425
426 def test_format_enum_str(self):
427 Directional = self.Directional
428 self.assertFormatIsValue('{}', Directional.WEST)
429 self.assertFormatIsValue('{:}', Directional.WEST)
430 self.assertFormatIsValue('{:20}', Directional.WEST)
431 self.assertFormatIsValue('{:^20}', Directional.WEST)
432 self.assertFormatIsValue('{:>20}', Directional.WEST)
433 self.assertFormatIsValue('{:<20}', Directional.WEST)
434
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700435 def test_hash(self):
436 Season = self.Season
437 dates = {}
438 dates[Season.WINTER] = '1225'
439 dates[Season.SPRING] = '0315'
440 dates[Season.SUMMER] = '0704'
441 dates[Season.AUTUMN] = '1031'
442 self.assertEqual(dates[Season.AUTUMN], '1031')
443
444 def test_intenum_from_scratch(self):
445 class phy(int, Enum):
446 pi = 3
447 tau = 2 * pi
448 self.assertTrue(phy.pi < phy.tau)
449
450 def test_intenum_inherited(self):
451 class IntEnum(int, Enum):
452 pass
453 class phy(IntEnum):
454 pi = 3
455 tau = 2 * pi
456 self.assertTrue(phy.pi < phy.tau)
457
458 def test_floatenum_from_scratch(self):
459 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700460 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700461 tau = 2 * pi
462 self.assertTrue(phy.pi < phy.tau)
463
464 def test_floatenum_inherited(self):
465 class FloatEnum(float, Enum):
466 pass
467 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700468 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700469 tau = 2 * pi
470 self.assertTrue(phy.pi < phy.tau)
471
472 def test_strenum_from_scratch(self):
473 class phy(str, Enum):
474 pi = 'Pi'
475 tau = 'Tau'
476 self.assertTrue(phy.pi < phy.tau)
477
478 def test_strenum_inherited(self):
479 class StrEnum(str, Enum):
480 pass
481 class phy(StrEnum):
482 pi = 'Pi'
483 tau = 'Tau'
484 self.assertTrue(phy.pi < phy.tau)
485
486
487 def test_intenum(self):
488 class WeekDay(IntEnum):
489 SUNDAY = 1
490 MONDAY = 2
491 TUESDAY = 3
492 WEDNESDAY = 4
493 THURSDAY = 5
494 FRIDAY = 6
495 SATURDAY = 7
496
497 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
498 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
499
500 lst = list(WeekDay)
501 self.assertEqual(len(lst), len(WeekDay))
502 self.assertEqual(len(WeekDay), 7)
503 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
504 target = target.split()
505 for i, weekday in enumerate(target, 1):
506 e = WeekDay(i)
507 self.assertEqual(e, i)
508 self.assertEqual(int(e), i)
509 self.assertEqual(e.name, weekday)
510 self.assertIn(e, WeekDay)
511 self.assertEqual(lst.index(e)+1, i)
512 self.assertTrue(0 < e < 8)
513 self.assertIs(type(e), WeekDay)
514 self.assertIsInstance(e, int)
515 self.assertIsInstance(e, Enum)
516
517 def test_intenum_duplicates(self):
518 class WeekDay(IntEnum):
519 SUNDAY = 1
520 MONDAY = 2
521 TUESDAY = TEUSDAY = 3
522 WEDNESDAY = 4
523 THURSDAY = 5
524 FRIDAY = 6
525 SATURDAY = 7
526 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
527 self.assertEqual(WeekDay(3).name, 'TUESDAY')
528 self.assertEqual([k for k,v in WeekDay.__members__.items()
529 if v.name != k], ['TEUSDAY', ])
530
531 def test_pickle_enum(self):
532 if isinstance(Stooges, Exception):
533 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800534 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
535 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700536
537 def test_pickle_int(self):
538 if isinstance(IntStooges, Exception):
539 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800540 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
541 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700542
543 def test_pickle_float(self):
544 if isinstance(FloatStooges, Exception):
545 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800546 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
547 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700548
549 def test_pickle_enum_function(self):
550 if isinstance(Answer, Exception):
551 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800552 test_pickle_dump_load(self.assertIs, Answer.him)
553 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700554
555 def test_pickle_enum_function_with_module(self):
556 if isinstance(Question, Exception):
557 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800558 test_pickle_dump_load(self.assertIs, Question.who)
559 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700560
Ethan Furmanca1b7942014-02-08 11:36:27 -0800561 def test_enum_function_with_qualname(self):
562 if isinstance(Theory, Exception):
563 raise Theory
564 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
565
566 def test_class_nested_enum_and_pickle_protocol_four(self):
567 # would normally just have this directly in the class namespace
568 class NestedEnum(Enum):
569 twigs = 'common'
570 shiny = 'rare'
571
572 self.__class__.NestedEnum = NestedEnum
573 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300574 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800575
Ethan Furman24e837f2015-03-18 17:27:57 -0700576 def test_pickle_by_name(self):
577 class ReplaceGlobalInt(IntEnum):
578 ONE = 1
579 TWO = 2
580 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
581 for proto in range(HIGHEST_PROTOCOL):
582 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
583
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700584 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800585 BadPickle = Enum(
586 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700587 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800588 # now break BadPickle to test exception raising
589 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800590 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
591 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700592
593 def test_string_enum(self):
594 class SkillLevel(str, Enum):
595 master = 'what is the sound of one hand clapping?'
596 journeyman = 'why did the chicken cross the road?'
597 apprentice = 'knock, knock!'
598 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
599
600 def test_getattr_getitem(self):
601 class Period(Enum):
602 morning = 1
603 noon = 2
604 evening = 3
605 night = 4
606 self.assertIs(Period(2), Period.noon)
607 self.assertIs(getattr(Period, 'night'), Period.night)
608 self.assertIs(Period['morning'], Period.morning)
609
610 def test_getattr_dunder(self):
611 Season = self.Season
612 self.assertTrue(getattr(Season, '__eq__'))
613
614 def test_iteration_order(self):
615 class Season(Enum):
616 SUMMER = 2
617 WINTER = 4
618 AUTUMN = 3
619 SPRING = 1
620 self.assertEqual(
621 list(Season),
622 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
623 )
624
Ethan Furman2131a4a2013-09-14 18:11:24 -0700625 def test_reversed_iteration_order(self):
626 self.assertEqual(
627 list(reversed(self.Season)),
628 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
629 self.Season.SPRING]
630 )
631
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700632 def test_programatic_function_string(self):
633 SummerMonth = Enum('SummerMonth', 'june july august')
634 lst = list(SummerMonth)
635 self.assertEqual(len(lst), len(SummerMonth))
636 self.assertEqual(len(SummerMonth), 3, SummerMonth)
637 self.assertEqual(
638 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
639 lst,
640 )
641 for i, month in enumerate('june july august'.split(), 1):
642 e = SummerMonth(i)
643 self.assertEqual(int(e.value), i)
644 self.assertNotEqual(e, i)
645 self.assertEqual(e.name, month)
646 self.assertIn(e, SummerMonth)
647 self.assertIs(type(e), SummerMonth)
648
Ethan Furmand9925a12014-09-16 20:35:55 -0700649 def test_programatic_function_string_with_start(self):
650 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
651 lst = list(SummerMonth)
652 self.assertEqual(len(lst), len(SummerMonth))
653 self.assertEqual(len(SummerMonth), 3, SummerMonth)
654 self.assertEqual(
655 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
656 lst,
657 )
658 for i, month in enumerate('june july august'.split(), 10):
659 e = SummerMonth(i)
660 self.assertEqual(int(e.value), i)
661 self.assertNotEqual(e, i)
662 self.assertEqual(e.name, month)
663 self.assertIn(e, SummerMonth)
664 self.assertIs(type(e), SummerMonth)
665
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700666 def test_programatic_function_string_list(self):
667 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
668 lst = list(SummerMonth)
669 self.assertEqual(len(lst), len(SummerMonth))
670 self.assertEqual(len(SummerMonth), 3, SummerMonth)
671 self.assertEqual(
672 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
673 lst,
674 )
675 for i, month in enumerate('june july august'.split(), 1):
676 e = SummerMonth(i)
677 self.assertEqual(int(e.value), i)
678 self.assertNotEqual(e, i)
679 self.assertEqual(e.name, month)
680 self.assertIn(e, SummerMonth)
681 self.assertIs(type(e), SummerMonth)
682
Ethan Furmand9925a12014-09-16 20:35:55 -0700683 def test_programatic_function_string_list_with_start(self):
684 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
685 lst = list(SummerMonth)
686 self.assertEqual(len(lst), len(SummerMonth))
687 self.assertEqual(len(SummerMonth), 3, SummerMonth)
688 self.assertEqual(
689 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
690 lst,
691 )
692 for i, month in enumerate('june july august'.split(), 20):
693 e = SummerMonth(i)
694 self.assertEqual(int(e.value), i)
695 self.assertNotEqual(e, i)
696 self.assertEqual(e.name, month)
697 self.assertIn(e, SummerMonth)
698 self.assertIs(type(e), SummerMonth)
699
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700700 def test_programatic_function_iterable(self):
701 SummerMonth = Enum(
702 'SummerMonth',
703 (('june', 1), ('july', 2), ('august', 3))
704 )
705 lst = list(SummerMonth)
706 self.assertEqual(len(lst), len(SummerMonth))
707 self.assertEqual(len(SummerMonth), 3, SummerMonth)
708 self.assertEqual(
709 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
710 lst,
711 )
712 for i, month in enumerate('june july august'.split(), 1):
713 e = SummerMonth(i)
714 self.assertEqual(int(e.value), i)
715 self.assertNotEqual(e, i)
716 self.assertEqual(e.name, month)
717 self.assertIn(e, SummerMonth)
718 self.assertIs(type(e), SummerMonth)
719
720 def test_programatic_function_from_dict(self):
721 SummerMonth = Enum(
722 'SummerMonth',
723 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
724 )
725 lst = list(SummerMonth)
726 self.assertEqual(len(lst), len(SummerMonth))
727 self.assertEqual(len(SummerMonth), 3, SummerMonth)
728 self.assertEqual(
729 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
730 lst,
731 )
732 for i, month in enumerate('june july august'.split(), 1):
733 e = SummerMonth(i)
734 self.assertEqual(int(e.value), i)
735 self.assertNotEqual(e, i)
736 self.assertEqual(e.name, month)
737 self.assertIn(e, SummerMonth)
738 self.assertIs(type(e), SummerMonth)
739
740 def test_programatic_function_type(self):
741 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
742 lst = list(SummerMonth)
743 self.assertEqual(len(lst), len(SummerMonth))
744 self.assertEqual(len(SummerMonth), 3, SummerMonth)
745 self.assertEqual(
746 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
747 lst,
748 )
749 for i, month in enumerate('june july august'.split(), 1):
750 e = SummerMonth(i)
751 self.assertEqual(e, i)
752 self.assertEqual(e.name, month)
753 self.assertIn(e, SummerMonth)
754 self.assertIs(type(e), SummerMonth)
755
Ethan Furmand9925a12014-09-16 20:35:55 -0700756 def test_programatic_function_type_with_start(self):
757 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
758 lst = list(SummerMonth)
759 self.assertEqual(len(lst), len(SummerMonth))
760 self.assertEqual(len(SummerMonth), 3, SummerMonth)
761 self.assertEqual(
762 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
763 lst,
764 )
765 for i, month in enumerate('june july august'.split(), 30):
766 e = SummerMonth(i)
767 self.assertEqual(e, i)
768 self.assertEqual(e.name, month)
769 self.assertIn(e, SummerMonth)
770 self.assertIs(type(e), SummerMonth)
771
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700772 def test_programatic_function_type_from_subclass(self):
773 SummerMonth = IntEnum('SummerMonth', 'june july august')
774 lst = list(SummerMonth)
775 self.assertEqual(len(lst), len(SummerMonth))
776 self.assertEqual(len(SummerMonth), 3, SummerMonth)
777 self.assertEqual(
778 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
779 lst,
780 )
781 for i, month in enumerate('june july august'.split(), 1):
782 e = SummerMonth(i)
783 self.assertEqual(e, i)
784 self.assertEqual(e.name, month)
785 self.assertIn(e, SummerMonth)
786 self.assertIs(type(e), SummerMonth)
787
Ethan Furmand9925a12014-09-16 20:35:55 -0700788 def test_programatic_function_type_from_subclass_with_start(self):
789 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
790 lst = list(SummerMonth)
791 self.assertEqual(len(lst), len(SummerMonth))
792 self.assertEqual(len(SummerMonth), 3, SummerMonth)
793 self.assertEqual(
794 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
795 lst,
796 )
797 for i, month in enumerate('june july august'.split(), 40):
798 e = SummerMonth(i)
799 self.assertEqual(e, i)
800 self.assertEqual(e.name, month)
801 self.assertIn(e, SummerMonth)
802 self.assertIs(type(e), SummerMonth)
803
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700804 def test_subclassing(self):
805 if isinstance(Name, Exception):
806 raise Name
807 self.assertEqual(Name.BDFL, 'Guido van Rossum')
808 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
809 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800810 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700811
812 def test_extending(self):
813 class Color(Enum):
814 red = 1
815 green = 2
816 blue = 3
817 with self.assertRaises(TypeError):
818 class MoreColor(Color):
819 cyan = 4
820 magenta = 5
821 yellow = 6
822
823 def test_exclude_methods(self):
824 class whatever(Enum):
825 this = 'that'
826 these = 'those'
827 def really(self):
828 return 'no, not %s' % self.value
829 self.assertIsNot(type(whatever.really), whatever)
830 self.assertEqual(whatever.this.really(), 'no, not that')
831
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832 def test_wrong_inheritance_order(self):
833 with self.assertRaises(TypeError):
834 class Wrong(Enum, str):
835 NotHere = 'error before this point'
836
837 def test_intenum_transitivity(self):
838 class number(IntEnum):
839 one = 1
840 two = 2
841 three = 3
842 class numero(IntEnum):
843 uno = 1
844 dos = 2
845 tres = 3
846 self.assertEqual(number.one, numero.uno)
847 self.assertEqual(number.two, numero.dos)
848 self.assertEqual(number.three, numero.tres)
849
850 def test_wrong_enum_in_call(self):
851 class Monochrome(Enum):
852 black = 0
853 white = 1
854 class Gender(Enum):
855 male = 0
856 female = 1
857 self.assertRaises(ValueError, Monochrome, Gender.male)
858
859 def test_wrong_enum_in_mixed_call(self):
860 class Monochrome(IntEnum):
861 black = 0
862 white = 1
863 class Gender(Enum):
864 male = 0
865 female = 1
866 self.assertRaises(ValueError, Monochrome, Gender.male)
867
868 def test_mixed_enum_in_call_1(self):
869 class Monochrome(IntEnum):
870 black = 0
871 white = 1
872 class Gender(IntEnum):
873 male = 0
874 female = 1
875 self.assertIs(Monochrome(Gender.female), Monochrome.white)
876
877 def test_mixed_enum_in_call_2(self):
878 class Monochrome(Enum):
879 black = 0
880 white = 1
881 class Gender(IntEnum):
882 male = 0
883 female = 1
884 self.assertIs(Monochrome(Gender.male), Monochrome.black)
885
886 def test_flufl_enum(self):
887 class Fluflnum(Enum):
888 def __int__(self):
889 return int(self.value)
890 class MailManOptions(Fluflnum):
891 option1 = 1
892 option2 = 2
893 option3 = 3
894 self.assertEqual(int(MailManOptions.option1), 1)
895
Ethan Furman5e5a8232013-08-04 08:42:23 -0700896 def test_introspection(self):
897 class Number(IntEnum):
898 one = 100
899 two = 200
900 self.assertIs(Number.one._member_type_, int)
901 self.assertIs(Number._member_type_, int)
902 class String(str, Enum):
903 yarn = 'soft'
904 rope = 'rough'
905 wire = 'hard'
906 self.assertIs(String.yarn._member_type_, str)
907 self.assertIs(String._member_type_, str)
908 class Plain(Enum):
909 vanilla = 'white'
910 one = 1
911 self.assertIs(Plain.vanilla._member_type_, object)
912 self.assertIs(Plain._member_type_, object)
913
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700914 def test_no_such_enum_member(self):
915 class Color(Enum):
916 red = 1
917 green = 2
918 blue = 3
919 with self.assertRaises(ValueError):
920 Color(4)
921 with self.assertRaises(KeyError):
922 Color['chartreuse']
923
924 def test_new_repr(self):
925 class Color(Enum):
926 red = 1
927 green = 2
928 blue = 3
929 def __repr__(self):
930 return "don't you just love shades of %s?" % self.name
931 self.assertEqual(
932 repr(Color.blue),
933 "don't you just love shades of blue?",
934 )
935
936 def test_inherited_repr(self):
937 class MyEnum(Enum):
938 def __repr__(self):
939 return "My name is %s." % self.name
940 class MyIntEnum(int, MyEnum):
941 this = 1
942 that = 2
943 theother = 3
944 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
945
946 def test_multiple_mixin_mro(self):
947 class auto_enum(type(Enum)):
948 def __new__(metacls, cls, bases, classdict):
949 temp = type(classdict)()
950 names = set(classdict._member_names)
951 i = 0
952 for k in classdict._member_names:
953 v = classdict[k]
954 if v is Ellipsis:
955 v = i
956 else:
957 i = v
958 i += 1
959 temp[k] = v
960 for k, v in classdict.items():
961 if k not in names:
962 temp[k] = v
963 return super(auto_enum, metacls).__new__(
964 metacls, cls, bases, temp)
965
966 class AutoNumberedEnum(Enum, metaclass=auto_enum):
967 pass
968
969 class AutoIntEnum(IntEnum, metaclass=auto_enum):
970 pass
971
972 class TestAutoNumber(AutoNumberedEnum):
973 a = ...
974 b = 3
975 c = ...
976
977 class TestAutoInt(AutoIntEnum):
978 a = ...
979 b = 3
980 c = ...
981
982 def test_subclasses_with_getnewargs(self):
983 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800984 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700985 def __new__(cls, *args):
986 _args = args
987 name, *args = args
988 if len(args) == 0:
989 raise TypeError("name and value must be specified")
990 self = int.__new__(cls, *args)
991 self._intname = name
992 self._args = _args
993 return self
994 def __getnewargs__(self):
995 return self._args
996 @property
997 def __name__(self):
998 return self._intname
999 def __repr__(self):
1000 # repr() is updated to include the name and type info
1001 return "{}({!r}, {})".format(type(self).__name__,
1002 self.__name__,
1003 int.__repr__(self))
1004 def __str__(self):
1005 # str() is unchanged, even if it relies on the repr() fallback
1006 base = int
1007 base_str = base.__str__
1008 if base_str.__objclass__ is object:
1009 return base.__repr__(self)
1010 return base_str(self)
1011 # for simplicity, we only define one operator that
1012 # propagates expressions
1013 def __add__(self, other):
1014 temp = int(self) + int( other)
1015 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1016 return NamedInt(
1017 '({0} + {1})'.format(self.__name__, other.__name__),
1018 temp )
1019 else:
1020 return temp
1021
1022 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001023 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001024 x = ('the-x', 1)
1025 y = ('the-y', 2)
1026
Ethan Furman2aa27322013-07-19 19:35:56 -07001027
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001028 self.assertIs(NEI.__new__, Enum.__new__)
1029 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1030 globals()['NamedInt'] = NamedInt
1031 globals()['NEI'] = NEI
1032 NI5 = NamedInt('test', 5)
1033 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001034 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001035 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001036 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001037 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001038
Ethan Furmanca1b7942014-02-08 11:36:27 -08001039 def test_subclasses_with_getnewargs_ex(self):
1040 class NamedInt(int):
1041 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1042 def __new__(cls, *args):
1043 _args = args
1044 name, *args = args
1045 if len(args) == 0:
1046 raise TypeError("name and value must be specified")
1047 self = int.__new__(cls, *args)
1048 self._intname = name
1049 self._args = _args
1050 return self
1051 def __getnewargs_ex__(self):
1052 return self._args, {}
1053 @property
1054 def __name__(self):
1055 return self._intname
1056 def __repr__(self):
1057 # repr() is updated to include the name and type info
1058 return "{}({!r}, {})".format(type(self).__name__,
1059 self.__name__,
1060 int.__repr__(self))
1061 def __str__(self):
1062 # str() is unchanged, even if it relies on the repr() fallback
1063 base = int
1064 base_str = base.__str__
1065 if base_str.__objclass__ is object:
1066 return base.__repr__(self)
1067 return base_str(self)
1068 # for simplicity, we only define one operator that
1069 # propagates expressions
1070 def __add__(self, other):
1071 temp = int(self) + int( other)
1072 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1073 return NamedInt(
1074 '({0} + {1})'.format(self.__name__, other.__name__),
1075 temp )
1076 else:
1077 return temp
1078
1079 class NEI(NamedInt, Enum):
1080 __qualname__ = 'NEI' # needed for pickle protocol 4
1081 x = ('the-x', 1)
1082 y = ('the-y', 2)
1083
1084
1085 self.assertIs(NEI.__new__, Enum.__new__)
1086 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1087 globals()['NamedInt'] = NamedInt
1088 globals()['NEI'] = NEI
1089 NI5 = NamedInt('test', 5)
1090 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001091 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001092 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001093 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001094 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001095
1096 def test_subclasses_with_reduce(self):
1097 class NamedInt(int):
1098 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1099 def __new__(cls, *args):
1100 _args = args
1101 name, *args = args
1102 if len(args) == 0:
1103 raise TypeError("name and value must be specified")
1104 self = int.__new__(cls, *args)
1105 self._intname = name
1106 self._args = _args
1107 return self
1108 def __reduce__(self):
1109 return self.__class__, self._args
1110 @property
1111 def __name__(self):
1112 return self._intname
1113 def __repr__(self):
1114 # repr() is updated to include the name and type info
1115 return "{}({!r}, {})".format(type(self).__name__,
1116 self.__name__,
1117 int.__repr__(self))
1118 def __str__(self):
1119 # str() is unchanged, even if it relies on the repr() fallback
1120 base = int
1121 base_str = base.__str__
1122 if base_str.__objclass__ is object:
1123 return base.__repr__(self)
1124 return base_str(self)
1125 # for simplicity, we only define one operator that
1126 # propagates expressions
1127 def __add__(self, other):
1128 temp = int(self) + int( other)
1129 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1130 return NamedInt(
1131 '({0} + {1})'.format(self.__name__, other.__name__),
1132 temp )
1133 else:
1134 return temp
1135
1136 class NEI(NamedInt, Enum):
1137 __qualname__ = 'NEI' # needed for pickle protocol 4
1138 x = ('the-x', 1)
1139 y = ('the-y', 2)
1140
1141
1142 self.assertIs(NEI.__new__, Enum.__new__)
1143 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1144 globals()['NamedInt'] = NamedInt
1145 globals()['NEI'] = NEI
1146 NI5 = NamedInt('test', 5)
1147 self.assertEqual(NI5, 5)
1148 test_pickle_dump_load(self.assertEqual, NI5, 5)
1149 self.assertEqual(NEI.y.value, 2)
1150 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001151 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001152
1153 def test_subclasses_with_reduce_ex(self):
1154 class NamedInt(int):
1155 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1156 def __new__(cls, *args):
1157 _args = args
1158 name, *args = args
1159 if len(args) == 0:
1160 raise TypeError("name and value must be specified")
1161 self = int.__new__(cls, *args)
1162 self._intname = name
1163 self._args = _args
1164 return self
1165 def __reduce_ex__(self, proto):
1166 return self.__class__, self._args
1167 @property
1168 def __name__(self):
1169 return self._intname
1170 def __repr__(self):
1171 # repr() is updated to include the name and type info
1172 return "{}({!r}, {})".format(type(self).__name__,
1173 self.__name__,
1174 int.__repr__(self))
1175 def __str__(self):
1176 # str() is unchanged, even if it relies on the repr() fallback
1177 base = int
1178 base_str = base.__str__
1179 if base_str.__objclass__ is object:
1180 return base.__repr__(self)
1181 return base_str(self)
1182 # for simplicity, we only define one operator that
1183 # propagates expressions
1184 def __add__(self, other):
1185 temp = int(self) + int( other)
1186 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1187 return NamedInt(
1188 '({0} + {1})'.format(self.__name__, other.__name__),
1189 temp )
1190 else:
1191 return temp
1192
1193 class NEI(NamedInt, Enum):
1194 __qualname__ = 'NEI' # needed for pickle protocol 4
1195 x = ('the-x', 1)
1196 y = ('the-y', 2)
1197
1198
1199 self.assertIs(NEI.__new__, Enum.__new__)
1200 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1201 globals()['NamedInt'] = NamedInt
1202 globals()['NEI'] = NEI
1203 NI5 = NamedInt('test', 5)
1204 self.assertEqual(NI5, 5)
1205 test_pickle_dump_load(self.assertEqual, NI5, 5)
1206 self.assertEqual(NEI.y.value, 2)
1207 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001208 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001209
Ethan Furmandc870522014-02-18 12:37:12 -08001210 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001211 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001212 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001213 def __new__(cls, *args):
1214 _args = args
1215 name, *args = args
1216 if len(args) == 0:
1217 raise TypeError("name and value must be specified")
1218 self = int.__new__(cls, *args)
1219 self._intname = name
1220 self._args = _args
1221 return self
1222 @property
1223 def __name__(self):
1224 return self._intname
1225 def __repr__(self):
1226 # repr() is updated to include the name and type info
1227 return "{}({!r}, {})".format(type(self).__name__,
1228 self.__name__,
1229 int.__repr__(self))
1230 def __str__(self):
1231 # str() is unchanged, even if it relies on the repr() fallback
1232 base = int
1233 base_str = base.__str__
1234 if base_str.__objclass__ is object:
1235 return base.__repr__(self)
1236 return base_str(self)
1237 # for simplicity, we only define one operator that
1238 # propagates expressions
1239 def __add__(self, other):
1240 temp = int(self) + int( other)
1241 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1242 return NamedInt(
1243 '({0} + {1})'.format(self.__name__, other.__name__),
1244 temp )
1245 else:
1246 return temp
1247
1248 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001249 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001250 x = ('the-x', 1)
1251 y = ('the-y', 2)
1252
1253 self.assertIs(NEI.__new__, Enum.__new__)
1254 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1255 globals()['NamedInt'] = NamedInt
1256 globals()['NEI'] = NEI
1257 NI5 = NamedInt('test', 5)
1258 self.assertEqual(NI5, 5)
1259 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001260 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1261 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001262
Ethan Furmandc870522014-02-18 12:37:12 -08001263 def test_subclasses_without_direct_pickle_support_using_name(self):
1264 class NamedInt(int):
1265 __qualname__ = 'NamedInt'
1266 def __new__(cls, *args):
1267 _args = args
1268 name, *args = args
1269 if len(args) == 0:
1270 raise TypeError("name and value must be specified")
1271 self = int.__new__(cls, *args)
1272 self._intname = name
1273 self._args = _args
1274 return self
1275 @property
1276 def __name__(self):
1277 return self._intname
1278 def __repr__(self):
1279 # repr() is updated to include the name and type info
1280 return "{}({!r}, {})".format(type(self).__name__,
1281 self.__name__,
1282 int.__repr__(self))
1283 def __str__(self):
1284 # str() is unchanged, even if it relies on the repr() fallback
1285 base = int
1286 base_str = base.__str__
1287 if base_str.__objclass__ is object:
1288 return base.__repr__(self)
1289 return base_str(self)
1290 # for simplicity, we only define one operator that
1291 # propagates expressions
1292 def __add__(self, other):
1293 temp = int(self) + int( other)
1294 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1295 return NamedInt(
1296 '({0} + {1})'.format(self.__name__, other.__name__),
1297 temp )
1298 else:
1299 return temp
1300
1301 class NEI(NamedInt, Enum):
1302 __qualname__ = 'NEI'
1303 x = ('the-x', 1)
1304 y = ('the-y', 2)
1305 def __reduce_ex__(self, proto):
1306 return getattr, (self.__class__, self._name_)
1307
1308 self.assertIs(NEI.__new__, Enum.__new__)
1309 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1310 globals()['NamedInt'] = NamedInt
1311 globals()['NEI'] = NEI
1312 NI5 = NamedInt('test', 5)
1313 self.assertEqual(NI5, 5)
1314 self.assertEqual(NEI.y.value, 2)
1315 test_pickle_dump_load(self.assertIs, NEI.y)
1316 test_pickle_dump_load(self.assertIs, NEI)
1317
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001318 def test_tuple_subclass(self):
1319 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001320 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001321 first = (1, 'for the money')
1322 second = (2, 'for the show')
1323 third = (3, 'for the music')
1324 self.assertIs(type(SomeTuple.first), SomeTuple)
1325 self.assertIsInstance(SomeTuple.second, tuple)
1326 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1327 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001328 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001329
1330 def test_duplicate_values_give_unique_enum_items(self):
1331 class AutoNumber(Enum):
1332 first = ()
1333 second = ()
1334 third = ()
1335 def __new__(cls):
1336 value = len(cls.__members__) + 1
1337 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001338 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001339 return obj
1340 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001341 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001342 self.assertEqual(
1343 list(AutoNumber),
1344 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1345 )
1346 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001347 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001348 self.assertIs(AutoNumber(1), AutoNumber.first)
1349
1350 def test_inherited_new_from_enhanced_enum(self):
1351 class AutoNumber(Enum):
1352 def __new__(cls):
1353 value = len(cls.__members__) + 1
1354 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001355 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001356 return obj
1357 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001358 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001359 class Color(AutoNumber):
1360 red = ()
1361 green = ()
1362 blue = ()
1363 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1364 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1365
1366 def test_inherited_new_from_mixed_enum(self):
1367 class AutoNumber(IntEnum):
1368 def __new__(cls):
1369 value = len(cls.__members__) + 1
1370 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001371 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001372 return obj
1373 class Color(AutoNumber):
1374 red = ()
1375 green = ()
1376 blue = ()
1377 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1378 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1379
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001380 def test_equality(self):
1381 class AlwaysEqual:
1382 def __eq__(self, other):
1383 return True
1384 class OrdinaryEnum(Enum):
1385 a = 1
1386 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1387 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1388
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001389 def test_ordered_mixin(self):
1390 class OrderedEnum(Enum):
1391 def __ge__(self, other):
1392 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001393 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001394 return NotImplemented
1395 def __gt__(self, other):
1396 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001397 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001398 return NotImplemented
1399 def __le__(self, other):
1400 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001401 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001402 return NotImplemented
1403 def __lt__(self, other):
1404 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001405 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001406 return NotImplemented
1407 class Grade(OrderedEnum):
1408 A = 5
1409 B = 4
1410 C = 3
1411 D = 2
1412 F = 1
1413 self.assertGreater(Grade.A, Grade.B)
1414 self.assertLessEqual(Grade.F, Grade.C)
1415 self.assertLess(Grade.D, Grade.A)
1416 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001417 self.assertEqual(Grade.B, Grade.B)
1418 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001419
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001420 def test_extending2(self):
1421 class Shade(Enum):
1422 def shade(self):
1423 print(self.name)
1424 class Color(Shade):
1425 red = 1
1426 green = 2
1427 blue = 3
1428 with self.assertRaises(TypeError):
1429 class MoreColor(Color):
1430 cyan = 4
1431 magenta = 5
1432 yellow = 6
1433
1434 def test_extending3(self):
1435 class Shade(Enum):
1436 def shade(self):
1437 return self.name
1438 class Color(Shade):
1439 def hex(self):
1440 return '%s hexlified!' % self.value
1441 class MoreColor(Color):
1442 cyan = 4
1443 magenta = 5
1444 yellow = 6
1445 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1446
1447
1448 def test_no_duplicates(self):
1449 class UniqueEnum(Enum):
1450 def __init__(self, *args):
1451 cls = self.__class__
1452 if any(self.value == e.value for e in cls):
1453 a = self.name
1454 e = cls(self.value).name
1455 raise ValueError(
1456 "aliases not allowed in UniqueEnum: %r --> %r"
1457 % (a, e)
1458 )
1459 class Color(UniqueEnum):
1460 red = 1
1461 green = 2
1462 blue = 3
1463 with self.assertRaises(ValueError):
1464 class Color(UniqueEnum):
1465 red = 1
1466 green = 2
1467 blue = 3
1468 grene = 2
1469
1470 def test_init(self):
1471 class Planet(Enum):
1472 MERCURY = (3.303e+23, 2.4397e6)
1473 VENUS = (4.869e+24, 6.0518e6)
1474 EARTH = (5.976e+24, 6.37814e6)
1475 MARS = (6.421e+23, 3.3972e6)
1476 JUPITER = (1.9e+27, 7.1492e7)
1477 SATURN = (5.688e+26, 6.0268e7)
1478 URANUS = (8.686e+25, 2.5559e7)
1479 NEPTUNE = (1.024e+26, 2.4746e7)
1480 def __init__(self, mass, radius):
1481 self.mass = mass # in kilograms
1482 self.radius = radius # in meters
1483 @property
1484 def surface_gravity(self):
1485 # universal gravitational constant (m3 kg-1 s-2)
1486 G = 6.67300E-11
1487 return G * self.mass / (self.radius * self.radius)
1488 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1489 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1490
Ethan Furman2aa27322013-07-19 19:35:56 -07001491 def test_nonhash_value(self):
1492 class AutoNumberInAList(Enum):
1493 def __new__(cls):
1494 value = [len(cls.__members__) + 1]
1495 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001496 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001497 return obj
1498 class ColorInAList(AutoNumberInAList):
1499 red = ()
1500 green = ()
1501 blue = ()
1502 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001503 for enum, value in zip(ColorInAList, range(3)):
1504 value += 1
1505 self.assertEqual(enum.value, [value])
1506 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001507
Ethan Furmanb41803e2013-07-25 13:50:45 -07001508 def test_conflicting_types_resolved_in_new(self):
1509 class LabelledIntEnum(int, Enum):
1510 def __new__(cls, *args):
1511 value, label = args
1512 obj = int.__new__(cls, value)
1513 obj.label = label
1514 obj._value_ = value
1515 return obj
1516
1517 class LabelledList(LabelledIntEnum):
1518 unprocessed = (1, "Unprocessed")
1519 payment_complete = (2, "Payment Complete")
1520
1521 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1522 self.assertEqual(LabelledList.unprocessed, 1)
1523 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001524
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001525
Ethan Furmanf24bb352013-07-18 17:05:39 -07001526class TestUnique(unittest.TestCase):
1527
1528 def test_unique_clean(self):
1529 @unique
1530 class Clean(Enum):
1531 one = 1
1532 two = 'dos'
1533 tres = 4.0
1534 @unique
1535 class Cleaner(IntEnum):
1536 single = 1
1537 double = 2
1538 triple = 3
1539
1540 def test_unique_dirty(self):
1541 with self.assertRaisesRegex(ValueError, 'tres.*one'):
1542 @unique
1543 class Dirty(Enum):
1544 one = 1
1545 two = 'dos'
1546 tres = 1
1547 with self.assertRaisesRegex(
1548 ValueError,
1549 'double.*single.*turkey.*triple',
1550 ):
1551 @unique
1552 class Dirtier(IntEnum):
1553 single = 1
1554 double = 1
1555 triple = 3
1556 turkey = 3
1557
1558
Ethan Furman3323da92015-04-11 09:39:59 -07001559expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07001560Help on class Color in module %s:
1561
1562class Color(enum.Enum)
Ethan Furman48a724f2015-04-11 23:23:06 -07001563 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03001564 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07001565 | Method resolution order:
1566 | Color
1567 | enum.Enum
1568 | builtins.object
1569 |\x20\x20
1570 | Data and other attributes defined here:
1571 |\x20\x20
1572 | blue = <Color.blue: 3>
1573 |\x20\x20
1574 | green = <Color.green: 2>
1575 |\x20\x20
1576 | red = <Color.red: 1>
1577 |\x20\x20
1578 | ----------------------------------------------------------------------
1579 | Data descriptors inherited from enum.Enum:
1580 |\x20\x20
1581 | name
1582 | The name of the Enum member.
1583 |\x20\x20
1584 | value
1585 | The value of the Enum member.
1586 |\x20\x20
1587 | ----------------------------------------------------------------------
1588 | Data descriptors inherited from enum.EnumMeta:
1589 |\x20\x20
1590 | __members__
1591 | Returns a mapping of member name->value.
1592 |\x20\x20\x20\x20\x20\x20
1593 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07001594 | is a read-only view of the internal mapping."""
1595
1596expected_help_output_without_docs = """\
1597Help on class Color in module %s:
1598
1599class Color(enum.Enum)
1600 | Method resolution order:
1601 | Color
1602 | enum.Enum
1603 | builtins.object
1604 |\x20\x20
1605 | Data and other attributes defined here:
1606 |\x20\x20
1607 | blue = <Color.blue: 3>
1608 |\x20\x20
1609 | green = <Color.green: 2>
1610 |\x20\x20
1611 | red = <Color.red: 1>
1612 |\x20\x20
1613 | ----------------------------------------------------------------------
1614 | Data descriptors inherited from enum.Enum:
1615 |\x20\x20
1616 | name
1617 |\x20\x20
1618 | value
1619 |\x20\x20
1620 | ----------------------------------------------------------------------
1621 | Data descriptors inherited from enum.EnumMeta:
1622 |\x20\x20
1623 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07001624
1625class TestStdLib(unittest.TestCase):
1626
Ethan Furman48a724f2015-04-11 23:23:06 -07001627 maxDiff = None
1628
Ethan Furman5875d742013-10-21 20:45:55 -07001629 class Color(Enum):
1630 red = 1
1631 green = 2
1632 blue = 3
1633
1634 def test_pydoc(self):
1635 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07001636 if StrEnum.__doc__ is None:
1637 expected_text = expected_help_output_without_docs % __name__
1638 else:
1639 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07001640 output = StringIO()
1641 helper = pydoc.Helper(output=output)
1642 helper(self.Color)
1643 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02001644 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07001645
1646 def test_inspect_getmembers(self):
1647 values = dict((
1648 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07001649 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07001650 ('__members__', self.Color.__members__),
1651 ('__module__', __name__),
1652 ('blue', self.Color.blue),
1653 ('green', self.Color.green),
1654 ('name', Enum.__dict__['name']),
1655 ('red', self.Color.red),
1656 ('value', Enum.__dict__['value']),
1657 ))
1658 result = dict(inspect.getmembers(self.Color))
1659 self.assertEqual(values.keys(), result.keys())
1660 failed = False
1661 for k in values.keys():
1662 if result[k] != values[k]:
1663 print()
1664 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
1665 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
1666 failed = True
1667 if failed:
1668 self.fail("result does not equal expected, see print above")
1669
1670 def test_inspect_classify_class_attrs(self):
1671 # indirectly test __objclass__
1672 from inspect import Attribute
1673 values = [
1674 Attribute(name='__class__', kind='data',
1675 defining_class=object, object=EnumMeta),
1676 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07001677 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07001678 Attribute(name='__members__', kind='property',
1679 defining_class=EnumMeta, object=EnumMeta.__members__),
1680 Attribute(name='__module__', kind='data',
1681 defining_class=self.Color, object=__name__),
1682 Attribute(name='blue', kind='data',
1683 defining_class=self.Color, object=self.Color.blue),
1684 Attribute(name='green', kind='data',
1685 defining_class=self.Color, object=self.Color.green),
1686 Attribute(name='red', kind='data',
1687 defining_class=self.Color, object=self.Color.red),
1688 Attribute(name='name', kind='data',
1689 defining_class=Enum, object=Enum.__dict__['name']),
1690 Attribute(name='value', kind='data',
1691 defining_class=Enum, object=Enum.__dict__['value']),
1692 ]
1693 values.sort(key=lambda item: item.name)
1694 result = list(inspect.classify_class_attrs(self.Color))
1695 result.sort(key=lambda item: item.name)
1696 failed = False
1697 for v, r in zip(values, result):
1698 if r != v:
1699 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
1700 failed = True
1701 if failed:
1702 self.fail("result does not equal expected, see print above")
1703
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001704if __name__ == '__main__':
1705 unittest.main()