-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
242 lines (228 loc) · 10.6 KB
/
Copy pathpyproject.toml
File metadata and controls
242 lines (228 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"
[project]
name = "qector-decoder-v3"
version = "1.0.0"
description = "Production-grade Rust/Python quantum error correction decoder. 25+ decoder families: MWPM Blossom, Union-Find (weighted), BP-OSD, Relay-BP for LDPC/qLDPC, belief-matching, colour-code, correlated two-stage matching, ambiguity clustering, CUDA/GPU batch decoding, 7-tier AutoDecoder fallback. PyMatching/Stim/Sinter/qiskit-qec compatible. Ed25519 license verification."
readme = "README.md"
requires-python = ">=3.9"
license = { text = "PolyForm-Noncommercial-1.0.0" }
authors = [
{name = "Guillaume Lessard / iD01t Productions", email = "admin@qector.store"}
]
keywords = ["quantum", "error correction", "decoder", "union-find", "QEC", "rust", "MWPM", "Stim", "Sinter", "PyMatching", "qiskit", "LDPC", "qLDPC", "blossom", "belief propagation", "belief matching", "BP-OSD", "Relay-BP", "colour code", "color code", "toric code", "GPU decoding", "CUDA", "surface code", "syndrome decoding", "fault tolerance", "quantum computing"]
classifiers = [
"License :: Other/Proprietary License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Rust",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
"Topic :: Scientific/Engineering :: Physics",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Intended Audience :: Science/Research",
"Development Status :: 5 - Production/Stable",
]
dependencies = [
"numpy>=1.24.0,<2.3",
# SECURITY FLOOR. `cryptography` is not incidental here: it performs the
# Ed25519 licence-token signature verification in
# `python/qector_decoder_v3/license.py`, so a vulnerable copy undermines
# licence enforcement itself.
#
# The previous floor of 3.4.0 (released 2021) permitted **39 known
# advisories** — 39 of the 45 findings `safety scan` reports against this
# manifest. 48.0.1 is the lowest release not covered by any of them.
# It supports every interpreter this package targets
# (`!=3.9.0,!=3.9.1,>=3.9`), so the floor costs no compatibility except on
# 3.9.0/3.9.1 specifically.
"cryptography>=48.0.1",
]
[project.optional-dependencies]
dev = [
# `pytest>=9.0.3` clears the one advisory Safety reports, but pytest 9.x
# requires Python >=3.10 while this package (and the CI matrix) still
# support 3.9. Split by marker rather than dropping 3.9 or staying
# vulnerable: 8.4.2 is the newest release that still allows 3.9.
"pytest>=9.0.3; python_version>='3.10'",
"pytest>=8.4.2; python_version<'3.10'",
# A9-01: `tests.yml` invokes `pytest --timeout=120`. Without this plugin that
# is an unrecognized argument and the whole job dies at collection.
"pytest-timeout>=2.1.0",
# Four packaging tests parse pyproject.toml with `tomllib`, which only
# entered the stdlib in 3.11. Without this the 3.9/3.10 matrix legs die at
# collection with ModuleNotFoundError rather than running the tests.
"tomli>=2.0; python_version<'3.11'",
"hypothesis>=6.0.4", # clears 1 Safety advisory; 6.0.4 still allows py3.6+
"fastapi>=0.110.0",
"uvicorn>=0.29.0",
"httpx>=0.27.0",
"mypy>=1.0.0",
"ruff>=0.1.0",
"pytest-cov>=4.0.0",
"stripe>=5.0",
"python-dotenv>=1.0",
]
# Stim ecosystem: DEM loading, syndrome sampling, Sinter harness, and
# PyMatching / belief-matching / BP-OSD cross-checks.
stim = [
"stim>=1.12",
"pymatching>=2.0",
"sinter>=1.12",
"ldpc>=2.0",
"beliefmatching>=0.2,<=2.2.6",
]
# Reproducible benchmark harness: memory probing, plots and tables.
bench = [
"psutil>=5.9",
"matplotlib>=3.7",
"tabulate>=0.9",
"scipy>=1.10",
]
# Stripe license fulfillment: checkout sessions, webhook signature verification.
stripe = [
"stripe>=5.0",
# `stripe_integration` reads STRIPE_SECRET_KEY / QECTOR_LICENSE_PRIVATE_KEY_B64
# from a repo-root .env. Without python-dotenv that import is a silent no-op
# and every secret in .env stays invisible, which surfaces as
# "STRIPE_SECRET_KEY is not configured" on a machine where it plainly is.
"python-dotenv>=1.0",
]
cuda = []
opencl = []
cupy = ["cupy>=12.3.0"] # unbounded before: 4 Safety advisories below 12.3.0
cupy-cuda12x = ["cupy-cuda12x>=13"]
all = [
"stim>=1.12",
"pymatching>=2.0",
"sinter>=1.12",
"ldpc>=2.0",
"beliefmatching>=0.2,<=2.2.6",
"psutil>=5.9",
"matplotlib>=3.7",
"tabulate>=0.9",
"scipy>=1.10",
"cupy-cuda12x>=13",
"stripe>=5.0",
"python-dotenv>=1.0",
]
[project.urls]
# PyPI gives a few of these keys dedicated icons in the sidebar: Homepage,
# Documentation, Source, Issues, Changelog and Funding. "Funding" is why the
# sponsors link is spelled exactly that way -- rename it and the icon is lost.
Homepage = "https://www.qector.store"
Documentation = "https://github.com/GuillaumeLessard/qector-decoder/tree/main/docs"
Source = "https://github.com/GuillaumeLessard/qector-decoder"
Repository = "https://github.com/GuillaumeLessard/qector-decoder"
Issues = "https://github.com/GuillaumeLessard/qector-decoder/issues"
Changelog = "https://github.com/GuillaumeLessard/qector-decoder/blob/main/CHANGELOG.md"
"Release Notes" = "https://github.com/GuillaumeLessard/qector-decoder/blob/main/RELEASE_NOTES.md"
Funding = "https://github.com/sponsors/qectorlab"
Pricing = "https://www.qector.store/pricing"
Purchase = "https://buy.stripe.com/7sY9AVdwlgoyfse9bYeUU00"
"Commercial Licensing" = "https://github.com/GuillaumeLessard/qector-decoder/blob/main/COMMERCIAL.md"
Security = "https://github.com/GuillaumeLessard/qector-decoder/blob/main/SECURITY.md"
[project.scripts]
qector = "qector_decoder_v3.cli:main"
qector-bench-quick = "qector_decoder_v3.bench_quick:main"
qector-doctor = "qector_decoder_v3.doctor:main"
[project.entry-points.sinter_decoder]
qector_blossom = "qector_decoder_v3.sinter_compat:QectorSinterDecoder"
qector_belief = "qector_decoder_v3.sinter_compat:QectorSinterDecoder"
qector_unionfind = "qector_decoder_v3.sinter_compat:QectorSinterDecoder"
qector_bposd = "qector_decoder_v3.sinter_compat:QectorSinterDecoder"
qector_unionfind_unweighted = "qector_decoder_v3.sinter_compat:QectorSinterDecoder"
[project.entry-points."qiskit.qec"]
qector = "qector_decoder_v3.qiskit_plugin"
[tool.maturin]
features = ["pyo3/extension-module", "cuda"]
module-name = "qector_decoder_v3.qector_decoder_v3"
python-source = "python"
manifest-path = "Cargo.toml"
sdist-include = ["LICENSE", "README.md", "CHANGELOG.md", "COMMERCIAL.md", "docs/**/*.md"]
exclude = [
"src/**",
"tests/**",
"actions-runner/**",
"artifacts/**",
"target/**",
".venv/**",
]
strip = true
[tool.pytest.ini_options]
testpaths = ["python/tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
filterwarnings = [
# Starlette's TestClient deprecation warning is registered in
# python/tests/conftest.py, NOT here. pytest resolves a class path in this
# list at config-parse time, so naming a class that a older starlette does
# not have aborts the entire session with a usage error (exit 4) on the
# 3.9/3.10 legs. conftest can tolerate its absence; this list cannot.
]
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = true
[tool.ruff]
line-length = 120
target-version = "py39"
extend-exclude = [".venv", ".venv_clean_test", "target", "dist", "lib", "proto"]
[tool.ruff.format]
# Ensure consistent formatting on Linux CI runners (LF) even when edited on Windows.
line-ending = "lf"
quote-style = "double"
indent-style = "space"
docstring-code-format = true
[tool.ruff.lint]
# E702: semicolons used intentionally for chained one-liners in plotting helpers.
# E731: lambda assignments used for compact callback tables in a few helpers.
# E741: single-letter variable names (l, I, O) are domain-conventional in QEC math.
# S110, BLE001, C414, C401, RUF*, ISC004, UP045, B017, PLW1510, SIM118: style & optional-dep guards.
#
# FA102 is deliberately NOT ignored: `requires-python = ">=3.9"`, and a bare
# PEP 604 `X | Y` in a signature is evaluated at import time, so on 3.9 it
# raises TypeError and makes the whole package unimportable. Keep it enforcing.
ignore = ["E702", "E731", "E741", "S110", "BLE001", "FA100", "C414", "C401", "RUF012", "RUF023", "RUF034", "RUF046", "RUF059", "RUF100", "ISC004", "UP045", "B017", "PLW1510", "SIM118"]
[tool.ruff.lint.per-file-ignores]
# __init__: late imports (E402) are intentional (runtime optional deps).
#
# BLE001: the broad `except Exception` guards around optional imports (torch,
# sinter, routing, the GPU probes) are deliberate. Narrowing them to ImportError
# would be wrong -- a third-party package with a broken __init__ can raise
# anything at import time, and an optional dependency must never take down
# `import qector_decoder_v3`. Each site degrades to None and is marked
# `# pragma: no cover - defensive`.
#
# FA100: adding `from __future__ import annotations` here would make every
# annotation lazy, changing runtime introspection for the re-exported PyO3
# classes -- not worth it to satisfy a style rule on a py39 target.
"python/qector_decoder_v3/__init__.py" = ["E402", "BLE001", "FA100"]
# workbench.py: json imported for optional serialization path, Tuple aliased for py3.8 compat.
"python/qector_decoder_v3/workbench.py" = ["F401"]
# qiskit_plugin.py: Tuple re-exported for downstream type annotations.
"python/qector_decoder_v3/qiskit_plugin.py" = ["F401"]
# Test files: many use sys.path manipulation (E402), conditional imports (F401),
# convenience imports kept for symmetry (F401), unused locals in scaffolding (F841),
# f-strings used as comment-like strings for readability (F541).
"python/tests/*.py" = ["E402", "F401", "F541", "F841"]
"python/tests/**/*.py" = ["E402", "F401", "F541", "F841"]
# matplotlib.use("Agg") must precede pyplot import to force a non-interactive
# backend before any GUI backend can be auto-selected; this ordering is required.
"cpu_benchmark_report.py" = ["E402"]
# test_exports.py runs a manual integration script top-to-bottom; the smoke_test_wheel
# import is intentionally placed after other exercises run, and imported for side effects.
"test_exports.py" = ["E402"]
# Benchmark/dev scripts: sys.path insertion must precede the qector_decoder_v3
# import when running from a source checkout (E402) -- same pattern as tests.
"scripts/*.py" = ["E402"]