Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
438 lines (419 loc) · 21.8 KB
/
Copy pathpyproject.toml
File metadata and controls
438 lines (419 loc) · 21.8 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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# pyproject.toml — bngsim Python package
#
# Build system: scikit-build-core + pybind11
# Usage: pip install . (from bngsim/ directory)
# uv pip install . (preferred)
[build-system]
requires = [
"scikit-build-core>=0.10",
"pybind11>=2.13",
# Note: scikit-build-core automatically provides ninja when needed,
# so it should NOT be listed here (causes warnings).
]
build-backend = "scikit_build_core.build"
[project]
name = "bngsim"
version = "0.17.2"
description = "Embeddable simulation engine for BioNetGen reaction networks"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.10"
authors = [
{name = "William S. Hlavacek"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Programming Language :: C++",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Topic :: Scientific/Engineering :: Bio-Informatics",
"Topic :: Scientific/Engineering :: Chemistry",
]
dependencies = [
"numpy>=1.24",
"python-libsbml>=5.20",
# sympy is required by _codegen.py to chain-rule through derived
# rate-constant parameters (BNG2.pl-emitted ``_rateLaw{N}``-style
# ConstantExpressions, including non-product forms like ``5/MEK``).
# Without it, ``_compute_derived_param_jacobian`` silently returns
# None and codegen sensitivities for the underlying primary
# parameters are wrong (issue #2 regression).
"sympy>=1.10",
]
[project.urls]
Homepage = "https://github.com/lanl/bngsim"
Documentation = "https://bngsim.readthedocs.io"
Repository = "https://github.com/lanl/bngsim"
Changelog = "https://github.com/lanl/bngsim/blob/HEAD/CHANGELOG.md"
Issues = "https://github.com/lanl/bngsim/issues"
[project.optional-dependencies]
# Antimony (.ant) input. Deliberately an extra and NOT a base dependency: the
# project publishes no sdist, and its four wheels cover fewer platforms than
# bngsim's own -- macosx_14_0_arm64 (bngsim targets 11.0), macosx_15_0_x86_64
# (bngsim targets 10.15), manylinux_2_28_x86_64, win_amd64. With no sdist to
# fall back on, promoting it would turn `pip install bngsim` into a hard
# "no matching distribution" failure on pre-14 Apple Silicon, pre-15 Intel
# macOS, linux aarch64 and musllinux. Environment markers cannot express the
# macOS floors, so there is no partial promotion either.
antimony = [
# 3.1.2 was tagged upstream but never published to PyPI (the release is
# empty there) -- the showcase benchmark pins a CI-artifact wheel for it,
# see benchmarks/suites/showcase/requirements_showcase_pinned.txt. 3.1.3 is
# the first published successor.
"antimony>=3.1.3",
]
pandas = ["pandas>=2.0"]
hdf5 = ["h5py>=3.0"]
# Labeled-array access: Result.xr (per-field DataArray, AMICI-style) and
# Result.to_xarray() (one Dataset with every field). Both are shipped public
# API in _result.py, but xarray was undeclared by ANY extra -- so the 12 tests
# guarding them skipped in every environment and the feature had never actually
# run. Same failure as the jsonschema note below.
# The floor is ecosystem alignment, not a feature we need: the accessors use
# only long-stable DataArray/Dataset API, and 2024.7 is the era whose
# `pandas>=2.0` requirement matches this project's own `pandas` extra.
xarray = ["xarray>=2024.7"]
# BNGL (.bngl) input for Model.from_bngl / Model.load (GH #162). bngsim has no
# BNGL parser: rules become a network only through BNG2.pl, and PyBioNetGen is
# how BNG2.pl reaches PyPI.
#
# This must NOT become a base dependency, and is not folded into `dev` either.
# `bionetgen` 0.8.6 is a 12.8 MB wheel requiring cement, nbopen, numpy, pyyaml,
# colorlog, xmltodict, seaborn, libroadrunner, sympy, lxml, networkx,
# python-libsbml, pylru, pyparsing. Promoting it would pull **libroadrunner**
# into every install -- contradicting the `roadrunner` extra's stated policy
# three stanzas down -- add seaborn and networkx to a core scientific install,
# add a Perl runtime requirement (BNG2.pl is Perl: fine on macOS/Linux, absent
# on stock Windows), and invert the layering, since PyBioNetGen *consumes*
# bngsim through its in-Python bridge (RuleWorld/PyBioNetGen#102).
#
# It is also NOT the `parity` group, which pins `bionetgen @ git+...@43b09a5`
# for engine-routing provenance (the older 5109a46 silently routed
# simulator='bngsim' to legacy BNG2.pl -- see
# parity_checks/requirements-pybionetgen.txt). A user loading a BNGL file needs
# BNG2.pl, not that commit; the PyPI release here does not satisfy the parity
# suite, and keeping them apart is what stops a resolver from having to
# reconcile a range with a git pin. That separation is also why `dev` omits this
# extra: a developer venv gets BNG2.pl from `--group parity` (or $BNGPATH), and
# a dev environment carrying both requirements would have to resolve them.
bngl = ["bionetgen>=0.8.6"]
test = [
"pytest>=8.0",
"pytest-cov>=5.0",
# The pre-push hook runs python/tests in parallel through
# ci/pre_push_pytest.py: 44m29s serially, 4m42s on 12 workers.
"pytest-xdist>=3.5",
# test_ssa_time_dependent_rate imports antimony at module scope.
"antimony>=3.1.3",
"scipy>=1.15",
# parity_checks/tests/test_corpus_manifest_schema.py validates manifest.json
# against manifest.schema.json behind a pytest.importorskip("jsonschema").
# Undeclared, that guard skipped in EVERY environment — and because `uv sync`
# prunes anything not in the lock, hand-installing it never survived the next
# sync. Declaring it is what makes the check actually run.
"jsonschema>=4.0",
# test_new_features.py's TestXarrayAccessor / to_xarray cases sit behind a
# pytest.importorskip("xarray"); same reasoning as jsonschema above.
"xarray>=2024.7",
# test_sedml_schema.py validates every SED-ML document the writers produce
# against the vendored L1V3 XSD with lxml.etree.XMLSchema, the validator
# `xmllint --schema` runs (issue #1734). The dev extra reached lxml only
# through bioservices; declared here, the check does not hang on that.
"lxml>=5.0",
]
jax = [
"jax>=0.4",
"jaxlib>=0.4",
"diffrax>=0.6",
]
# Optional Vivarium process shell (bngsim.vivarium, GH #102). vivarium-core's
# process interface is migrating to process-bigraph; the shell stays thin.
vivarium = ["vivarium-core>=1.6"]
benchmarks = [
"bioservices>=1.11",
]
# Reference engine for the parity_checks/ cross-validation suites (and a few
# cross-validate tests that skip when it is absent). DEVELOPER-ONLY: RoadRunner
# is never a base dependency, so regular users never receive it in any form. The
# rr_parity matrix's per-model RoadRunner *load* timing additionally needs the
# source-instrumented fork (parity_checks/rr_parity/INSTRUMENTED_ROADRUNNER.md +
# dev/notes/build_instrumented_roadrunner.sh); stock libroadrunner here covers
# the correctness/oracle role.
roadrunner = [
"libroadrunner>=2.7",
]
dev = [
"bngsim[antimony,pandas,hdf5,xarray,test,jax,vivarium,benchmarks,roadrunner]",
"ruff>=0.8",
# Regenerates python/bngsim/_bngsim_core.pyi from the built extension in
# scripts/rebuild_editable.py, keeping the type stub in sync with the C++
# bindings so mypy does not drift into spurious attr-defined errors.
"pybind11-stubgen>=2.5",
# The *other* thing scripts/rebuild_editable.py needs, and the one nothing
# else provides. That script drives cmake directly against this venv, so
# find_package(pybind11) has to resolve from here — but pybind11 is a
# [build-system] requirement, which uv puts in a transient isolated build
# env and never installs into .venv. Undeclared, the script worked only on
# machines carrying a system pybind11 (or a venv that happened to keep one
# from some earlier `uv pip install`, until the next `uv sync` pruned it) —
# and it is the remedy the stale-binary guard names, so its failure pushed
# people toward BNGSIM_ALLOW_STALE_CORE=1. GH #229.
#
# The specifier must match [build-system] requires above: the two are the
# same dependency reached by two routes, and a skew means the incremental
# cmake rebuild and `uv sync --reinstall-package bngsim` can compile the
# same source against different pybind11 versions.
# test_rebuild_editable_pybind11.py fails if they drift.
"pybind11>=2.13",
]
# PEP 735 dependency groups — local-only, NEVER part of published metadata.
# `parity` has to live here rather than in [project.optional-dependencies]
# because it carries a `git+https://` direct reference, and PyPI rejects any
# distribution whose metadata contains one. A group keeps bngsim publishable
# while still giving `uv sync --group parity` a one-command provisioning path.
[dependency-groups]
# The legacy BioNetGen stack for parity_checks/. PyBioNetGen bundles BNG2.pl
# (plus bin/run_network and bin/NFsim), which is the ONLY thing bngsim cannot do
# itself — it has no BNGL parser, so every BNGL job shells out to BNG2.pl for
# network generation before simulating in-process. Installing this group is what
# turns the parity suite's engine tests from skipped into run.
#
# The commit MUST match parity_checks/requirements-pybionetgen.txt — that file
# is the source of truth (it carries the rationale for the pin, and GH #4 bumped
# it). parity_checks/tests/test_pin_agreement.py fails if the two drift.
parity = [
"bionetgen @ git+https://github.com/RuleWorld/PyBioNetGen.git@43b09a5",
]
# AMICI — the reference engine for parity_checks/amici_parity, and the second
# oracle for forward sensitivity. A group and not an extra for the same reason
# `parity` is one: the pin is a commit, so the requirement is a direct
# reference, and PyPI rejects those in published metadata.
#
# The commit MUST match parity_checks/amici_parity/AMICI_PIN.json — that file is
# the source of truth (it carries the rationale, and every AMICI result recorded
# in AMICI_KNOWN_ISSUES.md is tied to it). test_pin_agreement.py fails if the
# two drift.
#
# It has to be the commit, not `amici==1.0.1` off PyPI: the pin is 12 commits
# past the release tag and those commits touch `_symbolic/de_model.py`, the
# exporters and the SWIG template — i.e. the engine, not just its tests.
#
# Undeclared until now, which meant `uv sync` silently uninstalled it and the
# whole amici_parity suite went quiet — the failure mode CONTRIBUTING.md warns
# about for hand-installed packages. It is also what let a 5x-wrong sensitivity
# column survive (issue #144 follow-up): with no second engine in the
# environment, a finite difference that shares a defect with the engine is the
# only oracle left.
#
# Building it needs more than a wheel fetch: swig, a C++ toolchain, and a BLAS.
# On macOS that BLAS is Accelerate (there is no openblas dependency to install);
# on Linux the build pulls scipy-openblas64 itself. The clone also touches
# git-lfs, so a machine with `filter.lfs.*` configured must actually have the
# git-lfs binary present or the checkout aborts.
# The marker is load-bearing, not decoration. bngsim supports Python >=3.10 and
# AMICI requires >=3.11, so an unmarked entry makes the *whole project* lock
# unsatisfiable — `uv lock` fails outright, not just `--group amici`. The
# alternative, raising bngsim's own requires-python, would drop 3.10 for every
# user to buy a developer convenience. On 3.10 the group simply resolves empty.
amici = [
"amici @ git+https://github.com/AMICI-dev/AMICI.git@667b17b6bfc16a28f95fc5ef9564c3e2c4db2126#subdirectory=python/sdist ; python_version >= '3.11'",
]
[tool.uv]
# PyBioNetGen's setup.py shells out to `pip install numpy` and downloads BNG2.pl
# at build time, so it cannot build in an isolated env that lacks them. Same
# reason bootstrap_parity_env.py passes --no-build-isolation by hand.
no-build-isolation-package = ["bionetgen"]
# Consequence worth knowing before you edit anything above: with isolation off,
# PyBioNetGen builds against THIS venv, so re-locking needs `setuptools` and
# `pip` installed in it. And `uv.lock` records `provides-extras`, so any edit to
# the dependency metadata in this file invalidates the lock and forces exactly
# that re-resolve. See CONTRIBUTING.md, "Re-locking after a pyproject change".
[project.scripts]
# SBML → .net network converter (GH #215). Also runnable as
# ``python -m bngsim.convert``.
bngsim-sbml2net = "bngsim.convert._cli:main"
# .net → SBML network converter (GH #216), the reverse direction.
bngsim-net2sbml = "bngsim.convert._cli:net2sbml_main"
# SBML → compartmental .bngl (cBNGL) writer (GH #224): recovers static volumes.
bngsim-sbml2bngl = "bngsim.convert._cli:sbml2bngl_main"
# Conversion-validation framework (GH #217): L0–L4 gate over either direction.
bngsim-validate-conversion = "bngsim.convert._cli:validate_main"
# COMBINE archive (.omex) packaging (GH #219): pack/unpack SBML + SED-ML + manifest.
bngsim-omex = "bngsim.convert._cli:omex_main"
# Codegen artifact cache: info / clean / prune / clear (issue #205). Also runnable
# as ``python -m bngsim.cache``, which is the form that works without reinstalling.
bngsim-cache = "bngsim.cache:main"
[tool.scikit-build]
cmake.source-dir = "."
cmake.build-type = "Release"
cmake.args = [
"-DBNGSIM_BUILD_TESTS=OFF",
"-DBNGSIM_BUILD_PYTHON=ON",
]
# Let CMake auto-detect generator (prefers Ninja, falls back to Unix Makefiles).
# ninja is in build-system.requires for wheel builds; for editable installs
# it uses whatever's in PATH, falling back gracefully if unavailable.
wheel.packages = ["python/bngsim"]
wheel.install-dir = "bngsim"
build-dir = "build/{wheel_tag}"
# Disable automatic rebuild on import for editable installs. While convenient,
# it causes import failures when the build environment (especially ninja from
# scikit-build-core) isn't persistently available at runtime. Developers
# should manually rebuild after C++ changes:
# uv pip install -e . --force-reinstall --no-deps
# See issue #23.
editable.rebuild = false
sdist.exclude = [
".pytest_cache",
".venv",
"benchmarks",
"build",
"dev",
"harness",
"python/bngsim/__pycache__",
"python/bngsim/__pycache__/**",
"python/bngsim/_bngsim_core*.dylib",
"python/bngsim/_bngsim_core*.pyd",
"python/bngsim/_bngsim_core*.so",
"python/tests",
"run_tests.sh",
"scripts",
"tests",
]
wheel.exclude = [
"python/bngsim/__pycache__",
"python/bngsim/__pycache__/**",
"python/bngsim/_bngsim_core*.dylib",
"python/bngsim/_bngsim_core*.pyd",
"python/bngsim/_bngsim_core*.so",
]
[tool.scikit-build.cmake.define]
BNGSIM_BUILD_PYTHON = "ON"
# Every pip build — wheel AND sdist source-install — must get SuiteSparse/KLU or
# fail loudly with the GH #209 message, never a silent dense-only fallback (KLU is
# essential for efficiency on sparse networks). Defining it here guarantees it
# reaches CMake for all scikit-build-core builds; the cibuildwheel `environment`
# sets the same var but as a bare env var it does not reach CMake's option().
BNGSIM_REQUIRE_KLU = "ON"
[tool.pytest.ini_options]
testpaths = ["python/tests"]
addopts = "-v --tb=short --import-mode=importlib"
[tool.mypy]
python_version = "3.10"
files = ["python/bngsim"]
ignore_missing_imports = true
follow_imports = "silent"
[tool.ruff]
target-version = "py310"
line-length = 99
# Notebooks are interactive scratch/showcase content; lint via nbqa
# in CI if/when we want it, not as part of the Python source pass.
# benchmarks/temp is a tracked scratch area for one-off benchmark scripts kept
# so they don't get lost across machines; not held to the style bar.
extend-exclude = ["*.ipynb", "benchmarks/temp"]
# Apply excludes even when pre-commit passes file paths explicitly.
force-exclude = true
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
[tool.ruff.lint.per-file-ignores]
# Research/benchmark/showcase code: long format strings (LaTeX
# captions, multi-line doc messages, tabular output) are clearer
# on one line. Hard line-length is enforced for the shipped
# package + tests, not for these scripts.
"benchmarks/**" = ["E501"]
"harness/**" = ["E501"]
"scripts/**" = ["E501"]
"parity_checks/**" = ["E501"]
# These test modules embed long single-line SBML/MathML reference documents
# (one <sbml>/<species>/<reaction> chunk per line). XML inter-element and
# inter-attribute whitespace is insignificant, so the data is deliberately kept
# unwrapped for readability — reflowing it to 99 cols would only obscure the
# fixture. E501 stays enforced on the test *code*; only these fixture-dominated
# modules are exempt.
"python/tests/test_jacobian_selfcheck.py" = ["E501"]
"python/tests/test_rhs_nonneg_clamp.py" = ["E501"]
"python/tests/test_sbml_no_species_time.py" = ["E501"]
"python/tests/test_sbml_suite_grading.py" = ["E501"]
"python/tests/test_sbml_variable_volume_dilution.py" = ["E501"]
"python/tests/test_compartment_size_write.py" = ["E501"]
"python/tests/test_compartment_size_sensitivity.py" = ["E501"]
"python/tests/test_compartment_size_live.py" = ["E501"]
"python/tests/test_compartment_size_codegen_live.py" = ["E501"]
"python/tests/test_compartment_size_initial_assignment.py" = ["E501"]
"python/tests/test_sbml_initial_assignment_param_lift.py" = ["E501"]
"python/tests/test_compartment_size_xcompartment.py" = ["E501"]
"python/tests/test_sbml_nonfinite_compartment_size.py" = ["E501"]
"python/tests/test_sbml_to_net.py" = ["E501"]
# ── cibuildwheel: binary wheels for Linux / macOS / Windows (GH #140) ─────────
# Wheels bundle SuiteSparse/KLU: BNGSIM_REQUIRE_KLU=ON makes a build that cannot
# find KLU fail loudly instead of silently shipping the dense-only fallback, and
# auditwheel/delocate/delvewheel then vendor the KLU shared libs into the wheel.
# SUNDIALS is fetched + statically linked by CMake (no runtime dependency).
[tool.cibuildwheel]
build = "cp310-* cp311-* cp312-* cp313-* cp314-* cp315-*"
# Skip musllinux (SuiteSparse on musl needs a source build — add later) and
# 32-bit targets. PyPy is already excluded by the cpXY-only `build` selector
# above (an explicit `pp*` skip trips a cibuildwheel v4 "invalid selector" warning).
skip = "*-musllinux_* *_i686 *-win32"
build-verbosity = 1
environment = { BNGSIM_ENABLE_KLU = "ON", BNGSIM_REQUIRE_KLU = "ON" }
# Smoke test: the wheel imports in a clean env, and the SuiteSparse/KLU vendored
# into it actually factorizes -- routed to KLU on a model past the auto gates,
# cross-checked against the dense LU (which touches no SuiteSparse) and against
# exact mass conservation. See ci/wheel_smoke_klu.py.
#
# This used to be `assert bngsim.HAS_KLU` alone, which is a COMPILE-TIME flag
# (issue #303): True because the extension was built against SuiteSparse, and
# still True when the libraries inside the wheel cannot do anything. Every wheel
# here is repaired -- delvewheel content-hashes the DLL names and injects a
# loader patch, delocate rewrites install names, auditwheel mangles SONAMEs --
# and none of that is exercised by the source build windows-klu.yml tests (#296).
#
# Global rather than per-platform on purpose: Windows at least has a source-build
# leg now, while the macOS and Linux repairs have no counterpart anywhere.
# The script needs no C compiler and nothing beyond bngsim's own runtime
# dependencies, so there is no test-requires and it runs on every CPython here.
#
# ci/wheel_smoke_stop_condition.py runs a stop condition that meets 0/0 (issue
# #1556): on Python 3.13 and later a numpy warning inside a condition refused the
# run, and the pull-request suites run 3.12 only, so the wheels are where 3.13
# and later are exercised. Same constraints: bngsim and numpy only.
test-command = "python {project}/ci/wheel_smoke_klu.py && python {project}/ci/wheel_smoke_stop_condition.py"
[tool.cibuildwheel.linux]
# manylinux_2_28 = AlmaLinux 8 (has dnf); SuiteSparse/KLU comes from EPEL. Its
# klu.h lands in /usr/include/suitesparse — covered by the CMake find_path
# suffix. "native" builds each runner's own architecture, x86_64 on
# ubuntu-latest and aarch64 on ubuntu-24.04-arm, with no emulation (#1491).
archs = ["native"]
manylinux-x86_64-image = "manylinux_2_28"
manylinux-aarch64-image = "manylinux_2_28"
before-all = "dnf install -y epel-release && dnf install -y suitesparse-devel"
[tool.cibuildwheel.macos]
# SuiteSparse/KLU built FROM SOURCE (shared, KLU subset) at a low deployment
# target -> broad-compat wheels (brew's suite-sparse targets the runner OS, so
# delocate forced a runner-OS wheel tag). Installs to $HOME/suitesparse; delocate
# bundles the dylibs. See ci/build_suitesparse.sh (reads MACOSX_DEPLOYMENT_TARGET
# so the dylibs' min target matches the wheel's).
before-all = "bash ci/build_suitesparse.sh $HOME/suitesparse"
environment = { BNGSIM_ENABLE_KLU = "ON", BNGSIM_REQUIRE_KLU = "ON", SUITESPARSE_ROOT = "$HOME/suitesparse", CMAKE_PREFIX_PATH = "$HOME/suitesparse" }
[tool.cibuildwheel.windows]
# SuiteSparse/KLU built FROM SOURCE (shared, KLU subset) with MSVC -> the
# amd/colamd/btf import libs SUNDIALS' KLU TPL needs (vcpkg ships only
# klu+suitesparseconfig -> AMD/COLAMD/BTF_LIBRARY-NOTFOUND). Installs to
# C:/suitesparse; delvewheel bundles the DLLs from C:/suitesparse/bin.
# See ci/build_suitesparse.ps1.
before-all = "powershell -ExecutionPolicy Bypass -File ci/build_suitesparse.ps1 -Prefix C:/suitesparse"
before-build = "pip install delvewheel"
# CL=-MP: MSBuild compiles one source at a time without it, so each of the
# wheels was a serial build and the job took 50 minutes; see windows-tail.yml's
# build step. cibuildwheel applies `environment` to before-all as well, so the
# SuiteSparse build compiles in parallel too.
environment = { BNGSIM_ENABLE_KLU = "ON", BNGSIM_REQUIRE_KLU = "ON", SUITESPARSE_ROOT = "C:/suitesparse", CMAKE_PREFIX_PATH = "C:/suitesparse", CL = "-MP" }
repair-wheel-command = "delvewheel repair -w {dest_dir} {wheel} --add-path C:/suitesparse/bin"