Skip to content

Commit 6abc0ba

Browse files
committed
fix python 3.11+ usage and add member/nonmember decorator tests for #29
1 parent 60787e1 commit 6abc0ba

File tree

3 files changed

+76
-9
lines changed

3 files changed

+76
-9
lines changed

doc/source/usage.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,16 @@ Nested Classes
261261
262262
.. note::
263263
264-
Nested classes behave normally on enums that inherit from
264+
In python <3.13, nested classes behave normally on enums that inherit from
265265
:py:class:`~enum_properties.EnumProperties` and that specify at least one
266-
property.
267-
268-
On enums that inherit from Enum_ nested classes become enumeration values
269-
because types may be values and a quirk of Python makes it difficult to
270-
determine if a type on a class is declared as a nested class during __new__.
271-
For enums with properties we can distinguish declared classes because values
272-
must be tuples.
266+
property. In python 3.13 this behavior will remain unchanged in
267+
enum-properties and normal Enum_ classes will adopt it.
268+
269+
On enums that inherit from Enum_ in python < 3.13 nested classes become
270+
enumeration values because types may be values and a quirk of Python makes it
271+
difficult to determine if a type on a class is declared as a nested class
272+
during __new__. For enums with properties we can distinguish declared classes
273+
because values must be tuples.
273274
274275
Using :py:class:`~enum_properties.EnumProperties` this is possible:
275276

enum_properties/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ def __setitem__(self, key, value):
320320
len(class_dict._member_names) > before and
321321
# base class lets nested classes through! see:
322322
# https://github.com/bckohan/enum-properties/issues/29
323+
# todo remove below when minimum python >= 3.13
323324
not isinstance(value, type)
324325
):
325326
try:
@@ -354,9 +355,17 @@ def __setitem__(self, key, value):
354355
super().__setitem__(key, value)
355356

356357
if remove:
358+
# todo remove when minimum python >= 3.13
357359
# base class lets nested classes through! see:
358360
# https://github.com/bckohan/enum-properties/issues/29
359-
self._member_names.remove(key)
361+
if isinstance(
362+
self._member_names,
363+
list
364+
): # pragma: no cover
365+
self._member_names.remove(key)
366+
else: # pragma: no cover
367+
# >= python 3.11
368+
del self._member_names[key]
360369
else:
361370
super().__setitem__(key, value)
362371

enum_properties/tests/tests.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pickle
2+
import sys
23
from collections.abc import Hashable
34
from enum import Enum, auto
45
from io import BytesIO
@@ -1288,6 +1289,7 @@ class Type3:
12881289
def test_example(self):
12891290

12901291
class MyEnum(EnumProperties, p('label')):
1292+
12911293
class Type1:
12921294
pass
12931295

@@ -1309,3 +1311,58 @@ class Type3:
13091311
self.assertTrue(MyEnum.Type1().__class__ is MyEnum.Type1)
13101312
self.assertTrue(MyEnum.Type2().__class__ is MyEnum.Type2)
13111313
self.assertTrue(MyEnum.Type3().__class__ is MyEnum.Type3)
1314+
1315+
if sys.version_info >= (3, 11): # pragma: no cover
1316+
def test_nonmember_decorator(self):
1317+
from enum import nonmember
1318+
1319+
class MyEnum(EnumProperties, p('label')):
1320+
1321+
@nonmember
1322+
class Type1:
1323+
pass
1324+
1325+
@nonmember
1326+
class Type2:
1327+
pass
1328+
1329+
@nonmember
1330+
class Type3:
1331+
pass
1332+
1333+
VALUE1 = Type1, 'label1'
1334+
VALUE2 = Type2, 'label2'
1335+
VALUE3 = Type3, 'label3'
1336+
VALUE4 = nonmember((Type3, 'label4'))
1337+
1338+
# nested classes are usable like normal
1339+
self.assertEqual(MyEnum.Type1, MyEnum.VALUE1.value)
1340+
self.assertEqual(MyEnum.Type2, MyEnum.VALUE2.value)
1341+
self.assertEqual(MyEnum.Type3, MyEnum.VALUE3.value)
1342+
self.assertEqual(len(MyEnum), 3)
1343+
self.assertEqual(MyEnum.VALUE4, (MyEnum.Type3, 'label4'))
1344+
self.assertTrue(MyEnum.Type1().__class__ is MyEnum.Type1)
1345+
self.assertTrue(MyEnum.Type2().__class__ is MyEnum.Type2)
1346+
self.assertTrue(MyEnum.Type3().__class__ is MyEnum.Type3)
1347+
1348+
def test_member_decorator(self):
1349+
from enum import member
1350+
1351+
with self.assertRaises(ValueError):
1352+
class MyEnum(EnumProperties, p('label')):
1353+
1354+
@member
1355+
class Type1:
1356+
pass
1357+
1358+
@member
1359+
class Type2:
1360+
pass
1361+
1362+
@member
1363+
class Type3:
1364+
pass
1365+
1366+
VALUE1 = Type1, 'label1'
1367+
VALUE2 = Type2, 'label2'
1368+
VALUE3 = Type3, 'label3'

0 commit comments

Comments
 (0)