Files
Pratik Bhadane 71b6343e92 feat: refresh benchmark coverage and harden CI tooling
Refresh the benchmark and performance surface across the repo. This updates the benchmark wrappers and helper scripts, regenerates the checked-in benchmark and perf-contract artifacts, and folds in the related roadmap, compatibility, and example notebook changes that belong with this performance-focused pass.

Harden the Python CI and local pre-push flow so the same checks pass reliably in both places. The workflow and pre-push script now use module-safe uv typecheck invocations, the Python test environment installs the optional MCP dependency needed by the MCP server tests, and one-off root benchmark outputs are ignored to keep the repo clean.

Align local tooling with the current project configuration by updating the Ruff pre-commit hook, tightening the API typing and MCP server helpers, and refreshing the lockfile to pick up the audited PyJWT fix while preserving the rest of the staged source changes.
2026-03-24 14:52:20 +05:30

109 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Generate the Speed Comparison markdown table from benchmarks/results.json.
Requires results from the full suite:
pytest benchmarks/test_speed.py --benchmark-only --benchmark-json=benchmarks/results.json -v
Reads results.json and prints a markdown table: all indicators × all libraries.
Unsupported (indicator, library) pairs show N/A. Supported pairs missing benchmark
data show ERR (indicating the benchmark run was incomplete or failed).
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
# Ensure project root is on path when run as script
_root = Path(__file__).resolve().parent.parent
if _root not in (Path(p).resolve() for p in sys.path):
sys.path.insert(0, str(_root))
from benchmarks.wrapper_registry import (
INDICATOR_CATEGORIES,
is_supported,
)
from benchmarks.wrapper_registry import (
LIBRARY_NAMES as LIBS,
)
def _all_indicators() -> list[str]:
"""All indicators in category order (matches test_speed parametrization)."""
return [ind for cat in INDICATOR_CATEGORIES for ind in INDICATOR_CATEGORIES[cat]]
def main():
p = Path(__file__).parent / "results.json"
if not p.exists():
print(
"Run: pytest benchmarks/test_speed.py --benchmark-only --benchmark-json=benchmarks/results.json -v",
file=sys.stderr,
)
sys.exit(1)
raw = p.read_text().strip()
if not raw:
print(
"results.json is empty. Run the full benchmark suite first.",
file=sys.stderr,
)
sys.exit(1)
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
print(f"Invalid JSON in results.json: {e}", file=sys.stderr)
sys.exit(1)
benchmarks = data.get("benchmarks", [])
# Collect test_speed[Category/Indicator/library] -> median µs
table: dict[str, dict[str, float]] = {}
for b in benchmarks:
name = b.get("name") or ""
if "test_speed[" not in name:
continue
params = b.get("params") or {}
ind = params.get("indicator")
lib = params.get("library")
if not ind or not lib or lib not in LIBS:
continue
median_sec = (b.get("stats") or {}).get("median")
if median_sec is None:
continue
if ind not in table:
table[ind] = {}
table[ind][lib] = median_sec * 1e6 # to µs
all_indicators = _all_indicators()
if not all_indicators:
print("No indicators from INDICATOR_CATEGORIES.", file=sys.stderr)
sys.exit(1)
# Header: Indicator | ferro_ta | talib | ...
lib_header = " | ".join(LIBS)
print(f"| Indicator | {lib_header} |")
print("|-----------|" + "|".join(["--------:" for _ in LIBS]) + "|")
for ind in all_indicators:
row = table.get(ind, {})
cells = []
for lib in LIBS:
if lib in row:
cells.append(str(round(row[lib])))
elif not is_supported(lib, ind):
cells.append("N/A")
else:
cells.append("ERR")
print(f"| {ind} | {' | '.join(cells)} |")
print()
print(
"(Median time in µs, lower is better. N/A = unsupported pair. "
"ERR = supported pair missing benchmark data. Source: results.json from full test_speed run.)"
)
if __name__ == "__main__":
main()