with:
mode: simulation
run: uv run --no-sync pytest tests/benchmarks --codspeed
+ - name: CodSpeed memory benchmark
+ uses: CodSpeedHQ/action@a4a36bb07c0638b0b4ca52bf1f3dad1b4289e52f # v4.18.1
+ with:
+ mode: memory
+ run: uv run --no-sync pytest tests/memory_benchmarks --codspeed
coverage-combine:
needs:
"pwdlib[argon2] >=0.2.1",
"pyjwt >=2.9.0",
"pytest >=9.0.0",
- "pytest-codspeed >=4.2.0",
+ "pytest-codspeed >=4.3.0",
"pyyaml >=5.3.1,<7.0.0",
"sqlmodel >=0.0.31",
"strawberry-graphql >=0.200.0,<1.0.0",
context = '${CONTEXT}'
omit = [
"tests/benchmarks/*",
+ "tests/memory_benchmarks/*",
"docs_src/response_model/tutorial003_04_py310.py",
"docs_src/dependencies/tutorial013_an_py310.py", # temporary code example?
"docs_src/dependencies/tutorial014_an_py310.py", # temporary code example?
--- /dev/null
+import inspect
+import sys
+from collections.abc import Callable
+from typing import Any
+
+import pytest
+from fastapi import Depends, FastAPI
+from fastapi.routing import APIRoute
+
+if "--codspeed" not in sys.argv:
+ pytest.skip(
+ "Benchmark tests are skipped by default; run with --codspeed.",
+ allow_module_level=True,
+ )
+
+LAST_DEPENDENCY_INDEX = 100
+ENDPOINT_PARAMETER_COUNT = 50
+ROUTE_PATH = "/dynamic-health"
+
+
+def _create_app() -> FastAPI:
+ app = FastAPI()
+ dependencies: dict[int, Callable[..., Any]] = {}
+
+ def create_dependency(index: int) -> Callable[..., Any]:
+ if index == LAST_DEPENDENCY_INDEX:
+
+ def dependency() -> str:
+ return str(index)
+
+ dependency.__name__ = f"dependency_{index}"
+ return dependency
+
+ next_dependency = dependencies[index + 1]
+
+ async def dependency(
+ sub_dependency: str = Depends(next_dependency),
+ ) -> str:
+ return f"{index} -> {sub_dependency}"
+
+ dependency.__name__ = f"dependency_{index}"
+ return dependency
+
+ for index in reversed(range(LAST_DEPENDENCY_INDEX + 1)):
+ dependencies[index] = create_dependency(index)
+
+ def create_endpoint() -> Callable[..., Any]:
+ parameters = [
+ inspect.Parameter(
+ name=f"arg_{index}",
+ kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
+ default=Depends(dependencies[index]),
+ annotation=str,
+ )
+ for index in range(ENDPOINT_PARAMETER_COUNT)
+ ]
+
+ async def endpoint(**kwargs: str) -> dict[str, int]:
+ return {"parameter_count": len(kwargs)}
+
+ endpoint_with_signature: Any = endpoint
+ endpoint_with_signature.__signature__ = inspect.Signature(parameters)
+ return endpoint
+
+ for method in ("GET", "POST"):
+ app.add_api_route(
+ ROUTE_PATH,
+ create_endpoint(),
+ methods=[method],
+ )
+
+ return app
+
+
+def test_dependency_graph(benchmark) -> None:
+ app = benchmark(_create_app)
+ dynamic_routes = [
+ route
+ for route in app.routes
+ if isinstance(route, APIRoute) and route.path == ROUTE_PATH
+ ]
+ assert len(dynamic_routes) == 2
+ assert {method for route in dynamic_routes for method in route.methods} == {
+ "GET",
+ "POST",
+ }
{ name = "pygithub", specifier = ">=2.8.1" },
{ name = "pyjwt", specifier = ">=2.9.0" },
{ name = "pytest", specifier = ">=9.0.0" },
- { name = "pytest-codspeed", specifier = ">=4.2.0" },
+ { name = "pytest-codspeed", specifier = ">=4.3.0" },
{ name = "pytest-cov", specifier = ">=4.0.0" },
{ name = "pytest-sugar", specifier = ">=1.0.0" },
{ name = "pytest-timeout", specifier = ">=2.4.0" },
{ name = "pwdlib", extras = ["argon2"], specifier = ">=0.2.1" },
{ name = "pyjwt", specifier = ">=2.9.0" },
{ name = "pytest", specifier = ">=9.0.0" },
- { name = "pytest-codspeed", specifier = ">=4.2.0" },
+ { name = "pytest-codspeed", specifier = ">=4.3.0" },
{ name = "pytest-cov", specifier = ">=4.0.0" },
{ name = "pytest-sugar", specifier = ">=1.0.0" },
{ name = "pytest-timeout", specifier = ">=2.4.0" },