Skip to content

Commit f4a1814

Browse files
Sync environment.yml with pyproject.toml via pyproject2conda pre-commit hook (#713)
* Sync environment.yml with pyproject.toml via pyproject2conda pre-commit hook - Add pyproject2conda pre-commit hook to regenerate environment.yml from pyproject.toml when deps change (base + dev extra + conda-only deps) - Add [tool.pyproject2conda] with conda-forge channel in pyproject.toml - Regenerate environment.yml; adds pymc-marketing and full dev deps Closes #712 Co-authored-by: Cursor <cursoragent@cursor.com> * Address adversarial review: CI env-sync check, CONTRIBUTING note, hook comments - Add check-environment-yml CI job to fail if environment.yml is out of sync - Document in CONTRIBUTING that environment.yml is generated from pyproject.toml - Comment in pre-commit-config: python>=3.12 and conda-only deps Co-authored-by: Cursor <cursoragent@cursor.com> * ci: set persist-credentials: false in check-environment-yml job Address GitHub Advanced Security warning about credential persistence. Co-authored-by: Cursor <cursoragent@cursor.com> * Move pymc-marketing to docs extra; document pip vs conda - pyproject.toml: remove pymc-marketing from core deps, add to docs extra - environment.yml: regenerated (no pymc-marketing in default env) - Integration tests: skip BSTS tests when pymc_marketing not installed (importorskip) - AGENTS.md: deps in pyproject.toml; supported dev setup is conda (pip -e .[dev] lacks conda-only tooling) - README: add fallback line for PyMC install issues (try conda) - ci.yml: add security comment for test job persist-credentials Co-authored-by: Cursor <cursoragent@cursor.com> * Skip BSTS coverage tests when pymc-marketing not installed Add autouse fixture to TestBayesianBasisExpansionTimeSeriesCoverage that calls pytest.importorskip('pymc_marketing') so the whole class is skipped when the optional dependency is missing (e.g. in CI without docs extra). Co-authored-by: Cursor <cursoragent@cursor.com> Made-with: Cursor --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 59931e6 commit f4a1814

10 files changed

Lines changed: 101 additions & 8 deletions

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ on:
99
permissions: {}
1010

1111
jobs:
12+
check-environment-yml:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
steps:
17+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
# Security: do not set to true — prevents credential leakage (GitHub Advanced Security).
20+
persist-credentials: false
21+
- name: Set up Python
22+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
23+
with:
24+
python-version: "3.12"
25+
- name: Install pyproject2conda
26+
run: pip install pyproject2conda
27+
- name: Regenerate environment.yml (same args as pre-commit hook)
28+
run: |
29+
pyproject2conda yaml -e dev -o /tmp/environment.generated.yml -n CausalPy \
30+
-w force --no-header \
31+
--python-include "python>=3.12" \
32+
-d make -d pip -d pymc-bart -r "marimo[mcp]"
33+
- name: Check environment.yml is in sync with pyproject.toml
34+
run: |
35+
# Compare YAML body only (skip 9-line autogenerated header in environment.yml)
36+
tail -n +10 environment.yml > /tmp/environment.current.yml
37+
diff -u /tmp/environment.current.yml /tmp/environment.generated.yml && echo "environment.yml is in sync with pyproject.toml"
38+
1239
test:
1340
runs-on: ubuntu-latest
1441
permissions:
@@ -20,6 +47,7 @@ jobs:
2047
steps:
2148
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2249
with:
50+
# Security: do not set to true — prevents credential leakage (GitHub Advanced Security).
2351
persist-credentials: false
2452
- name: Set up Python
2553
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0

.pre-commit-config.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@ repos:
6767
rev: v0.25
6868
hooks:
6969
- id: validate-pyproject
70+
# Regenerate environment.yml from pyproject.toml when deps change (run on commit; review diff).
71+
# Dev env uses python>=3.12; conda-only deps (make, pip, pymc-bart, marimo[mcp]) are in args.
72+
- repo: https://github.com/usnistgov/pyproject2conda
73+
rev: v0.22.1
74+
hooks:
75+
- id: pyproject2conda-yaml
76+
name: Sync environment.yml from pyproject.toml
77+
args:
78+
- -e
79+
- dev
80+
- -o
81+
- environment.yml
82+
- -n
83+
- CausalPy
84+
- -w
85+
- force
86+
- --python-include
87+
- "python>=3.12"
88+
- -d
89+
- make
90+
- -d
91+
- pip
92+
- -d
93+
- pymc-bart
94+
- -r
95+
- "marimo[mcp]"
7096
- repo: local
7197
hooks:
7298
- id: validate-bibtex

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Use `mamba`, `micromamba`, or `conda` (in that preference order) to manage the `
66

77
See the [python-environment skill](.github/skills/python-environment/SKILL.md) for full setup instructions: tool detection, environment creation, editable install, and troubleshooting.
88

9+
- Dependencies live in `pyproject.toml`; `environment.yml` is generated from it (do not edit by hand—see CONTRIBUTING). Optional: `pymc-marketing` is in the `docs` extra only.
10+
- **Development**: The supported setup is the conda env (`environment.yml`). `pip install -e .[dev]` works but does not include conda-only tooling (e.g. `make`, `pymc-bart`, `marimo`); do not suggest pip-only dev as equivalent.
11+
912
## Testing preferences
1013

1114
- Write all Python tests as `pytest` style functions, not unittest classes

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ For more instructions see the [Pull request checklist](#pull-request-checklist)
115115
conda env create -f environment.yml
116116
```
117117
118-
To update an existing environment after changes to `environment.yml`:
118+
**Note:** `environment.yml` is generated from `pyproject.toml` by a pre-commit hook. To change dependencies, edit `pyproject.toml` and run `pre-commit run --all-files` (or regenerate with `pyproject2conda yaml` using the same args as in `.pre-commit-config.yaml`). Do not edit `environment.yml` by hand—it will be overwritten when `pyproject.toml` is committed.
119+
120+
To update an existing environment after changes to `environment.yml` (e.g. after pulling or after regenerating it from `pyproject.toml`):
119121
120122
```bash
121123
conda env update --file environment.yml --prune

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ To get the latest release:
2424
pip install CausalPy
2525
```
2626

27+
If you run into installation issues with PyMC (e.g. BLAS or compilation), try the conda install: `conda install -c conda-forge causalpy`.
28+
2729
Alternatively, if you want the very latest version of the package you can install from GitHub:
2830

2931
```bash

causalpy/tests/test_integration_its_new_timeseries.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
@pytest.mark.integration
2424
def test_its_with_bsts_model():
2525
"""InterruptedTimeSeries integration using BayesianBasisExpansionTimeSeries."""
26+
pytest.importorskip(
27+
"pymc_marketing", reason="pymc-marketing optional for default BSTS components"
28+
)
2629
# Prepare data
2730
df = (
2831
cp.load_data("its")

causalpy/tests/test_integration_pymc_examples.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,9 @@ def test_inverse_prop(mock_pymc_sample):
850850
@pytest.mark.integration
851851
def test_bayesian_structural_time_series():
852852
"""Test the BayesianBasisExpansionTimeSeries model."""
853+
pytest.importorskip(
854+
"pymc_marketing", reason="pymc-marketing optional for default BSTS components"
855+
)
853856
# Generate synthetic data
854857
rng = np.random.default_rng(seed=123)
855858
dates = pd.date_range(start="2020-01-01", end="2021-12-31", freq="D")

causalpy/tests/test_timeseries_model_coverage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ class MockComponentNoApply:
4242
class TestBayesianBasisExpansionTimeSeriesCoverage:
4343
"""Test uncovered branches in BayesianBasisExpansionTimeSeries."""
4444

45+
@pytest.fixture(autouse=True)
46+
def _skip_if_no_pymc_marketing(self):
47+
"""Skip entire class when pymc-marketing not installed (needed for default BSTS components)."""
48+
pytest.importorskip(
49+
"pymc_marketing",
50+
reason="pymc-marketing optional for default BSTS components",
51+
)
52+
4553
@pytest.fixture
4654
def sample_data(self):
4755
"""Create sample time series data."""

environment.yml

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
1+
#
2+
# This file is autogenerated by pyproject2conda
3+
# with the following command:
4+
#
5+
# $ pre-commit
6+
#
7+
# You should not manually edit this file.
8+
# Instead edit the corresponding pyproject.toml file.
9+
#
110
name: CausalPy
211
channels:
312
- conda-forge
413
dependencies:
14+
- python>=3.12
515
- arviz>=0.14.0
16+
- codespell
617
- graphviz
7-
- make
18+
- interrogate
819
- ipython!=8.7.0
20+
- make
921
- matplotlib>=3.5.3
10-
- numpy
22+
- nbconvert
23+
- nbformat
24+
- numpy<2.4
1125
- pandas
1226
- patsy
1327
- pre-commit
28+
- pymc-bart
29+
- pymc-extras>=0.3.0
1430
- pymc>=5.15.1
1531
- scikit-learn>=1
1632
- scipy
1733
- seaborn>=0.11.2
1834
- statsmodels
35+
- twine
1936
- xarray>=v2022.11.0
20-
- pymc-extras>=0.3.0
21-
- pymc-bart
22-
- python>=3.12
2337
- pip
24-
- "marimo[mcp]"
38+
- pip:
39+
- marimo[mcp]

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ dependencies = [
4747
"pandas",
4848
"patsy",
4949
"pymc>=5.15.1",
50-
"pymc-marketing>=0.13.1",
5150
"scikit-learn>=1",
5251
"scipy",
5352
"seaborn>=0.11.2",
@@ -73,6 +72,7 @@ dev = [
7372
]
7473
docs = [
7574
"ipykernel",
75+
"pymc-marketing>=0.13.1",
7676
"daft-pgm",
7777
"linkify-it-py",
7878
"myst-nb<=1.0.0",
@@ -95,6 +95,9 @@ docs = [
9595
lint = ["interrogate", "pre-commit", "ruff", "mypy"]
9696
test = ["pytest", "pytest-cov", "codespell", "nbformat", "nbconvert", "papermill"]
9797

98+
[tool.pyproject2conda]
99+
channels = ["conda-forge"]
100+
98101
[project.urls]
99102
Homepage = "https://github.com/pymc-labs/CausalPy"
100103
"Bug Reports" = "https://github.com/pymc-labs/CausalPy/issues"

0 commit comments

Comments
 (0)