Skip to content

Commit 8ba6fbc

Browse files
committed
fix nested class howto
1 parent ce866e2 commit 8ba6fbc

File tree

7 files changed

+84
-13
lines changed

7 files changed

+84
-13
lines changed

doc/source/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
extensions = [
4242
'sphinx.ext.autodoc',
4343
'sphinx.ext.todo',
44-
'sphinx.ext.intersphinx'
44+
'sphinx.ext.intersphinx',
45+
"sphinx_tabs.tabs"
4546
]
4647

4748
# Add any paths that contain templates here, relative to this directory.

doc/source/howto.rst

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,22 +207,28 @@ are supported on flags. Boundary specifiers must be supplied as named arguments:
207207
Use Nested Classes as Enums
208208
---------------------------
209209

210-
.. note::
211-
212-
In python <3.13, nested classes behave normally on enums that inherit from
213-
:py:class:`~enum_properties.EnumProperties` and that specify at least one
214-
property. In python 3.13 this behavior will remain unchanged in
215-
enum-properties and normal :class:`enum.Enum` classes will adopt it.
210+
You can use nested classes as enumeration values. The tricky part is keeping them from becoming
211+
values themselves.
216212

217213
On enums that inherit from :class:`enum.Enum` in python < 3.13 nested classes become
218214
enumeration values because types may be values and a quirk of Python makes it
219215
difficult to determine if a type on a class is declared as a nested class
220216
during __new__. For enums with properties we can distinguish declared classes
221217
because values must be tuples.
222218

223-
Using :py:class:`~enum_properties.EnumProperties` this is possible:
219+
Note that on 3.13 and above you must use the nonmember/member decorators. Also note that
220+
the position of ``label`` is important.
221+
222+
.. tabs::
223+
224+
.. tab:: <3.13
225+
226+
.. literalinclude:: ../../tests/examples/howto_nested_classes.py
227+
228+
.. tab:: >=3.11 (required >=3.13)
229+
230+
.. literalinclude:: ../../tests/examples/howto_nested_classes_313.py
224231

225-
.. literalinclude:: ../../tests/examples/howto_nested_classes.py
226232

227233
What about dataclass Enums?
228234
---------------------------

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ docs = [
6767
"readme-renderer[md]>=43.0",
6868
"sphinx>=7.1.2",
6969
"sphinx-autobuild>=2021.3.14",
70+
"sphinx-tabs>=3.4.7",
7071
]
7172

7273

tests/examples/howto_nested_classes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ class Type3:
2020

2121

2222
# only the expected values become enumeration values
23-
assert MyEnum.Type1 == MyEnum.VALUE1.value
24-
assert MyEnum.Type2 == MyEnum.VALUE2.value
25-
assert MyEnum.Type3 == MyEnum.VALUE3.value
26-
assert len(MyEnum) == 3
23+
assert MyEnum.Type1 == MyEnum.VALUE1
24+
assert MyEnum.Type2 == MyEnum.VALUE2
25+
assert MyEnum.Type3 == MyEnum.VALUE3
26+
assert len(MyEnum) == 3, len(MyEnum)
2727

2828
# nested classes behave as expected
2929
assert MyEnum.Type1().__class__ is MyEnum.Type1
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from enum_properties import EnumProperties
2+
from enum import nonmember, member
3+
4+
5+
class MyEnum(EnumProperties):
6+
7+
@nonmember
8+
class Type1:
9+
pass
10+
11+
@nonmember
12+
class Type2:
13+
pass
14+
15+
@nonmember
16+
class Type3:
17+
pass
18+
19+
label: str
20+
21+
VALUE1 = member(Type1), 'label1'
22+
VALUE2 = member(Type2), 'label2'
23+
VALUE3 = member(Type3), 'label3'
24+
25+
26+
# only the expected values become enumeration values
27+
assert MyEnum.Type1 == MyEnum.VALUE1
28+
assert MyEnum.Type2 == MyEnum.VALUE2
29+
assert MyEnum.Type3 == MyEnum.VALUE3
30+
assert len(MyEnum) == 3, len(MyEnum)
31+
32+
# nested classes behave as expected
33+
assert MyEnum.Type1().__class__ is MyEnum.Type1
34+
assert MyEnum.Type2().__class__ is MyEnum.Type2
35+
assert MyEnum.Type3().__class__ is MyEnum.Type3

tests/examples/test_examples.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,15 @@ def test_howto_flag_boundaries():
9191
from tests.examples import howto_flag_boundaries
9292

9393

94+
@pytest.mark.skipif(sys.version_info < (3, 11), reason="requires Python 3.11 or higher")
9495
def test_howto_nested_classes():
96+
with warnings.catch_warnings():
97+
warnings.simplefilter("ignore", DeprecationWarning)
98+
from tests.examples import howto_nested_classes_313
99+
100+
101+
@pytest.mark.skipif(sys.version_info >= (3, 13), reason="requires Python < 3.13")
102+
def test_howto_nested_classes_313():
95103
with warnings.catch_warnings():
96104
warnings.simplefilter("ignore", DeprecationWarning)
97105
from tests.examples import howto_nested_classes

uv.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)