1
+ from __future__ import annotations
2
+
1
3
import gc
2
4
import os
3
5
import pkgutil
4
6
import sys
5
7
from dataclasses import dataclass , field
6
- from typing import (
7
- TYPE_CHECKING ,
8
- Any ,
9
- Callable ,
10
- Dict ,
11
- List ,
12
- Optional ,
13
- Tuple ,
14
- TypeVar ,
15
- Union ,
16
- )
8
+ from typing import TYPE_CHECKING
17
9
18
10
import pytest
19
11
from _pytest .fixtures import FixtureManager
24
16
from ._wrapper import get_lib
25
17
26
18
if TYPE_CHECKING :
19
+ from typing import Any , Callable , TypeVar
20
+
27
21
from ._wrapper import LibType
28
22
23
+ T = TypeVar ("T" )
24
+
29
25
IS_PYTEST_BENCHMARK_INSTALLED = pkgutil .find_loader ("pytest_benchmark" ) is not None
30
26
SUPPORTS_PERF_TRAMPOLINE = sys .version_info >= (3 , 12 )
31
27
BEFORE_PYTEST_8_1_1 = pytest .version_tuple < (8 , 1 , 1 )
32
28
33
29
34
30
@pytest .hookimpl (trylast = True )
35
- def pytest_addoption (parser : " pytest.Parser" ):
31
+ def pytest_addoption (parser : pytest .Parser ):
36
32
group = parser .getgroup ("CodSpeed benchmarking" )
37
33
group .addoption (
38
34
"--codspeed" ,
@@ -46,20 +42,20 @@ def pytest_addoption(parser: "pytest.Parser"):
46
42
class CodSpeedPlugin :
47
43
is_codspeed_enabled : bool
48
44
should_measure : bool
49
- lib : Optional [ " LibType" ]
50
- disabled_plugins : Tuple [str , ...]
45
+ lib : LibType | None
46
+ disabled_plugins : tuple [str , ...]
51
47
benchmark_count : int = field (default = 0 , hash = False , compare = False )
52
48
53
49
54
50
PLUGIN_NAME = "codspeed_plugin"
55
51
56
52
57
- def get_plugin (config : " pytest.Config" ) -> " CodSpeedPlugin" :
53
+ def get_plugin (config : pytest .Config ) -> CodSpeedPlugin :
58
54
return config .pluginmanager .get_plugin (PLUGIN_NAME )
59
55
60
56
61
57
@pytest .hookimpl (tryfirst = True )
62
- def pytest_configure (config : " pytest.Config" ):
58
+ def pytest_configure (config : pytest .Config ):
63
59
config .addinivalue_line (
64
60
"markers" , "codspeed_benchmark: mark an entire test for codspeed benchmarking"
65
61
)
@@ -73,7 +69,7 @@ def pytest_configure(config: "pytest.Config"):
73
69
lib = get_lib () if should_measure else None
74
70
if lib is not None :
75
71
lib .dump_stats_at (f"Metadata: pytest-codspeed { __version__ } " .encode ("ascii" ))
76
- disabled_plugins : List [str ] = []
72
+ disabled_plugins : list [str ] = []
77
73
# Disable pytest-benchmark if codspeed is enabled
78
74
if is_codspeed_enabled and IS_PYTEST_BENCHMARK_INSTALLED :
79
75
object .__setattr__ (config .option , "benchmark_disable" , True )
@@ -89,7 +85,7 @@ def pytest_configure(config: "pytest.Config"):
89
85
config .pluginmanager .register (plugin , PLUGIN_NAME )
90
86
91
87
92
- def pytest_plugin_registered (plugin , manager : " pytest.PytestPluginManager" ):
88
+ def pytest_plugin_registered (plugin , manager : pytest .PytestPluginManager ):
93
89
"""Patch the benchmark fixture to use the codspeed one if codspeed is enabled"""
94
90
if IS_PYTEST_BENCHMARK_INSTALLED and isinstance (plugin , FixtureManager ):
95
91
fixture_manager = plugin
@@ -111,7 +107,7 @@ def pytest_plugin_registered(plugin, manager: "pytest.PytestPluginManager"):
111
107
112
108
113
109
@pytest .hookimpl (trylast = True )
114
- def pytest_report_header (config : " pytest.Config" ):
110
+ def pytest_report_header (config : pytest .Config ):
115
111
out = [
116
112
f"codspeed: { __version__ } "
117
113
f"(callgraph: { 'enabled' if SUPPORTS_PERF_TRAMPOLINE else 'not supported' } )"
@@ -132,24 +128,24 @@ def pytest_report_header(config: "pytest.Config"):
132
128
return "\n " .join (out )
133
129
134
130
135
- def has_benchmark_fixture (item : " pytest.Item" ) -> bool :
131
+ def has_benchmark_fixture (item : pytest .Item ) -> bool :
136
132
item_fixtures = getattr (item , "fixturenames" , [])
137
133
return "benchmark" in item_fixtures or "codspeed_benchmark" in item_fixtures
138
134
139
135
140
- def has_benchmark_marker (item : " pytest.Item" ) -> bool :
136
+ def has_benchmark_marker (item : pytest .Item ) -> bool :
141
137
return (
142
138
item .get_closest_marker ("codspeed_benchmark" ) is not None
143
139
or item .get_closest_marker ("benchmark" ) is not None
144
140
)
145
141
146
142
147
- def should_benchmark_item (item : " pytest.Item" ) -> bool :
143
+ def should_benchmark_item (item : pytest .Item ) -> bool :
148
144
return has_benchmark_fixture (item ) or has_benchmark_marker (item )
149
145
150
146
151
147
@pytest .hookimpl ()
152
- def pytest_sessionstart (session : " pytest.Session" ):
148
+ def pytest_sessionstart (session : pytest .Session ):
153
149
plugin = get_plugin (session .config )
154
150
if plugin .is_codspeed_enabled :
155
151
plugin .benchmark_count = 0
@@ -159,7 +155,7 @@ def pytest_sessionstart(session: "pytest.Session"):
159
155
160
156
@pytest .hookimpl (trylast = True )
161
157
def pytest_collection_modifyitems (
162
- session : " pytest.Session" , config : " pytest.Config" , items : "List [pytest.Item]"
158
+ session : pytest .Session , config : pytest .Config , items : list [pytest .Item ]
163
159
):
164
160
plugin = get_plugin (config )
165
161
if plugin .is_codspeed_enabled :
@@ -175,9 +171,9 @@ def pytest_collection_modifyitems(
175
171
176
172
177
173
def _run_with_instrumentation (
178
- lib : " LibType" ,
174
+ lib : LibType ,
179
175
nodeId : str ,
180
- config : " pytest.Config" ,
176
+ config : pytest .Config ,
181
177
fn : Callable [..., Any ],
182
178
* args ,
183
179
** kwargs ,
@@ -209,7 +205,7 @@ def __codspeed_root_frame__():
209
205
210
206
211
207
@pytest .hookimpl (tryfirst = True )
212
- def pytest_runtest_protocol (item : " pytest.Item" , nextitem : Union [ " pytest.Item" , None ] ):
208
+ def pytest_runtest_protocol (item : pytest .Item , nextitem : pytest .Item | None ):
213
209
plugin = get_plugin (item .config )
214
210
if not plugin .is_codspeed_enabled or not should_benchmark_item (item ):
215
211
return (
@@ -258,14 +254,11 @@ def pytest_runtest_protocol(item: "pytest.Item", nextitem: Union["pytest.Item",
258
254
return reports # Deny further protocol hooks execution
259
255
260
256
261
- T = TypeVar ("T" )
262
-
263
-
264
257
class BenchmarkFixture :
265
258
"""The fixture that can be used to benchmark a function."""
266
259
267
- def __init__ (self , request : " pytest.FixtureRequest" ):
268
- self .extra_info : Dict = {}
260
+ def __init__ (self , request : pytest .FixtureRequest ):
261
+ self .extra_info : dict = {}
269
262
270
263
self ._request = request
271
264
@@ -283,22 +276,22 @@ def __call__(self, func: Callable[..., T], *args: Any, **kwargs: Any) -> T:
283
276
284
277
285
278
@pytest .fixture (scope = "function" )
286
- def codspeed_benchmark (request : " pytest.FixtureRequest" ) -> Callable :
279
+ def codspeed_benchmark (request : pytest .FixtureRequest ) -> Callable :
287
280
return BenchmarkFixture (request )
288
281
289
282
290
283
if not IS_PYTEST_BENCHMARK_INSTALLED :
291
284
292
285
@pytest .fixture (scope = "function" )
293
- def benchmark (codspeed_benchmark , request : " pytest.FixtureRequest" ):
286
+ def benchmark (codspeed_benchmark , request : pytest .FixtureRequest ):
294
287
"""
295
288
Compatibility with pytest-benchmark
296
289
"""
297
290
return codspeed_benchmark
298
291
299
292
300
293
@pytest .hookimpl ()
301
- def pytest_sessionfinish (session : " pytest.Session" , exitstatus ):
294
+ def pytest_sessionfinish (session : pytest .Session , exitstatus ):
302
295
plugin = get_plugin (session .config )
303
296
if plugin .is_codspeed_enabled :
304
297
reporter = session .config .pluginmanager .get_plugin ("terminalreporter" )
0 commit comments