benchmatrix 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. benchmatrix-0.2.1/.gitignore +49 -0
  2. benchmatrix-0.2.1/CHANGELOG.md +56 -0
  3. benchmatrix-0.2.1/CITATION.cff +24 -0
  4. benchmatrix-0.2.1/CODE_OF_CONDUCT.md +31 -0
  5. benchmatrix-0.2.1/CONTRIBUTING.md +66 -0
  6. benchmatrix-0.2.1/LICENSE +21 -0
  7. benchmatrix-0.2.1/PKG-INFO +154 -0
  8. benchmatrix-0.2.1/README.md +123 -0
  9. benchmatrix-0.2.1/RELEASING.md +61 -0
  10. benchmatrix-0.2.1/SECURITY.md +30 -0
  11. benchmatrix-0.2.1/docs/_scripts/gen_api_reference.py +34 -0
  12. benchmatrix-0.2.1/docs/changelog.md +13 -0
  13. benchmatrix-0.2.1/docs/contributing.md +27 -0
  14. benchmatrix-0.2.1/docs/development.md +106 -0
  15. benchmatrix-0.2.1/docs/explanation/ai.md +18 -0
  16. benchmatrix-0.2.1/docs/explanation/architecture.md +29 -0
  17. benchmatrix-0.2.1/docs/explanation/dependency-policy.md +49 -0
  18. benchmatrix-0.2.1/docs/explanation/deployment-environments.md +54 -0
  19. benchmatrix-0.2.1/docs/explanation/deprecations.md +45 -0
  20. benchmatrix-0.2.1/docs/explanation/first-release.md +25 -0
  21. benchmatrix-0.2.1/docs/explanation/github-actions-security.md +40 -0
  22. benchmatrix-0.2.1/docs/explanation/license-policy.md +19 -0
  23. benchmatrix-0.2.1/docs/explanation/lifecycle.md +53 -0
  24. benchmatrix-0.2.1/docs/explanation/performance.md +52 -0
  25. benchmatrix-0.2.1/docs/explanation/publishing.md +125 -0
  26. benchmatrix-0.2.1/docs/explanation/repository-health.md +18 -0
  27. benchmatrix-0.2.1/docs/explanation/repository-settings.md +150 -0
  28. benchmatrix-0.2.1/docs/explanation/secrets.md +22 -0
  29. benchmatrix-0.2.1/docs/explanation/threat-model.md +26 -0
  30. benchmatrix-0.2.1/docs/how-to/create-benchmark-matrix.md +62 -0
  31. benchmatrix-0.2.1/docs/how-to/parse-results.md +35 -0
  32. benchmatrix-0.2.1/docs/how-to/run-with-docker.md +99 -0
  33. benchmatrix-0.2.1/docs/how-to/troubleshooting.md +48 -0
  34. benchmatrix-0.2.1/docs/index.md +37 -0
  35. benchmatrix-0.2.1/docs/reference/compatibility.md +127 -0
  36. benchmatrix-0.2.1/docs/reference/configuration.md +182 -0
  37. benchmatrix-0.2.1/docs/reference/index.md +16 -0
  38. benchmatrix-0.2.1/docs/runbooks/container-release.md +72 -0
  39. benchmatrix-0.2.1/docs/runbooks/dependency-update.md +78 -0
  40. benchmatrix-0.2.1/docs/runbooks/failed-ci.md +34 -0
  41. benchmatrix-0.2.1/docs/runbooks/incident-response.md +32 -0
  42. benchmatrix-0.2.1/docs/runbooks/index.md +18 -0
  43. benchmatrix-0.2.1/docs/runbooks/ownership-transfer.md +27 -0
  44. benchmatrix-0.2.1/docs/runbooks/release.md +147 -0
  45. benchmatrix-0.2.1/docs/runbooks/repository-setup.md +147 -0
  46. benchmatrix-0.2.1/docs/runbooks/security-report.md +36 -0
  47. benchmatrix-0.2.1/docs/tutorials/first-benchmark.md +72 -0
  48. benchmatrix-0.2.1/examples/test_factorial_benchmarks.py +78 -0
  49. benchmatrix-0.2.1/examples/test_factorial_benchmarks_simplified.py +61 -0
  50. benchmatrix-0.2.1/mkdocs.yml +92 -0
  51. benchmatrix-0.2.1/noxfile.py +97 -0
  52. benchmatrix-0.2.1/pyproject.toml +185 -0
  53. benchmatrix-0.2.1/src/benchmatrix/__init__.py +57 -0
  54. benchmatrix-0.2.1/src/benchmatrix/_schema.py +79 -0
  55. benchmatrix-0.2.1/src/benchmatrix/bench_harness.py +1060 -0
  56. benchmatrix-0.2.1/src/benchmatrix/bench_results.py +536 -0
  57. benchmatrix-0.2.1/src/benchmatrix/exceptions.py +13 -0
  58. benchmatrix-0.2.1/src/benchmatrix/py.typed +0 -0
  59. benchmatrix-0.2.1/tests/fixtures/benchmark_results/invalid_tail_missing_data.json +20 -0
  60. benchmatrix-0.2.1/tests/fixtures/benchmark_results/mixed_metrics.json +56 -0
  61. benchmatrix-0.2.1/tests/test_bench_harness.py +615 -0
  62. benchmatrix-0.2.1/tests/test_bench_results.py +445 -0
  63. benchmatrix-0.2.1/tests/test_integration.py +185 -0
  64. benchmatrix-0.2.1/tests/test_properties.py +93 -0
  65. benchmatrix-0.2.1/tests/test_public_api.py +53 -0
@@ -0,0 +1,49 @@
1
+ # Python bytecode and caches
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .pre-commit-cache/
7
+ .mypy_cache/
8
+ .pyright/
9
+ .ipynb_checkpoints/
10
+
11
+ # Virtual environments
12
+ .nox/
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Build artifacts
18
+ build/
19
+ dist/
20
+ *.egg-info/
21
+ site/
22
+
23
+ # Test coverage and reports
24
+ .coverage
25
+ htmlcov/
26
+ reports/
27
+
28
+ # Environment and secrets
29
+ .env
30
+ .env.*
31
+ !.env.example
32
+
33
+ # OS/editor noise
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Node / npm
38
+ node_modules/
39
+ npm-debug.log*
40
+ yarn-debug.log*
41
+ yarn-error.log*
42
+ pnpm-debug.log*
43
+ .npm/
44
+
45
+ # Notes
46
+ TODO.md
47
+
48
+ # Generated example benchmark output
49
+ examples/benchmark_results/
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ All notable changes to benchmatrix will be documented in this file.
4
+
5
+ The project follows [Semantic Versioning](https://semver.org/), with the
6
+ additional pre-1.0 compatibility expectations described in
7
+ [the release policy](RELEASING.md).
8
+
9
+ ## Unreleased
10
+
11
+ ### Added
12
+
13
+ ### Changed
14
+
15
+ ## 0.2.1 - 2026-06-22
16
+
17
+ ### Changed
18
+
19
+ * Fix release and release-verify workflow bugs preventing creation of PyPI
20
+ releases.
21
+
22
+ ## 0.2.0 - 2026-06-22
23
+
24
+ ### Added
25
+
26
+ * Initial benchmark matrix utilities.
27
+ * pytest-benchmark JSON parsing and display utilities.
28
+ * Automated linting, typing, security, dependency, test, coverage, and package
29
+ validation for local development and pull requests, including scheduled
30
+ audits of locked dependencies for known vulnerabilities.
31
+ * Pre-commit automation, secret scanning, Markdown linting, GitHub Actions
32
+ workflow linting, and repository text and binary file attributes.
33
+ * MkDocs documentation site with strict builds, generated API reference pages,
34
+ and operational maintainer runbooks.
35
+ * Reproducible CycloneDX SBOM generation for locked runtime dependencies.
36
+ * uv-backed nox automation for supported-Python tests, quality checks, and
37
+ release artifact smoke testing.
38
+ * GitHub pull request auto-labeling and labels-as-code configuration for
39
+ maintainers.
40
+ * Dependabot automation for Python, Node, pre-commit, GitHub Actions, Docker,
41
+ and devcontainer dependency updates.
42
+ * Repository settings-as-code plus external setup checklists for branch
43
+ protection, security features, Pages, environments, and PyPI publishing.
44
+ * Focused Python dependency groups for test, lint, type, docs, security,
45
+ release, and automation tooling, with `dev` as the aggregate group.
46
+ * Compatibility, lifecycle, security-fix, release-branch, and deprecation
47
+ policy documentation.
48
+ * GitHub Actions CI/CD workflows for quality checks, multi-version and
49
+ cross-OS tests, docs deployment, PyPI Trusted Publishing, artifact
50
+ attestations, CodeQL, dependency review, OpenSSF Scorecard, and workflow
51
+ linting.
52
+ * CI test and coverage report artifacts, documentation link checking, minimum-
53
+ dependency tests, and post-release PyPI installation verification.
54
+ * Docker runtime and test images, local Docker targets, Docker-outside-of-Docker
55
+ devcontainer support, Dockerfile linting, GHCR publishing, image
56
+ SBOM/provenance, and critical-vulnerability image scanning.
@@ -0,0 +1,24 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use benchmatrix in your work, please cite it using this metadata."
3
+ title: "benchmatrix"
4
+ abstract: >-
5
+ Utilities for building pytest-benchmark benchmark matrices and parsing
6
+ pytest-benchmark JSON output.
7
+ type: software
8
+ authors:
9
+ - family-names: "Wallace"
10
+ given-names: "Ryan"
11
+ email: "ryancswallace@gmail.com"
12
+ alias: "ryancswallace"
13
+ version: 0.2.1
14
+ date-released: "2026-06-22"
15
+ license: MIT
16
+ repository-code: "https://github.com/ryancswallace/benchmatrix"
17
+ url: "https://github.com/ryancswallace/benchmatrix"
18
+ keywords:
19
+ - "python"
20
+ - "benchmarking"
21
+ - "benchmark"
22
+ - "performance"
23
+ - "pytest"
24
+ - "pytest-benchmark"
@@ -0,0 +1,31 @@
1
+ # Code of conduct
2
+
3
+ ## Our commitment
4
+
5
+ We are committed to making participation in the benchmatrix community a
6
+ welcoming and harassment-free experience for everyone, regardless of
7
+ background, identity, appearance, experience level, or ability.
8
+
9
+ ## Expected behavior
10
+
11
+ Examples of behavior that contributes to a positive community include:
12
+
13
+ * being respectful, constructive, and empathetic;
14
+ * giving and accepting technical feedback gracefully;
15
+ * focusing disagreement on ideas and outcomes rather than people;
16
+ * taking responsibility for mistakes and learning from them.
17
+
18
+ Unacceptable behavior includes harassment, discrimination, threats, sustained
19
+ disruption, sexualized attention, deliberate intimidation, or publishing
20
+ someone's private information without permission.
21
+
22
+ ## Enforcement
23
+
24
+ Report conduct concerns privately to Ryan Wallace at
25
+ <ryancswallace@gmail.com>. Reports will be reviewed promptly and handled as
26
+ confidentially as practical. The maintainer may edit or remove contributions,
27
+ temporarily or permanently restrict participation, or take other action
28
+ appropriate to the circumstances.
29
+
30
+ This policy applies in project spaces and when someone is publicly representing
31
+ the project.
@@ -0,0 +1,66 @@
1
+ # Contributing to benchmatrix
2
+
3
+ Thanks for considering a contribution.
4
+
5
+ ## Before you start
6
+
7
+ For substantial changes, open an issue first so the problem and proposed
8
+ direction can be discussed. Small fixes and documentation improvements can go
9
+ directly to a pull request.
10
+
11
+ By participating, you agree to follow the [code of conduct](CODE_OF_CONDUCT.md).
12
+ Please report security vulnerabilities through the process in
13
+ [SECURITY.md](SECURITY.md), not through a public issue.
14
+
15
+ ## Development
16
+
17
+ benchmatrix requires Python 3.11 or newer and uses
18
+ [uv](https://docs.astral.sh/uv/) for Python dependency management.
19
+
20
+ Set up and verify the development environment:
21
+
22
+ ```bash
23
+ make ready
24
+ make hooks-install
25
+ ```
26
+
27
+ Before submitting a change, run:
28
+
29
+ ```bash
30
+ make format
31
+ make check
32
+ ```
33
+
34
+ For changes that may vary by interpreter or packaging environment, also run:
35
+
36
+ ```bash
37
+ make test-matrix
38
+ ```
39
+
40
+ This runs tests on Python 3.11 through 3.14 plus focused lint, type, dependency,
41
+ security, and release-artifact smoke sessions.
42
+
43
+ Documentation changes should pass `make docs`; API behavior changes should update
44
+ docstrings so the generated API reference stays current.
45
+
46
+ `make check` verifies the uv lockfile, Ruff formatting and linting, Markdown,
47
+ the documentation site, GitHub Actions workflows, CSpell, secret scanning,
48
+ Bandit, deptry, pip-audit, pytest and coverage, basedpyright, and built
49
+ distributions, including CycloneDX SBOM generation. New behavior should include
50
+ tests, and public APIs should include Google-style docstrings.
51
+
52
+ The Git hooks run fast, file-oriented checks. Use `make precommit` to run every
53
+ hook manually. Treat additions to `.secrets.baseline` as security-sensitive
54
+ changes and review each detected value before updating the baseline.
55
+
56
+ ## Pull requests
57
+
58
+ Keep each pull request focused on one coherent change. In the description:
59
+
60
+ * explain the problem and the chosen approach;
61
+ * identify any public API or compatibility impact;
62
+ * include tests for behavior changes;
63
+ * update documentation and `CHANGELOG.md` when users will notice the change.
64
+
65
+ Maintainers may request changes before merging. Contributions are accepted
66
+ under the project's [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryan Wallace
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: benchmatrix
3
+ Version: 0.2.1
4
+ Summary: A pytest-benchmark matrix, metadata, and JSON results layer.
5
+ Project-URL: Homepage, https://github.com/ryancswallace/benchmatrix
6
+ Project-URL: Changelog, https://github.com/ryancswallace/benchmatrix/blob/main/CHANGELOG.md
7
+ Project-URL: Documentation, https://github.com/ryancswallace/benchmatrix#readme
8
+ Project-URL: Issues, https://github.com/ryancswallace/benchmatrix/issues
9
+ Project-URL: Source, https://github.com/ryancswallace/benchmatrix
10
+ Author-email: Ryan Wallace <ryancswallace@gmail.com>
11
+ Maintainer-email: Ryan Wallace <ryancswallace@gmail.com>
12
+ License-Expression: MIT
13
+ License-File: LICENSE
14
+ Keywords: benchmark,benchmarking,performance,pytest,pytest-benchmark
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Framework :: Pytest
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Programming Language :: Python :: Implementation :: CPython
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Requires-Python: <3.15,>=3.11
28
+ Requires-Dist: pytest-benchmark>=5.2.3
29
+ Requires-Dist: pytest>=9.1.1
30
+ Description-Content-Type: text/markdown
31
+
32
+ # benchmatrix
33
+
34
+ [![CI](https://github.com/ryancswallace/benchmatrix/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/ci.yml)
35
+ [![Documentation](https://github.com/ryancswallace/benchmatrix/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/docs.yml)
36
+ [![Docker](https://github.com/ryancswallace/benchmatrix/actions/workflows/docker.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/docker.yml)
37
+ [![CodeQL](https://github.com/ryancswallace/benchmatrix/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/codeql.yml)
38
+ [![OpenSSF Scorecard](https://github.com/ryancswallace/benchmatrix/actions/workflows/scorecard.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/scorecard.yml)
39
+ [![Workflow lint](https://github.com/ryancswallace/benchmatrix/actions/workflows/workflow-lint.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/workflow-lint.yml)
40
+ [![Python 3.11-3.14](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-3776AB?logo=python&logoColor=white)](https://github.com/ryancswallace/benchmatrix/blob/main/pyproject.toml)
41
+ [![Typed with basedpyright](https://img.shields.io/badge/types-basedpyright-2f6fdd)](https://github.com/DetachHead/basedpyright)
42
+ [![Linted with Ruff](https://img.shields.io/badge/lint-Ruff-46a2f1)](https://docs.astral.sh/ruff/)
43
+ [![Coverage gate: 95%](https://img.shields.io/badge/coverage%20gate-%E2%89%A595%25-2e7d32)](https://github.com/ryancswallace/benchmatrix/blob/main/pyproject.toml)
44
+ [![SBOM: CycloneDX 1.6](https://img.shields.io/badge/SBOM-CycloneDX%201.6-6f42c1)](https://cyclonedx.org/)
45
+
46
+ **Benchmark matrices for Python projects that need performance data they can
47
+ trust, compare, and parse.**
48
+
49
+ benchmatrix sits on top of
50
+ [pytest-benchmark](https://pytest-benchmark.readthedocs.io/) and adds the layer
51
+ that benchmark suites usually grow by hand: implementation-by-case matrices,
52
+ strict JSON-safe metadata, metric-aware result parsing, and concise display of
53
+ saved benchmark runs.
54
+
55
+ | Build repeatable suites | Keep metrics honest | Parse saved runs |
56
+ | --- | --- | --- |
57
+ | Generate pytest benchmark tests across implementations, cases, and metric views. | Separate latency, throughput, and local distribution comparisons instead of mixing unlike numbers. | Load benchmatrix-tagged pytest-benchmark JSON rows into structured Python objects. |
58
+
59
+ ## Quick Start
60
+
61
+ Create a benchmark matrix from ordinary synchronous callables:
62
+
63
+ ```python
64
+ from benchmatrix import BenchmarkCase, make_benchmark_test
65
+
66
+ implementations = {
67
+ "builtin": sum,
68
+ "loop": lambda vs: sum(v for v in vs),
69
+ }
70
+
71
+ cases = [
72
+ BenchmarkCase.from_values(
73
+ "small",
74
+ list(range(100)),
75
+ work_units=100,
76
+ work_unit_name="items",
77
+ ),
78
+ ]
79
+
80
+ test_sum_matrix = make_benchmark_test(implementations, cases)
81
+ ```
82
+
83
+ Run it with pytest-benchmark and keep the machine-readable output:
84
+
85
+ ```bash
86
+ uv run pytest tests/test_sum_benchmark.py --benchmark-json benchmark.json
87
+ ```
88
+
89
+ Read the tagged rows back later:
90
+
91
+ ```python
92
+ from benchmatrix import display_benchmark_rows, load_benchmark_json
93
+
94
+ rows = load_benchmark_json("benchmark.json")
95
+ display_benchmark_rows(rows)
96
+ ```
97
+
98
+ ## Why It Exists
99
+
100
+ pytest-benchmark owns timing, calibration, statistics, terminal reporting, and
101
+ JSON export. benchmatrix owns the repeatable structure around those timings.
102
+
103
+ | Need | benchmatrix gives you |
104
+ | --- | --- |
105
+ | Compare multiple implementations | One generated pytest benchmark matrix instead of repeated parametrization code. |
106
+ | Track what each timing means | JSON-safe invocation metadata with implementation, case, and metric identity. |
107
+ | Report different metric views | Single-call latency, logical-work throughput, and local tail-latency summaries. |
108
+ | Reuse benchmark output | Parsers and display helpers for pytest-benchmark JSON produced by benchmatrix tests. |
109
+
110
+ benchmatrix is intentionally narrow: it benchmarks synchronous Python callables.
111
+ It is not a load-testing framework, production latency monitor, or replacement
112
+ for pytest-benchmark.
113
+
114
+ ## Install
115
+
116
+ For local development from this repository:
117
+
118
+ ```bash
119
+ make ready
120
+ ```
121
+
122
+ To try the package from another project before the first PyPI release, install
123
+ from GitHub:
124
+
125
+ ```bash
126
+ uv add "benchmatrix @ git+https://github.com/ryancswallace/benchmatrix"
127
+ ```
128
+
129
+ ## Documentation
130
+
131
+ | Start here | Use it for |
132
+ | --- | --- |
133
+ | [First benchmark](docs/tutorials/first-benchmark.md) | A complete first benchmark from test file to parsed JSON. |
134
+ | [Create a benchmark matrix](docs/how-to/create-benchmark-matrix.md) | Cases, work units, fresh inputs, and synchronous target wrappers. |
135
+ | [Parse benchmark results](docs/how-to/parse-results.md) | Loading and displaying benchmatrix-tagged pytest-benchmark JSON. |
136
+ | [Performance model](docs/explanation/performance.md) | What the metrics mean and what they do not prove. |
137
+ | [Configuration and automation](docs/reference/configuration.md) | Make targets, CI workflows, Docker checks, docs, and SBOM generation. |
138
+
139
+ The MkDocs site builds in strict mode and generates API reference pages from the
140
+ package docstrings.
141
+
142
+ ## Project Links
143
+
144
+ * [Examples](examples/)
145
+ * [Contributing](CONTRIBUTING.md)
146
+ * [Changelog](CHANGELOG.md)
147
+ * [Security policy](SECURITY.md)
148
+ * [Release policy](RELEASING.md)
149
+ * [Code of conduct](CODE_OF_CONDUCT.md)
150
+ * [Citation metadata](CITATION.cff)
151
+
152
+ ## License
153
+
154
+ benchmatrix is distributed under the [MIT License](LICENSE).
@@ -0,0 +1,123 @@
1
+ # benchmatrix
2
+
3
+ [![CI](https://github.com/ryancswallace/benchmatrix/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/ci.yml)
4
+ [![Documentation](https://github.com/ryancswallace/benchmatrix/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/docs.yml)
5
+ [![Docker](https://github.com/ryancswallace/benchmatrix/actions/workflows/docker.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/docker.yml)
6
+ [![CodeQL](https://github.com/ryancswallace/benchmatrix/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/codeql.yml)
7
+ [![OpenSSF Scorecard](https://github.com/ryancswallace/benchmatrix/actions/workflows/scorecard.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/scorecard.yml)
8
+ [![Workflow lint](https://github.com/ryancswallace/benchmatrix/actions/workflows/workflow-lint.yml/badge.svg?branch=main)](https://github.com/ryancswallace/benchmatrix/actions/workflows/workflow-lint.yml)
9
+ [![Python 3.11-3.14](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-3776AB?logo=python&logoColor=white)](https://github.com/ryancswallace/benchmatrix/blob/main/pyproject.toml)
10
+ [![Typed with basedpyright](https://img.shields.io/badge/types-basedpyright-2f6fdd)](https://github.com/DetachHead/basedpyright)
11
+ [![Linted with Ruff](https://img.shields.io/badge/lint-Ruff-46a2f1)](https://docs.astral.sh/ruff/)
12
+ [![Coverage gate: 95%](https://img.shields.io/badge/coverage%20gate-%E2%89%A595%25-2e7d32)](https://github.com/ryancswallace/benchmatrix/blob/main/pyproject.toml)
13
+ [![SBOM: CycloneDX 1.6](https://img.shields.io/badge/SBOM-CycloneDX%201.6-6f42c1)](https://cyclonedx.org/)
14
+
15
+ **Benchmark matrices for Python projects that need performance data they can
16
+ trust, compare, and parse.**
17
+
18
+ benchmatrix sits on top of
19
+ [pytest-benchmark](https://pytest-benchmark.readthedocs.io/) and adds the layer
20
+ that benchmark suites usually grow by hand: implementation-by-case matrices,
21
+ strict JSON-safe metadata, metric-aware result parsing, and concise display of
22
+ saved benchmark runs.
23
+
24
+ | Build repeatable suites | Keep metrics honest | Parse saved runs |
25
+ | --- | --- | --- |
26
+ | Generate pytest benchmark tests across implementations, cases, and metric views. | Separate latency, throughput, and local distribution comparisons instead of mixing unlike numbers. | Load benchmatrix-tagged pytest-benchmark JSON rows into structured Python objects. |
27
+
28
+ ## Quick Start
29
+
30
+ Create a benchmark matrix from ordinary synchronous callables:
31
+
32
+ ```python
33
+ from benchmatrix import BenchmarkCase, make_benchmark_test
34
+
35
+ implementations = {
36
+ "builtin": sum,
37
+ "loop": lambda vs: sum(v for v in vs),
38
+ }
39
+
40
+ cases = [
41
+ BenchmarkCase.from_values(
42
+ "small",
43
+ list(range(100)),
44
+ work_units=100,
45
+ work_unit_name="items",
46
+ ),
47
+ ]
48
+
49
+ test_sum_matrix = make_benchmark_test(implementations, cases)
50
+ ```
51
+
52
+ Run it with pytest-benchmark and keep the machine-readable output:
53
+
54
+ ```bash
55
+ uv run pytest tests/test_sum_benchmark.py --benchmark-json benchmark.json
56
+ ```
57
+
58
+ Read the tagged rows back later:
59
+
60
+ ```python
61
+ from benchmatrix import display_benchmark_rows, load_benchmark_json
62
+
63
+ rows = load_benchmark_json("benchmark.json")
64
+ display_benchmark_rows(rows)
65
+ ```
66
+
67
+ ## Why It Exists
68
+
69
+ pytest-benchmark owns timing, calibration, statistics, terminal reporting, and
70
+ JSON export. benchmatrix owns the repeatable structure around those timings.
71
+
72
+ | Need | benchmatrix gives you |
73
+ | --- | --- |
74
+ | Compare multiple implementations | One generated pytest benchmark matrix instead of repeated parametrization code. |
75
+ | Track what each timing means | JSON-safe invocation metadata with implementation, case, and metric identity. |
76
+ | Report different metric views | Single-call latency, logical-work throughput, and local tail-latency summaries. |
77
+ | Reuse benchmark output | Parsers and display helpers for pytest-benchmark JSON produced by benchmatrix tests. |
78
+
79
+ benchmatrix is intentionally narrow: it benchmarks synchronous Python callables.
80
+ It is not a load-testing framework, production latency monitor, or replacement
81
+ for pytest-benchmark.
82
+
83
+ ## Install
84
+
85
+ For local development from this repository:
86
+
87
+ ```bash
88
+ make ready
89
+ ```
90
+
91
+ To try the package from another project before the first PyPI release, install
92
+ from GitHub:
93
+
94
+ ```bash
95
+ uv add "benchmatrix @ git+https://github.com/ryancswallace/benchmatrix"
96
+ ```
97
+
98
+ ## Documentation
99
+
100
+ | Start here | Use it for |
101
+ | --- | --- |
102
+ | [First benchmark](docs/tutorials/first-benchmark.md) | A complete first benchmark from test file to parsed JSON. |
103
+ | [Create a benchmark matrix](docs/how-to/create-benchmark-matrix.md) | Cases, work units, fresh inputs, and synchronous target wrappers. |
104
+ | [Parse benchmark results](docs/how-to/parse-results.md) | Loading and displaying benchmatrix-tagged pytest-benchmark JSON. |
105
+ | [Performance model](docs/explanation/performance.md) | What the metrics mean and what they do not prove. |
106
+ | [Configuration and automation](docs/reference/configuration.md) | Make targets, CI workflows, Docker checks, docs, and SBOM generation. |
107
+
108
+ The MkDocs site builds in strict mode and generates API reference pages from the
109
+ package docstrings.
110
+
111
+ ## Project Links
112
+
113
+ * [Examples](examples/)
114
+ * [Contributing](CONTRIBUTING.md)
115
+ * [Changelog](CHANGELOG.md)
116
+ * [Security policy](SECURITY.md)
117
+ * [Release policy](RELEASING.md)
118
+ * [Code of conduct](CODE_OF_CONDUCT.md)
119
+ * [Citation metadata](CITATION.cff)
120
+
121
+ ## License
122
+
123
+ benchmatrix is distributed under the [MIT License](LICENSE).
@@ -0,0 +1,61 @@
1
+ # Release policy
2
+
3
+ benchmatrix uses [Semantic Versioning](https://semver.org/).
4
+
5
+ ## Compatibility
6
+
7
+ While the project is pre-1.0:
8
+
9
+ * patch releases contain compatible fixes and documentation improvements;
10
+ * minor releases may introduce breaking API changes;
11
+ * breaking changes should be called out clearly in the changelog.
12
+
13
+ Starting with 1.0, incompatible public API changes require a major release.
14
+ The supported public API is the set of names exported from
15
+ `benchmatrix.__init__`. Private modules and names beginning with an underscore
16
+ are not covered by the compatibility guarantee.
17
+
18
+ Python version support may change in a minor release before 1.0 and in a major
19
+ release after 1.0. Dropping a Python version will be documented in advance when
20
+ practical.
21
+
22
+ Release branches are not maintained as standing support branches. The active
23
+ support branch is `main`; temporary release or security branches may be used for
24
+ coordination and retired after release.
25
+
26
+ ## Release process
27
+
28
+ Releases are prepared in a normal pull request and published by the GitHub
29
+ Actions release workflow after a GitHub Release is published.
30
+
31
+ 1. Choose the next version from the changelog and compatibility policy.
32
+ 2. Update release metadata:
33
+
34
+ * set `project.version` in `pyproject.toml`;
35
+ * set `version` in `CITATION.cff`;
36
+ * add or update `date-released` in `CITATION.cff` once the release date is
37
+ known.
38
+
39
+ 3. Move user-visible `CHANGELOG.md` entries from `Unreleased` into a versioned
40
+ section such as `## 0.2.0 - 2026-06-20`, then leave a fresh `Unreleased`
41
+ section at the top.
42
+ 4. Run the release validation commands:
43
+
44
+ ```bash
45
+ make check-all
46
+ make build
47
+ ```
48
+
49
+ 5. Confirm `dist/` contains one source distribution, one wheel, and
50
+ `benchmatrix.cdx.json` for the intended version.
51
+ 6. Merge the release pull request after required checks pass.
52
+ 7. Create and push an annotated tag named `vX.Y.Z` for the release commit.
53
+ 8. Draft GitHub release notes from the changelog section for that version.
54
+ 9. Publish the GitHub Release. Publishing the release triggers
55
+ `.github/workflows/release.yml`, which rebuilds artifacts, attests them, and
56
+ publishes to PyPI through Trusted Publishing.
57
+ 10. Verify the package from PyPI in a clean environment.
58
+ 11. If any post-release fix is needed, prepare a new patch release. Do not
59
+ replace files for an already-published PyPI version.
60
+
61
+ The detailed operational checklist lives in `docs/runbooks/release.md`.
@@ -0,0 +1,30 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are provided for the latest released version of benchmatrix.
6
+ Because the project is currently pre-1.0, fixes are not routinely backported to
7
+ older minor versions.
8
+
9
+ The active support branch is `main`. Temporary security release branches may be
10
+ created for coordinated disclosure, but they are not maintained after the fix is
11
+ released unless the release notes explicitly say otherwise.
12
+
13
+ A backport to an older release may be considered when the issue is high impact,
14
+ the patch is small and safe, the affected release still has meaningful user
15
+ adoption, and the maintainer has capacity to validate and publish the backport.
16
+
17
+ ## Reporting a vulnerability
18
+
19
+ Please do not open a public issue for a suspected vulnerability.
20
+
21
+ Email Ryan Wallace at <ryancswallace@gmail.com> with:
22
+
23
+ * the affected version;
24
+ * steps to reproduce the issue;
25
+ * the potential impact;
26
+ * any suggested mitigation, if known.
27
+
28
+ You should receive an acknowledgement within seven days. The maintainer will
29
+ coordinate validation, remediation, and disclosure with the reporter. Please
30
+ allow a reasonable period for a fix before publishing details.
@@ -0,0 +1,34 @@
1
+ """Generate mkdocstrings API reference pages for benchmatrix modules."""
2
+
3
+ from pathlib import Path
4
+
5
+ import mkdocs_gen_files
6
+
7
+ PACKAGE_ROOT = Path("src/benchmatrix")
8
+ REFERENCE_ROOT = Path("reference/api")
9
+
10
+
11
+ def _iter_public_modules() -> list[tuple[str, Path, Path]]:
12
+ """Return import path, source path, and generated docs path tuples."""
13
+ modules: list[tuple[str, Path, Path]] = []
14
+ for source_path in sorted(PACKAGE_ROOT.glob("*.py")):
15
+ if source_path.name.startswith("_") and source_path.name != "__init__.py":
16
+ continue
17
+
18
+ module_parts = source_path.relative_to("src").with_suffix("").parts
19
+ import_path = ".".join(part for part in module_parts if part != "__init__")
20
+ if source_path.name == "__init__.py":
21
+ docs_path = REFERENCE_ROOT / "index.md"
22
+ else:
23
+ docs_path = REFERENCE_ROOT / f"{source_path.stem}.md"
24
+ modules.append((import_path, source_path, docs_path))
25
+ return modules
26
+
27
+
28
+ for module, source, docs_path in _iter_public_modules():
29
+ title = "benchmatrix" if module == "benchmatrix" else module.rsplit(".", 1)[-1].replace("_", " ").title()
30
+ with mkdocs_gen_files.open(docs_path, "w") as output:
31
+ output.write(f"# {title}\n\n")
32
+ output.write(f"::: {module}\n")
33
+
34
+ mkdocs_gen_files.set_edit_path(docs_path, source)
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ The repository changelog is the source of truth for release notes.
4
+
5
+ For each user-visible change:
6
+
7
+ 1. add an entry under `Unreleased` in `CHANGELOG.md`;
8
+ 2. group the entry under the appropriate heading;
9
+ 3. mention compatibility or migration notes when behavior changes;
10
+ 4. move entries into a versioned section during release preparation.
11
+
12
+ The project follows Semantic Versioning with the pre-1.0 expectations described
13
+ in the release policy.