Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
421 lines (378 loc) · 13.5 KB
/
Copy pathpyproject.toml
File metadata and controls
421 lines (378 loc) · 13.5 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
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "gpjax"
dynamic = ["version"]
description = 'Gaussian processes in JAX.'
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
keywords = ["gaussian-processes jax machine-learning bayesian"]
authors = [{ name = "Thomas Pinder", email = "tompinder@live.co.uk" }]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dependencies = [
"jax>=0.5.0",
"jaxlib>=0.5.0",
"optax>0.2.1",
"numpyro>=0.19.0",
"jaxtyping>0.2.10",
"tqdm>4.66.2",
"beartype>0.16.1",
"equinox>=0.11.0",
"paramax>=0.0.5",
"lineax>=0.0.6",
"scipy>=1.14",
"numpy>=2.0.0",
"rich>=13.0.0",
]
[project.optional-dependencies]
# Sphinx documentation stack. Mirrors impulso's `docs` dependency group
# (../impulso/pyproject.toml) so both repositories share one build idiom.
docs = [
# -- Sphinx toolchain (ported verbatim from impulso) --
"sphinx>=8.1",
"myst-nb>=1.2", # MyST markdown + executable notebooks
"shibuya>=2024.10", # theme
"sphinx-copybutton>=0.5.2",
"sphinx-design>=0.6",
"sphinxcontrib-bibtex>=2.6",
"sphinx-codeautolink>=0.15", # tutorial <-> reference cross-links
"sphinx-sitemap>=2.6",
"ipykernel>=6.29",
"jupytext>=1.16", # py:percent notebooks read via nb_custom_formats
# -- GPJax-specific, no impulso counterpart --
# GPJax writes $...$ maths in docstrings; impulso does not. MyST's dollarmath
# reaches .md and notebooks but NOT docstrings, which napoleon hands to
# docutils as reStructuredText. sphinx-math-dollar is a doctree transform that
# runs after napoleon and converts them, so the docstring source keeps the
# notation the codebase already uses.
"sphinx-math-dollar>=1.3",
# ~79 published URLs move (/api/* -> /reference/*, /_examples/* -> /examples/*).
"sphinx-reredirects>=0.1.4",
# og:/twitter: meta tags and generated PNG social cards. shibuya gates its own
# opengraph block on this extension being absent, so it is the theme-sanctioned
# way to fill in the per-page description and card image. Card generation uses
# matplotlib, already present further down this list.
"sphinxext-opengraph>=0.9",
# docs/scripts/check_mathjax.py drives a headless browser over the built site
# to catch MathJax errors, which are produced client-side and are therefore
# invisible to sphinx-build. CI must also run
# `playwright install --with-deps chromium` to fetch the browser itself.
"playwright>=1.49",
# -- Example notebook dependencies (unchanged) --
"matplotlib>=3.7.1",
"qc-core>=0.0.4", # QuantClimate "Calibrated Ledger" plot style
"seaborn>=0.12.2",
"networkx>=3.0",
"ipython>=8.11.0",
"watermark>=2.3.1",
"blackjax>=0.9.6",
"ipywidgets>=8.0.5",
"pandas>=1.5.3",
"scikit-learn>=1.5.1",
"ucimlrepo>=0.0.7",
"xarray>=2024.1", # docs/examples/xarray_workflow.py
]
# Labelled-data bridge (`gpjax.xarray`). Optional so the core install stays
# pure JAX; `import gpjax` never imports it.
xarray = [
"xarray>=2024.1",
]
[tool.uv]
exclude-newer = "7 days"
# qc-core is QuantClimate's own package, published by PyPI trusted publishing
# from QuantClimate/core, so it skips the cooldown. A new qc-core release can
# then reach the docs on the day it ships.
exclude-newer-package = { qc-core = false }
managed = true
# PEP 735 dependency group. Must stay here rather than under `[tool.uv]`:
# Dependabot's uv parser only reads `dependency-groups`, `project.dependencies`
# and `project.optional-dependencies`, so `[tool.uv].dev-dependencies` was
# invisible to it and never got updated.
[dependency-groups]
dev = [
"asv>=0.6",
"ruff>=0.6",
"pre-commit>=3.2.2",
"interrogate>=1.5.0",
"codespell>=2.2.4",
"pytest>=7.2.2",
"pytest-cov>=4.0.0",
"pytest-pretty>=1.1.1",
"pytest-xdist>=3.2.1",
"coverage>=7.2.2",
"absolufy-imports>=0.3.1",
"xdoctest>=1.1.1",
"mktestdocs>=0.2.1",
"networkx",
"jupytext",
"pytest-beartype",
"poethepoet>=0.37.0",
"twine>=6.2.0",
"hypothesis>=6.148.2",
# The `xarray` extra, repeated here because CI syncs without extras and the
# `gpjax.xarray` tests must still run.
"xarray>=2024.1",
# Workflow security audit (`poe lint-actions`, .github/workflows/zizmor.yml).
# Pinned through uv.lock rather than `uvx zizmor@latest` so a new release
# cannot turn every open PR red without a commit.
"zizmor>=1.14",
# Dev-only live-reload docs server (`poe docs-live`). Deliberately NOT in the
# `docs` extra: CI has no use for a watcher, and keeping it out means it can
# never affect a published build.
"sphinx-autobuild>=2024.10",
]
[project.urls]
Documentation = "https://gpjax.quantclimate.com/"
Issues = "https://github.com/QuantClimate/GPJax/issues"
Source = "https://github.com/QuantClimate/GPJax"
[tool.hatch.version]
path = "gpjax/__init__.py"
[tool.poe.tasks]
# Run Github actions locally
[tool.poe.tasks.local-actions]
cmd = "act -W .github/workflows/tests.yml"
help = "Run Github actions locally"
# Formatting tasks
[tool.poe.tasks.format]
sequence = [
{ cmd = "ruff check --select I --fix ./gpjax ./tests ./benchmarks" },
{ cmd = "ruff format ./gpjax ./tests ./benchmarks" }
]
help = "Format code using ruff"
# Linting tasks
[tool.poe.tasks.lint]
sequence = [
{ cmd = "ruff format --check --diff ./gpjax ./tests ./benchmarks" },
{ cmd = "ruff check --fix ./gpjax ./tests ./benchmarks" }
]
help = "Check code formatting and style"
[tool.poe.tasks.lint-ci]
sequence = [
{ cmd = "ruff format --check --diff ./gpjax ./tests ./benchmarks" },
{ cmd = "ruff check --no-fix ./gpjax ./tests ./benchmarks" }
]
help = "Check code formatting and style without mutating files (used by CI)"
# Local counterpart of .github/workflows/zizmor.yml. The workflow renders SARIF
# for code scanning; this renders the annotated form a human wants, and unlike
# SARIF it exits 14 when there are findings, so it gates on its own exit code.
# The online audits resolve action refs through the GitHub API: export
# GH_TOKEN=$(gh auth token) to enable them, or they are skipped silently.
[tool.poe.tasks.lint-actions]
cmd = "zizmor ."
help = "Audit the GitHub Actions workflows with zizmor"
# Testing tasks
[tool.poe.tasks.test]
cmd = "pytest tests -v -n 8 -m 'not slow' --beartype-packages='gpjax'"
help = "Run tests with pytest"
[tool.poe.tasks.test-slow]
cmd = "pytest tests -v -n 8 --beartype-packages='gpjax'"
help = "Run tests including slow tests"
[tool.poe.tasks.coverage]
cmd = "pytest . -v --cov=./gpjax --cov-report=xml:./coverage.xml"
help = "Run tests with coverage reporting"
[tool.poe.tasks.docstrings]
cmd = "xdoctest ./gpjax"
help = "Test docstring examples"
# Documentation tasks. Ports of impulso's Makefile docs targets
# (../impulso/Makefile) — same commands, same flags, poe instead of make.
[tool.poe.tasks.docs]
cmd = "uv run --extra docs sphinx-build -b html docs docs/_build/html"
help = "Build the Sphinx/MyST-NB docs (executes + caches notebooks)"
[tool.poe.tasks.docs-ci]
cmd = "uv run --extra docs sphinx-build -W --keep-going -b html docs docs/_build/html"
env = { GPJAX_DOCS_CI = "1" }
help = "Build docs in smoke mode, warnings-as-errors (CI gate)"
[tool.poe.tasks.docs-serve]
sequence = [
{ ref = "docs" },
{ cmd = "uv run --extra docs python -m http.server 8000 --directory docs/_build/html" }
]
help = "Serve the built docs locally on :8000"
# `--ignore` is load-bearing, not tidiness: `autosummary_generate = True` writes
# .rst stubs into docs/reference/generated/, which is inside the watched tree, so
# without it every build triggers the next one forever. The notebook cache means
# a prose or docstring edit rebuilds in seconds.
[tool.poe.tasks.docs-live]
cmd = """uv run --extra docs --group dev sphinx-autobuild
--ignore '*/reference/generated/*'
--ignore '*/_build/*'
--watch gpjax
--open-browser
docs docs/_build/html"""
help = "Live-reloading docs server for local authoring (rebuilds on save)"
[tool.poe.tasks.docs-check-math]
cmd = "uv run --extra docs python docs/scripts/check_mathjax.py docs/_build/html"
help = "Load every built page with maths in a headless browser and fail on MathJax errors"
[tool.poe.tasks.docs-linkcheck]
cmd = "uv run --extra docs sphinx-build -b linkcheck -D nb_execution_mode=off docs docs/_build/linkcheck"
help = "Check external links in the docs resolve (no notebook execution)"
[tool.poe.tasks.docs-clean]
shell = "rm -rf docs/_build/html docs/_build/doctrees docs/reference/generated"
help = "Remove built docs (keeps the notebook exec cache)"
[tool.poe.tasks.integration]
cmd = "python tests/integration_tests.py"
help = "Run integration tests"
# Benchmark tasks (continuous benchmarking via ASV)
[tool.poe.tasks.bench-check]
help = "Validate benchmark suite structure (does NOT run benchmarks). Requires asv-constraints.txt + benchmarks/ to exist on the commit referenced by asv.conf.json's `branches`."
cmd = "asv check"
[tool.poe.tasks.bench-constraints]
help = "Regenerate asv-constraints.txt from uv.lock so ASV envs install the same versions as .venv."
cmd = "uv export --frozen --no-dev --no-emit-project --no-hashes --no-editable --no-annotate --no-header -o asv-constraints.txt"
[tool.poe.tasks.bench]
help = "Run ASV benchmarks against current HEAD on this machine. Pass an optional range via -- (e.g. uv run poe bench -- v0.10..HEAD)."
shell = "asv run --machine $(hostname -s) HEAD^! ${@}"
[tool.poe.tasks.bench-publish]
help = "Generate the static HTML dashboard locally at .asv/html/."
cmd = "asv publish"
[tool.poe.tasks.bench-push]
help = "Commit and push results in .asv-results worktree (the asv-results branch)."
shell = """
cd .asv-results && \
git add results/ && \
git commit -m \"bench results $(date -u +%Y-%m-%dT%H:%M:%SZ)\" && \
git push
"""
[tool.poe.tasks.bench-all]
help = "Chain: refresh constraints, run benchmarks, generate HTML, push results."
sequence = ["bench-constraints", "bench", "bench-publish", "bench-push"]
[tool.poe.tasks.bench-compare]
help = "Run benchmarks on two refs and print a regression report. Usage: uv run poe bench-compare <baseline-ref> <branch-ref>"
shell = "asv continuous --machine $(hostname -s) -e ${1} ${2}"
# Combined tasks
[tool.poe.tasks.all-tests]
sequence = ["lint", "docstrings", "bench-check", "test"]
help = "Run all checks and tests"
[tool.poe.tasks.all-tests-slow]
sequence = ["lint", "docstrings", "test-slow"]
help = "Run all checks and tests including slow tests"
[tool.coverage.run]
source_pkgs = ["gpjax", "tests"]
branch = true
parallel = true
omit = ["gpjax/__init__.py"]
[tool.coverage.paths]
gpjax = ["gpjax", "*/gpjax/"]
tests = ["tests", "*/gpjax/tests"]
[tool.coverage.report]
exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
fail_under = 50
precision = 1
show_missing = true
skip_covered = true
[tool.pytest.ini_options] # https://docs.pytest.org/en/latest/reference/reference.html#ini-options-ref
filterwarnings = ["error", "ignore::DeprecationWarning"]
testpaths = ["tests"]
xfail_strict = true
markers = [
"slow: long-running numerical and memory stress tests (opt-in via poe all-tests-slow)",
]
[tool.ruff] # https://github.com/charliermarsh/ruff
fix = true
cache-dir = "~/.cache/ruff"
# The example notebooks moved under docs/, so "docs/" now covers them too.
exclude = ["docs/"]
line-length = 88
src = ["gpjax", "tests", "benchmarks"]
target-version = "py311"
[tool.ruff.lint]
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
select = [
"F",
# pycodestyle
"E",
"W",
# isort
"I",
# flake8-2020
"YTT",
# flake8-bugbear
"B",
# flake8-quotes
"Q",
# pylint
"PLE",
"PLR",
"PLW",
# misc lints
"PIE",
# flake8-pyi
"PYI",
# tidy imports
"TID",
# implicit string concatenation
"ISC",
# pyupgrade
"UP",
# flake8-simplify
"SIM",
# ruff-specific
"RUF",
]
ignore = [
# calls in argument defaults
"B008",
# space before : (needed for how black formats slicing)
# "E203", # not yet implemented
# module level import not at top of file
"E402",
# do not assign a lambda expression, use a def
"E731",
"E501",
"S303",
"S307",
"RET504",
"S101",
"F722",
'PLR2004',
"PLR0913",
# too-many-positional-arguments. Kernels, likelihoods and variational
# families are constructed positionally with defaults (e.g.
# `RBF(active_dims, lengthscale, variance, n_dims, compute_engine)`);
# forcing keyword-only arguments would break those public signatures.
# Paired with PLR0913 above, which ignores the same shape of constructor.
"PLR0917",
# intentional math Unicode (σ, ℓ) in docstrings and comments
"RUF002",
"RUF003",
]
unfixable = ["ERA001", "F401", "F841", "T201", "T203"]
[tool.ruff.lint.isort]
combine-as-imports = true
force-sort-within-sections = true
force-wrap-aliases = true
[tool.ruff.lint.pydocstyle]
# Matches `napoleon_google_docstring = True` in docs/conf.py.
convention = "google"
[tool.ruff.lint.per-file-ignores]
"gpjax/__init__.py" = ['I', 'F401', 'E402', 'D104']
"gpjax/scan.py" = ["PLR0913"]
"gpjax/citation.py" = ["F811"]
"gpjax/gps.py" = ["F811"]
"tests/test_objectives.py" = ["PLR0913"]
"docs/examples/barycentres.py" = ["PLR0913"]
"tests/*.py" = ["PLW0108"]
[tool.interrogate]
ignore-init-method = true
ignore-init-module = true
fail-under = 64
exclude = [
"setup.py",
"docs",
"tests",
"gpjax/__init__.py",
"gpjax/citation.py",
]
verbose = 2
quiet = false
color = true