polyform-lattice 0.1.0__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.
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This project adheres
4
+ to [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.1.0] — 2026-07-13
7
+
8
+ ### Added
9
+ - First packaged release of PolyForm.
10
+ - `polyform.run_support_mode` — global support-mode structural metrics on the
11
+ choice-free modal lattice (state access, grade distributions, fibre refinement).
12
+ - `polyform.run_weight_mode` — demonstration occupancy metrics on real observed
13
+ proteoform supports.
14
+ - `polyform.run_topology` — tissue-resolved Hamming-1 support topology on a
15
+ top-down human atlas (empirical + k=0-anchored), including accession-level
16
+ sharing and lattice heatmaps.
17
+ - `polyform.core` — pure, importable primitives (PTM parsing, FASTA reading,
18
+ Hamming topology, information measures) copied verbatim from the manuscript
19
+ analysis scripts.
20
+ - `polyform` command-line interface with `support`, `weight`, and `topology`
21
+ subcommands.
22
+
23
+ ### Notes
24
+ - The computational bodies of the original manuscript scripts (in `manuscript/`)
25
+ are preserved unchanged as the provenance record. The packaged functions were
26
+ validated to reproduce their reference outputs exactly.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 James N. Cobley
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 NONINFRINGEMENT. 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,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: polyform-lattice
3
+ Version: 0.1.0
4
+ Summary: Structured analysis of proteoform distributions on finite, bounded, k-graded modal lattices.
5
+ Project-URL: Homepage, https://github.com/JamesCobley/PolyForm
6
+ Project-URL: Repository, https://github.com/JamesCobley/PolyForm
7
+ Project-URL: Issues, https://github.com/JamesCobley/PolyForm/issues
8
+ Author: James N. Cobley
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 James N. Cobley
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: PTM,hamming,mass-spectrometry,modal-lattice,occupancy,proteoform,proteomics,top-down,topology
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
42
+ Requires-Python: >=3.9
43
+ Requires-Dist: matplotlib>=3.6
44
+ Requires-Dist: numpy>=1.23
45
+ Requires-Dist: openpyxl>=3.0
46
+ Requires-Dist: pandas>=1.5
47
+ Provides-Extra: dev
48
+ Requires-Dist: build; extra == 'dev'
49
+ Requires-Dist: pytest; extra == 'dev'
50
+ Requires-Dist: twine; extra == 'dev'
51
+ Description-Content-Type: text/markdown
52
+
53
+ # PolyForm
54
+
55
+ PolyForm is a Python package for structured analysis of proteoform
56
+ distributions. It maps measured proteoform catalogues onto finite, bounded,
57
+ *k*-graded modal lattices and computes structure-derived metrics including
58
+ state identity, occupancy, grade spread, support topology, native clustering,
59
+ principal occupied components, and statistical surprise.
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ pip install polyform-lattice
65
+ ```
66
+
67
+ > The **import** name is `polyform`; the **PyPI distribution** name is
68
+ > `polyform-lattice` (the plain name `polyform` was already taken by an
69
+ > unrelated project). So you `pip install polyform-lattice` but `import polyform`.
70
+
71
+ From source (for development):
72
+
73
+ ```bash
74
+ git clone https://github.com/JamesCobley/PolyForm.git
75
+ cd PolyForm
76
+ pip install -e .
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ ### Python API
82
+
83
+ Each analysis is a single call that returns a dict of pandas DataFrames and,
84
+ by default, writes CSVs and figures to an output directory.
85
+
86
+ ```python
87
+ import polyform
88
+
89
+ # Global support-mode structural metrics on the choice-free modal lattice
90
+ support = polyform.run_support_mode(csv="proteoforms.csv", outdir="out_support")
91
+ support["global"] # one-row global summary
92
+ support["protein_metrics"] # protein-level structural metrics
93
+ support["grade"] # protein-by-grade metrics
94
+
95
+ # Demonstration occupancy metrics on real observed supports
96
+ weight = polyform.run_weight_mode(csv="proteoforms.csv", outdir="out_weight")
97
+ weight["selected"] # proteins selected for demonstration
98
+ weight["metrics"] # occupancy-dependent metrics
99
+
100
+ # Tissue-resolved Hamming-1 support topology on a top-down atlas
101
+ topology = polyform.run_topology(xlsx="atlas.xlsx", outdir="out_topology")
102
+ topology["tissue_summary"]
103
+ topology["components"]
104
+ ```
105
+
106
+ Set `make_figures=False` to skip figure rendering (faster; CSVs still written).
107
+
108
+ ### Command line
109
+
110
+ ```bash
111
+ polyform support --csv proteoforms.csv --outdir out_support
112
+ polyform weight --csv proteoforms.csv --outdir out_weight
113
+ polyform topology --xlsx atlas.xlsx --outdir out_topology
114
+
115
+ polyform support --help # per-command options
116
+ polyform --version
117
+ ```
118
+
119
+ ### Core primitives
120
+
121
+ The lattice/topology/information primitives are importable directly:
122
+
123
+ ```python
124
+ from polyform.core import (
125
+ parse_ptms, read_fasta, log10_comb, hamming_distance_state,
126
+ connected_components_for_states, shannon_entropy, normalized_entropy,
127
+ )
128
+ ```
129
+
130
+ ## Inputs
131
+
132
+ - **Support / weight modes** expect a proteoform catalogue CSV with at least
133
+ `Entry Accession` and `PTMs` columns; protein lengths are resolved from an
134
+ `Isoform Sequence` column or an optional `--fasta`. PTM strings use the
135
+ `RESID:<code>@<position>` form, `|`-separated.
136
+ - **Topology mode** expects the multi-tissue top-down atlas spreadsheet
137
+ (`--sheet`, default `All_Tissues`).
138
+
139
+ ## Outputs
140
+
141
+ Each mode writes a set of `.csv` tables plus publication `.png`/`.pdf` figures
142
+ into its `--outdir`. See each function's docstring for the exact file list.
143
+
144
+ ## Reproducibility
145
+
146
+ The original manuscript analysis scripts are preserved unchanged under
147
+ [`manuscript/`](manuscript/) as the provenance record. The packaged `run_*`
148
+ functions wrap those exact computational bodies (only parameterising
149
+ configuration and routing outputs) and were validated to reproduce the
150
+ manuscript reference outputs.
151
+
152
+ ## Releasing (maintainers)
153
+
154
+ Releases publish to PyPI via **Trusted Publishing** (OIDC — no API tokens).
155
+ One-time setup: on PyPI, add a trusted publisher for the project pointing at
156
+ this repo's `publish.yml` workflow and a `pypi` environment.
157
+
158
+ To cut a release:
159
+
160
+ ```bash
161
+ # bump version in pyproject.toml and src/polyform/__init__.py, update CHANGELOG.md
162
+ git commit -am "Release v0.1.0"
163
+ git tag v0.1.0
164
+ git push origin main --tags
165
+ ```
166
+
167
+ Pushing the tag triggers `.github/workflows/publish.yml`, which builds the
168
+ sdist + wheel, runs `twine check`, and publishes to PyPI.
169
+
170
+ ## License
171
+
172
+ MIT © 2026 James N. Cobley
@@ -0,0 +1,120 @@
1
+ # PolyForm
2
+
3
+ PolyForm is a Python package for structured analysis of proteoform
4
+ distributions. It maps measured proteoform catalogues onto finite, bounded,
5
+ *k*-graded modal lattices and computes structure-derived metrics including
6
+ state identity, occupancy, grade spread, support topology, native clustering,
7
+ principal occupied components, and statistical surprise.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install polyform-lattice
13
+ ```
14
+
15
+ > The **import** name is `polyform`; the **PyPI distribution** name is
16
+ > `polyform-lattice` (the plain name `polyform` was already taken by an
17
+ > unrelated project). So you `pip install polyform-lattice` but `import polyform`.
18
+
19
+ From source (for development):
20
+
21
+ ```bash
22
+ git clone https://github.com/JamesCobley/PolyForm.git
23
+ cd PolyForm
24
+ pip install -e .
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Python API
30
+
31
+ Each analysis is a single call that returns a dict of pandas DataFrames and,
32
+ by default, writes CSVs and figures to an output directory.
33
+
34
+ ```python
35
+ import polyform
36
+
37
+ # Global support-mode structural metrics on the choice-free modal lattice
38
+ support = polyform.run_support_mode(csv="proteoforms.csv", outdir="out_support")
39
+ support["global"] # one-row global summary
40
+ support["protein_metrics"] # protein-level structural metrics
41
+ support["grade"] # protein-by-grade metrics
42
+
43
+ # Demonstration occupancy metrics on real observed supports
44
+ weight = polyform.run_weight_mode(csv="proteoforms.csv", outdir="out_weight")
45
+ weight["selected"] # proteins selected for demonstration
46
+ weight["metrics"] # occupancy-dependent metrics
47
+
48
+ # Tissue-resolved Hamming-1 support topology on a top-down atlas
49
+ topology = polyform.run_topology(xlsx="atlas.xlsx", outdir="out_topology")
50
+ topology["tissue_summary"]
51
+ topology["components"]
52
+ ```
53
+
54
+ Set `make_figures=False` to skip figure rendering (faster; CSVs still written).
55
+
56
+ ### Command line
57
+
58
+ ```bash
59
+ polyform support --csv proteoforms.csv --outdir out_support
60
+ polyform weight --csv proteoforms.csv --outdir out_weight
61
+ polyform topology --xlsx atlas.xlsx --outdir out_topology
62
+
63
+ polyform support --help # per-command options
64
+ polyform --version
65
+ ```
66
+
67
+ ### Core primitives
68
+
69
+ The lattice/topology/information primitives are importable directly:
70
+
71
+ ```python
72
+ from polyform.core import (
73
+ parse_ptms, read_fasta, log10_comb, hamming_distance_state,
74
+ connected_components_for_states, shannon_entropy, normalized_entropy,
75
+ )
76
+ ```
77
+
78
+ ## Inputs
79
+
80
+ - **Support / weight modes** expect a proteoform catalogue CSV with at least
81
+ `Entry Accession` and `PTMs` columns; protein lengths are resolved from an
82
+ `Isoform Sequence` column or an optional `--fasta`. PTM strings use the
83
+ `RESID:<code>@<position>` form, `|`-separated.
84
+ - **Topology mode** expects the multi-tissue top-down atlas spreadsheet
85
+ (`--sheet`, default `All_Tissues`).
86
+
87
+ ## Outputs
88
+
89
+ Each mode writes a set of `.csv` tables plus publication `.png`/`.pdf` figures
90
+ into its `--outdir`. See each function's docstring for the exact file list.
91
+
92
+ ## Reproducibility
93
+
94
+ The original manuscript analysis scripts are preserved unchanged under
95
+ [`manuscript/`](manuscript/) as the provenance record. The packaged `run_*`
96
+ functions wrap those exact computational bodies (only parameterising
97
+ configuration and routing outputs) and were validated to reproduce the
98
+ manuscript reference outputs.
99
+
100
+ ## Releasing (maintainers)
101
+
102
+ Releases publish to PyPI via **Trusted Publishing** (OIDC — no API tokens).
103
+ One-time setup: on PyPI, add a trusted publisher for the project pointing at
104
+ this repo's `publish.yml` workflow and a `pypi` environment.
105
+
106
+ To cut a release:
107
+
108
+ ```bash
109
+ # bump version in pyproject.toml and src/polyform/__init__.py, update CHANGELOG.md
110
+ git commit -am "Release v0.1.0"
111
+ git tag v0.1.0
112
+ git push origin main --tags
113
+ ```
114
+
115
+ Pushing the tag triggers `.github/workflows/publish.yml`, which builds the
116
+ sdist + wheel, runs `twine check`, and publishes to PyPI.
117
+
118
+ ## License
119
+
120
+ MIT © 2026 James N. Cobley
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ # NOTE: the PyPI *distribution* name is `polyform-lattice` because the plain
7
+ # name `polyform` is already taken by an unrelated project. The *import* name
8
+ # is still `polyform` (i.e. `import polyform`). To change the distribution
9
+ # name, edit the single `name` field below.
10
+ name = "polyform-lattice"
11
+ version = "0.1.0"
12
+ description = "Structured analysis of proteoform distributions on finite, bounded, k-graded modal lattices."
13
+ readme = "README.md"
14
+ requires-python = ">=3.9"
15
+ license = { file = "LICENSE" }
16
+ authors = [{ name = "James N. Cobley" }]
17
+ keywords = [
18
+ "proteoform", "proteomics", "modal-lattice", "PTM", "top-down",
19
+ "hamming", "topology", "occupancy", "mass-spectrometry",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 4 - Beta",
23
+ "Intended Audience :: Science/Research",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
32
+ ]
33
+ dependencies = [
34
+ "numpy>=1.23",
35
+ "pandas>=1.5",
36
+ "matplotlib>=3.6",
37
+ "openpyxl>=3.0",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ dev = ["build", "twine", "pytest"]
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/JamesCobley/PolyForm"
45
+ Repository = "https://github.com/JamesCobley/PolyForm"
46
+ Issues = "https://github.com/JamesCobley/PolyForm/issues"
47
+
48
+ [project.scripts]
49
+ polyform = "polyform.cli:main"
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/polyform"]
53
+
54
+ [tool.hatch.build.targets.sdist]
55
+ # keep the distributed source archive lean: ship the package + docs only,
56
+ # not the multi-megabyte manuscript data.
57
+ include = [
58
+ "src/polyform",
59
+ "README.md",
60
+ "LICENSE",
61
+ "CHANGELOG.md",
62
+ "pyproject.toml",
63
+ ]
@@ -0,0 +1,49 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes on every pushed tag that looks like a version, e.g. v0.1.0
4
+ on:
5
+ push:
6
+ tags:
7
+ - "v*"
8
+
9
+ jobs:
10
+ build:
11
+ name: Build distributions
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+
20
+ - name: Build sdist and wheel
21
+ run: |
22
+ python -m pip install --upgrade build
23
+ python -m build
24
+
25
+ - name: Check metadata
26
+ run: |
27
+ python -m pip install --upgrade twine
28
+ python -m twine check dist/*
29
+
30
+ - uses: actions/upload-artifact@v4
31
+ with:
32
+ name: dist
33
+ path: dist/
34
+
35
+ publish:
36
+ name: Publish to PyPI
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment: pypi
40
+ permissions:
41
+ id-token: write # required for Trusted Publishing (OIDC); no API token needed
42
+ steps:
43
+ - uses: actions/download-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/
47
+
48
+ - name: Publish
49
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,107 @@
1
+ """
2
+ Command-line interface for PolyForm.
3
+
4
+ polyform support --csv proteoforms.csv --outdir out_support
5
+ polyform weight --csv proteoforms.csv --outdir out_weight
6
+ polyform topology --xlsx atlas.xlsx --outdir out_topology
7
+
8
+ Each subcommand runs the corresponding analysis, writes CSVs (and, unless
9
+ ``--no-figures`` is passed, figures) to ``--outdir``, and prints a short
10
+ summary of the result tables.
11
+ """
12
+ import argparse
13
+ import sys
14
+
15
+ from . import __version__
16
+
17
+
18
+ def _summarise(results):
19
+ for key, df in results.items():
20
+ try:
21
+ print(f" {key:28s} {len(df):>8d} rows x {len(df.columns):>3d} cols")
22
+ except Exception:
23
+ print(f" {key:28s} {type(df).__name__}")
24
+
25
+
26
+ def main(argv=None):
27
+ argv = list(sys.argv[1:] if argv is None else argv)
28
+
29
+ parser = argparse.ArgumentParser(
30
+ prog="polyform",
31
+ description="Structured analysis of proteoform distributions on modal lattices.",
32
+ )
33
+ parser.add_argument("--version", action="version",
34
+ version=f"polyform {__version__}")
35
+ sub = parser.add_subparsers(dest="command", required=True)
36
+
37
+ # support --------------------------------------------------------------
38
+ p_sup = sub.add_parser("support", help="global support-mode structural metrics")
39
+ p_sup.add_argument("--csv", default="proteoforms.csv",
40
+ help="proteoform catalogue CSV (default: proteoforms.csv)")
41
+ p_sup.add_argument("--fasta", default=None,
42
+ help="optional UniProt FASTA to resolve lengths")
43
+ p_sup.add_argument("--pos-base", type=int, default=0,
44
+ help="set to 1 if RESID positions are 1-based")
45
+ p_sup.add_argument("--outdir", default="polyform_support_outputs")
46
+ p_sup.add_argument("--dpi", type=int, default=300)
47
+ p_sup.add_argument("--no-figures", action="store_true")
48
+
49
+ # weight ---------------------------------------------------------------
50
+ p_w = sub.add_parser("weight", help="demonstration occupancy metrics")
51
+ p_w.add_argument("--csv", default="proteoforms.csv")
52
+ p_w.add_argument("--fasta", default=None)
53
+ p_w.add_argument("--pos-base", type=int, default=0)
54
+ p_w.add_argument("--outdir", default="polyform_02_demo_occupancy_outputs")
55
+ p_w.add_argument("--select-n", type=int, default=8)
56
+ p_w.add_argument("--min-states", type=int, default=5)
57
+ p_w.add_argument("--min-delta-k", type=int, default=3)
58
+ p_w.add_argument("--dpi", type=int, default=300)
59
+ p_w.add_argument("--seed", type=int, default=7)
60
+ p_w.add_argument("--no-figures", action="store_true")
61
+
62
+ # topology -------------------------------------------------------------
63
+ p_t = sub.add_parser("topology", help="tissue-resolved support topology")
64
+ p_t.add_argument("--xlsx", default="pr2c00034_si_002 (1).xlsx",
65
+ help="multi-tissue atlas spreadsheet")
66
+ p_t.add_argument("--outdir", default="polyform_03_tissue_support_topology_outputs")
67
+ p_t.add_argument("--sheet", default="All_Tissues")
68
+ p_t.add_argument("--no-group-by-sequence", action="store_true")
69
+ p_t.add_argument("--no-k0-anchor", action="store_true")
70
+ p_t.add_argument("--dpi", type=int, default=300)
71
+ p_t.add_argument("--seed", type=int, default=7)
72
+ p_t.add_argument("--no-figures", action="store_true")
73
+
74
+ args = parser.parse_args(argv)
75
+
76
+ if args.command == "support":
77
+ from .support_mode import run_support_mode
78
+ results = run_support_mode(
79
+ csv=args.csv, fasta_path=args.fasta, pos_base=args.pos_base,
80
+ outdir=args.outdir, make_figures=not args.no_figures, dpi=args.dpi,
81
+ )
82
+ elif args.command == "weight":
83
+ from .weight_mode import run_weight_mode
84
+ results = run_weight_mode(
85
+ csv=args.csv, fasta_path=args.fasta, pos_base=args.pos_base,
86
+ outdir=args.outdir, select_n=args.select_n, min_states=args.min_states,
87
+ min_delta_k=args.min_delta_k, make_figures=not args.no_figures,
88
+ dpi=args.dpi, random_seed=args.seed,
89
+ )
90
+ elif args.command == "topology":
91
+ from .topology import run_topology
92
+ results = run_topology(
93
+ xlsx=args.xlsx, outdir=args.outdir, sheet_name=args.sheet,
94
+ group_by_sequence=not args.no_group_by_sequence,
95
+ add_k0_anchor=not args.no_k0_anchor,
96
+ make_figures=not args.no_figures, dpi=args.dpi, random_seed=args.seed,
97
+ )
98
+ else: # pragma: no cover
99
+ parser.error(f"unknown command {args.command!r}")
100
+
101
+ print(f"\nResult tables (written to {args.outdir}):")
102
+ _summarise(results)
103
+ return 0
104
+
105
+
106
+ if __name__ == "__main__":
107
+ raise SystemExit(main())