pyRadMC 0.2.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.
- pyradmc-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- pyradmc-0.2.0/.github/workflows/ci.yml +158 -0
- pyradmc-0.2.0/.github/workflows/release.yml +114 -0
- pyradmc-0.2.0/.github/workflows/validation.yml +55 -0
- pyradmc-0.2.0/.gitignore +51 -0
- pyradmc-0.2.0/.gitlab-ci.yml +93 -0
- pyradmc-0.2.0/.pre-commit-config.yaml +51 -0
- pyradmc-0.2.0/.readthedocs.yaml +27 -0
- pyradmc-0.2.0/AGENTS.md +408 -0
- pyradmc-0.2.0/CHANGELOG.md +573 -0
- pyradmc-0.2.0/CITATION.cff +27 -0
- pyradmc-0.2.0/CLAUDE.md +53 -0
- pyradmc-0.2.0/CONTRIBUTING.md +111 -0
- pyradmc-0.2.0/LICENSE +201 -0
- pyradmc-0.2.0/NOTICE +60 -0
- pyradmc-0.2.0/PKG-INFO +162 -0
- pyradmc-0.2.0/README.md +102 -0
- pyradmc-0.2.0/docs/api.md +136 -0
- pyradmc-0.2.0/docs/assets/commissioning_vsm_example.png +0 -0
- pyradmc-0.2.0/docs/assets/dij_demo.png +0 -0
- pyradmc-0.2.0/docs/assets/electron_transport_demo.png +0 -0
- pyradmc-0.2.0/docs/assets/pencil_kernel_demo.png +0 -0
- pyradmc-0.2.0/docs/assets/reference_engine_demo.png +0 -0
- pyradmc-0.2.0/docs/assets/warp_backend_demo.png +0 -0
- pyradmc-0.2.0/docs/contributing.md +1 -0
- pyradmc-0.2.0/docs/data.md +88 -0
- pyradmc-0.2.0/docs/decisions.md +185 -0
- pyradmc-0.2.0/docs/getting-started.md +250 -0
- pyradmc-0.2.0/docs/index.md +66 -0
- pyradmc-0.2.0/docs/validation.md +86 -0
- pyradmc-0.2.0/examples/collimation_demo.py +298 -0
- pyradmc-0.2.0/examples/commissioning_vsm_example.py +3141 -0
- pyradmc-0.2.0/examples/ct_demo.py +165 -0
- pyradmc-0.2.0/examples/custom_source_demo.py +151 -0
- pyradmc-0.2.0/examples/dij_demo.py +243 -0
- pyradmc-0.2.0/examples/dose_grid_demo.py +221 -0
- pyradmc-0.2.0/examples/electron_transport_demo.py +153 -0
- pyradmc-0.2.0/examples/materials_demo.py +162 -0
- pyradmc-0.2.0/examples/noise_bias_study.py +557 -0
- pyradmc-0.2.0/examples/pencil_kernel_database.py +306 -0
- pyradmc-0.2.0/examples/pencil_kernel_demo.py +225 -0
- pyradmc-0.2.0/examples/phasespace_demo.py +186 -0
- pyradmc-0.2.0/examples/reference_engine_demo.py +280 -0
- pyradmc-0.2.0/examples/spectral_source_demo.py +162 -0
- pyradmc-0.2.0/examples/tabulated_demo.py +151 -0
- pyradmc-0.2.0/examples/virtual_source_demo.py +346 -0
- pyradmc-0.2.0/examples/warp_backend_demo.py +179 -0
- pyradmc-0.2.0/mkdocs.yml +68 -0
- pyradmc-0.2.0/pyproject.toml +171 -0
- pyradmc-0.2.0/pyradmc/__init__.py +308 -0
- pyradmc-0.2.0/pyradmc/adapters/__init__.py +9 -0
- pyradmc-0.2.0/pyradmc/adapters/ct.py +244 -0
- pyradmc-0.2.0/pyradmc/backends/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/backends/ref/__init__.py +5 -0
- pyradmc-0.2.0/pyradmc/backends/ref/engine.py +463 -0
- pyradmc-0.2.0/pyradmc/backends/results.py +115 -0
- pyradmc-0.2.0/pyradmc/backends/warp/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/backends/warp/engine.py +3451 -0
- pyradmc-0.2.0/pyradmc/backends/warp/kernels.py +2401 -0
- pyradmc-0.2.0/pyradmc/backends/warp/physics.py +211 -0
- pyradmc-0.2.0/pyradmc/backends/warp/presolve.py +742 -0
- pyradmc-0.2.0/pyradmc/data/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/data/analytic.py +321 -0
- pyradmc-0.2.0/pyradmc/data/berger_seltzer.py +240 -0
- pyradmc-0.2.0/pyradmc/data/goudsmit_saunderson.py +1122 -0
- pyradmc-0.2.0/pyradmc/data/handles.py +34 -0
- pyradmc-0.2.0/pyradmc/data/interface.py +437 -0
- pyradmc-0.2.0/pyradmc/data/materials.py +345 -0
- pyradmc-0.2.0/pyradmc/data/tables.py +362 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/__init__.py +10 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/build.py +211 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/eedl.py +315 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/endf.py +258 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/epdl.py +234 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/format.py +102 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/model.py +48 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/precompile.py +267 -0
- pyradmc-0.2.0/pyradmc/data/tabulated/source.py +241 -0
- pyradmc-0.2.0/pyradmc/geometry/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/geometry/collimation.py +1284 -0
- pyradmc-0.2.0/pyradmc/geometry/cylinder.py +118 -0
- pyradmc-0.2.0/pyradmc/geometry/fluence.py +147 -0
- pyradmc-0.2.0/pyradmc/geometry/grid.py +337 -0
- pyradmc-0.2.0/pyradmc/geometry/head.py +599 -0
- pyradmc-0.2.0/pyradmc/geometry/phasespace.py +769 -0
- pyradmc-0.2.0/pyradmc/geometry/source.py +1195 -0
- pyradmc-0.2.0/pyradmc/geometry/spectrum.py +310 -0
- pyradmc-0.2.0/pyradmc/physics/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/physics/brems.py +83 -0
- pyradmc-0.2.0/pyradmc/physics/channel.py +55 -0
- pyradmc-0.2.0/pyradmc/physics/compton.py +118 -0
- pyradmc-0.2.0/pyradmc/physics/direction.py +81 -0
- pyradmc-0.2.0/pyradmc/physics/gs.py +166 -0
- pyradmc-0.2.0/pyradmc/physics/moller.py +87 -0
- pyradmc-0.2.0/pyradmc/physics/msc.py +54 -0
- pyradmc-0.2.0/pyradmc/physics/path.py +35 -0
- pyradmc-0.2.0/pyradmc/physics/rayleigh.py +118 -0
- pyradmc-0.2.0/pyradmc/physics/roulette.py +34 -0
- pyradmc-0.2.0/pyradmc/progress.py +96 -0
- pyradmc-0.2.0/pyradmc/py.typed +0 -0
- pyradmc-0.2.0/pyradmc/rng/__init__.py +12 -0
- pyradmc-0.2.0/pyradmc/rng/host.py +48 -0
- pyradmc-0.2.0/pyradmc/rng/interface.py +64 -0
- pyradmc-0.2.0/pyradmc/rng/warp_shim.py +81 -0
- pyradmc-0.2.0/pyradmc/scoring/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/scoring/cylinder.py +513 -0
- pyradmc-0.2.0/pyradmc/scoring/dij.py +434 -0
- pyradmc-0.2.0/pyradmc/scoring/dose.py +207 -0
- pyradmc-0.2.0/pyradmc/scoring/dose_to_water.py +84 -0
- pyradmc-0.2.0/pyradmc/scoring/grid.py +219 -0
- pyradmc-0.2.0/pyradmc/study.py +150 -0
- pyradmc-0.2.0/pyradmc/transport/__init__.py +1 -0
- pyradmc-0.2.0/pyradmc/transport/electron.py +481 -0
- pyradmc-0.2.0/pyradmc/transport/history.py +150 -0
- pyradmc-0.2.0/pyradmc/transport/particles.py +102 -0
- pyradmc-0.2.0/pyradmc/transport/photon.py +348 -0
- pyradmc-0.2.0/tests/conftest.py +196 -0
- pyradmc-0.2.0/tests/dij/test_collimated_dij.py +133 -0
- pyradmc-0.2.0/tests/dij/test_custom_beamlet_source.py +88 -0
- pyradmc-0.2.0/tests/dij/test_custom_beamlet_source_warp.py +111 -0
- pyradmc-0.2.0/tests/dij/test_custom_beamlet_source_warp_kernel.py +157 -0
- pyradmc-0.2.0/tests/dij/test_dij_concurrent_batches.py +142 -0
- pyradmc-0.2.0/tests/dij/test_dij_correlated.py +265 -0
- pyradmc-0.2.0/tests/dij/test_dij_multi_device.py +175 -0
- pyradmc-0.2.0/tests/dij/test_dij_progress.py +186 -0
- pyradmc-0.2.0/tests/dij/test_dij_ref.py +212 -0
- pyradmc-0.2.0/tests/dij/test_dij_scoring_grid.py +177 -0
- pyradmc-0.2.0/tests/dij/test_dij_warp.py +339 -0
- pyradmc-0.2.0/tests/dij/test_mask_dij.py +65 -0
- pyradmc-0.2.0/tests/dij/test_primary_fluence_dij.py +124 -0
- pyradmc-0.2.0/tests/dij/test_spectral_source_dij.py +63 -0
- pyradmc-0.2.0/tests/dij/test_spectral_source_warp.py +158 -0
- pyradmc-0.2.0/tests/dij/test_weighted_beamlet_ledger.py +168 -0
- pyradmc-0.2.0/tests/integration/test_attenuation.py +133 -0
- pyradmc-0.2.0/tests/integration/test_boundary_truncation.py +110 -0
- pyradmc-0.2.0/tests/integration/test_broad_beam.py +98 -0
- pyradmc-0.2.0/tests/integration/test_channel_complete.py +105 -0
- pyradmc-0.2.0/tests/integration/test_collimated_transport.py +131 -0
- pyradmc-0.2.0/tests/integration/test_composite_source_transport.py +95 -0
- pyradmc-0.2.0/tests/integration/test_custom_source_warp.py +127 -0
- pyradmc-0.2.0/tests/integration/test_custom_source_warp_kernel.py +115 -0
- pyradmc-0.2.0/tests/integration/test_deposit_resolution.py +208 -0
- pyradmc-0.2.0/tests/integration/test_device_presolve_transport.py +181 -0
- pyradmc-0.2.0/tests/integration/test_dose_to_water.py +140 -0
- pyradmc-0.2.0/tests/integration/test_electron_transport.py +158 -0
- pyradmc-0.2.0/tests/integration/test_engine_invariants.py +63 -0
- pyradmc-0.2.0/tests/integration/test_gaussian_spot_transport.py +80 -0
- pyradmc-0.2.0/tests/integration/test_gs_step_schedule.py +150 -0
- pyradmc-0.2.0/tests/integration/test_gs_transport_warp.py +243 -0
- pyradmc-0.2.0/tests/integration/test_head_presolve_transport.py +160 -0
- pyradmc-0.2.0/tests/integration/test_inmemory_phasespace_transport.py +104 -0
- pyradmc-0.2.0/tests/integration/test_multimaterial_transport.py +101 -0
- pyradmc-0.2.0/tests/integration/test_pencil_kernel_transport.py +324 -0
- pyradmc-0.2.0/tests/integration/test_phasespace_transport.py +97 -0
- pyradmc-0.2.0/tests/integration/test_primary_fluence_transport.py +125 -0
- pyradmc-0.2.0/tests/integration/test_result_provenance.py +150 -0
- pyradmc-0.2.0/tests/integration/test_roulette_transport.py +90 -0
- pyradmc-0.2.0/tests/integration/test_run_concurrent_batches.py +137 -0
- pyradmc-0.2.0/tests/integration/test_scoring_grid_transport.py +157 -0
- pyradmc-0.2.0/tests/integration/test_spectral_source_inkernel_warp.py +153 -0
- pyradmc-0.2.0/tests/integration/test_split_transport.py +202 -0
- pyradmc-0.2.0/tests/integration/test_step_energy_fraction_knob.py +148 -0
- pyradmc-0.2.0/tests/integration/test_transmission_mask_warp.py +126 -0
- pyradmc-0.2.0/tests/integration/test_warp_backend.py +198 -0
- pyradmc-0.2.0/tests/integration/test_warp_device_reduction.py +733 -0
- pyradmc-0.2.0/tests/integration/test_warp_dose_to_water.py +144 -0
- pyradmc-0.2.0/tests/integration/test_warp_material_narrowing.py +53 -0
- pyradmc-0.2.0/tests/integration/test_warp_phasespace.py +159 -0
- pyradmc-0.2.0/tests/integration/test_warp_physics_import_leak.py +62 -0
- pyradmc-0.2.0/tests/integration/test_warp_scoring_grid.py +166 -0
- pyradmc-0.2.0/tests/integration/test_warp_table_cache.py +77 -0
- pyradmc-0.2.0/tests/perf/test_ct_throughput.py +138 -0
- pyradmc-0.2.0/tests/perf/test_dij_throughput.py +97 -0
- pyradmc-0.2.0/tests/perf/test_warp_throughput.py +82 -0
- pyradmc-0.2.0/tests/phsp_fixtures.py +98 -0
- pyradmc-0.2.0/tests/physics/test_channel_selection.py +86 -0
- pyradmc-0.2.0/tests/physics/test_compton_sampling.py +152 -0
- pyradmc-0.2.0/tests/physics/test_direction_sampling.py +99 -0
- pyradmc-0.2.0/tests/physics/test_electron_sampling.py +192 -0
- pyradmc-0.2.0/tests/physics/test_path_sampling.py +63 -0
- pyradmc-0.2.0/tests/physics/test_presolve_compton.py +68 -0
- pyradmc-0.2.0/tests/physics/test_rayleigh_sampling.py +124 -0
- pyradmc-0.2.0/tests/physics/test_roulette_sampling.py +65 -0
- pyradmc-0.2.0/tests/physics/test_substep_deposit_spread.py +141 -0
- pyradmc-0.2.0/tests/physics/test_warp_boundary_distance.py +134 -0
- pyradmc-0.2.0/tests/physics/test_warp_collimation_geometry.py +217 -0
- pyradmc-0.2.0/tests/physics/test_warp_compiled_stack.py +125 -0
- pyradmc-0.2.0/tests/physics/test_warp_gs_sampler.py +207 -0
- pyradmc-0.2.0/tests/physics/test_warp_physics.py +313 -0
- pyradmc-0.2.0/tests/physics/test_warp_presolve.py +226 -0
- pyradmc-0.2.0/tests/unit/test_beamlet_source.py +121 -0
- pyradmc-0.2.0/tests/unit/test_berger_seltzer.py +156 -0
- pyradmc-0.2.0/tests/unit/test_build.py +166 -0
- pyradmc-0.2.0/tests/unit/test_collimated_source.py +206 -0
- pyradmc-0.2.0/tests/unit/test_collimation.py +675 -0
- pyradmc-0.2.0/tests/unit/test_composite_sources.py +115 -0
- pyradmc-0.2.0/tests/unit/test_cross_sections_water.py +82 -0
- pyradmc-0.2.0/tests/unit/test_ct_calibration.py +160 -0
- pyradmc-0.2.0/tests/unit/test_ct_reader.py +121 -0
- pyradmc-0.2.0/tests/unit/test_cylindrical_scoring.py +419 -0
- pyradmc-0.2.0/tests/unit/test_dij_group_autosize.py +58 -0
- pyradmc-0.2.0/tests/unit/test_dij_scoring.py +291 -0
- pyradmc-0.2.0/tests/unit/test_dose_to_water_spr.py +103 -0
- pyradmc-0.2.0/tests/unit/test_eedl.py +328 -0
- pyradmc-0.2.0/tests/unit/test_elastic_screening.py +172 -0
- pyradmc-0.2.0/tests/unit/test_electron_data.py +213 -0
- pyradmc-0.2.0/tests/unit/test_endf.py +79 -0
- pyradmc-0.2.0/tests/unit/test_epdl.py +155 -0
- pyradmc-0.2.0/tests/unit/test_gaussian_spot_source.py +192 -0
- pyradmc-0.2.0/tests/unit/test_geometry.py +200 -0
- pyradmc-0.2.0/tests/unit/test_gs_grid.py +340 -0
- pyradmc-0.2.0/tests/unit/test_gs_moments.py +319 -0
- pyradmc-0.2.0/tests/unit/test_gs_sampler.py +390 -0
- pyradmc-0.2.0/tests/unit/test_head_presolve.py +318 -0
- pyradmc-0.2.0/tests/unit/test_iaea_phsp.py +275 -0
- pyradmc-0.2.0/tests/unit/test_icrp_media.py +167 -0
- pyradmc-0.2.0/tests/unit/test_inmemory_phasespace.py +153 -0
- pyradmc-0.2.0/tests/unit/test_interface_contracts.py +281 -0
- pyradmc-0.2.0/tests/unit/test_materials.py +129 -0
- pyradmc-0.2.0/tests/unit/test_oracle_power.py +116 -0
- pyradmc-0.2.0/tests/unit/test_phasespace_source.py +161 -0
- pyradmc-0.2.0/tests/unit/test_precompile.py +37 -0
- pyradmc-0.2.0/tests/unit/test_primary_fluence_source.py +285 -0
- pyradmc-0.2.0/tests/unit/test_progress.py +94 -0
- pyradmc-0.2.0/tests/unit/test_public_api.py +135 -0
- pyradmc-0.2.0/tests/unit/test_radial_fluence.py +142 -0
- pyradmc-0.2.0/tests/unit/test_range_tables.py +74 -0
- pyradmc-0.2.0/tests/unit/test_restricted_range.py +73 -0
- pyradmc-0.2.0/tests/unit/test_scattering_power_anchor.py +147 -0
- pyradmc-0.2.0/tests/unit/test_scoring.py +164 -0
- pyradmc-0.2.0/tests/unit/test_scoring_grid.py +144 -0
- pyradmc-0.2.0/tests/unit/test_source_interface.py +118 -0
- pyradmc-0.2.0/tests/unit/test_spectral_source.py +274 -0
- pyradmc-0.2.0/tests/unit/test_spectrum.py +252 -0
- pyradmc-0.2.0/tests/unit/test_study.py +118 -0
- pyradmc-0.2.0/tests/unit/test_tables.py +336 -0
- pyradmc-0.2.0/tests/unit/test_tabulated_format.py +102 -0
- pyradmc-0.2.0/tests/unit/test_tabulated_source.py +188 -0
- pyradmc-0.2.0/tests/unit/test_transmission_mask.py +178 -0
- pyradmc-0.2.0/tests/unit/test_tungsten.py +125 -0
- pyradmc-0.2.0/tests/unit/test_tungsten_alloy.py +156 -0
- pyradmc-0.2.0/tests/unit/test_warp_module_options.py +45 -0
- pyradmc-0.2.0/tests/unit/test_warp_rng.py +147 -0
- pyradmc-0.2.0/tests/unit/test_warp_sizing.py +143 -0
- pyradmc-0.2.0/tests/validation/data/README.md +34 -0
- pyradmc-0.2.0/tests/validation/data/center_ray_dose_EGSNrc_intRadius6.0mm.txt +201 -0
- pyradmc-0.2.0/tests/validation/test_ali_rogers_mu_parameterization.py +121 -0
- pyradmc-0.2.0/tests/validation/test_eedl_water_estar.py +65 -0
- pyradmc-0.2.0/tests/validation/test_eedl_water_scattering.py +98 -0
- pyradmc-0.2.0/tests/validation/test_epdl_water_nist.py +113 -0
- pyradmc-0.2.0/tests/validation/test_epics_library_digests.py +74 -0
- pyradmc-0.2.0/tests/validation/test_gs_eta_ladder.py +160 -0
- pyradmc-0.2.0/tests/validation/test_gs_thorax_cross_backend.py +147 -0
- pyradmc-0.2.0/tests/validation/test_penumbra_width.py +169 -0
- pyradmc-0.2.0/tests/validation/test_ranges_and_pdd.py +367 -0
- pyradmc-0.2.0/tests/validation/test_tabulated_materials_compile.py +190 -0
- pyradmc-0.2.0/tests/validation/test_tabulated_water_compile.py +204 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The PR title becomes the squash-commit subject on develop. It should follow
|
|
3
|
+
AGENTS.md 9.2: type(scope): imperative description
|
|
4
|
+
(description <= 50 chars; whole line <= 72)
|
|
5
|
+
The description below becomes the commit body: wrap lines at 72.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
## What and why
|
|
9
|
+
|
|
10
|
+
<!-- The physics / the reasoning, not the diff. Measurements go here. -->
|
|
11
|
+
|
|
12
|
+
## Checklist
|
|
13
|
+
|
|
14
|
+
- [ ] A failing test motivated this change (AGENTS.md 2.1)
|
|
15
|
+
- [ ] `pre-commit run --all-files` and `pytest` pass locally
|
|
16
|
+
- [ ] Docs, README and docstrings this change made stale are updated
|
|
17
|
+
- [ ] If a user-visible capability: a runnable example under `examples/`
|
|
18
|
+
- [ ] If it can move a computed dose: `CHANGELOG.md` entry + the measurement
|
|
19
|
+
- [ ] If it touches `ECUT`/`PCUT`/truncation/step defaults: the dosimetric-effect
|
|
20
|
+
test of AGENTS.md 2.8 is included
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# GitHub is the primary remote (AGENTS.md 9): task branches squash-merge into develop
|
|
4
|
+
# through pull requests, and releases merge rc/* into main. The DKFZ GitLab mirror runs
|
|
5
|
+
# its own validate-only pipeline (.gitlab-ci.yml).
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
# rc/** included so a release candidate builds its wheel even before the PR exists.
|
|
9
|
+
branches: [main, develop, "rc/**"]
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: [main, develop]
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ci-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
23
|
+
FORCE_COLOR: "1"
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
quality:
|
|
27
|
+
name: lint, format, types
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.13"
|
|
34
|
+
cache: pip
|
|
35
|
+
cache-dependency-path: pyproject.toml
|
|
36
|
+
# The warp extra is installed for mypy: it type-checks the engine modules that
|
|
37
|
+
# import warp, even though the kernels themselves are exempt (AGENTS.md 5).
|
|
38
|
+
- run: pip install -e ".[warp,dev]"
|
|
39
|
+
- uses: actions/cache@v4
|
|
40
|
+
with:
|
|
41
|
+
path: ~/.cache/pre-commit
|
|
42
|
+
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
|
|
43
|
+
# Run the hook definitions rather than re-listing the tools here. The pinned revs
|
|
44
|
+
# in .pre-commit-config.yaml are then the single authority: CI and a developer's
|
|
45
|
+
# commit hook cannot disagree, and neither can drift onto a new linter release.
|
|
46
|
+
# (mypy is a `language: system` hook, so it uses the environment installed above.)
|
|
47
|
+
- run: pre-commit run --all-files --show-diff-on-failure
|
|
48
|
+
|
|
49
|
+
test:
|
|
50
|
+
name: tests (py${{ matrix.python }}, ${{ matrix.os }})
|
|
51
|
+
runs-on: ${{ matrix.os }}
|
|
52
|
+
strategy:
|
|
53
|
+
fail-fast: false
|
|
54
|
+
matrix:
|
|
55
|
+
os: [ubuntu-latest]
|
|
56
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
57
|
+
include:
|
|
58
|
+
# Coverage wherever it is nearly free, which is every job on 3.12+: the
|
|
59
|
+
# sysmon core below costs 1.01x, so these keep measuring (Codecov merges
|
|
60
|
+
# the uploads for a commit). It is dropped only from 3.10 and 3.11, where
|
|
61
|
+
# sys.monitoring does not exist and coverage.py falls back to the C tracer
|
|
62
|
+
# -- measured at 2.09x on the full fast suite, which is what made running
|
|
63
|
+
# it on all five jobs expensive. These merge into the matrix combinations
|
|
64
|
+
# they name rather than adding jobs, since every key here matches one.
|
|
65
|
+
- os: ubuntu-latest
|
|
66
|
+
python: "3.12"
|
|
67
|
+
coverage: true
|
|
68
|
+
- os: ubuntu-latest
|
|
69
|
+
python: "3.13"
|
|
70
|
+
coverage: true
|
|
71
|
+
# The maintainer develops on Windows, and several past bugs were
|
|
72
|
+
# Windows-specific (path handling, subprocess behaviour). One job keeps that
|
|
73
|
+
# platform honest without quadrupling the matrix -- and it carries coverage
|
|
74
|
+
# so that a Windows-only branch still reaches the report.
|
|
75
|
+
- os: windows-latest
|
|
76
|
+
python: "3.13"
|
|
77
|
+
coverage: true
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
- uses: actions/setup-python@v5
|
|
81
|
+
with:
|
|
82
|
+
python-version: ${{ matrix.python }}
|
|
83
|
+
cache: pip
|
|
84
|
+
cache-dependency-path: pyproject.toml
|
|
85
|
+
- run: pip install -e ".[warp,dev]"
|
|
86
|
+
# Runners have no CUDA device: warp runs on CPU and the gpu-marked tests skip
|
|
87
|
+
# themselves via wp.is_cuda_available(). The validation and perf tiers are
|
|
88
|
+
# excluded by the default addopts; validation runs on its own schedule.
|
|
89
|
+
# COVERAGE_CORE=sysmon puts coverage.py on CPython's sys.monitoring (3.12+)
|
|
90
|
+
# instead of its C tracer, which is what makes coverage affordable at all here:
|
|
91
|
+
# same suite, 630 s under the tracer against 308 s under sysmon and 304 s with
|
|
92
|
+
# no coverage — 2.09x overhead down to 1.01x. Set at job level and inert on the
|
|
93
|
+
# jobs that pass no --cov, which are exactly the pre-3.12 ones, so no job ever
|
|
94
|
+
# asks for a core it lacks. (No branch coverage is configured; that is the one
|
|
95
|
+
# feature the sysmon core does not support.)
|
|
96
|
+
- env:
|
|
97
|
+
COVERAGE_CORE: sysmon
|
|
98
|
+
run: pytest -q ${{ matrix.coverage && '--cov' || '' }} --junitxml=junit.xml -o junit_family=legacy
|
|
99
|
+
- name: Upload coverage to Codecov
|
|
100
|
+
if: ${{ matrix.coverage && !cancelled() }}
|
|
101
|
+
uses: codecov/codecov-action@v5
|
|
102
|
+
with:
|
|
103
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
104
|
+
# Same action twice: codecov deprecated test-results-action@v1 in favor of
|
|
105
|
+
# codecov-action with report_type, run once per report kind.
|
|
106
|
+
- name: Upload test results to Codecov
|
|
107
|
+
if: ${{ !cancelled() }}
|
|
108
|
+
uses: codecov/codecov-action@v5
|
|
109
|
+
with:
|
|
110
|
+
report_type: test_results
|
|
111
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
112
|
+
|
|
113
|
+
docs:
|
|
114
|
+
name: docs build
|
|
115
|
+
runs-on: ubuntu-latest
|
|
116
|
+
steps:
|
|
117
|
+
- uses: actions/checkout@v4
|
|
118
|
+
- uses: actions/setup-python@v5
|
|
119
|
+
with:
|
|
120
|
+
python-version: "3.13"
|
|
121
|
+
cache: pip
|
|
122
|
+
cache-dependency-path: pyproject.toml
|
|
123
|
+
- run: pip install -e ".[docs]"
|
|
124
|
+
# --strict turns broken references and missing nav entries into failures. The API
|
|
125
|
+
# reference is generated from the source, so a renamed public symbol breaks the
|
|
126
|
+
# docs build here rather than silently emptying a page on ReadTheDocs.
|
|
127
|
+
- run: mkdocs build --strict
|
|
128
|
+
|
|
129
|
+
build:
|
|
130
|
+
name: build distributions
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
steps:
|
|
133
|
+
- uses: actions/checkout@v4
|
|
134
|
+
- uses: actions/setup-python@v5
|
|
135
|
+
with:
|
|
136
|
+
python-version: "3.13"
|
|
137
|
+
cache: pip
|
|
138
|
+
- run: pip install build twine
|
|
139
|
+
- run: python -m build
|
|
140
|
+
- run: twine check dist/*
|
|
141
|
+
# Installing the built wheel into a clean environment is the only check that
|
|
142
|
+
# catches a package that imports fine from the source tree but ships broken:
|
|
143
|
+
# a missing py.typed, a subpackage left out of the wheel, a bad entry point.
|
|
144
|
+
- name: verify the wheel installs and imports standalone
|
|
145
|
+
run: |
|
|
146
|
+
python -m venv /tmp/fresh
|
|
147
|
+
/tmp/fresh/bin/pip install dist/*.whl
|
|
148
|
+
/tmp/fresh/bin/python -c "
|
|
149
|
+
import pyradmc, pathlib
|
|
150
|
+
print('version', pyradmc.__version__)
|
|
151
|
+
assert (pathlib.Path(pyradmc.__file__).parent / 'py.typed').is_file(), 'py.typed missing from wheel'
|
|
152
|
+
assert pyradmc.VoxelGrid is not None
|
|
153
|
+
print('public names:', len(pyradmc.__all__))
|
|
154
|
+
"
|
|
155
|
+
- uses: actions/upload-artifact@v4
|
|
156
|
+
with:
|
|
157
|
+
name: distributions
|
|
158
|
+
path: dist/
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Tagging is the release action: the tag lands on an rc/* merge commit on main, per the
|
|
4
|
+
# release flow of AGENTS.md 9.4. A manual dispatch builds and verifies only — the
|
|
5
|
+
# publish jobs are gated on a v* tag ref, so nothing can reach PyPI without one.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
name: build and verify
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.13"
|
|
26
|
+
cache: pip
|
|
27
|
+
|
|
28
|
+
# The version is single-sourced from pyradmc/__init__.py, so a tag is a *claim*
|
|
29
|
+
# about it that nothing else checks. A mismatch here would publish a release whose
|
|
30
|
+
# artifacts report a different version than the tag they were cut from — and every
|
|
31
|
+
# RunProvenance record stamped by that build would carry the wrong number. Refuse.
|
|
32
|
+
- name: tag must match pyradmc.__version__
|
|
33
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
34
|
+
run: |
|
|
35
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
36
|
+
version=$(python -c "import re,pathlib; print(re.search(r'__version__ = \"([^\"]+)\"', pathlib.Path('pyradmc/__init__.py').read_text()).group(1))")
|
|
37
|
+
echo "tag=$tag __version__=$version"
|
|
38
|
+
if [ "$tag" != "$version" ]; then
|
|
39
|
+
echo "::error::tag v$tag does not match pyradmc.__version__ ($version)"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# A stale CITATION.cff is how a release ends up being cited as the previous one.
|
|
44
|
+
- name: CITATION.cff version must match the release
|
|
45
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
46
|
+
run: |
|
|
47
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
48
|
+
cited=$(grep -E '^version:' CITATION.cff | head -1 | sed 's/version:[[:space:]]*//' | tr -d '"')
|
|
49
|
+
echo "tag=$tag CITATION.cff=$cited"
|
|
50
|
+
if [ "$tag" != "$cited" ]; then
|
|
51
|
+
echo "::error::CITATION.cff says $cited but the tag is v$tag; update it before releasing"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
- run: pip install build twine
|
|
56
|
+
- run: python -m build
|
|
57
|
+
- run: twine check dist/*
|
|
58
|
+
|
|
59
|
+
- name: verify the wheel installs and imports standalone
|
|
60
|
+
run: |
|
|
61
|
+
python -m venv /tmp/fresh
|
|
62
|
+
/tmp/fresh/bin/pip install dist/*.whl
|
|
63
|
+
/tmp/fresh/bin/python -c "
|
|
64
|
+
import pyradmc, pathlib
|
|
65
|
+
assert (pathlib.Path(pyradmc.__file__).parent / 'py.typed').is_file()
|
|
66
|
+
print('ok', pyradmc.__version__)
|
|
67
|
+
"
|
|
68
|
+
|
|
69
|
+
- uses: actions/upload-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
name: distributions
|
|
72
|
+
path: dist/
|
|
73
|
+
|
|
74
|
+
publish:
|
|
75
|
+
name: publish to PyPI
|
|
76
|
+
needs: build
|
|
77
|
+
# Only ever from a version tag: a workflow_dispatch run stops after build.
|
|
78
|
+
if: success() && startsWith(github.ref, 'refs/tags/v')
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
# Trusted publishing (OIDC): PyPI verifies this workflow's identity directly, so
|
|
81
|
+
# there is no long-lived API token to store or rotate. Configure the publisher once
|
|
82
|
+
# at https://pypi.org/manage/project/pyradmc/settings/publishing/ with
|
|
83
|
+
# owner e0404, repository pyRadMC, workflow release.yml, environment pypi.
|
|
84
|
+
environment:
|
|
85
|
+
name: pypi
|
|
86
|
+
url: https://pypi.org/p/pyRadMC
|
|
87
|
+
permissions:
|
|
88
|
+
id-token: write
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/download-artifact@v4
|
|
91
|
+
with:
|
|
92
|
+
name: distributions
|
|
93
|
+
path: dist/
|
|
94
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
95
|
+
|
|
96
|
+
github-release:
|
|
97
|
+
name: GitHub release
|
|
98
|
+
needs: publish
|
|
99
|
+
if: success() && startsWith(github.ref, 'refs/tags/v')
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
permissions:
|
|
102
|
+
contents: write
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/download-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: distributions
|
|
107
|
+
path: dist/
|
|
108
|
+
- uses: softprops/action-gh-release@v2
|
|
109
|
+
with:
|
|
110
|
+
files: dist/*
|
|
111
|
+
generate_release_notes: true
|
|
112
|
+
body: |
|
|
113
|
+
See [CHANGELOG.md](https://github.com/e0404/pyRadMC/blob/main/CHANGELOG.md)
|
|
114
|
+
for what changed, including anything that can move a computed dose.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Validation tier
|
|
2
|
+
|
|
3
|
+
# Deliberately NOT on push: the validation tier is slow, needs the ~120 MB EPICS
|
|
4
|
+
# libraries, and gates physics rather than code. AGENTS.md section 7 requires it to pass
|
|
5
|
+
# before a release, so it runs on a schedule (to catch rot) and on demand (before
|
|
6
|
+
# tagging), not on every commit.
|
|
7
|
+
on:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "0 3 * * 1" # Mondays, 03:00 UTC
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
validation:
|
|
17
|
+
name: validation tier (with EPICS libraries)
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 120
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.13"
|
|
25
|
+
cache: pip
|
|
26
|
+
cache-dependency-path: pyproject.toml
|
|
27
|
+
- run: pip install -e ".[warp,dev]"
|
|
28
|
+
|
|
29
|
+
# Cached so a scheduled run does not re-fetch 120 MB from the IAEA every week.
|
|
30
|
+
# The cache key carries the pinned digests, so changing a pin necessarily misses
|
|
31
|
+
# the cache and re-downloads — which is the correct behaviour, since a changed pin
|
|
32
|
+
# means the libraries themselves are supposed to be different.
|
|
33
|
+
- name: cache EPICS libraries
|
|
34
|
+
id: epics-cache
|
|
35
|
+
uses: actions/cache@v4
|
|
36
|
+
with:
|
|
37
|
+
path: ~/.cache/pyradmc/epics
|
|
38
|
+
key: epics-2023-${{ hashFiles('pyradmc/data/tabulated/build.py') }}
|
|
39
|
+
|
|
40
|
+
# download_library verifies every file against its pinned SHA-256 and fails
|
|
41
|
+
# closed. This is also what exercises the pins themselves in CI: a silent upstream
|
|
42
|
+
# revision shows up here as a hard failure rather than as drift in a dose gate.
|
|
43
|
+
- name: fetch and verify EPICS libraries
|
|
44
|
+
run: |
|
|
45
|
+
python -c "
|
|
46
|
+
from pyradmc.data.tabulated import build
|
|
47
|
+
for which in ('epdl', 'eedl'):
|
|
48
|
+
print(which, '->', build.download_library(which))
|
|
49
|
+
"
|
|
50
|
+
|
|
51
|
+
- name: run the validation tier
|
|
52
|
+
env:
|
|
53
|
+
PYRADMC_EPDL_PATH: ~/.cache/pyradmc/epics/EPDL2023.ALL
|
|
54
|
+
PYRADMC_EEDL_PATH: ~/.cache/pyradmc/epics/EEDL2023.ALL
|
|
55
|
+
run: pytest -m validation -q
|
pyradmc-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.hypothesis/
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
.benchmarks/
|
|
12
|
+
|
|
13
|
+
# Compiled tabulated cross-section tables: derived from the (uncommitted, user-side)
|
|
14
|
+
# EPICS libraries by pyradmc.data.tabulated.build, so not tracked.
|
|
15
|
+
*.npz
|
|
16
|
+
|
|
17
|
+
# Phase-space demo outputs derive from an external (proprietary, machine-local)
|
|
18
|
+
# phase-space file and are not reproducible in the repo, so they are not tracked.
|
|
19
|
+
examples/phasespace_demo.png
|
|
20
|
+
examples/phasespace_demo.csv
|
|
21
|
+
site/
|
|
22
|
+
|
|
23
|
+
# Vendor beam data and anything fitted from it. The workbook a head is commissioned
|
|
24
|
+
# against is licensed to its owner, not to this repository, and at ~500 KB it slips
|
|
25
|
+
# under the check-added-large-files gate rather than being caught by it. The fitted
|
|
26
|
+
# radial-fluence table is derived from those measured profiles, so it travels with
|
|
27
|
+
# them: the shipped default is the analytic cone, and PRIMARY_FLUENCE_FILE is the hook
|
|
28
|
+
# for the table you fit against your own data.
|
|
29
|
+
*.xlsx
|
|
30
|
+
examples/halcyon_primary_fluence.dat
|
|
31
|
+
|
|
32
|
+
# Everything the examples render. They are regenerable by definition -- that is what an
|
|
33
|
+
# example is -- and tracking them cost ~5 MB of binaries that no reader of the repository
|
|
34
|
+
# opens from here, churned on every re-run, and went stale against the scripts that write
|
|
35
|
+
# them. The figures the README embeds live in docs/assets/ instead, which is where a
|
|
36
|
+
# documentation asset belongs; an example's own output is not one.
|
|
37
|
+
examples/*.png
|
|
38
|
+
examples/*.csv
|
|
39
|
+
|
|
40
|
+
# Local scratch: comparison scripts, sweeps and figures that need the vendor workbook,
|
|
41
|
+
# plus the run logs they were driven from. Not reproducible here, so not tracked.
|
|
42
|
+
local_*
|
|
43
|
+
*.log
|
|
44
|
+
|
|
45
|
+
.vscode/
|
|
46
|
+
|
|
47
|
+
# Coverage and test-result artifacts (pytest --cov / --junitxml, uploaded to Codecov in CI)
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
coverage.xml
|
|
51
|
+
junit.xml
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# GitLab CI for the DKFZ GitLab mirror. GitHub (github.com/e0404/pyRadMC) is the
|
|
2
|
+
# primary remote (AGENTS.md 9): pull requests, reviews and releases happen there.
|
|
3
|
+
#
|
|
4
|
+
# This pipeline VALIDATES ONLY — there is deliberately no deploy stage. Releases
|
|
5
|
+
# (PyPI, GitHub Releases) and the documentation build run from GitHub, where trusted
|
|
6
|
+
# publishing and ReadTheDocs are wired up; see .github/workflows/release.yml. Keeping
|
|
7
|
+
# publication in exactly one place is what prevents two pipelines racing to upload the
|
|
8
|
+
# same version.
|
|
9
|
+
#
|
|
10
|
+
# The validation tier is not here either: it needs the ~120 MB EPICS libraries and runs
|
|
11
|
+
# on a schedule in .github/workflows/validation.yml.
|
|
12
|
+
|
|
13
|
+
stages: [check, test, build]
|
|
14
|
+
|
|
15
|
+
default:
|
|
16
|
+
image: python:3.13-slim
|
|
17
|
+
# Warp and SciPy wheels are large; caching pip keeps repeat pipelines cheap.
|
|
18
|
+
cache:
|
|
19
|
+
key:
|
|
20
|
+
files: [pyproject.toml]
|
|
21
|
+
paths: [.cache/pip]
|
|
22
|
+
before_script:
|
|
23
|
+
- python -V
|
|
24
|
+
- pip install --quiet --upgrade pip
|
|
25
|
+
|
|
26
|
+
variables:
|
|
27
|
+
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
|
28
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
29
|
+
|
|
30
|
+
workflow:
|
|
31
|
+
rules:
|
|
32
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
33
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
34
|
+
- if: $CI_COMMIT_BRANCH == "develop"
|
|
35
|
+
- if: $CI_PIPELINE_SOURCE == "web"
|
|
36
|
+
|
|
37
|
+
quality:
|
|
38
|
+
stage: check
|
|
39
|
+
variables:
|
|
40
|
+
PRE_COMMIT_HOME: "$CI_PROJECT_DIR/.cache/pre-commit"
|
|
41
|
+
cache:
|
|
42
|
+
key:
|
|
43
|
+
files: [.pre-commit-config.yaml]
|
|
44
|
+
paths: [.cache/pre-commit, .cache/pip]
|
|
45
|
+
script:
|
|
46
|
+
- pip install --quiet -e ".[warp,dev]"
|
|
47
|
+
# Run the hook definitions rather than re-listing the tools. The pinned revs in
|
|
48
|
+
# .pre-commit-config.yaml are the single authority, so this pipeline, the GitHub
|
|
49
|
+
# one, and a developer's commit hook cannot disagree or drift onto a new release.
|
|
50
|
+
- pre-commit run --all-files --show-diff-on-failure
|
|
51
|
+
before_script:
|
|
52
|
+
- python -V
|
|
53
|
+
- pip install --quiet --upgrade pip
|
|
54
|
+
- git config --global --add safe.directory "$CI_PROJECT_DIR"
|
|
55
|
+
|
|
56
|
+
tests:
|
|
57
|
+
stage: test
|
|
58
|
+
parallel:
|
|
59
|
+
matrix:
|
|
60
|
+
- PYTHON_VERSION: ["3.10", "3.11", "3.12", "3.13"]
|
|
61
|
+
image: python:$PYTHON_VERSION-slim
|
|
62
|
+
script:
|
|
63
|
+
- pip install --quiet -e ".[warp,dev]"
|
|
64
|
+
# No CUDA device on a standard runner: warp runs on CPU and the gpu-marked tests
|
|
65
|
+
# skip themselves. The default addopts already exclude the validation and perf tiers.
|
|
66
|
+
- pytest -q --junitxml=report.xml
|
|
67
|
+
artifacts:
|
|
68
|
+
when: always
|
|
69
|
+
reports:
|
|
70
|
+
junit: report.xml
|
|
71
|
+
expire_in: 1 week
|
|
72
|
+
|
|
73
|
+
docs:
|
|
74
|
+
stage: check
|
|
75
|
+
script:
|
|
76
|
+
- pip install --quiet -e ".[docs]"
|
|
77
|
+
# --strict only; the built site is not published from here.
|
|
78
|
+
- mkdocs build --strict
|
|
79
|
+
|
|
80
|
+
build:
|
|
81
|
+
stage: build
|
|
82
|
+
script:
|
|
83
|
+
- pip install --quiet build twine
|
|
84
|
+
- python -m build
|
|
85
|
+
- twine check dist/*
|
|
86
|
+
# The wheel must import from a clean environment — this catches a missing py.typed
|
|
87
|
+
# or a subpackage left out of the wheel, which a source-tree import never would.
|
|
88
|
+
- python -m venv /tmp/fresh
|
|
89
|
+
- /tmp/fresh/bin/pip install --quiet dist/*.whl
|
|
90
|
+
- /tmp/fresh/bin/python -c "import pyradmc, pathlib; assert (pathlib.Path(pyradmc.__file__).parent / 'py.typed').is_file(); print(pyradmc.__version__)"
|
|
91
|
+
artifacts:
|
|
92
|
+
paths: [dist/]
|
|
93
|
+
expire_in: 1 week
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Pre-commit gates: fast, file-scoped checks only.
|
|
2
|
+
#
|
|
3
|
+
# pip install -e ".[dev]" && pre-commit install
|
|
4
|
+
#
|
|
5
|
+
# Deliberately NO test run. The suite takes minutes, and a gate slow enough to be
|
|
6
|
+
# resented is a gate that gets bypassed with --no-verify. Tests are CI's job — see
|
|
7
|
+
# .github/workflows/ci.yml and .gitlab-ci.yml, which run the fast tiers on every push to
|
|
8
|
+
# main and develop, and the validation tier on its own schedule.
|
|
9
|
+
#
|
|
10
|
+
# Run against everything (not just staged files) with: pre-commit run --all-files
|
|
11
|
+
default_language_version:
|
|
12
|
+
python: python3
|
|
13
|
+
|
|
14
|
+
repos:
|
|
15
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
16
|
+
rev: v6.0.0
|
|
17
|
+
hooks:
|
|
18
|
+
- id: trailing-whitespace
|
|
19
|
+
# The EGSnrc benchmark is stored verbatim; reformatting reference data would
|
|
20
|
+
# silently change what the validation tier compares against.
|
|
21
|
+
exclude: ^tests/validation/data/
|
|
22
|
+
- id: end-of-file-fixer
|
|
23
|
+
exclude: ^tests/validation/data/
|
|
24
|
+
- id: check-yaml
|
|
25
|
+
- id: check-toml
|
|
26
|
+
- id: check-merge-conflict
|
|
27
|
+
- id: check-case-conflict
|
|
28
|
+
- id: check-added-large-files
|
|
29
|
+
# The committed example figures run to ~230 KB; this catches an accidental
|
|
30
|
+
# cross-section table or phase-space file, which are the real risks.
|
|
31
|
+
args: [--maxkb=512]
|
|
32
|
+
|
|
33
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
34
|
+
rev: v0.15.1
|
|
35
|
+
hooks:
|
|
36
|
+
- id: ruff-check
|
|
37
|
+
args: [--fix]
|
|
38
|
+
- id: ruff-format
|
|
39
|
+
|
|
40
|
+
- repo: local
|
|
41
|
+
hooks:
|
|
42
|
+
# Run from the project environment, not an isolated one: mypy --strict needs the
|
|
43
|
+
# real NumPy, SciPy and Warp stubs to say anything true, and it is configured
|
|
44
|
+
# whole-package in pyproject.toml (kernels exempt), so it does not take filenames.
|
|
45
|
+
- id: mypy
|
|
46
|
+
name: mypy --strict (non-kernel code)
|
|
47
|
+
entry: mypy pyradmc
|
|
48
|
+
language: system
|
|
49
|
+
types: [python]
|
|
50
|
+
pass_filenames: false
|
|
51
|
+
require_serial: true
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# ReadTheDocs build configuration.
|
|
2
|
+
#
|
|
3
|
+
# RTD builds from the primary remote, github.com/e0404/pyRadMC.
|
|
4
|
+
version: 2
|
|
5
|
+
|
|
6
|
+
build:
|
|
7
|
+
os: ubuntu-24.04
|
|
8
|
+
tools:
|
|
9
|
+
python: "3.13"
|
|
10
|
+
|
|
11
|
+
mkdocs:
|
|
12
|
+
configuration: mkdocs.yml
|
|
13
|
+
# Broken references and missing nav entries fail the build. The API reference is
|
|
14
|
+
# generated from the source, so a renamed or removed public symbol is caught here
|
|
15
|
+
# rather than silently rendering an empty page.
|
|
16
|
+
fail_on_warning: true
|
|
17
|
+
|
|
18
|
+
python:
|
|
19
|
+
install:
|
|
20
|
+
# The docs extra pulls mkdocs-material and mkdocstrings; the package itself is
|
|
21
|
+
# installed because mkdocstrings imports it to read signatures and docstrings.
|
|
22
|
+
# No warp extra: mkdocstrings resolves the lazily re-exported names through the
|
|
23
|
+
# TYPE_CHECKING block, so the API reference builds without a CUDA toolchain.
|
|
24
|
+
- method: pip
|
|
25
|
+
path: .
|
|
26
|
+
extra_requirements:
|
|
27
|
+
- docs
|