pylmrob 0.5.13__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.
- pylmrob-0.5.13/.github/workflows/ci.yml +106 -0
- pylmrob-0.5.13/.github/workflows/wheels.yml +109 -0
- pylmrob-0.5.13/.gitignore +58 -0
- pylmrob-0.5.13/.pre-commit-config.yaml +37 -0
- pylmrob-0.5.13/.readthedocs.yaml +26 -0
- pylmrob-0.5.13/CHANGELOG.md +635 -0
- pylmrob-0.5.13/CITATION.cff +82 -0
- pylmrob-0.5.13/LICENSE +674 -0
- pylmrob-0.5.13/NOTICE +46 -0
- pylmrob-0.5.13/PKG-INFO +877 -0
- pylmrob-0.5.13/README.md +154 -0
- pylmrob-0.5.13/docs/Makefile +15 -0
- pylmrob-0.5.13/docs/api.md +49 -0
- pylmrob-0.5.13/docs/bench-report.md +107 -0
- pylmrob-0.5.13/docs/conf.py +108 -0
- pylmrob-0.5.13/docs/dev/engine_c_parallel.md +158 -0
- pylmrob-0.5.13/docs/engine_c.md +103 -0
- pylmrob-0.5.13/docs/index.md +71 -0
- pylmrob-0.5.13/docs/numerical-notes.md +189 -0
- pylmrob-0.5.13/docs/porting-from-r.md +77 -0
- pylmrob-0.5.13/docs/quickstart.md +146 -0
- pylmrob-0.5.13/docs/r-source-map.md +47 -0
- pylmrob-0.5.13/docs/research-notes.md +73 -0
- pylmrob-0.5.13/meson.build +85 -0
- pylmrob-0.5.13/plan.md +658 -0
- pylmrob-0.5.13/pyproject.toml +156 -0
- pylmrob-0.5.13/scripts/bench_engine_c.py +84 -0
- pylmrob-0.5.13/scripts/benchmark.R +175 -0
- pylmrob-0.5.13/scripts/benchmark.py +263 -0
- pylmrob-0.5.13/scripts/build_bench_report.py +219 -0
- pylmrob-0.5.13/scripts/generate_r_reference.R +288 -0
- pylmrob-0.5.13/src/pylmrob/__init__.py +21 -0
- pylmrob-0.5.13/src/pylmrob/_core/__init__.py +19 -0
- pylmrob-0.5.13/src/pylmrob/_core/_fast_s.pyx +938 -0
- pylmrob-0.5.13/src/pylmrob/_core/_lmrob.pyx +2364 -0
- pylmrob-0.5.13/src/pylmrob/_core/_psi.pyx +874 -0
- pylmrob-0.5.13/src/pylmrob/_core/_stub.pyx +27 -0
- pylmrob-0.5.13/src/pylmrob/_core/meson.build +55 -0
- pylmrob-0.5.13/src/pylmrob/_fast_s.py +686 -0
- pylmrob-0.5.13/src/pylmrob/_mm.py +54 -0
- pylmrob-0.5.13/src/pylmrob/_psifuns.py +811 -0
- pylmrob-0.5.13/src/pylmrob/_utils.py +28 -0
- pylmrob-0.5.13/src/pylmrob/_version.py +9 -0
- pylmrob-0.5.13/src/pylmrob/anova.py +231 -0
- pylmrob-0.5.13/src/pylmrob/control.py +173 -0
- pylmrob-0.5.13/src/pylmrob/d_scale.py +217 -0
- pylmrob-0.5.13/src/pylmrob/diagnostics.py +123 -0
- pylmrob-0.5.13/src/pylmrob/formula.py +154 -0
- pylmrob-0.5.13/src/pylmrob/inference.py +429 -0
- pylmrob-0.5.13/src/pylmrob/lmrob.py +734 -0
- pylmrob-0.5.13/src/pylmrob/meson.build +24 -0
- pylmrob-0.5.13/src/pylmrob/ms_estimator.py +273 -0
- pylmrob-0.5.13/src/pylmrob/psi.py +148 -0
- pylmrob-0.5.13/src/pylmrob/results.py +128 -0
- pylmrob-0.5.13/src/pylmrob/scale.py +284 -0
- pylmrob-0.5.13/src/pylmrob/summary.py +224 -0
- pylmrob-0.5.13/tests/__init__.py +0 -0
- pylmrob-0.5.13/tests/bench/py/classical_aircraft.json +138 -0
- pylmrob-0.5.13/tests/bench/py/classical_coleman.json +143 -0
- pylmrob-0.5.13/tests/bench/py/classical_delivery.json +122 -0
- pylmrob-0.5.13/tests/bench/py/classical_hbk.json +282 -0
- pylmrob-0.5.13/tests/bench/py/classical_pension.json +93 -0
- pylmrob-0.5.13/tests/bench/py/classical_phosphor.json +101 -0
- pylmrob-0.5.13/tests/bench/py/classical_salinity.json +141 -0
- pylmrob-0.5.13/tests/bench/py/classical_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py/classical_starsCYG.json +180 -0
- pylmrob-0.5.13/tests/bench/py/classical_wood.json +143 -0
- pylmrob-0.5.13/tests/bench/py/psi_bisquare.json +120 -0
- pylmrob-0.5.13/tests/bench/py/psi_ggw.json +120 -0
- pylmrob-0.5.13/tests/bench/py/psi_hampel.json +120 -0
- pylmrob-0.5.13/tests/bench/py/psi_lqq.json +120 -0
- pylmrob-0.5.13/tests/bench/py/psi_optimal.json +120 -0
- pylmrob-0.5.13/tests/bench/py/setting_KS2011_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py/setting_KS2014_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py/synth_bisquare_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_bisquare_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py/synth_ggw_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_ggw_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py/synth_hampel_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_hampel_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py/synth_lqq_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_lqq_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py/synth_n10000_p20.json +30533 -0
- pylmrob-0.5.13/tests/bench/py/synth_n10000_p50.json +32783 -0
- pylmrob-0.5.13/tests/bench/py/synth_n1000_p10.json +3183 -0
- pylmrob-0.5.13/tests/bench/py/synth_n100_p5.json +383 -0
- pylmrob-0.5.13/tests/bench/py/synth_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_n5000_p20.json +15533 -0
- pylmrob-0.5.13/tests/bench/py/synth_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py/synth_optimal_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py/synth_optimal_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_aircraft.json +138 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_coleman.json +143 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_delivery.json +122 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_hbk.json +282 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_pension.json +93 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_phosphor.json +101 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_salinity.json +141 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_starsCYG.json +180 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/classical_wood.json +143 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/psi_bisquare.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/psi_ggw.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/psi_hampel.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/psi_lqq.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/psi_optimal.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/setting_KS2011_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/setting_KS2014_stackloss.json +120 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_bisquare_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_bisquare_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_ggw_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_ggw_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_hampel_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_hampel_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_lqq_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_lqq_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n10000_p20.json +30533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n10000_p50.json +32783 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n1000_p10.json +3183 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n100_p5.json +383 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n5000_p20.json +15533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_optimal_n2000_p20.json +6533 -0
- pylmrob-0.5.13/tests/bench/py_engine_c/synth_optimal_n500_p10.json +1683 -0
- pylmrob-0.5.13/tests/bench/r/classical_aircraft.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_coleman.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_delivery.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_hbk.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_pension.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_phosphor.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_salinity.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_stackloss.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_starsCYG.json +1 -0
- pylmrob-0.5.13/tests/bench/r/classical_wood.json +1 -0
- pylmrob-0.5.13/tests/bench/r/psi_bisquare.json +1 -0
- pylmrob-0.5.13/tests/bench/r/psi_ggw.json +1 -0
- pylmrob-0.5.13/tests/bench/r/psi_hampel.json +1 -0
- pylmrob-0.5.13/tests/bench/r/psi_lqq.json +1 -0
- pylmrob-0.5.13/tests/bench/r/psi_optimal.json +1 -0
- pylmrob-0.5.13/tests/bench/r/setting_KS2011_stackloss.json +1 -0
- pylmrob-0.5.13/tests/bench/r/setting_KS2014_stackloss.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_bisquare_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_bisquare_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_ggw_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_ggw_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_hampel_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_hampel_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_lqq_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_lqq_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n10000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n10000_p50.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n1000_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n100_p5.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n5000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_optimal_n2000_p20.json +1 -0
- pylmrob-0.5.13/tests/bench/r/synth_optimal_n500_p10.json +1 -0
- pylmrob-0.5.13/tests/conftest.py +234 -0
- pylmrob-0.5.13/tests/data/aircraft.csv +24 -0
- pylmrob-0.5.13/tests/data/coleman.csv +21 -0
- pylmrob-0.5.13/tests/data/delivery.csv +26 -0
- pylmrob-0.5.13/tests/data/education.csv +51 -0
- pylmrob-0.5.13/tests/data/hbk.csv +76 -0
- pylmrob-0.5.13/tests/data/pension.csv +19 -0
- pylmrob-0.5.13/tests/data/phosphor.csv +19 -0
- pylmrob-0.5.13/tests/data/salinity.csv +29 -0
- pylmrob-0.5.13/tests/data/stackloss.csv +22 -0
- pylmrob-0.5.13/tests/data/starsCYG.csv +48 -0
- pylmrob-0.5.13/tests/data/synth_n10000_p20.csv +10001 -0
- pylmrob-0.5.13/tests/data/synth_n10000_p50.csv +10001 -0
- pylmrob-0.5.13/tests/data/synth_n1000_p10.csv +1001 -0
- pylmrob-0.5.13/tests/data/synth_n100_p5.csv +101 -0
- pylmrob-0.5.13/tests/data/synth_n2000_p20.csv +2001 -0
- pylmrob-0.5.13/tests/data/synth_n5000_p20.csv +5001 -0
- pylmrob-0.5.13/tests/data/synth_n500_p10.csv +501 -0
- pylmrob-0.5.13/tests/data/wood.csv +21 -0
- pylmrob-0.5.13/tests/integration/__init__.py +0 -0
- pylmrob-0.5.13/tests/integration/test_engine_c_parity.py +70 -0
- pylmrob-0.5.13/tests/integration/test_factor_designs.py +163 -0
- pylmrob-0.5.13/tests/integration/test_lmrob_api.py +173 -0
- pylmrob-0.5.13/tests/property/__init__.py +0 -0
- pylmrob-0.5.13/tests/property/test_equivariance.py +107 -0
- pylmrob-0.5.13/tests/reference/aircraft_default.json +1 -0
- pylmrob-0.5.13/tests/reference/coleman_default.json +1 -0
- pylmrob-0.5.13/tests/reference/delivery_default.json +1 -0
- pylmrob-0.5.13/tests/reference/education_simple.json +1 -0
- pylmrob-0.5.13/tests/reference/hbk_default.json +1 -0
- pylmrob-0.5.13/tests/reference/pension_default.json +1 -0
- pylmrob-0.5.13/tests/reference/phosphor_default.json +1 -0
- pylmrob-0.5.13/tests/reference/salinity_default.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_KS2011.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_KS2014.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_default.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_psi_bisquare.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_psi_ggw.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_psi_hampel.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_psi_lqq.json +1 -0
- pylmrob-0.5.13/tests/reference/stackloss_psi_optimal.json +1 -0
- pylmrob-0.5.13/tests/reference/starsCYG_default.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p10_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p10_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p10_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p3_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p3_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n1000_p3_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p10_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p10_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p10_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p3_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p3_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n200_p3_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p10_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p10_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p10_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p3_c00.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p3_c10.json +1 -0
- pylmrob-0.5.13/tests/reference/synthetic_n50_p3_c30.json +1 -0
- pylmrob-0.5.13/tests/reference/wood_default.json +1 -0
- pylmrob-0.5.13/tests/unit/__init__.py +0 -0
- pylmrob-0.5.13/tests/unit/test_d_scale.py +182 -0
- pylmrob-0.5.13/tests/unit/test_fast_s_parallel.py +127 -0
- pylmrob-0.5.13/tests/unit/test_inference.py +104 -0
- pylmrob-0.5.13/tests/unit/test_lmrob_kernel.py +138 -0
- pylmrob-0.5.13/tests/unit/test_psi.py +131 -0
- pylmrob-0.5.13/tests/unit/test_scale.py +56 -0
- pylmrob-0.5.13/tests/unit/test_smoke.py +44 -0
- pylmrob-0.5.13/tests/validation/__init__.py +0 -0
- pylmrob-0.5.13/tests/validation/test_reference_loader.py +87 -0
- pylmrob-0.5.13/tests/validation/test_summary_anova.py +219 -0
- pylmrob-0.5.13/tests/validation/test_vs_r_classical.py +100 -0
- pylmrob-0.5.13/tests/validation/test_vs_r_psi_families.py +83 -0
- pylmrob-0.5.13/tests/validation/test_weights_vs_r.py +149 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
# Cancel in-progress runs of the same workflow on the same ref.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lint:
|
|
16
|
+
name: Lint + type check
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
cache: "pip"
|
|
24
|
+
- name: Install project + lint deps
|
|
25
|
+
# Install the project (so ty sees numpy/scipy/pandas/formulaic in
|
|
26
|
+
# the same env) plus ruff and ty.
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
python -m pip install ".[dev]" ruff ty
|
|
30
|
+
- name: Ruff
|
|
31
|
+
run: ruff check src tests
|
|
32
|
+
- name: Ruff format check
|
|
33
|
+
run: ruff format --check src tests
|
|
34
|
+
- name: ty (type check)
|
|
35
|
+
# Astral's ty is the project's standard type checker (replaces mypy).
|
|
36
|
+
run: ty check src/pylmrob
|
|
37
|
+
|
|
38
|
+
test:
|
|
39
|
+
name: Tests (${{ matrix.os }} / py${{ matrix.python-version }})
|
|
40
|
+
runs-on: ${{ matrix.os }}
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
45
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- uses: actions/setup-python@v5
|
|
50
|
+
with:
|
|
51
|
+
python-version: ${{ matrix.python-version }}
|
|
52
|
+
cache: "pip"
|
|
53
|
+
|
|
54
|
+
# ------------------------------------------------------------------
|
|
55
|
+
# R + robustbase. We only run rpy2-backed tests on Linux to keep CI
|
|
56
|
+
# cheap; correctness against the JSON references is platform-agnostic.
|
|
57
|
+
# ------------------------------------------------------------------
|
|
58
|
+
- name: Install R (Linux)
|
|
59
|
+
if: runner.os == 'Linux'
|
|
60
|
+
uses: r-lib/actions/setup-r@v2
|
|
61
|
+
with:
|
|
62
|
+
r-version: "release"
|
|
63
|
+
use-public-rspm: true
|
|
64
|
+
|
|
65
|
+
- name: Cache R packages (Linux)
|
|
66
|
+
if: runner.os == 'Linux'
|
|
67
|
+
uses: actions/cache@v4
|
|
68
|
+
with:
|
|
69
|
+
path: ${{ env.R_LIBS_USER }}
|
|
70
|
+
key: r-${{ runner.os }}-robustbase-${{ hashFiles('scripts/generate_r_reference.R') }}
|
|
71
|
+
|
|
72
|
+
- name: Install robustbase (Linux)
|
|
73
|
+
if: runner.os == 'Linux'
|
|
74
|
+
run: Rscript -e 'install.packages(c("robustbase","jsonlite"), repos="https://cloud.r-project.org")'
|
|
75
|
+
|
|
76
|
+
- name: Install OpenMP runtime (macOS)
|
|
77
|
+
if: runner.os == 'macOS'
|
|
78
|
+
run: |
|
|
79
|
+
brew install libomp
|
|
80
|
+
echo "LDFLAGS=-L$(brew --prefix libomp)/lib" >> $GITHUB_ENV
|
|
81
|
+
echo "CPPFLAGS=-I$(brew --prefix libomp)/include" >> $GITHUB_ENV
|
|
82
|
+
|
|
83
|
+
- name: Install build deps + project (no rpy2)
|
|
84
|
+
# Non-editable install: lets meson-python's build-isolation handle
|
|
85
|
+
# Cython/meson/ninja without us tracking them. Editable mode would
|
|
86
|
+
# require keeping the build env around for the rebuild-on-import
|
|
87
|
+
# loop, which is more brittle on CI.
|
|
88
|
+
run: |
|
|
89
|
+
python -m pip install --upgrade pip
|
|
90
|
+
python -m pip install -v ".[dev]"
|
|
91
|
+
|
|
92
|
+
# rpy2 is only needed for the live R-bridge tests, which we skip on
|
|
93
|
+
# macOS/Windows. Installing it elsewhere fails because the build
|
|
94
|
+
# requires R to be on PATH.
|
|
95
|
+
- name: Install rpy2 (Linux only)
|
|
96
|
+
if: runner.os == 'Linux'
|
|
97
|
+
run: python -m pip install ".[validation]"
|
|
98
|
+
|
|
99
|
+
- name: Generate R reference (Linux only)
|
|
100
|
+
if: runner.os == 'Linux'
|
|
101
|
+
run: Rscript scripts/generate_r_reference.R
|
|
102
|
+
|
|
103
|
+
- name: Run pytest
|
|
104
|
+
env:
|
|
105
|
+
PYROBUSTLM_SKIP_RPY2: ${{ runner.os != 'Linux' && '1' || '' }}
|
|
106
|
+
run: pytest -v --maxfail=10
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
name: Build wheels
|
|
2
|
+
|
|
3
|
+
# Manual trigger only for the first release; once we've confirmed that
|
|
4
|
+
# wheels build and ``pip install pylmrob`` works from TestPyPI, flip
|
|
5
|
+
# to ``push: tags: ["v*"]`` so tagging publishes to real PyPI
|
|
6
|
+
# automatically.
|
|
7
|
+
on:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
target:
|
|
11
|
+
description: "Publish target"
|
|
12
|
+
required: true
|
|
13
|
+
default: "testpypi"
|
|
14
|
+
type: choice
|
|
15
|
+
options:
|
|
16
|
+
- testpypi
|
|
17
|
+
- pypi
|
|
18
|
+
- none
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build_wheels:
|
|
22
|
+
name: ${{ matrix.os }} ${{ matrix.arch }}
|
|
23
|
+
runs-on: ${{ matrix.os }}
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
include:
|
|
28
|
+
- os: ubuntu-latest
|
|
29
|
+
arch: x86_64
|
|
30
|
+
- os: ubuntu-latest
|
|
31
|
+
arch: aarch64
|
|
32
|
+
# macos-13 (Intel) dropped: the free runner queue is unusable
|
|
33
|
+
# in 2026 (5+ hour waits) as GitHub winds down Intel mac
|
|
34
|
+
# capacity. Apple Silicon covers all Macs sold since late
|
|
35
|
+
# 2020; Intel users can install from the sdist.
|
|
36
|
+
- os: macos-14 # Apple Silicon runner
|
|
37
|
+
arch: arm64
|
|
38
|
+
- os: windows-latest
|
|
39
|
+
arch: AMD64
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up QEMU (linux aarch64)
|
|
44
|
+
if: matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64'
|
|
45
|
+
uses: docker/setup-qemu-action@v3
|
|
46
|
+
with:
|
|
47
|
+
platforms: arm64
|
|
48
|
+
|
|
49
|
+
- name: Build wheels
|
|
50
|
+
uses: pypa/cibuildwheel@v2.21
|
|
51
|
+
env:
|
|
52
|
+
CIBW_ARCHS: ${{ matrix.arch }}
|
|
53
|
+
|
|
54
|
+
- uses: actions/upload-artifact@v4
|
|
55
|
+
with:
|
|
56
|
+
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
|
|
57
|
+
path: ./wheelhouse/*.whl
|
|
58
|
+
|
|
59
|
+
build_sdist:
|
|
60
|
+
name: Build sdist
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
- uses: actions/setup-python@v5
|
|
65
|
+
with:
|
|
66
|
+
python-version: "3.12"
|
|
67
|
+
- run: |
|
|
68
|
+
python -m pip install --upgrade pip build
|
|
69
|
+
python -m build --sdist
|
|
70
|
+
- uses: actions/upload-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
name: sdist
|
|
73
|
+
path: dist/*.tar.gz
|
|
74
|
+
|
|
75
|
+
publish_testpypi:
|
|
76
|
+
name: Publish to TestPyPI
|
|
77
|
+
needs: [build_wheels, build_sdist]
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
if: inputs.target == 'testpypi'
|
|
80
|
+
environment:
|
|
81
|
+
name: testpypi
|
|
82
|
+
url: https://test.pypi.org/p/pylmrob
|
|
83
|
+
permissions:
|
|
84
|
+
id-token: write # OIDC trusted publisher
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/download-artifact@v4
|
|
87
|
+
with:
|
|
88
|
+
path: dist
|
|
89
|
+
merge-multiple: true
|
|
90
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
91
|
+
with:
|
|
92
|
+
repository-url: https://test.pypi.org/legacy/
|
|
93
|
+
|
|
94
|
+
publish:
|
|
95
|
+
name: Publish to PyPI
|
|
96
|
+
needs: [build_wheels, build_sdist]
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
if: inputs.target == 'pypi' || startsWith(github.ref, 'refs/tags/v')
|
|
99
|
+
environment:
|
|
100
|
+
name: pypi
|
|
101
|
+
url: https://pypi.org/p/pylmrob
|
|
102
|
+
permissions:
|
|
103
|
+
id-token: write # OIDC trusted publisher
|
|
104
|
+
steps:
|
|
105
|
+
- uses: actions/download-artifact@v4
|
|
106
|
+
with:
|
|
107
|
+
path: dist
|
|
108
|
+
merge-multiple: true
|
|
109
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Build artifacts
|
|
2
|
+
build/
|
|
3
|
+
builddir/
|
|
4
|
+
dist/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
*.egg
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*.so
|
|
10
|
+
*.dylib
|
|
11
|
+
*.pyd
|
|
12
|
+
*.dll
|
|
13
|
+
|
|
14
|
+
# Cython generated
|
|
15
|
+
src/pylmrob/_core/*.c
|
|
16
|
+
src/pylmrob/_core/*.cpp
|
|
17
|
+
src/pylmrob/_core/*.html
|
|
18
|
+
|
|
19
|
+
# Environments
|
|
20
|
+
.venv/
|
|
21
|
+
venv/
|
|
22
|
+
.env
|
|
23
|
+
.python-version
|
|
24
|
+
|
|
25
|
+
# Tooling caches
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
.ruff_cache/
|
|
29
|
+
.hypothesis/
|
|
30
|
+
.coverage
|
|
31
|
+
.coverage.*
|
|
32
|
+
htmlcov/
|
|
33
|
+
coverage.xml
|
|
34
|
+
.tox/
|
|
35
|
+
|
|
36
|
+
# IDE / editor
|
|
37
|
+
.idea/
|
|
38
|
+
.vscode/
|
|
39
|
+
*.swp
|
|
40
|
+
*~
|
|
41
|
+
\#*\#
|
|
42
|
+
.DS_Store
|
|
43
|
+
|
|
44
|
+
# Generated docs
|
|
45
|
+
docs/_build/
|
|
46
|
+
docs/_static/
|
|
47
|
+
docs/api/_autosummary/
|
|
48
|
+
|
|
49
|
+
# R reference outputs (regenerated on demand; small ones may be committed under tests/reference/)
|
|
50
|
+
scripts/_rcache/
|
|
51
|
+
|
|
52
|
+
# Test scratch (regenerated by tests/unit/test_d_scale.py)
|
|
53
|
+
tests/data/_d_test_*.csv
|
|
54
|
+
|
|
55
|
+
# Local-only
|
|
56
|
+
local/
|
|
57
|
+
scratch/
|
|
58
|
+
uv.lock
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v4.6.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
- id: check-toml
|
|
9
|
+
- id: check-merge-conflict
|
|
10
|
+
- id: check-added-large-files
|
|
11
|
+
args: ["--maxkb=500"]
|
|
12
|
+
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.6.9
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: ["--fix"]
|
|
18
|
+
- id: ruff-format
|
|
19
|
+
|
|
20
|
+
# ty is run in CI via `uvx ty check`. Adding it here as a local hook so
|
|
21
|
+
# it runs against the project venv (which has the compiled extension
|
|
22
|
+
# available, unlike isolated pre-commit envs).
|
|
23
|
+
- repo: local
|
|
24
|
+
hooks:
|
|
25
|
+
- id: ty
|
|
26
|
+
name: ty (type check)
|
|
27
|
+
entry: uvx ty check
|
|
28
|
+
language: system
|
|
29
|
+
pass_filenames: false
|
|
30
|
+
files: ^src/pylmrob/.*\.py$
|
|
31
|
+
|
|
32
|
+
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
33
|
+
rev: v3.4.0
|
|
34
|
+
hooks:
|
|
35
|
+
- id: conventional-pre-commit
|
|
36
|
+
stages: [commit-msg]
|
|
37
|
+
args: []
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
# Read the Docs config for pylmrob. Build the Sphinx site from docs/.
|
|
3
|
+
|
|
4
|
+
version: 2
|
|
5
|
+
|
|
6
|
+
build:
|
|
7
|
+
os: ubuntu-22.04
|
|
8
|
+
tools:
|
|
9
|
+
python: "3.11"
|
|
10
|
+
apt_packages:
|
|
11
|
+
- libopenblas-dev
|
|
12
|
+
- liblapack-dev
|
|
13
|
+
jobs:
|
|
14
|
+
# meson-python needs the package built before Sphinx can autodoc it.
|
|
15
|
+
# Install the build chain explicitly so --no-build-isolation works.
|
|
16
|
+
post_install:
|
|
17
|
+
- pip install "meson-python>=0.16" "meson>=1.4" ninja "Cython>=3" "numpy>=2"
|
|
18
|
+
- pip install -e ".[docs]" --no-build-isolation
|
|
19
|
+
|
|
20
|
+
sphinx:
|
|
21
|
+
configuration: docs/conf.py
|
|
22
|
+
builder: html
|
|
23
|
+
fail_on_warning: true
|
|
24
|
+
|
|
25
|
+
# Don't ship epub/pdf builders; HTML only.
|
|
26
|
+
formats: []
|