From 23044f0309e559aa48e9a5cbd58e14e087d8a5f5 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 15:12:51 -0400 Subject: [PATCH 1/8] add fixture --- causalpy/tests/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/causalpy/tests/conftest.py b/causalpy/tests/conftest.py index f01dc693..563290f5 100644 --- a/causalpy/tests/conftest.py +++ b/causalpy/tests/conftest.py @@ -20,6 +20,7 @@ import numpy as np import pytest +from pymc.testing import mock_sample_setup_and_teardown @pytest.fixture(scope="session") @@ -27,3 +28,6 @@ def rng() -> np.random.Generator: """Random number generator that can persist through a pytest session""" seed: int = sum(map(ord, "causalpy")) return np.random.default_rng(seed=seed) + + +mock_pymc_sample = pytest.fixture(mock_sample_setup_and_teardown, scope="session") From 09be0a749f04cbb34190ad696bcca2cf4c5045ec Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 15:13:07 -0400 Subject: [PATCH 2/8] save ~10s --- causalpy/tests/test_pymc_models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/causalpy/tests/test_pymc_models.py b/causalpy/tests/test_pymc_models.py index 29664d18..bd6f799c 100644 --- a/causalpy/tests/test_pymc_models.py +++ b/causalpy/tests/test_pymc_models.py @@ -93,7 +93,7 @@ def test_fit_build_not_implemented(self): argvalues=[None, {"a": 1}], ids=["None-coords", "dict-coords"], ) - def test_fit_predict(self, coords, rng) -> None: + def test_fit_predict(self, coords, rng, mock_pymc_sample) -> None: """ Test fit and predict methods on MyToyModel. @@ -122,7 +122,7 @@ def test_fit_predict(self, coords, rng) -> None: assert isinstance(predictions, az.InferenceData) -def test_idata_property(): +def test_idata_property(mock_pymc_sample): """Test that we can access the idata property of the model""" df = cp.load_data("did") result = cp.DifferenceInDifferences( @@ -140,7 +140,7 @@ def test_idata_property(): @pytest.mark.parametrize("seed", seeds) -def test_result_reproducibility(seed): +def test_result_reproducibility(seed, mock_pymc_sample): """Test that we can reproduce the results from the model. We could in theory test this with all the model and experiment types, but what is being targeted is the PyMCModel.fit method, so we should be safe testing with just one model. Here From eb4c4a2810f984d73405fa269ba5514032d7bf52 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 15:17:53 -0400 Subject: [PATCH 3/8] save ~40s --- .../tests/test_integration_pymc_examples.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/causalpy/tests/test_integration_pymc_examples.py b/causalpy/tests/test_integration_pymc_examples.py index 224e22fc..76f454ef 100644 --- a/causalpy/tests/test_integration_pymc_examples.py +++ b/causalpy/tests/test_integration_pymc_examples.py @@ -23,7 +23,7 @@ @pytest.mark.integration -def test_did(): +def test_did(mock_pymc_sample): """ Test Difference in Differences (DID) PyMC experiment. @@ -57,7 +57,7 @@ def test_did(): @pytest.mark.integration -def test_did_banks_simple(): +def test_did_banks_simple(mock_pymc_sample): """ Test simple Differences In Differences Experiment on the 'banks' data set. @@ -113,7 +113,7 @@ def test_did_banks_simple(): @pytest.mark.integration -def test_did_banks_multi(): +def test_did_banks_multi(mock_pymc_sample): """ Test multiple regression Differences In Differences Experiment on the 'banks' data set. @@ -168,7 +168,7 @@ def test_did_banks_multi(): @pytest.mark.integration -def test_rd(): +def test_rd(mock_pymc_sample): """ Test Regression Discontinuity experiment. @@ -199,7 +199,7 @@ def test_rd(): @pytest.mark.integration -def test_rd_bandwidth(): +def test_rd_bandwidth(mock_pymc_sample): """ Test Regression Discontinuity experiment with bandwidth parameter. @@ -229,7 +229,7 @@ def test_rd_bandwidth(): @pytest.mark.integration -def test_rd_drinking(): +def test_rd_drinking(mock_pymc_sample): """ Test Regression Discontinuity experiment on drinking age data. @@ -289,7 +289,7 @@ def reg_kink_function(x, beta, kink): @pytest.mark.integration -def test_rkink(): +def test_rkink(mock_pymc_sample): """ Test Regression Kink design. @@ -320,7 +320,7 @@ def test_rkink(): @pytest.mark.integration -def test_rkink_bandwidth(): +def test_rkink_bandwidth(mock_pymc_sample): """ Test Regression Kink experiment with bandwidth parameter. @@ -350,7 +350,7 @@ def test_rkink_bandwidth(): @pytest.mark.integration -def test_its(): +def test_its(mock_pymc_sample): """ Test Interrupted Time-Series experiment. @@ -403,7 +403,7 @@ def test_its(): @pytest.mark.integration -def test_its_covid(): +def test_its_covid(mock_pymc_sample): """ Test Interrupted Time-Series experiment on COVID data. @@ -457,7 +457,7 @@ def test_its_covid(): @pytest.mark.integration -def test_sc(): +def test_sc(mock_pymc_sample): """ Test Synthetic Control experiment. @@ -516,7 +516,7 @@ def test_sc(): @pytest.mark.integration -def test_sc_brexit(): +def test_sc_brexit(mock_pymc_sample): """ Test Synthetic Control experiment on Brexit data. @@ -579,7 +579,7 @@ def test_sc_brexit(): @pytest.mark.integration -def test_ancova(): +def test_ancova(mock_pymc_sample): """ Test Pre-PostNEGD experiment on anova1 data. @@ -611,7 +611,7 @@ def test_ancova(): @pytest.mark.integration -def test_geolift1(): +def test_geolift1(mock_pymc_sample): """ Test Synthetic Control experiment on geo lift data. @@ -648,7 +648,7 @@ def test_geolift1(): @pytest.mark.integration -def test_iv_reg(): +def test_iv_reg(mock_pymc_sample): df = cp.load_data("risk") instruments_formula = "risk ~ 1 + logmort0" formula = "loggdp ~ 1 + risk" @@ -676,7 +676,7 @@ def test_iv_reg(): @pytest.mark.integration -def test_inverse_prop(): +def test_inverse_prop(mock_pymc_sample): """Test the InversePropensityWeighting class.""" df = cp.load_data("nhefs") sample_kwargs = { From 5dcb7c90cad0e91fffb2309529c0a795cddfd3b9 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 16:09:38 -0400 Subject: [PATCH 4/8] remove the default adopts --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 29f86277..3ac3a242 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,6 @@ addopts = [ "--strict-config", "--cov=causalpy", "--cov-report=term-missing", - "--doctest-modules", ] testpaths = "causalpy/tests" markers = [ From 6c45f793aa758d86592658b8d49944f39243c777 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 16:10:01 -0400 Subject: [PATCH 5/8] mock for doctest --- causalpy/tests/conftest.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/causalpy/tests/conftest.py b/causalpy/tests/conftest.py index 563290f5..f966a785 100644 --- a/causalpy/tests/conftest.py +++ b/causalpy/tests/conftest.py @@ -20,7 +20,7 @@ import numpy as np import pytest -from pymc.testing import mock_sample_setup_and_teardown +from pymc.testing import mock_sample, mock_sample_setup_and_teardown @pytest.fixture(scope="session") @@ -31,3 +31,13 @@ def rng() -> np.random.Generator: mock_pymc_sample = pytest.fixture(mock_sample_setup_and_teardown, scope="session") + + +@pytest.fixture(autouse=True) +def mock_sample_for_doctest(request): + if not request.config.getoption("--doctest-modules", default=False): + return + + import pymc as pm + + pm.sample = mock_sample From 1c3cb92ff8cafaa392c5991308ce70bce4bce043 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 16:10:57 -0400 Subject: [PATCH 6/8] point to the config file --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72b0e00d..13d211ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - name: Setup environment run: pip install -e .[test] - name: Run doctests - run: pytest --doctest-modules --ignore=causalpy/tests/ causalpy/ + run: pytest --doctest-modules --ignore=causalpy/tests/ causalpy/ --config-file=causalpy/tests/conftest.py - name: Run extra tests run: pytest docs/source/.codespell/test_notebook_to_markdown.py - name: Run tests From 9250f3dc6befe7bd84cd00ff8d4af15ea44890d3 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Mon, 16 Jun 2025 16:14:07 -0400 Subject: [PATCH 7/8] skip the failing one --- causalpy/experiments/prepostnegd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/causalpy/experiments/prepostnegd.py b/causalpy/experiments/prepostnegd.py index beec847e..7a5620fb 100644 --- a/causalpy/experiments/prepostnegd.py +++ b/causalpy/experiments/prepostnegd.py @@ -72,7 +72,7 @@ class PrePostNEGD(BaseExperiment): ... } ... ), ... ) - >>> result.summary(round_to=1) # doctest: +NUMBER + >>> result.summary(round_to=1) # doctest: +SKIP ==================Pretest/posttest Nonequivalent Group Design=================== Formula: post ~ 1 + C(group) + pre From 990104d16d00e2359ed422bbe7ce508222d795ec Mon Sep 17 00:00:00 2001 From: Will Dean Date: Sun, 29 Jun 2025 09:30:15 -0400 Subject: [PATCH 8/8] point to the conftest file in make command --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9f2b1971..d109ae39 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: init lint check_lint test uml html cleandocs +.PHONY: init lint check_lint test uml html cleandocs doctest init: python -m pip install -e . --no-deps @@ -13,7 +13,7 @@ check_lint: interrogate . doctest: - pytest --doctest-modules --ignore=causalpy/tests/ causalpy/ + pytest --doctest-modules --ignore=causalpy/tests/ causalpy/ --config-file=causalpy/tests/conftest.py test: pytest