lme-python 0.1.4__tar.gz → 0.1.8__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 (199) hide show
  1. lme_python-0.1.8/.github/workflows/audit.yml +73 -0
  2. {lme_python-0.1.4 → lme_python-0.1.8}/.github/workflows/benchmarks.yml +0 -61
  3. lme_python-0.1.8/.github/workflows/ci.yml +247 -0
  4. lme_python-0.1.8/.github/workflows/crate-publish-dry-run.yml +28 -0
  5. lme_python-0.1.8/.github/workflows/fuzz-smoke.yml +34 -0
  6. {lme_python-0.1.4 → lme_python-0.1.8}/.github/workflows/python-release.yml +15 -14
  7. {lme_python-0.1.4 → lme_python-0.1.8}/.github/workflows/repo-metadata.yml +12 -2
  8. {lme_python-0.1.4 → lme_python-0.1.8}/.gitignore +3 -0
  9. lme_python-0.1.8/AGENTS.md +173 -0
  10. {lme_python-0.1.4 → lme_python-0.1.8}/BENCHMARKS.md +1 -1
  11. lme_python-0.1.8/CHANGELOG.md +118 -0
  12. lme_python-0.1.8/CONTRIBUTING.md +176 -0
  13. {lme_python-0.1.4 → lme_python-0.1.8}/Cargo.lock +13 -13
  14. {lme_python-0.1.4 → lme_python-0.1.8}/Cargo.toml +30 -2
  15. {lme_python-0.1.4 → lme_python-0.1.8}/GUIDE.md +65 -8
  16. {lme_python-0.1.4 → lme_python-0.1.8}/PKG-INFO +5 -1
  17. {lme_python-0.1.4 → lme_python-0.1.8}/README.md +13 -8
  18. lme_python-0.1.8/RELEASING.md +255 -0
  19. lme_python-0.1.8/REPO_COMPLETION_BY_AREA.md +74 -0
  20. lme_python-0.1.8/Taskfile.yml +108 -0
  21. lme_python-0.1.8/benches/bench_load_production.rs +188 -0
  22. {lme_python-0.1.4 → lme_python-0.1.8}/benches/bench_math.rs +41 -0
  23. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/COMPARISONS.md +309 -78
  24. lme_python-0.1.8/comparisons/categorical_anova.R +17 -0
  25. lme_python-0.1.8/comparisons/categorical_anova.jl +13 -0
  26. lme_python-0.1.8/comparisons/categorical_anova.py +16 -0
  27. lme_python-0.1.8/comparisons/categorical_anova.rs +24 -0
  28. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_cbpp.R +15 -5
  29. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_cbpp.jl +3 -0
  30. lme_python-0.1.8/comparisons/glmm_cbpp.py +66 -0
  31. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_cbpp.rs +8 -4
  32. lme_python-0.1.8/comparisons/glmm_gaussian.R +29 -0
  33. lme_python-0.1.8/comparisons/glmm_gaussian.jl +29 -0
  34. lme_python-0.1.8/comparisons/glmm_gaussian.py +54 -0
  35. lme_python-0.1.8/comparisons/glmm_gaussian.rs +46 -0
  36. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_grouseticks.rs +1 -1
  37. lme_python-0.1.8/comparisons/lmer_weighted.R +28 -0
  38. lme_python-0.1.8/comparisons/lmer_weighted.jl +37 -0
  39. lme_python-0.1.8/comparisons/lmer_weighted.py +63 -0
  40. lme_python-0.1.8/comparisons/lmer_weighted.rs +51 -0
  41. lme_python-0.1.8/comparisons/lmm_dyestuff.py +33 -0
  42. lme_python-0.1.8/comparisons/lmm_pastes.py +47 -0
  43. lme_python-0.1.8/comparisons/lmm_penicillin.py +43 -0
  44. lme_python-0.1.8/lefthook.yml +40 -0
  45. lme_python-0.1.8/mise.toml +16 -0
  46. {lme_python-0.1.4 → lme_python-0.1.8}/pyproject.toml +20 -0
  47. {lme_python-0.1.4 → lme_python-0.1.8}/python/Cargo.lock +28 -59
  48. {lme_python-0.1.4 → lme_python-0.1.8}/python/Cargo.toml +3 -2
  49. {lme_python-0.1.4 → lme_python-0.1.8}/python/PYTHON_GUIDE.md +42 -14
  50. {lme_python-0.1.4 → lme_python-0.1.8}/python/examples/glmer_cbpp.py +5 -4
  51. {lme_python-0.1.4 → lme_python-0.1.8}/python/examples/glmer_grouseticks.py +15 -14
  52. {lme_python-0.1.4 → lme_python-0.1.8}/python/examples/lm_basics.py +2 -2
  53. {lme_python-0.1.4 → lme_python-0.1.8}/python/examples/lmer_sleepstudy.py +9 -7
  54. {lme_python-0.1.4 → lme_python-0.1.8}/python/examples/model_comparison.py +22 -20
  55. lme_python-0.1.8/python/examples/plotting_demo/.gitignore +6 -0
  56. lme_python-0.1.8/python/examples/plotting_demo/README.md +129 -0
  57. lme_python-0.1.8/python/examples/plotting_demo/compare_plots.py +318 -0
  58. lme_python-0.1.8/python/examples/plotting_demo/figure_specs.py +45 -0
  59. lme_python-0.1.8/python/examples/plotting_demo/find_rscript.py +91 -0
  60. lme_python-0.1.8/python/examples/plotting_demo/numeric_overlay.py +141 -0
  61. lme_python-0.1.8/python/examples/plotting_demo/paths.py +14 -0
  62. lme_python-0.1.8/python/examples/plotting_demo/plot_demo.py +191 -0
  63. lme_python-0.1.8/python/examples/plotting_demo/plot_r.R +177 -0
  64. lme_python-0.1.8/python/examples/plotting_demo/run_all.py +65 -0
  65. lme_python-0.1.8/python/examples/verification_project/README.md +42 -0
  66. lme_python-0.1.8/python/examples/verification_project/conftest.py +8 -0
  67. lme_python-0.1.8/python/examples/verification_project/parity.py +193 -0
  68. lme_python-0.1.8/python/examples/verification_project/paths.py +14 -0
  69. lme_python-0.1.8/python/examples/verification_project/run.py +39 -0
  70. lme_python-0.1.8/python/examples/verification_project/test_parity.py +41 -0
  71. lme_python-0.1.8/python/lme_python.pyi +150 -0
  72. lme_python-0.1.8/python/requirements-ci.txt +87 -0
  73. {lme_python-0.1.4 → lme_python-0.1.8}/python/src/lib.rs +638 -70
  74. lme_python-0.1.8/python/tests/test_api_parity.py +138 -0
  75. {lme_python-0.1.4 → lme_python-0.1.8}/python/tests/test_basic.py +97 -66
  76. lme_python-0.1.8/scripts/ci/README.md +27 -0
  77. lme_python-0.1.8/scripts/ci/lme_ci.py +404 -0
  78. lme_python-0.1.8/scripts/ci/run.sh +30 -0
  79. lme_python-0.1.8/scripts/local_ci.ps1 +4 -0
  80. lme_python-0.1.8/scripts/local_ci.sh +4 -0
  81. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/run_cross_language_benchmarks.py +19 -1
  82. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/sync_github_repo_metadata.py +35 -4
  83. lme_python-0.1.8/src/anova.rs +235 -0
  84. lme_python-0.1.8/src/anova_contrasts.rs +208 -0
  85. lme_python-0.1.8/src/contrast.rs +266 -0
  86. lme_python-0.1.8/src/ddf.rs +202 -0
  87. {lme_python-0.1.4 → lme_python-0.1.8}/src/formula.rs +21 -0
  88. lme_python-0.1.8/src/glmm_math.rs +1237 -0
  89. {lme_python-0.1.4 → lme_python-0.1.8}/src/kenward_roger.rs +11 -1
  90. lme_python-0.1.8/src/kr_modcomp.rs +327 -0
  91. lme_python-0.1.8/src/kr_vcov_adj.rs +296 -0
  92. {lme_python-0.1.4 → lme_python-0.1.8}/src/lib.rs +228 -28
  93. {lme_python-0.1.4 → lme_python-0.1.8}/src/model_matrix.rs +254 -14
  94. lme_python-0.1.8/src/nlmm/fit.rs +528 -0
  95. lme_python-0.1.8/src/nlmm/formula.rs +124 -0
  96. lme_python-0.1.8/src/nlmm/mod.rs +37 -0
  97. lme_python-0.1.8/src/nlmm/sslogis.rs +37 -0
  98. {lme_python-0.1.4 → lme_python-0.1.8}/src/optimizer.rs +94 -65
  99. {lme_python-0.1.4 → lme_python-0.1.8}/src/robust.rs +8 -2
  100. {lme_python-0.1.4 → lme_python-0.1.8}/src/satterthwaite.rs +32 -22
  101. lme_python-0.1.8/tests/categorical_anova_test.rs +42 -0
  102. lme_python-0.1.8/tests/data/golden_parity_manifest.json +466 -0
  103. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/intercept_only.json +2 -0
  104. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/mock_ml.json +2 -0
  105. lme_python-0.1.8/tests/data/orange.csv +36 -0
  106. lme_python-0.1.8/tests/data/orange_nlmer.json +15 -0
  107. lme_python-0.1.8/tests/data/pastes_cask_reml.json +17 -0
  108. lme_python-0.1.8/tests/data/penicillin.csv +145 -0
  109. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/penicillin.json +2 -0
  110. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/random_slopes.json +2 -0
  111. lme_python-0.1.8/tests/generate_test_data.R +506 -0
  112. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_anova.rs +6 -6
  113. lme_python-0.1.8/tests/test_anova_types.rs +56 -0
  114. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_confint_simulate.rs +13 -2
  115. lme_python-0.1.8/tests/test_contrast.rs +83 -0
  116. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_coverage_edge_cases.rs +2 -1
  117. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_coverage_gaps.rs +3 -0
  118. lme_python-0.1.8/tests/test_failure_modes.rs +235 -0
  119. lme_python-0.1.8/tests/test_formula_stress.rs +316 -0
  120. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_gaps.rs +10 -3
  121. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_glmm.rs +96 -3
  122. lme_python-0.1.8/tests/test_glmm_weighted.rs +64 -0
  123. lme_python-0.1.8/tests/test_golden_parity.rs +543 -0
  124. lme_python-0.1.8/tests/test_kr_modcomp_pastes.rs +51 -0
  125. lme_python-0.1.8/tests/test_nlmm_orange.rs +54 -0
  126. lme_python-0.1.8/tests/test_production_load.rs +360 -0
  127. lme_python-0.1.8/tests/test_statistical_identities.rs +294 -0
  128. lme_python-0.1.4/.github/workflows/ci.yml +0 -66
  129. lme_python-0.1.4/CHANGELOG.md +0 -72
  130. lme_python-0.1.4/CONTRIBUTING.md +0 -91
  131. lme_python-0.1.4/RELEASING.md +0 -185
  132. lme_python-0.1.4/comparisons/glmm_cbpp.py +0 -45
  133. lme_python-0.1.4/comparisons/lmm_dyestuff.py +0 -21
  134. lme_python-0.1.4/comparisons/lmm_pastes.py +0 -35
  135. lme_python-0.1.4/comparisons/lmm_penicillin.py +0 -35
  136. lme_python-0.1.4/src/anova.rs +0 -164
  137. lme_python-0.1.4/src/glmm_math.rs +0 -606
  138. lme_python-0.1.4/tests/data/penicillin.csv +0 -145
  139. lme_python-0.1.4/tests/generate_test_data.R +0 -231
  140. {lme_python-0.1.4 → lme_python-0.1.8}/LICENSE +0 -0
  141. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/comparison_chart.png +0 -0
  142. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_grouseticks.R +0 -0
  143. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_grouseticks.jl +0 -0
  144. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/glmm_grouseticks.py +0 -0
  145. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_dyestuff.R +0 -0
  146. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_dyestuff.jl +0 -0
  147. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_dyestuff.rs +0 -0
  148. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_pastes.R +0 -0
  149. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_pastes.jl +0 -0
  150. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_pastes.rs +0 -0
  151. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_penicillin.R +0 -0
  152. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_penicillin.jl +0 -0
  153. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/lmm_penicillin.rs +0 -0
  154. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy.R +0 -0
  155. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy.jl +0 -0
  156. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy.py +0 -0
  157. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy.rs +0 -0
  158. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy_ml.R +0 -0
  159. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy_ml.jl +0 -0
  160. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy_ml.py +0 -0
  161. {lme_python-0.1.4 → lme_python-0.1.8}/comparisons/sleepstudy_ml.rs +0 -0
  162. {lme_python-0.1.4 → lme_python-0.1.8}/docs/benchmarks/app.js +0 -0
  163. {lme_python-0.1.4 → lme_python-0.1.8}/docs/benchmarks/index.html +0 -0
  164. {lme_python-0.1.4 → lme_python-0.1.8}/docs/benchmarks/styles.css +0 -0
  165. {lme_python-0.1.4 → lme_python-0.1.8}/docs/index.html +0 -0
  166. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/ast_explorations/test_fiasto.rs +0 -0
  167. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/ast_explorations/test_fiasto_offset.rs +0 -0
  168. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/build_benchmark_site.py +0 -0
  169. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/dump_dyestuff.R +0 -0
  170. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/dump_pastes.R +0 -0
  171. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/make_penicillin_csv.py +0 -0
  172. {lme_python-0.1.4 → lme_python-0.1.8}/scripts/plot_comparisons.py +0 -0
  173. {lme_python-0.1.4 → lme_python-0.1.8}/src/family.rs +0 -0
  174. {lme_python-0.1.4 → lme_python-0.1.8}/src/math.rs +0 -0
  175. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/cbpp_binary.csv +0 -0
  176. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/dyestuff.csv +0 -0
  177. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/glmm_binomial.json +0 -0
  178. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/glmm_poisson.json +0 -0
  179. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/grouseticks.csv +0 -0
  180. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/mock_crossed.json +0 -0
  181. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/pastes.csv +0 -0
  182. {lme_python-0.1.4 → lme_python-0.1.8}/tests/data/sleepstudy.csv +0 -0
  183. {lme_python-0.1.4 → lme_python-0.1.8}/tests/generate_mock_data.py +0 -0
  184. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_conditional_real.rs +0 -0
  185. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_crossed_mock.rs +0 -0
  186. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_e2e_lmer.rs +0 -0
  187. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_edge_cases.rs +0 -0
  188. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_errors.rs +0 -0
  189. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_formula.rs +0 -0
  190. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_intercept_only.rs +0 -0
  191. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_kenward_roger.rs +0 -0
  192. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_ml_optimization.rs +0 -0
  193. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_no_intercept.rs +0 -0
  194. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_numerical_parity.rs +0 -0
  195. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_predict.rs +0 -0
  196. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_random_slopes.rs +0 -0
  197. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_robust.rs +0 -0
  198. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_sandwich_math.R +0 -0
  199. {lme_python-0.1.4 → lme_python-0.1.8}/tests/test_satterthwaite.rs +0 -0
@@ -0,0 +1,73 @@
1
+ name: Security audit
2
+
3
+ on:
4
+ schedule:
5
+ # Weekly: Mondays 12:00 UTC
6
+ - cron: "0 12 * * 1"
7
+ workflow_dispatch:
8
+ push:
9
+ branches: [master]
10
+ paths:
11
+ - "**/Cargo.toml"
12
+ - "**/Cargo.lock"
13
+ - "python/pyproject.toml"
14
+ - "python/requirements-ci.txt"
15
+ pull_request:
16
+ branches: [master]
17
+ paths:
18
+ - "**/Cargo.toml"
19
+ - "**/Cargo.lock"
20
+ - "python/pyproject.toml"
21
+ - "python/requirements-ci.txt"
22
+
23
+ permissions:
24
+ contents: read
25
+
26
+ concurrency:
27
+ group: audit-${{ github.workflow }}-${{ github.ref }}
28
+ cancel-in-progress: true
29
+
30
+ jobs:
31
+ audit:
32
+ name: cargo audit
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v6
36
+
37
+ - uses: dtolnay/rust-toolchain@stable
38
+
39
+ - name: Install cargo-audit
40
+ uses: taiki-e/install-action@v2
41
+ with:
42
+ tool: cargo-audit@0.22.1
43
+
44
+ - name: Run cargo audit (root)
45
+ run: cargo audit
46
+
47
+ - name: Run cargo audit (python/)
48
+ working-directory: python
49
+ run: cargo audit
50
+
51
+ pip-audit:
52
+ name: pip-audit (python lockfile)
53
+ runs-on: ubuntu-latest
54
+ steps:
55
+ - uses: actions/checkout@v6
56
+
57
+ - name: Set up Python
58
+ uses: actions/setup-python@v6
59
+ with:
60
+ python-version: "3.11"
61
+ cache: pip
62
+ cache-dependency-path: python/requirements-ci.txt
63
+
64
+ - name: Install locked CI dependencies
65
+ working-directory: python
66
+ run: |
67
+ set -euo pipefail
68
+ python -m pip install -U pip
69
+ python -m pip install -r requirements-ci.txt
70
+
71
+ - name: pip-audit
72
+ working-directory: python
73
+ run: python -m pip_audit
@@ -17,7 +17,6 @@ on:
17
17
 
18
18
  permissions:
19
19
  contents: write
20
- pages: write
21
20
  id-token: write
22
21
 
23
22
  env:
@@ -172,63 +171,3 @@ jobs:
172
171
  echo "Cross-language benchmark script failed with exit code ${{ steps.cross_language_run.outputs.status }}." >&2
173
172
  exit 1
174
173
 
175
- pages:
176
- name: Publish Benchmark Dashboard
177
- runs-on: ubuntu-latest
178
- needs:
179
- - criterion
180
- - cross-language
181
- if: needs.criterion.result == 'success' && needs.cross-language.result == 'success' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))
182
- environment:
183
- name: github-pages
184
- url: ${{ steps.deploy.outputs.page_url }}
185
- steps:
186
- - uses: actions/checkout@v6
187
-
188
- - uses: actions/setup-python@v6
189
- with:
190
- python-version: "3.11"
191
-
192
- - name: Download cross-language artifact
193
- uses: actions/download-artifact@v5
194
- with:
195
- name: cross-language-${{ github.sha }}
196
- path: site-input
197
-
198
- - name: Resolve release URL
199
- id: release_url
200
- run: |
201
- if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
202
- echo "value=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
203
- else
204
- echo "value=" >> "$GITHUB_OUTPUT"
205
- fi
206
-
207
- - name: Build benchmark dashboard
208
- run: |
209
- set -euo pipefail
210
- mkdir -p site
211
- cp -R docs/. site/
212
- mkdir -p site/benchmarks/data
213
- cross_json="$(find site-input -name 'cross-language-*.json' -print -quit)"
214
- python scripts/build_benchmark_site.py \
215
- --cross-language-json "$cross_json" \
216
- --output-dir "site/benchmarks/data" \
217
- --run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \
218
- --release-url "${{ steps.release_url.outputs.value }}" \
219
- --criterion-asset-name "criterion-${GITHUB_SHA}.tar.gz" \
220
- --cross-language-asset-name "cross-language-${GITHUB_SHA}.json" \
221
- --ref-name "${GITHUB_REF_NAME}"
222
-
223
- - uses: actions/configure-pages@v5
224
- with:
225
- token: ${{ secrets.REPO_ADMIN_TOKEN != '' && secrets.REPO_ADMIN_TOKEN || github.token }}
226
- enablement: ${{ secrets.REPO_ADMIN_TOKEN != '' }}
227
-
228
- - uses: actions/upload-pages-artifact@v3
229
- with:
230
- path: site
231
-
232
- - name: Deploy to GitHub Pages
233
- id: deploy
234
- uses: actions/deploy-pages@v4
@@ -0,0 +1,247 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ paths-ignore:
7
+ - "**/*.md"
8
+ - "LICENSE"
9
+ pull_request:
10
+ branches: [master]
11
+ paths-ignore:
12
+ - "**/*.md"
13
+ - "LICENSE"
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ concurrency:
19
+ group: ci-${{ github.workflow }}-${{ github.ref }}
20
+ cancel-in-progress: true
21
+
22
+ env:
23
+ CARGO_TERM_COLOR: always
24
+
25
+ jobs:
26
+ rust-lint:
27
+ name: Rust fmt & clippy
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v6
31
+ - uses: dtolnay/rust-toolchain@stable
32
+ - name: Install OpenBLAS
33
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
34
+ - name: Cache cargo registry & build
35
+ uses: actions/cache@v5
36
+ with:
37
+ path: |
38
+ ~/.cargo/registry
39
+ ~/.cargo/git
40
+ target
41
+ key: ubuntu-lint-${{ hashFiles('**/Cargo.lock') }}
42
+ restore-keys: ubuntu-lint-
43
+ - name: rustfmt --check
44
+ run: python3 scripts/ci/lme_ci.py fmt-check
45
+ - name: clippy
46
+ run: python3 scripts/ci/lme_ci.py clippy
47
+
48
+ test:
49
+ name: Test (${{ matrix.os }})
50
+ runs-on: ${{ matrix.os }}
51
+ strategy:
52
+ fail-fast: false
53
+ matrix:
54
+ os: [ubuntu-latest, windows-latest, macos-latest]
55
+
56
+ steps:
57
+ - uses: actions/checkout@v6
58
+
59
+ - name: Install Rust toolchain
60
+ uses: dtolnay/rust-toolchain@stable
61
+
62
+ - name: Install OpenBLAS (Ubuntu)
63
+ if: matrix.os == 'ubuntu-latest'
64
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
65
+
66
+ - name: Cache cargo registry & build
67
+ uses: actions/cache@v5
68
+ with:
69
+ path: |
70
+ ~/.cargo/registry
71
+ ~/.cargo/git
72
+ target
73
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
74
+ restore-keys: ${{ runner.os }}-cargo-
75
+
76
+ - name: Set OpenBLAS target (macOS)
77
+ if: matrix.os == 'macos-latest'
78
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
79
+
80
+ - name: Build
81
+ run: cargo build --verbose --locked
82
+
83
+ - name: Run tests
84
+ run: cargo test --verbose --locked
85
+
86
+ - name: Set up Python
87
+ uses: actions/setup-python@v6
88
+ with:
89
+ python-version: "3.11"
90
+ cache: pip
91
+ cache-dependency-path: python/requirements-ci.txt
92
+
93
+ - name: Python bindings (maturin develop, pytest, wheel install, pytest)
94
+ working-directory: python
95
+ shell: bash
96
+ run: |
97
+ set -euo pipefail
98
+ python -m venv .venv
99
+ if [ -f .venv/Scripts/python.exe ]; then
100
+ VPY=.venv/Scripts/python.exe
101
+ else
102
+ VPY=.venv/bin/python
103
+ fi
104
+ "$VPY" -m pip install -U pip
105
+ "$VPY" -m pip install -r requirements-ci.txt
106
+ "$VPY" -m maturin develop --release
107
+ "$VPY" -m pytest tests/ -v
108
+ "$VPY" -m maturin build --release -o dist
109
+ shopt -s nullglob
110
+ wheels=(dist/lme_python-*.whl)
111
+ if [ ${#wheels[@]} -eq 0 ]; then
112
+ echo "No wheel found under python/dist"
113
+ ls -la dist 2>/dev/null || true
114
+ exit 1
115
+ fi
116
+ "$VPY" -m pip install --force-reinstall "${wheels[0]}"
117
+ "$VPY" -m pytest tests/ -v
118
+
119
+ rust-all-targets:
120
+ name: Rust check (all targets)
121
+ runs-on: ubuntu-latest
122
+ steps:
123
+ - uses: actions/checkout@v6
124
+ - uses: dtolnay/rust-toolchain@stable
125
+ - name: Install OpenBLAS
126
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
127
+ - name: Cache cargo registry & build
128
+ uses: actions/cache@v5
129
+ with:
130
+ path: |
131
+ ~/.cargo/registry
132
+ ~/.cargo/git
133
+ target
134
+ key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
135
+ restore-keys: ubuntu-cargo-
136
+ - name: cargo check --workspace --all-targets
137
+ run: cargo check --workspace --all-targets --locked -v
138
+
139
+ production-load:
140
+ name: Production load & perf gates (ubuntu, release)
141
+ runs-on: ubuntu-latest
142
+ steps:
143
+ - uses: actions/checkout@v6
144
+
145
+ - name: Install Rust toolchain
146
+ uses: dtolnay/rust-toolchain@stable
147
+
148
+ - name: Install OpenBLAS (Ubuntu)
149
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
150
+
151
+ - name: Cache cargo registry & build
152
+ uses: actions/cache@v5
153
+ with:
154
+ path: |
155
+ ~/.cargo/registry
156
+ ~/.cargo/git
157
+ target
158
+ key: ubuntu-prodload-${{ hashFiles('**/Cargo.lock') }}
159
+ restore-keys: ubuntu-prodload-
160
+
161
+ - name: Production load tests (smoke + release wall-clock gates)
162
+ run: cargo test --release --locked --verbose --test test_production_load
163
+
164
+ - name: Heavy production load tests (ignored)
165
+ run: cargo test --release --locked --verbose --test test_production_load -- --ignored --test-threads=1
166
+
167
+ rust-doctests:
168
+ name: Rust doctests
169
+ runs-on: ubuntu-latest
170
+ steps:
171
+ - uses: actions/checkout@v6
172
+ - uses: dtolnay/rust-toolchain@stable
173
+ - name: Install OpenBLAS
174
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
175
+ - name: Cache cargo registry & build
176
+ uses: actions/cache@v5
177
+ with:
178
+ path: |
179
+ ~/.cargo/registry
180
+ ~/.cargo/git
181
+ target
182
+ key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
183
+ restore-keys: ubuntu-cargo-
184
+ - name: cargo test --doc
185
+ run: cargo test --doc --locked --verbose
186
+
187
+ python-bindings-versions:
188
+ name: Python ${{ matrix.python-version }} (ubuntu)
189
+ runs-on: ubuntu-latest
190
+ strategy:
191
+ fail-fast: false
192
+ matrix:
193
+ python-version: ["3.10", "3.12", "3.13"]
194
+ steps:
195
+ - uses: actions/checkout@v6
196
+ - uses: dtolnay/rust-toolchain@stable
197
+ - name: Install OpenBLAS
198
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
199
+ - name: Cache cargo registry & build
200
+ uses: actions/cache@v5
201
+ with:
202
+ path: |
203
+ ~/.cargo/registry
204
+ ~/.cargo/git
205
+ target
206
+ key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
207
+ restore-keys: ubuntu-cargo-
208
+ - name: Set up Python
209
+ uses: actions/setup-python@v6
210
+ with:
211
+ python-version: ${{ matrix.python-version }}
212
+ cache: pip
213
+ cache-dependency-path: python/requirements-ci.txt
214
+ - name: Python bindings (maturin develop, pytest, wheel install, pytest)
215
+ working-directory: python
216
+ shell: bash
217
+ run: |
218
+ set -euo pipefail
219
+ python -m venv .venv
220
+ if [ -f .venv/Scripts/python.exe ]; then
221
+ VPY=.venv/Scripts/python.exe
222
+ else
223
+ VPY=.venv/bin/python
224
+ fi
225
+ "$VPY" -m pip install -U pip
226
+ "$VPY" -m pip install -r requirements-ci.txt
227
+ "$VPY" -m maturin develop --release
228
+ "$VPY" -m pytest tests/ -v
229
+ "$VPY" -m maturin build --release -o dist
230
+ shopt -s nullglob
231
+ wheels=(dist/lme_python-*.whl)
232
+ if [ ${#wheels[@]} -eq 0 ]; then
233
+ echo "No wheel found under python/dist"
234
+ ls -la dist 2>/dev/null || true
235
+ exit 1
236
+ fi
237
+ "$VPY" -m pip install --force-reinstall "${wheels[0]}"
238
+ "$VPY" -m pytest tests/ -v
239
+
240
+ docs:
241
+ name: Build docs
242
+ runs-on: ubuntu-latest
243
+ steps:
244
+ - uses: actions/checkout@v6
245
+ - uses: dtolnay/rust-toolchain@stable
246
+ - name: Build documentation
247
+ run: cargo doc --no-deps --verbose --locked
@@ -0,0 +1,28 @@
1
+ name: Crate publish (dry-run)
2
+
3
+ # Verifies `cargo publish` packaging (metadata, README, excluded files) without uploading.
4
+
5
+ on:
6
+ push:
7
+ tags:
8
+ - "v*"
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: publish-dry-run-${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ dry-run:
20
+ name: cargo publish --dry-run
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v6
24
+
25
+ - uses: dtolnay/rust-toolchain@stable
26
+
27
+ - name: Dry-run publish (root crate)
28
+ run: cargo publish --dry-run --locked
@@ -0,0 +1,34 @@
1
+ # Manual libFuzzer smoke (long compile + short run). Trigger from the Actions tab.
2
+ name: Fuzz (manual)
3
+
4
+ on:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ libfuzzer-smoke:
9
+ runs-on: ubuntu-latest
10
+ timeout-minutes: 120
11
+ defaults:
12
+ run:
13
+ working-directory: fuzz
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: dtolnay/rust-toolchain@nightly
19
+
20
+ - name: Install cargo-fuzz
21
+ run: cargo install cargo-fuzz --locked
22
+
23
+ - uses: Swatinem/rust-cache@v2
24
+ with:
25
+ workspaces: fuzz
26
+
27
+ - name: Build fuzz targets
28
+ run: cargo fuzz build formula_parse && cargo fuzz build formula_pipeline
29
+
30
+ - name: Run formula_parse
31
+ run: cargo fuzz run formula_parse corpus/formula_parse -- -runs=15000 -max_len=16384
32
+
33
+ - name: Run formula_pipeline
34
+ run: cargo fuzz run formula_pipeline corpus/formula_parse -- -runs=15000 -max_len=16384
@@ -23,8 +23,8 @@ jobs:
23
23
  matrix:
24
24
  target: [x86_64, aarch64]
25
25
  steps:
26
- - uses: actions/checkout@v4
27
- - uses: actions/setup-python@v5
26
+ - uses: actions/checkout@v6
27
+ - uses: actions/setup-python@v6
28
28
  with:
29
29
  python-version: '3.10'
30
30
  - name: Build wheels
@@ -44,7 +44,7 @@ jobs:
44
44
  CFLAGS: "-std=gnu99"
45
45
  CFLAGS_aarch64_unknown_linux_gnu: "-std=gnu99"
46
46
  - name: Upload wheels
47
- uses: actions/upload-artifact@v4
47
+ uses: actions/upload-artifact@v7
48
48
  with:
49
49
  name: wheels-linux-${{ matrix.target }}
50
50
  path: dist
@@ -55,8 +55,8 @@ jobs:
55
55
  matrix:
56
56
  target: [x64]
57
57
  steps:
58
- - uses: actions/checkout@v4
59
- - uses: actions/setup-python@v5
58
+ - uses: actions/checkout@v6
59
+ - uses: actions/setup-python@v6
60
60
  with:
61
61
  python-version: '3.10'
62
62
  architecture: ${{ matrix.target }}
@@ -67,7 +67,7 @@ jobs:
67
67
  args: --release --out dist --manifest-path python/Cargo.toml
68
68
  sccache: 'true'
69
69
  - name: Upload wheels
70
- uses: actions/upload-artifact@v4
70
+ uses: actions/upload-artifact@v7
71
71
  with:
72
72
  name: wheels-windows-${{ matrix.target }}
73
73
  path: dist
@@ -78,12 +78,13 @@ jobs:
78
78
  matrix:
79
79
  target: [x86_64, aarch64]
80
80
  steps:
81
- - uses: actions/checkout@v4
82
- - uses: actions/setup-python@v5
81
+ - uses: actions/checkout@v6
82
+ - uses: actions/setup-python@v6
83
83
  with:
84
84
  python-version: '3.10'
85
- - name: Install OpenBLAS
86
- run: brew install openblas
85
+ - name: Set OpenBLAS target (Apple Silicon wheel)
86
+ if: matrix.target == 'aarch64'
87
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
87
88
  - name: Build wheels
88
89
  uses: PyO3/maturin-action@v1
89
90
  with:
@@ -91,7 +92,7 @@ jobs:
91
92
  args: --release --out dist --manifest-path python/Cargo.toml
92
93
  sccache: 'true'
93
94
  - name: Upload wheels
94
- uses: actions/upload-artifact@v4
95
+ uses: actions/upload-artifact@v7
95
96
  with:
96
97
  name: wheels-macos-${{ matrix.target }}
97
98
  path: dist
@@ -99,14 +100,14 @@ jobs:
99
100
  sdist:
100
101
  runs-on: ubuntu-latest
101
102
  steps:
102
- - uses: actions/checkout@v4
103
+ - uses: actions/checkout@v6
103
104
  - name: Build sdist
104
105
  uses: PyO3/maturin-action@v1
105
106
  with:
106
107
  command: sdist
107
108
  args: --out dist --manifest-path python/Cargo.toml
108
109
  - name: Upload sdist
109
- uses: actions/upload-artifact@v4
110
+ uses: actions/upload-artifact@v7
110
111
  with:
111
112
  name: wheels-sdist
112
113
  path: dist
@@ -122,7 +123,7 @@ jobs:
122
123
  id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
123
124
  contents: write # needed to create GitHub Release
124
125
  steps:
125
- - uses: actions/download-artifact@v4
126
+ - uses: actions/download-artifact@v7
126
127
  with:
127
128
  path: dist
128
129
  pattern: wheels-*
@@ -16,7 +16,7 @@ jobs:
16
16
  sync:
17
17
  runs-on: ubuntu-latest
18
18
  steps:
19
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@v6
20
20
 
21
21
  - name: Verify admin token is configured
22
22
  env:
@@ -24,10 +24,20 @@ jobs:
24
24
  run: |
25
25
  if [ -z "$REPO_ADMIN_TOKEN" ]; then
26
26
  echo "REPO_ADMIN_TOKEN is not set."
27
- echo "Create a fine-grained PAT or GitHub App token with repository Administration: write."
27
+ echo "Create a fine-grained PAT with repository Administration: Read and write."
28
+ echo "Add it under Settings → Secrets and variables → Actions → REPO_ADMIN_TOKEN."
28
29
  exit 1
29
30
  fi
30
31
 
32
+ - name: Dry-run metadata payload
33
+ run: python scripts/sync_github_repo_metadata.py --dry-run
34
+
35
+ - name: Verify admin token is valid
36
+ env:
37
+ REPO_ADMIN_TOKEN: ${{ secrets.REPO_ADMIN_TOKEN }}
38
+ GITHUB_REPOSITORY: ${{ github.repository }}
39
+ run: python scripts/sync_github_repo_metadata.py --verify-token
40
+
31
41
  - name: Sync repository metadata
32
42
  env:
33
43
  REPO_ADMIN_TOKEN: ${{ secrets.REPO_ADMIN_TOKEN }}
@@ -1,4 +1,7 @@
1
1
  /target
2
+ /fuzz/artifacts/
3
+ /fuzz/coverage/
4
+ /fuzz/target/
2
5
  reference/
3
6
  rlib/
4
7
  julia-portable/