Skip to content

Commit 1a94abf

Browse files
authored
Benchmark enums (#704)
* feat: Add benchmarks for enum structuring and unstructuring * refactor: Import define and frozen directly from attrs * Focus the benchmarks * Modernize older benchmarks * Tweak Justfile * feat: Add StrEnum benchmarks * feat: Bench enums on msgspec and orjson preconf converters The benchmark is removed since it's now redundant. * Install the `test` dep group for codspeed * codspeed: install extras
1 parent 7d04397 commit 1a94abf

7 files changed

Lines changed: 116 additions & 48 deletions

File tree

.github/workflows/codspeed.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ jobs:
3939
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1
4040
with:
4141
mode: simulation
42-
run: uv run --with pytest-codspeed --with pytest-benchmark pytest --codspeed bench/
42+
run: uv run --with pytest-codspeed --with pytest-benchmark --group test --extra msgspec --extra orjson pytest --codspeed bench/

Justfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ covall:
3838
@rm .coverage*
3939

4040
bench-cmp:
41-
uv run pytest bench --benchmark-compare
41+
uv run --group test pytest bench --benchmark-compare
4242

4343
bench:
44-
uv run pytest bench --benchmark-save base
44+
uv run --group test pytest bench --benchmark-save base
4545

4646
docs output_dir="_build": ## generate Sphinx HTML documentation, including API docs
4747
make -C docs -e BUILDDIR={{output_dir}} clean

bench/test_attrs_collections.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from enum import IntEnum
2-
from typing import Dict, List, Mapping, MutableMapping
2+
from typing import Mapping, MutableMapping
33

4-
import attr
54
import pytest
5+
from attrs import define, frozen
66

7-
from cattr import BaseConverter, Converter, UnstructureStrategy
7+
from cattrs import BaseConverter, Converter, UnstructureStrategy
88

99

1010
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter])
@@ -21,38 +21,38 @@ class E(IntEnum):
2121
ONE = 1
2222
TWO = 2
2323

24-
@attr.define
24+
@define
2525
class C:
26-
a: List[int]
27-
b: List[float]
28-
c: List[str]
29-
d: List[bytes]
30-
e: List[E]
31-
f: List[int]
32-
g: List[float]
33-
h: List[str]
34-
i: List[bytes]
35-
j: List[E]
36-
k: List[int]
37-
l: List[float] # noqa: E741
38-
m: List[str]
39-
n: List[bytes]
40-
o: List[E]
41-
p: List[int]
42-
q: List[float]
43-
r: List[str]
44-
s: List[bytes]
45-
t: List[E]
46-
u: List[int]
47-
v: List[float]
48-
w: List[str]
49-
x: List[bytes]
50-
y: List[E]
51-
z: List[int]
52-
aa: List[float]
53-
ab: List[str]
54-
ac: List[bytes]
55-
ad: List[E]
26+
a: list[int]
27+
b: list[float]
28+
c: list[str]
29+
d: list[bytes]
30+
e: list[E]
31+
f: list[int]
32+
g: list[float]
33+
h: list[str]
34+
i: list[bytes]
35+
j: list[E]
36+
k: list[int]
37+
l: list[float] # noqa: E741
38+
m: list[str]
39+
n: list[bytes]
40+
o: list[E]
41+
p: list[int]
42+
q: list[float]
43+
r: list[str]
44+
s: list[bytes]
45+
t: list[E]
46+
u: list[int]
47+
v: list[float]
48+
w: list[str]
49+
x: list[bytes]
50+
y: list[E]
51+
z: list[int]
52+
aa: list[float]
53+
ab: list[str]
54+
ac: list[bytes]
55+
ad: list[E]
5656

5757
c = converter_cls(unstruct_strat=unstructure_strat)
5858

@@ -102,14 +102,14 @@ def test_unstructure_attrs_mappings(benchmark, converter_cls, unstructure_strat)
102102
Benchmark an attrs class containing mappings.
103103
"""
104104

105-
@attr.frozen
105+
@frozen
106106
class FrozenCls:
107107
a: int
108108

109-
@attr.define
109+
@define
110110
class C:
111111
a: Mapping[int, str]
112-
b: Dict[float, bytes]
112+
b: dict[float, bytes]
113113
c: MutableMapping[int, FrozenCls]
114114

115115
c = converter_cls(unstruct_strat=unstructure_strat)
@@ -130,14 +130,14 @@ def test_structure_attrs_mappings(benchmark, converter_cls):
130130
Benchmark an attrs class containing mappings.
131131
"""
132132

133-
@attr.frozen
133+
@frozen
134134
class FrozenCls:
135135
a: int
136136

137-
@attr.define
137+
@define
138138
class C:
139139
a: Mapping[int, str]
140-
b: Dict[float, bytes]
140+
b: dict[float, bytes]
141141
c: MutableMapping[int, FrozenCls]
142142

143143
c = converter_cls()

bench/test_attrs_nested.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
from attrs import define
55

6-
from cattr import BaseConverter, Converter, UnstructureStrategy
6+
from cattrs import BaseConverter, Converter, UnstructureStrategy
77

88

99
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter])

bench/test_attrs_primitives.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
from enum import IntEnum
22

3-
import attr
43
import pytest
4+
from attrs import define
55

6-
from cattr import BaseConverter, Converter, UnstructureStrategy
6+
from cattrs import BaseConverter, Converter, UnstructureStrategy
77

88

99
class E(IntEnum):
1010
ONE = 1
1111
TWO = 2
1212

1313

14-
@attr.define
14+
@define
1515
class C:
1616
a: int
1717
b: float

bench/test_enums.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from enum import Enum, IntEnum, StrEnum
2+
3+
import pytest
4+
5+
from cattrs import BaseConverter, Converter
6+
from cattrs.preconf.msgspec import MsgspecJsonConverter
7+
from cattrs.preconf.orjson import OrjsonConverter
8+
9+
10+
class SimpleEnum(Enum):
11+
FIRST = "first"
12+
SECOND = "second"
13+
THIRD = "third"
14+
15+
16+
class SimpleIntEnum(IntEnum):
17+
ONE = 1
18+
TWO = 2
19+
THREE = 3
20+
21+
22+
class SimpleStrEnum(StrEnum):
23+
ALPHA = "alpha"
24+
BETA = "beta"
25+
GAMMA = "gamma"
26+
27+
28+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
29+
def test_unstructure_simple_enum(benchmark, converter_cls):
30+
"""Benchmark unstructuring a simple enum."""
31+
c = converter_cls()
32+
benchmark(c.unstructure, SimpleEnum.FIRST)
33+
34+
35+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
36+
def test_structure_simple_enum(benchmark, converter_cls):
37+
"""Benchmark structuring a simple enum."""
38+
c = converter_cls()
39+
benchmark(c.structure, "first", SimpleEnum)
40+
41+
42+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
43+
def test_unstructure_simple_int_enum(benchmark, converter_cls):
44+
"""Benchmark unstructuring a simple IntEnum."""
45+
c = converter_cls()
46+
benchmark(c.unstructure, SimpleIntEnum.ONE)
47+
48+
49+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
50+
def test_structure_simple_int_enum(benchmark, converter_cls):
51+
"""Benchmark structuring a simple IntEnum."""
52+
c = converter_cls()
53+
benchmark(c.structure, 1, SimpleIntEnum)
54+
55+
56+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
57+
def test_unstructure_simple_str_enum(benchmark, converter_cls):
58+
"""Benchmark unstructuring a simple StrEnum."""
59+
c = converter_cls()
60+
benchmark(c.unstructure, SimpleStrEnum.ALPHA)
61+
62+
63+
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter, MsgspecJsonConverter, OrjsonConverter])
64+
def test_structure_simple_str_enum(benchmark, converter_cls):
65+
"""Benchmark structuring a simple StrEnum."""
66+
c = converter_cls()
67+
benchmark(c.structure, "alpha", SimpleStrEnum)
68+

bench/test_primitives.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from cattr import BaseConverter, Converter
3+
from cattrs import BaseConverter, Converter
44

55

66
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter])

0 commit comments

Comments
 (0)