parameterrun 0.4.1__tar.gz → 0.5.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 (82) hide show
  1. parameterrun-0.5.1/.github/workflows/ci.yml +114 -0
  2. parameterrun-0.5.1/.github/workflows/docs.yml +53 -0
  3. {parameterrun-0.4.1 → parameterrun-0.5.1}/.github/workflows/publish.yml +1 -1
  4. {parameterrun-0.4.1 → parameterrun-0.5.1}/.gitignore +21 -2
  5. parameterrun-0.5.1/CHANGELOG.md +147 -0
  6. parameterrun-0.5.1/PKG-INFO +508 -0
  7. parameterrun-0.5.1/README.md +474 -0
  8. parameterrun-0.5.1/dev/checkpointing_design.md +141 -0
  9. parameterrun-0.5.1/dev/distributed_shuffle.py +117 -0
  10. parameterrun-0.5.1/dev/profile_scalene.sh +30 -0
  11. parameterrun-0.5.1/dev/very_large_swap.py +27 -0
  12. parameterrun-0.5.1/docs/assets/extra.css +28 -0
  13. parameterrun-0.5.1/docs/assets/favicon.ico +0 -0
  14. parameterrun-0.5.1/docs/assets/icon-app-tile.svg +1 -0
  15. parameterrun-0.5.1/docs/assets/logo-readme-dark.svg +1 -0
  16. parameterrun-0.5.1/docs/assets/logo-readme-light.svg +1 -0
  17. parameterrun-0.5.1/docs/changelog.md +1 -0
  18. parameterrun-0.5.1/docs/contributing.md +3 -0
  19. parameterrun-0.5.1/docs/guide/backends.md +3 -0
  20. parameterrun-0.5.1/docs/guide/errors.md +5 -0
  21. parameterrun-0.5.1/docs/guide/progress.md +3 -0
  22. parameterrun-0.5.1/docs/guide/results.md +5 -0
  23. parameterrun-0.5.1/docs/index.md +16 -0
  24. parameterrun-0.5.1/docs/quickstart.md +7 -0
  25. parameterrun-0.5.1/docs/reference.md +12 -0
  26. {parameterrun-0.4.1 → parameterrun-0.5.1}/examples/long_example.py +8 -2
  27. parameterrun-0.5.1/examples/minimal_example.py +19 -0
  28. {parameterrun-0.4.1 → parameterrun-0.5.1}/examples/minimal_example_mpi.py +2 -2
  29. parameterrun-0.5.1/internals/architecture.md +441 -0
  30. parameterrun-0.5.1/internals/checkpoints-and-shuffle.md +314 -0
  31. parameterrun-0.5.1/internals/github-actions.md +156 -0
  32. parameterrun-0.5.1/mkdocs.yml +91 -0
  33. {parameterrun-0.4.1 → parameterrun-0.5.1}/pyproject.toml +43 -12
  34. {parameterrun-0.4.1 → parameterrun-0.5.1}/scripts/bump_version.py +3 -13
  35. {parameterrun-0.4.1 → parameterrun-0.5.1}/src/parameterrun/__init__.py +1 -1
  36. parameterrun-0.5.1/src/parameterrun/_checkpoint.py +659 -0
  37. parameterrun-0.5.1/src/parameterrun/_delivery.py +118 -0
  38. parameterrun-0.5.1/src/parameterrun/_errors.py +158 -0
  39. parameterrun-0.5.1/src/parameterrun/_inputs.py +159 -0
  40. parameterrun-0.5.1/src/parameterrun/_joblib_backend.py +142 -0
  41. parameterrun-0.5.1/src/parameterrun/_mpi_dynamic.py +283 -0
  42. parameterrun-0.5.1/src/parameterrun/_mpi_static.py +509 -0
  43. parameterrun-0.5.1/src/parameterrun/_mpi_transfer.py +51 -0
  44. parameterrun-0.5.1/src/parameterrun/_progress.py +111 -0
  45. parameterrun-0.5.1/src/parameterrun/_pseudo_random.py +56 -0
  46. parameterrun-0.5.1/src/parameterrun/_results.py +60 -0
  47. parameterrun-0.5.1/src/parameterrun/_store.py +416 -0
  48. parameterrun-0.5.1/src/parameterrun/_utils.py +60 -0
  49. parameterrun-0.5.1/src/parameterrun/parallel_utils.py +447 -0
  50. parameterrun-0.5.1/src/parameterrun/py.typed +0 -0
  51. parameterrun-0.5.1/tests/test_checkpoint.py +659 -0
  52. parameterrun-0.5.1/tests/test_delivery.py +320 -0
  53. parameterrun-0.5.1/tests/test_depths.py +36 -0
  54. parameterrun-0.5.1/tests/test_dynamic_schedule.py +443 -0
  55. {parameterrun-0.4.1 → parameterrun-0.5.1}/tests/test_format_input.py +10 -11
  56. parameterrun-0.5.1/tests/test_get_iteration.py +11 -0
  57. parameterrun-0.5.1/tests/test_joblib.py +14 -0
  58. parameterrun-0.5.1/tests/test_mpi_integration.py +568 -0
  59. parameterrun-0.5.1/tests/test_mpi_rank_scaling.py +160 -0
  60. parameterrun-0.5.1/tests/test_normalized_time.py +13 -0
  61. parameterrun-0.5.1/tests/test_on_error.py +278 -0
  62. parameterrun-0.5.1/tests/test_parameter_run.py +243 -0
  63. {parameterrun-0.4.1 → parameterrun-0.5.1}/tests/test_pbar_format.py +29 -18
  64. parameterrun-0.5.1/tests/test_pbar_options.py +175 -0
  65. parameterrun-0.5.1/tests/test_pseudo_random.py +62 -0
  66. parameterrun-0.5.1/tests/test_result_checks.py +173 -0
  67. parameterrun-0.5.1/tests/test_review_regressions.py +490 -0
  68. parameterrun-0.4.1/.github/workflows/ci.yml +0 -65
  69. parameterrun-0.4.1/CHANGELOG.md +0 -72
  70. parameterrun-0.4.1/PKG-INFO +0 -289
  71. parameterrun-0.4.1/README.md +0 -257
  72. parameterrun-0.4.1/examples/minimal_example.py +0 -13
  73. parameterrun-0.4.1/src/parameterrun/parallel_utils.py +0 -494
  74. parameterrun-0.4.1/tests/test_depths.py +0 -36
  75. parameterrun-0.4.1/tests/test_get_iteration.py +0 -8
  76. parameterrun-0.4.1/tests/test_joblib.py +0 -14
  77. parameterrun-0.4.1/tests/test_mpi_integration.py +0 -30
  78. parameterrun-0.4.1/tests/test_normalized_time.py +0 -13
  79. parameterrun-0.4.1/tests/test_parameter_run.py +0 -136
  80. {parameterrun-0.4.1 → parameterrun-0.5.1}/.github/workflows/release.yml +0 -0
  81. {parameterrun-0.4.1 → parameterrun-0.5.1}/CONTRIBUTING.md +0 -0
  82. {parameterrun-0.4.1 → parameterrun-0.5.1}/LICENSE +0 -0
@@ -0,0 +1,114 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [ main ]
6
+ push:
7
+ branches: [ main ]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ name: non-mpi / ${{ matrix.os }} / py${{ matrix.python-version }}
15
+ runs-on: ${{ matrix.os }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ ubuntu-latest, macos-latest, windows-latest ]
20
+ python-version: [ "3.11", "3.12", "3.13", "3.14", "3.15" ]
21
+
22
+ steps:
23
+ - uses: actions/checkout@v6
24
+
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: ${{ matrix.python-version }}
28
+
29
+ - name: Install uv
30
+ run: python -m pip install uv
31
+
32
+ - name: Sync environment
33
+ run: uv sync
34
+
35
+ - name: Tests
36
+ run: uv run pytest -m "not mpi and not mpi_subprocess" --cov-report=xml
37
+
38
+ # One upload is enough for the README badge; a missing token or Codecov outage must not fail CI
39
+ - name: Upload coverage to Codecov
40
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
41
+ uses: codecov/codecov-action@v5
42
+ with:
43
+ files: coverage.xml
44
+ token: ${{ secrets.CODECOV_TOKEN }}
45
+ fail_ci_if_error: false
46
+
47
+ - name: Lint
48
+ run: uv run ruff check .
49
+
50
+ - name: Type check
51
+ run: uv run mypy
52
+
53
+ test-mpi:
54
+ name: mpi / ${{ matrix.os }} / ${{ matrix.mpi }} / py3.12 / 4+8 ranks
55
+ runs-on: ${{ matrix.os }}
56
+ env:
57
+ OMP_NUM_THREADS: "1"
58
+ OPENBLAS_NUM_THREADS: "1"
59
+ MKL_NUM_THREADS: "1"
60
+ strategy:
61
+ fail-fast: false
62
+ matrix:
63
+ include:
64
+ - os: ubuntu-latest
65
+ mpi: openmpi
66
+ - os: ubuntu-latest
67
+ mpi: mpich
68
+ - os: ubuntu-latest
69
+ mpi: intelmpi
70
+ - os: macos-latest
71
+ mpi: openmpi
72
+ - os: macos-latest
73
+ mpi: mpich
74
+ - os: windows-latest
75
+ mpi: msmpi
76
+ - os: windows-latest
77
+ mpi: intelmpi
78
+
79
+ steps:
80
+ - uses: actions/checkout@v6
81
+
82
+ - uses: actions/setup-python@v6
83
+ with:
84
+ python-version: "3.12"
85
+
86
+ - name: Setup MPI
87
+ uses: mpi4py/setup-mpi@v1
88
+ with:
89
+ mpi: ${{ matrix.mpi }}
90
+
91
+ - name: Install uv
92
+ run: python -m pip install uv
93
+
94
+ - name: Sync environment with MPI extra
95
+ run: uv sync --extra mpi
96
+
97
+ - name: Verify MPI runtime
98
+ env:
99
+ EXPECTED_MPI: ${{ matrix.mpi }}
100
+ run: >-
101
+ uv run python -c "import os; from mpi4py import MPI;
102
+ print(MPI.Get_library_version());
103
+ expected = {'openmpi': 'Open MPI', 'mpich': 'MPICH', 'intelmpi': 'Intel MPI', 'msmpi': 'Microsoft MPI'};
104
+ assert MPI.get_vendor()[0] == expected[os.environ['EXPECTED_MPI']], MPI.get_vendor()"
105
+
106
+ - name: MPI tests (4 ranks)
107
+ run: uv run mpiexec -n 4 python -m pytest -m mpi -o addopts="-q -m mpi"
108
+
109
+ - name: MPI scheduling and idle workers (8 ranks)
110
+ run: uv run mpiexec -n 8 python -m pytest tests/test_mpi_rank_scaling.py -m mpi -o addopts="-q -m mpi"
111
+
112
+ # Not under mpiexec: these tests start their own `mpiexec -n 4` (e.g. on_error="raise" must abort the job)
113
+ - name: MPI subprocess tests
114
+ run: uv run pytest -m mpi_subprocess -o addopts="-q -rs -m mpi_subprocess"
@@ -0,0 +1,53 @@
1
+ name: Docs
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: docs-${{ github.ref }}
15
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+
23
+ - uses: actions/setup-python@v6
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Install uv
28
+ run: python -m pip install uv
29
+
30
+ - name: Sync docs environment
31
+ run: uv sync --only-group docs
32
+
33
+ - name: Build site
34
+ run: uv run --no-sync zensical build --strict
35
+
36
+ - uses: actions/upload-pages-artifact@v4
37
+ if: github.event_name != 'pull_request'
38
+ with:
39
+ path: site
40
+
41
+ deploy:
42
+ if: github.event_name != 'pull_request'
43
+ needs: build
44
+ runs-on: ubuntu-latest
45
+ permissions:
46
+ pages: write
47
+ id-token: write
48
+ environment:
49
+ name: github-pages
50
+ url: ${{ steps.deployment.outputs.page_url }}
51
+ steps:
52
+ - id: deployment
53
+ uses: actions/deploy-pages@v4
@@ -21,7 +21,7 @@ jobs:
21
21
 
22
22
  - uses: actions/setup-python@v6
23
23
  with:
24
- python-version: "3.9"
24
+ python-version: "3.11"
25
25
 
26
26
  - name: Install uv
27
27
  run: python -m pip install uv
@@ -186,7 +186,7 @@ cython_debug/
186
186
  # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
187
  # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
188
  # you could uncomment the following to ignore the entire vscode folder
189
- # .vscode/
189
+ .vscode/
190
190
 
191
191
  # Ruff stuff:
192
192
  .ruff_cache/
@@ -207,4 +207,23 @@ marimo/_lsp/
207
207
  __marimo__/
208
208
 
209
209
  # uv files
210
- uv.lock
210
+ uv.lock
211
+
212
+ # profile files
213
+ dev/profiles/*
214
+
215
+ # Claude
216
+ .claude/
217
+ CLAUDE.md
218
+
219
+ # Reports
220
+ reports/
221
+
222
+ # HPC benchmarks (local only)
223
+ HPC_test/
224
+
225
+ # Ferry ignore patterns
226
+ .ferryignore
227
+
228
+ # Affinity lock files
229
+ *.af~lock~
@@ -0,0 +1,147 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on Keep a Changelog and the project follows Semantic Versioning.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.5.1] - 2026-11-06
10
+
11
+ ### Added
12
+
13
+ - Project logo: light/dark wordmark at the top of the README, plus icons, favicons and a GitHub social preview in
14
+ `logo/` (source file `logo/logos.af`). The `logo/` folder is excluded from the sdist.
15
+ - Documentation site at <https://davtax.github.io/ParameterRun/> (built with Zensical, checked on pull requests and deployed to GitHub Pages on every
16
+ push to `main`): user guide built from the README, API reference from the docstring, and changelog.
17
+
18
+ ## [0.5.0] - 2026-11-06
19
+
20
+ ### Added
21
+
22
+ - `shuffle_seed` parameter: seeds the permutation that distributes points among MPI ranks, making the distribution
23
+ reproducible. It was accepted by the MPI backend but never passed through. A keyword argument named `seed` is still
24
+ forwarded to the user function.
25
+ - `reshape="strict"` raises a `ValueError` when the result cannot be reshaped to the parameter grid.
26
+ - `RuntimeWarning` when some points return `None`, with the count and the parameters of the first one.
27
+ - `RuntimeWarning` when `backend="joblib"` with a negative `n_workers` runs inside an MPI job with more than one rank
28
+ (every rank would start a full-node pool).
29
+ - `on_error` parameter (`"raise"` by default, or `"nan"`) for exceptions raised by `fun`.
30
+ - `"raise"`: the exception keeps its type and gets the parameter values of the failing point as a note. Under MPI,
31
+ the failing rank prints the traceback once and calls `comm.Abort(1)`, instead of leaving the other ranks waiting
32
+ until the walltime limit.
33
+ - `"nan"`: failed points are filled with NaN of the right shape per output channel, and a `RuntimeWarning` reports
34
+ how many points failed and the traceback of the first one. If every point fails, a `RuntimeError` is raised.
35
+ - Dynamic MPI schedule (`mpi_schedule="dynamic"`): rank 0 becomes a manager that hands out chunks of points on demand,
36
+ and the other ranks compute. Fast ranks get more work, so the job no longer waits for the slowest rank. Numeric
37
+ outputs go straight into preallocated arrays on rank 0, the progress bar counts every point (not rank 0's share),
38
+ and with `on_error="raise"` the manager prints the failing point's traceback once and aborts the job. Results are
39
+ identical to the static schedule.
40
+ - `mpi_schedule` parameter: `"auto"` (default; dynamic with 8 ranks or more, static below), `"static"` or `"dynamic"`.
41
+ - `mpi_chunk_size` parameter: points per chunk for the dynamic schedule. The default (None) uses guided chunks that
42
+ shrink to one point at the end.
43
+ - `return_on` parameter: `"root"` (default), `"all"` (every MPI rank gets the result; numeric arrays are broadcast as
44
+ raw bytes, not pickled) or `"none"` (only the result file is written).
45
+ - `result_file` parameter: writes the result, reshaped to the grid, to a `.npy` file (one per output channel). Under
46
+ MPI, numeric outputs go into a memory-mapped file while the points arrive, so the result is no longer limited by
47
+ rank 0's memory.
48
+ - Checkpoints for long runs: `checkpoint` (a directory), `checkpoint_every` (points), `checkpoint_interval` (seconds,
49
+ 600 by default), `checkpoint_resume` (`"auto"`, `"force"`, `"restart"`) and `keep_checkpoint`. The finished points
50
+ are saved regularly, and calling `parameterrun` again with the same directory computes only the missing points, with
51
+ any backend, MPI schedule or number of ranks. Resuming checks the parameters, the extra keyword arguments and the code
52
+ of `fun` (bytecode, constants, defaults, closures, and helper functions of its module). The static MPI schedule
53
+ works in synchronised rounds between saves; the dynamic schedule saves without stopping the workers. `SIGUSR1`
54
+ saves at once (e.g. Slurm's `--signal=USR1@600`); `SIGTERM` saves, then ends the run. Snapshots are `.npz` files:
55
+ numeric outputs are stored without pickle, and outputs already in a memory-mapped `result_file` are not copied.
56
+
57
+ ### Changed
58
+
59
+ - `on_error`, `mpi_schedule`, `mpi_chunk_size`, `return_on`, `result_file` and the `checkpoint*` options are now
60
+ parameters of `parameterrun` itself, so keyword arguments with these names are no longer forwarded to `fun`.
61
+ - MPI, static schedule: results are no longer gathered as one pickled message per output channel. Numeric outputs are
62
+ sent as raw bytes in blocks of at most 64 MiB straight into preallocated arrays on rank 0. This removes the 2 GB
63
+ limit of pickled messages (`MPI_ERR_ARG` on large results) and most of rank 0's extra copies; non-numeric outputs
64
+ are still pickled. Both schedules now share this result store, so they return the same arrays.
65
+ - MPI: every call uses its own duplicated communicator, so messages of one call can never reach another.
66
+ - MPI runs with 8 ranks or more now use the dynamic schedule by default, which leaves rank 0 to the manager. Pass
67
+ `mpi_schedule="static"` for the previous behaviour.
68
+ - `backend=None` now falls back to joblib when `mpi4py` is installed but no MPI library is found, instead of failing
69
+ with `RuntimeError: cannot load MPI library`. `backend="mpi"` raises an `ImportError` that names the missing library.
70
+ - **Breaking:** dropped support for Python 3.9 and 3.10; `parameterrun` now requires Python >= 3.11.
71
+ - Added support for Python 3.13, 3.14 and 3.15 (classifiers and CI test matrix).
72
+ - A failed reshape now emits a `RuntimeWarning` that explains why, instead of printing "Could not reshape the result".
73
+ - `pbar_bool` now defaults to `None`: progress bars are shown on a terminal or in a notebook, hidden otherwise, and
74
+ `TQDM_DISABLE` is honoured. Forced bars on a non-terminal output (e.g. Slurm logs) print one plain line per refresh,
75
+ every 30 s by default (`TQDM_MININTERVAL` overrides it).
76
+ - MPI: rank 0 now waits for the workers with a blocking receive instead of a busy `Iprobe` loop.
77
+ - MPI: results are sorted with `np.argsort` instead of Python's `sorted`.
78
+
79
+ ### Removed
80
+
81
+ - The Open MPI 5.0.6 version-string workaround for the progress bar. Bars on MPI ranks whose stdout is a terminal now
82
+ end each refresh with a newline, so MPI launchers that forward output line by line show them with any MPI version.
83
+
84
+ ## [0.4.1] - 2026-04-21
85
+
86
+ ### Fixed
87
+
88
+ - Fix the display of the progress bar when running with `backend="joblib"`, since the previous implementation didn't
89
+ have access to the total number of runs to compute, which is required for the progress bar to work properly.
90
+
91
+ ### Added
92
+
93
+ - Added a test for the progress bar display when running with `backend="joblib"`.
94
+
95
+ ## [0.4.0] - 2026-04-21
96
+
97
+ ### Added
98
+
99
+ - Added `tests/test_mpi_integration.py` with MPI numerical-equivalence coverage for `parameterrun(..., backend="mpi")`.
100
+ - Added a dedicated Linux PR CI job that runs MPI tests with 4 ranks.
101
+
102
+ ### Changed
103
+
104
+ - Updated default test commands in docs and CI to run non-MPI tests with `-m "not mpi"`.
105
+ - Registered a pytest `mpi` marker in `pyproject.toml` for explicit MPI test selection.
106
+ - Update how the indices to compute are shared among workers. Previously, all the indices where computed by all workers,
107
+ which caused a significan overhead in the memory usage. Now, the indices are computed on the fly.
108
+
109
+ ## [0.3.0] - 2026-04-01
110
+
111
+ ### Changed
112
+
113
+ - Added `result_as_array` to `parameterrun(...)`: outputs are numpy arrays by default and can be converted to Python
114
+ lists with `result_as_array=False`.
115
+ - Removed the `pbar_kwargs` optional argument from `parameterrun(...)`, as it was unused.
116
+ - Added more tests for the depth of the parameter grid.
117
+ - Added the possibility to add parameter values as numpy arrays, which are converted to lists internally.
118
+
119
+ ## [0.2.1] - 2026-04-01
120
+
121
+ ### Added
122
+
123
+ - Modified GitHub Actions workflow to trigger on pull requests to the main branch, ensuring that all changes are
124
+ reviewed before merging.
125
+
126
+ ## [0.2.0] - 2026-03-26
127
+
128
+ ### Added
129
+
130
+ - Automated version management: single source of truth in `src/parameterrun/__init__.py`
131
+ - Version bump script `scripts/bump_version.py` for automatic version updates across all files
132
+ - VERSIONING.md guide for release workflows and version management
133
+ - `__version__` exported from main package: `from parameterrun import __version__`
134
+ - Dynamic version extraction in `pyproject.toml` (no more manual version updates needed)
135
+
136
+ ### Changed
137
+
138
+ - `parameterrun(..., reshape=True)` now reshapes outputs to the parameter-grid dimensions automatically (including
139
+ multi-output functions).
140
+ - Added early validation for duplicate parameter names, unknown swept parameters, unknown kwargs, and kwarg/sweep-name
141
+ conflicts.
142
+
143
+ ## [0.1.0] - 2026-03-25
144
+
145
+ ### Added
146
+
147
+ - Initial public release of `parameterrun`