Skip to content

Commit 1d83a41

Browse files
committed
A small benchmark, as a treat
1 parent ef5e60a commit 1d83a41

File tree

7 files changed

+91
-62
lines changed

7 files changed

+91
-62
lines changed

bench/test_attrs_collections.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from enum import IntEnum
22
from typing import Dict, List, 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,7 +21,7 @@ class E(IntEnum):
2121
ONE = 1
2222
TWO = 2
2323

24-
@attr.define
24+
@define
2525
class C:
2626
a: List[int]
2727
b: List[float]
@@ -62,32 +62,32 @@ class C:
6262
[1] * 3,
6363
[1.0] * 3,
6464
["a small string"] * 3,
65-
["test".encode()] * 3,
65+
[b"test"] * 3,
6666
[E.ONE] * 3,
6767
[2] * 3,
6868
[2.0] * 3,
6969
["a small string"] * 3,
70-
["test".encode()] * 3,
70+
[b"test"] * 3,
7171
[E.TWO] * 3,
7272
[3] * 3,
7373
[3.0] * 3,
7474
["a small string"] * 3,
75-
["test".encode()] * 3,
75+
[b"test"] * 3,
7676
[E.ONE] * 3,
7777
[4] * 3,
7878
[4.0] * 3,
7979
["a small string"] * 3,
80-
["test".encode()] * 3,
80+
[b"test"] * 3,
8181
[E.TWO] * 3,
8282
[5] * 3,
8383
[5.0] * 3,
8484
["a small string"] * 3,
85-
["test".encode()] * 3,
85+
[b"test"] * 3,
8686
[E.ONE] * 3,
8787
[6] * 3,
8888
[6.0] * 3,
8989
["a small string"] * 3,
90-
["test".encode()] * 3,
90+
[b"test"] * 3,
9191
[E.TWO] * 3,
9292
),
9393
)
@@ -102,11 +102,11 @@ 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]
112112
b: Dict[float, bytes]
@@ -130,11 +130,11 @@ 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]
140140
b: Dict[float, bytes]

bench/test_attrs_nested.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Benchmark attrs containing other attrs classes."""
2-
import attr
32
import pytest
3+
from attrs import define
44

5-
from cattr import BaseConverter, Converter, UnstructureStrategy
5+
from cattrs import BaseConverter, Converter, UnstructureStrategy
66

77

88
@pytest.mark.parametrize("converter_cls", [BaseConverter, Converter])
@@ -12,42 +12,42 @@
1212
def test_unstructure_attrs_nested(benchmark, converter_cls, unstructure_strat):
1313
c = converter_cls(unstruct_strat=unstructure_strat)
1414

15-
@attr.define
15+
@define
1616
class InnerA:
1717
a: int
1818
b: float
1919
c: str
2020
d: bytes
2121

22-
@attr.define
22+
@define
2323
class InnerB:
2424
a: int
2525
b: float
2626
c: str
2727
d: bytes
2828

29-
@attr.define
29+
@define
3030
class InnerC:
3131
a: int
3232
b: float
3333
c: str
3434
d: bytes
3535

36-
@attr.define
36+
@define
3737
class InnerD:
3838
a: int
3939
b: float
4040
c: str
4141
d: bytes
4242

43-
@attr.define
43+
@define
4444
class InnerE:
4545
a: int
4646
b: float
4747
c: str
4848
d: bytes
4949

50-
@attr.define
50+
@define
5151
class Outer:
5252
a: InnerA
5353
b: InnerB
@@ -56,11 +56,11 @@ class Outer:
5656
e: InnerE
5757

5858
inst = Outer(
59-
InnerA(1, 1.0, "one", "one".encode()),
60-
InnerB(2, 2.0, "two", "two".encode()),
61-
InnerC(3, 3.0, "three", "three".encode()),
62-
InnerD(4, 4.0, "four", "four".encode()),
63-
InnerE(5, 5.0, "five", "five".encode()),
59+
InnerA(1, 1.0, "one", b"one"),
60+
InnerB(2, 2.0, "two", b"two"),
61+
InnerC(3, 3.0, "three", b"three"),
62+
InnerD(4, 4.0, "four", b"four"),
63+
InnerE(5, 5.0, "five", b"five"),
6464
)
6565

6666
benchmark(c.unstructure, inst)
@@ -73,49 +73,49 @@ class Outer:
7373
def test_unstruct_attrs_deep_nest(benchmark, converter_cls, unstructure_strat):
7474
c = converter_cls(unstruct_strat=unstructure_strat)
7575

76-
@attr.define
76+
@define
7777
class InnerA:
7878
a: int
7979
b: float
8080
c: str
8181
d: bytes
8282

83-
@attr.define
83+
@define
8484
class InnerB:
8585
a: InnerA
8686
b: InnerA
8787
c: InnerA
8888
d: InnerA
8989

90-
@attr.define
90+
@define
9191
class InnerC:
9292
a: InnerB
9393
b: InnerB
9494
c: InnerB
9595
d: InnerB
9696

97-
@attr.define
97+
@define
9898
class InnerD:
9999
a: InnerC
100100
b: InnerC
101101
c: InnerC
102102
d: InnerC
103103

104-
@attr.define
104+
@define
105105
class InnerE:
106106
a: InnerD
107107
b: InnerD
108108
c: InnerD
109109
d: InnerD
110110

111-
@attr.define
111+
@define
112112
class Outer:
113113
a: InnerE
114114
b: InnerE
115115
c: InnerE
116116
d: InnerE
117117

118-
make_inner_a = lambda: InnerA(1, 1.0, "one", "one".encode())
118+
make_inner_a = lambda: InnerA(1, 1.0, "one", b"one")
119119
make_inner_b = lambda: InnerB(*[make_inner_a() for _ in range(4)])
120120
make_inner_c = lambda: InnerC(*[make_inner_b() for _ in range(4)])
121121
make_inner_d = lambda: InnerD(*[make_inner_c() for _ in range(4)])

bench/test_attrs_primitives.py

Lines changed: 15 additions & 15 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
@@ -60,32 +60,32 @@ def test_unstructure_attrs_primitives(benchmark, converter_cls, unstructure_stra
6060
1,
6161
1.0,
6262
"a small string",
63-
"test".encode(),
63+
b"test",
6464
E.ONE,
6565
2,
6666
2.0,
6767
"a small string",
68-
"test".encode(),
68+
b"test",
6969
E.TWO,
7070
3,
7171
3.0,
7272
"a small string",
73-
"test".encode(),
73+
b"test",
7474
E.ONE,
7575
4,
7676
4.0,
7777
"a small string",
78-
"test".encode(),
78+
b"test",
7979
E.TWO,
8080
5,
8181
5.0,
8282
"a small string",
83-
"test".encode(),
83+
b"test",
8484
E.ONE,
8585
6,
8686
6.0,
8787
"a small string",
88-
"test".encode(),
88+
b"test",
8989
E.TWO,
9090
),
9191
)
@@ -104,32 +104,32 @@ def test_structure_attrs_primitives(benchmark, converter_cls, unstructure_strat)
104104
1,
105105
1.0,
106106
"a small string",
107-
"test".encode(),
107+
b"test",
108108
E.ONE,
109109
2,
110110
2.0,
111111
"a small string",
112-
"test".encode(),
112+
b"test",
113113
E.TWO,
114114
3,
115115
3.0,
116116
"a small string",
117-
"test".encode(),
117+
b"test",
118118
E.ONE,
119119
4,
120120
4.0,
121121
"a small string",
122-
"test".encode(),
122+
b"test",
123123
E.TWO,
124124
5,
125125
5.0,
126126
"a small string",
127-
"test".encode(),
127+
b"test",
128128
E.ONE,
129129
6,
130130
6.0,
131131
"a small string",
132-
"test".encode(),
132+
b"test",
133133
E.TWO,
134134
)
135135

bench/test_validators.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Benchmarks for validators."""
2+
import pytest
3+
from attrs import define
4+
from attrs import fields as f
5+
6+
from cattrs import Converter
7+
from cattrs.v import V, customize, greater_than, len_between
8+
9+
10+
@define
11+
class Small:
12+
a: int
13+
b: str
14+
15+
16+
@pytest.mark.parametrize("dv", [True, False])
17+
def test_structure_success(dv: bool, benchmark):
18+
c = Converter(detailed_validation=dv)
19+
20+
hook = customize(
21+
c,
22+
Small,
23+
V((fs := f(Small)).a).ensure(greater_than(10)),
24+
V(fs.b).ensure(len_between(0, 10)),
25+
)
26+
27+
d = {"a": 11, "b": "abcde"}
28+
29+
benchmark(hook, d, None)

src/cattrs/v/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
IterableValidationError,
99
)
1010
from ._fluent import V, customize
11-
from ._validators import between, greater_than
11+
from ._validators import between, greater_than, len_between
1212

1313
__all__ = [
1414
"customize",
@@ -17,6 +17,7 @@
1717
"V",
1818
"between",
1919
"greater_than",
20+
"len_between",
2021
]
2122

2223

src/cattrs/v/_fluent.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
Iterable,
1010
Literal,
1111
Sequence,
12-
Sized,
1312
TypeVar,
1413
)
1514

@@ -118,17 +117,6 @@ def is_unique(val: Collection[Any]) -> None:
118117
raise ValueError(f"Value ({val}) not unique")
119118

120119

121-
def len_between(min: int, max: int) -> Callable[[Sized], None]:
122-
"""Ensure the length of the argument is between min (inclusive) and max (exclusive)."""
123-
124-
def assert_len_between(val: Sized, _min: int = min, _max: int = max) -> None:
125-
length = len(val)
126-
if not (_min <= length < max):
127-
raise ValueError(f"Length ({length}) not between {_min} and {_max}")
128-
129-
return assert_len_between
130-
131-
132120
def ignoring_none(*validators: Callable[[T], None]) -> Callable[[T | None], None]:
133121
"""
134122
A validator for (f.e.) strings cannot be applied to `str | None`, but it can

0 commit comments

Comments
 (0)