From 3630a655f28ef33f4084b9a4c41616f4dd0e4467 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Wed, 23 Apr 2025 13:18:58 +0100 Subject: [PATCH 1/8] added confidence intervals to ExactValue --- causal_testing/testing/causal_test_outcome.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/causal_testing/testing/causal_test_outcome.py b/causal_testing/testing/causal_test_outcome.py index 6c1ea86e..648f3cee 100644 --- a/causal_testing/testing/causal_test_outcome.py +++ b/causal_testing/testing/causal_test_outcome.py @@ -73,22 +73,24 @@ def apply(self, res: CausalTestResult) -> bool: raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") -class ExactValue(SomeEffect): +class ExactValue(CausalTestOutcome): """An extension of TestOutcome representing that the expected causal effect should be a specific value.""" - def __init__(self, value: float, atol: float = None): + def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_high: float = None): + if (ci_low is not None) ^ (ci_high is not None): + raise ValueError("If specifying confidence intervals, must specify `ci_low` and `ci_high` parameters.") self.value = value - if atol is None: - self.atol = abs(value * 0.05) - else: - self.atol = atol + self.ci_low = ci_low + self.ci_high = ci_high + self.atol = atol if atol is not None else abs(value * 0.05) if self.atol < 0: - raise ValueError("Tolerance must be an absolute value.") + raise ValueError("Tolerance must be an absolute (positive) value.") def apply(self, res: CausalTestResult) -> bool: - if res.ci_valid(): - return super().apply(res) and np.isclose(res.test_value.value, self.value, atol=self.atol) - return np.isclose(res.test_value.value, self.value, atol=self.atol) + close = np.isclose(res.test_value.value, self.value, atol=self.atol) + if res.ci_valid() and self.ci_low is not None and self.ci_high is not None: + return close and self.ci_low <= res.ci_low() and self.ci_high >= res.ci_high() + return close def __str__(self): return f"ExactValue: {self.value}±{self.atol}" From c867ac6ffc9bd53848d14b8b0602298b3e604a86 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Wed, 23 Apr 2025 13:20:47 +0100 Subject: [PATCH 2/8] Renamed CausalTestOutcome to CausalEffect --- causal_testing/main.py | 2 +- .../{causal_test_outcome.py => causal_effect.py} | 10 +++++----- causal_testing/testing/causal_test_case.py | 4 ++-- dafni/main_dafni.py | 2 +- docs/source/usage.rst | 2 +- examples/covasim_/doubling_beta/example_beta.py | 2 +- .../covasim_/vaccinating_elderly/example_vaccine.py | 2 +- examples/lr91/example_max_conductances.py | 2 +- examples/poisson-line-process/example_pure_python.py | 2 +- tests/testing_tests/test_causal_test_adequacy.py | 2 +- tests/testing_tests/test_causal_test_case.py | 2 +- tests/testing_tests/test_causal_test_outcome.py | 6 +++--- 12 files changed, 19 insertions(+), 19 deletions(-) rename causal_testing/testing/{causal_test_outcome.py => causal_effect.py} (95%) diff --git a/causal_testing/main.py b/causal_testing/main.py index 9685e723..89ae0e44 100644 --- a/causal_testing/main.py +++ b/causal_testing/main.py @@ -17,7 +17,7 @@ from causal_testing.specification.causal_specification import CausalSpecification from causal_testing.testing.causal_test_case import CausalTestCase from causal_testing.testing.base_test_case import BaseTestCase -from causal_testing.testing.causal_test_outcome import NoEffect, SomeEffect, Positive, Negative +from causal_testing.testing.causal_effect import NoEffect, SomeEffect, Positive, Negative from causal_testing.testing.causal_test_result import CausalTestResult, TestValue from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.estimation.logistic_regression_estimator import LogisticRegressionEstimator diff --git a/causal_testing/testing/causal_test_outcome.py b/causal_testing/testing/causal_effect.py similarity index 95% rename from causal_testing/testing/causal_test_outcome.py rename to causal_testing/testing/causal_effect.py index 648f3cee..9a99404a 100644 --- a/causal_testing/testing/causal_test_outcome.py +++ b/causal_testing/testing/causal_effect.py @@ -1,5 +1,5 @@ # pylint: disable=too-few-public-methods -"""This module contains the CausalTestOutcome abstract class, as well as the concrete extension classes: +"""This module contains the CausalEffect abstract class, as well as the concrete extension classes: ExactValue, Positive, Negative, SomeEffect, NoEffect""" from abc import ABC, abstractmethod @@ -9,7 +9,7 @@ from causal_testing.testing.causal_test_result import CausalTestResult -class CausalTestOutcome(ABC): +class CausalEffect(ABC): """An abstract class representing an expected causal effect.""" @abstractmethod @@ -23,7 +23,7 @@ def __str__(self) -> str: return type(self).__name__ -class SomeEffect(CausalTestOutcome): +class SomeEffect(CausalEffect): """An extension of TestOutcome representing that the expected causal effect should not be zero.""" def apply(self, res: CausalTestResult) -> bool: @@ -41,7 +41,7 @@ def apply(self, res: CausalTestResult) -> bool: raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") -class NoEffect(CausalTestOutcome): +class NoEffect(CausalEffect): """An extension of TestOutcome representing that the expected causal effect should be zero.""" def __init__(self, atol: float = 1e-10, ctol: float = 0.05): @@ -73,7 +73,7 @@ def apply(self, res: CausalTestResult) -> bool: raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") -class ExactValue(CausalTestOutcome): +class ExactValue(CausalEffect): """An extension of TestOutcome representing that the expected causal effect should be a specific value.""" def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_high: float = None): diff --git a/causal_testing/testing/causal_test_case.py b/causal_testing/testing/causal_test_case.py index 30343560..64fb75cb 100644 --- a/causal_testing/testing/causal_test_case.py +++ b/causal_testing/testing/causal_test_case.py @@ -4,7 +4,7 @@ from typing import Any from causal_testing.specification.variable import Variable -from causal_testing.testing.causal_test_outcome import CausalTestOutcome +from causal_testing.testing.causal_effect import CausalEffect from causal_testing.testing.base_test_case import BaseTestCase from causal_testing.estimation.abstract_estimator import Estimator from causal_testing.testing.causal_test_result import CausalTestResult, TestValue @@ -26,7 +26,7 @@ def __init__( # pylint: disable=too-many-arguments self, base_test_case: BaseTestCase, - expected_causal_effect: CausalTestOutcome, + expected_causal_effect: CausalEffect, estimate_type: str = "ate", estimate_params: dict = None, effect_modifier_configuration: dict[Variable:Any] = None, diff --git a/dafni/main_dafni.py b/dafni/main_dafni.py index ed310cda..a3d8f5c6 100644 --- a/dafni/main_dafni.py +++ b/dafni/main_dafni.py @@ -10,7 +10,7 @@ import pandas as pd from causal_testing.specification.scenario import Scenario from causal_testing.specification.variable import Input, Output -from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect, SomeEffect +from causal_testing.testing.causal_effect import Positive, Negative, NoEffect, SomeEffect from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.estimation.logistic_regression_estimator import LogisticRegressionEstimator from causal_testing.json_front.json_class import JsonUtility diff --git a/docs/source/usage.rst b/docs/source/usage.rst index adab3719..d4be317a 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -44,7 +44,7 @@ the given output and input and the desired effect. This information is the minim from causal_testing.testing.base_test_case import BaseTestCase from causal_testing.testing.causal_test_case import CausalTestCase - from causal_testing.testing.causal_test_outcome import Positive + from causal_testing.testing.causal_effect import Positive from causal_testing.testing.effect import Effect base_test_case = BaseTestCase( diff --git a/examples/covasim_/doubling_beta/example_beta.py b/examples/covasim_/doubling_beta/example_beta.py index 1655b352..e1a7be33 100644 --- a/examples/covasim_/doubling_beta/example_beta.py +++ b/examples/covasim_/doubling_beta/example_beta.py @@ -7,7 +7,7 @@ import numpy as np from causal_testing.specification.variable import Input, Output from causal_testing.testing.causal_test_case import CausalTestCase -from causal_testing.testing.causal_test_outcome import Positive +from causal_testing.testing.causal_effect import Positive from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.testing.base_test_case import BaseTestCase diff --git a/examples/covasim_/vaccinating_elderly/example_vaccine.py b/examples/covasim_/vaccinating_elderly/example_vaccine.py index 50936a0a..dede5d9e 100644 --- a/examples/covasim_/vaccinating_elderly/example_vaccine.py +++ b/examples/covasim_/vaccinating_elderly/example_vaccine.py @@ -7,7 +7,7 @@ from causal_testing.specification.variable import Input, Output from causal_testing.specification.causal_specification import CausalSpecification from causal_testing.testing.causal_test_case import CausalTestCase -from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect +from causal_testing.testing.causal_effect import Positive, Negative, NoEffect from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.testing.base_test_case import BaseTestCase diff --git a/examples/lr91/example_max_conductances.py b/examples/lr91/example_max_conductances.py index 6bd486c2..50ca0728 100644 --- a/examples/lr91/example_max_conductances.py +++ b/examples/lr91/example_max_conductances.py @@ -6,7 +6,7 @@ from causal_testing.specification.variable import Input, Output from causal_testing.specification.causal_specification import CausalSpecification from causal_testing.testing.causal_test_case import CausalTestCase -from causal_testing.testing.causal_test_outcome import Positive, Negative, NoEffect +from causal_testing.testing.causal_effect import Positive, Negative, NoEffect from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.testing.base_test_case import BaseTestCase from matplotlib.pyplot import rcParams diff --git a/examples/poisson-line-process/example_pure_python.py b/examples/poisson-line-process/example_pure_python.py index 0788896c..04f18616 100644 --- a/examples/poisson-line-process/example_pure_python.py +++ b/examples/poisson-line-process/example_pure_python.py @@ -8,7 +8,7 @@ from causal_testing.specification.variable import Input, Output from causal_testing.specification.causal_specification import CausalSpecification from causal_testing.testing.causal_test_case import CausalTestCase -from causal_testing.testing.causal_test_outcome import ExactValue, Positive +from causal_testing.testing.causal_effect import ExactValue, Positive from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.estimation.abstract_estimator import Estimator from causal_testing.testing.base_test_case import BaseTestCase diff --git a/tests/testing_tests/test_causal_test_adequacy.py b/tests/testing_tests/test_causal_test_adequacy.py index 56149024..aae1fc90 100644 --- a/tests/testing_tests/test_causal_test_adequacy.py +++ b/tests/testing_tests/test_causal_test_adequacy.py @@ -9,7 +9,7 @@ from causal_testing.testing.base_test_case import BaseTestCase from causal_testing.testing.causal_test_case import CausalTestCase from causal_testing.testing.causal_test_adequacy import DAGAdequacy -from causal_testing.testing.causal_test_outcome import NoEffect, SomeEffect +from causal_testing.testing.causal_effect import NoEffect, SomeEffect from causal_testing.specification.scenario import Scenario from causal_testing.testing.causal_test_adequacy import DataAdequacy from causal_testing.specification.variable import Input, Output diff --git a/tests/testing_tests/test_causal_test_case.py b/tests/testing_tests/test_causal_test_case.py index 17390819..4c4a69c6 100644 --- a/tests/testing_tests/test_causal_test_case.py +++ b/tests/testing_tests/test_causal_test_case.py @@ -9,7 +9,7 @@ from causal_testing.specification.variable import Input, Output from causal_testing.specification.causal_dag import CausalDAG from causal_testing.testing.causal_test_case import CausalTestCase -from causal_testing.testing.causal_test_outcome import ExactValue +from causal_testing.testing.causal_effect import ExactValue from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.testing.base_test_case import BaseTestCase diff --git a/tests/testing_tests/test_causal_test_outcome.py b/tests/testing_tests/test_causal_test_outcome.py index e1a7c40a..b5e91609 100644 --- a/tests/testing_tests/test_causal_test_outcome.py +++ b/tests/testing_tests/test_causal_test_outcome.py @@ -1,6 +1,6 @@ import unittest import pandas as pd -from causal_testing.testing.causal_test_outcome import ExactValue, SomeEffect, Positive, Negative, NoEffect +from causal_testing.testing.causal_effect import ExactValue, SomeEffect, Positive, Negative, NoEffect from causal_testing.testing.causal_test_result import CausalTestResult, TestValue from causal_testing.estimation.linear_regression_estimator import LinearRegressionEstimator from causal_testing.utils.validation import CausalValidator @@ -8,8 +8,8 @@ from causal_testing.specification.variable import Input, Output -class TestCausalTestOutcome(unittest.TestCase): - """Test the TestCausalTestOutcome basic methods.""" +class TestCausalEffect(unittest.TestCase): + """Test the TestCausalEffect basic methods.""" def setUp(self) -> None: base_test_case = BaseTestCase(Input("A", float), Output("A", float)) From 6515afc2843490fa78b890696161d834ca536e55 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Wed, 23 Apr 2025 13:41:03 +0100 Subject: [PATCH 3/8] pytests --- causal_testing/testing/causal_effect.py | 18 +++++++-- ..._test_outcome.py => test_causal_effect.py} | 38 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) rename tests/testing_tests/{test_causal_test_outcome.py => test_causal_effect.py} (89%) diff --git a/causal_testing/testing/causal_effect.py b/causal_testing/testing/causal_effect.py index 9a99404a..f06d746f 100644 --- a/causal_testing/testing/causal_effect.py +++ b/causal_testing/testing/causal_effect.py @@ -79,17 +79,29 @@ class ExactValue(CausalEffect): def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_high: float = None): if (ci_low is not None) ^ (ci_high is not None): raise ValueError("If specifying confidence intervals, must specify `ci_low` and `ci_high` parameters.") + if atol is not None and atol < 0: + raise ValueError("Tolerance must be an absolute (positive) value.") + self.value = value self.ci_low = ci_low self.ci_high = ci_high self.atol = atol if atol is not None else abs(value * 0.05) - if self.atol < 0: - raise ValueError("Tolerance must be an absolute (positive) value.") + + if self.ci_low is not None and self.ci_high is not None: + if not self.ci_low <= self.value <= self.ci_high: + raise ValueError("Specified value falls outside the specified confidence intervals.") + if self.value - self.atol < self.ci_low or self.value + self.atol > self.ci_high: + raise ValueError( + "Arithmetic tolerance falls outside the confidence intervals. Try specifyin a smaller value of atol." + ) def apply(self, res: CausalTestResult) -> bool: close = np.isclose(res.test_value.value, self.value, atol=self.atol) if res.ci_valid() and self.ci_low is not None and self.ci_high is not None: - return close and self.ci_low <= res.ci_low() and self.ci_high >= res.ci_high() + return all( + close and ci_low <= ci_low and ci_high >= ci_high + for ci_low, ci_high in zip(res.ci_low(), res.ci_high()) + ) return close def __str__(self): diff --git a/tests/testing_tests/test_causal_test_outcome.py b/tests/testing_tests/test_causal_effect.py similarity index 89% rename from tests/testing_tests/test_causal_test_outcome.py rename to tests/testing_tests/test_causal_effect.py index b5e91609..e0c7fdbf 100644 --- a/tests/testing_tests/test_causal_test_outcome.py +++ b/tests/testing_tests/test_causal_effect.py @@ -181,6 +181,28 @@ def test_exactValue_pass_ci(self): ev = ExactValue(5, 0.1) self.assertTrue(ev.apply(ctr)) + def test_exactValue_ci_pass_ci(self): + test_value = TestValue(type="ate", value=pd.Series(5.05)) + ctr = CausalTestResult( + estimator=self.estimator, + test_value=test_value, + confidence_intervals=[pd.Series(4.1), pd.Series(5.9)], + effect_modifier_configuration=None, + ) + ev = ExactValue(5, ci_low=4, ci_high=6) + self.assertTrue(ev.apply(ctr)) + + def test_exactValue_ci_fail_ci(self): + test_value = TestValue(type="ate", value=pd.Series(5.05)) + ctr = CausalTestResult( + estimator=self.estimator, + test_value=test_value, + confidence_intervals=[pd.Series(3.9), pd.Series(6.1)], + effect_modifier_configuration=None, + ) + ev = ExactValue(5, ci_low=4, ci_high=6) + self.assertTrue(ev.apply(ctr)) + def test_exactValue_fail(self): test_value = TestValue(type="ate", value=pd.Series(0)) ctr = CausalTestResult( @@ -196,6 +218,22 @@ def test_invalid_atol(self): with self.assertRaises(ValueError): ExactValue(5, -0.1) + def test_unspecified_ci_high(self): + with self.assertRaises(ValueError): + ExactValue(5, ci_low=-0.1) + + def test_unspecified_ci_low(self): + with self.assertRaises(ValueError): + ExactValue(5, ci_high=-0.1) + + def test_invalid_ci_range(self): + with self.assertRaises(ValueError): + ExactValue(5, ci_low=6, ci_high=7, atol=0.05) + + def test_invalid_ci_atol(self): + with self.assertRaises(ValueError): + ExactValue(1000, ci_low=1001, ci_high=1002, atol=0.05) + def test_invalid(self): test_value = TestValue(type="invalid", value=pd.Series(5.05)) ctr = CausalTestResult( From 4048707b805796a4b80f8c5bbf2e6219b0941b1b Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Wed, 23 Apr 2025 13:44:34 +0100 Subject: [PATCH 4/8] pylint --- causal_testing/testing/causal_effect.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/causal_testing/testing/causal_effect.py b/causal_testing/testing/causal_effect.py index f06d746f..658ba14e 100644 --- a/causal_testing/testing/causal_effect.py +++ b/causal_testing/testing/causal_effect.py @@ -90,16 +90,17 @@ def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_hi if self.ci_low is not None and self.ci_high is not None: if not self.ci_low <= self.value <= self.ci_high: raise ValueError("Specified value falls outside the specified confidence intervals.") - if self.value - self.atol < self.ci_low or self.value + self.atol > self.ci_high: - raise ValueError( - "Arithmetic tolerance falls outside the confidence intervals. Try specifyin a smaller value of atol." - ) + if self.value - self.atol < self.ci_low or self.value + self.atol > self.ci_high: + raise ValueError( + "Arithmetic tolerance falls outside the confidence intervals." + "Try specifying a smaller value of atol." + ) def apply(self, res: CausalTestResult) -> bool: close = np.isclose(res.test_value.value, self.value, atol=self.atol) if res.ci_valid() and self.ci_low is not None and self.ci_high is not None: return all( - close and ci_low <= ci_low and ci_high >= ci_high + close and self.ci_low <= ci_low and self.ci_high >= ci_high for ci_low, ci_high in zip(res.ci_low(), res.ci_high()) ) return close From 5316c59a616e0e903a8a3f0afd9381a371e29862 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Wed, 23 Apr 2025 14:02:10 +0100 Subject: [PATCH 5/8] Fixed pytest --- tests/testing_tests/test_causal_effect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testing_tests/test_causal_effect.py b/tests/testing_tests/test_causal_effect.py index e0c7fdbf..dd7272f4 100644 --- a/tests/testing_tests/test_causal_effect.py +++ b/tests/testing_tests/test_causal_effect.py @@ -201,7 +201,7 @@ def test_exactValue_ci_fail_ci(self): effect_modifier_configuration=None, ) ev = ExactValue(5, ci_low=4, ci_high=6) - self.assertTrue(ev.apply(ctr)) + self.assertFalse(ev.apply(ctr)) def test_exactValue_fail(self): test_value = TestValue(type="ate", value=pd.Series(0)) From 780f686063b3d1b1099384da3fc6e960af6689cb Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Thu, 24 Apr 2025 11:21:38 +0100 Subject: [PATCH 6/8] Removed TestOutome mentions --- causal_testing/testing/causal_effect.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/causal_testing/testing/causal_effect.py b/causal_testing/testing/causal_effect.py index 658ba14e..5f1eae3f 100644 --- a/causal_testing/testing/causal_effect.py +++ b/causal_testing/testing/causal_effect.py @@ -24,7 +24,7 @@ def __str__(self) -> str: class SomeEffect(CausalEffect): - """An extension of TestOutcome representing that the expected causal effect should not be zero.""" + """An extension of CausalEffect representing that the expected causal effect should not be zero.""" def apply(self, res: CausalTestResult) -> bool: if res.ci_low() is None or res.ci_high() is None: @@ -38,11 +38,11 @@ def apply(self, res: CausalTestResult) -> bool: 0 < ci_low < ci_high or ci_low < ci_high < 0 for ci_low, ci_high in zip(res.ci_low(), res.ci_high()) ) - raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") + raise ValueError(f"Test Value type {res.test_value.type} is not valid for this CausalEffect") class NoEffect(CausalEffect): - """An extension of TestOutcome representing that the expected causal effect should be zero.""" + """An extension of CausalEffect representing that the expected causal effect should be zero.""" def __init__(self, atol: float = 1e-10, ctol: float = 0.05): """ @@ -70,11 +70,11 @@ def apply(self, res: CausalTestResult) -> bool: < self.ctol ) - raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") + raise ValueError(f"Test Value type {res.test_value.type} is not valid for this CausalEffect") class ExactValue(CausalEffect): - """An extension of TestOutcome representing that the expected causal effect should be a specific value.""" + """An extension of CausalEffect representing that the expected causal effect should be a specific value.""" def __init__(self, value: float, atol: float = None, ci_low: float = None, ci_high: float = None): if (ci_low is not None) ^ (ci_high is not None): @@ -110,7 +110,7 @@ def __str__(self): class Positive(SomeEffect): - """An extension of TestOutcome representing that the expected causal effect should be positive. + """An extension of CausalEffect representing that the expected causal effect should be positive. Currently only single values are supported for the test value""" def apply(self, res: CausalTestResult) -> bool: @@ -122,11 +122,11 @@ def apply(self, res: CausalTestResult) -> bool: return bool(res.test_value.value[0] > 0) if res.test_value.type == "risk_ratio": return bool(res.test_value.value[0] > 1) - raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") + raise ValueError(f"Test Value type {res.test_value.type} is not valid for this CausalEffect") class Negative(SomeEffect): - """An extension of TestOutcome representing that the expected causal effect should be negative. + """An extension of CausalEffect representing that the expected causal effect should be negative. Currently only single values are supported for the test value""" def apply(self, res: CausalTestResult) -> bool: @@ -139,4 +139,4 @@ def apply(self, res: CausalTestResult) -> bool: if res.test_value.type == "risk_ratio": return bool(res.test_value.value[0] < 1) # Dead code but necessary for pylint - raise ValueError(f"Test Value type {res.test_value.type} is not valid for this TestOutcome") + raise ValueError(f"Test Value type {res.test_value.type} is not valid for this CausalEffect") From ddc38fdd7dec887f4ee38c5e9ce12d28bd119888 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Fri, 25 Apr 2025 15:28:11 +0100 Subject: [PATCH 7/8] Extra tests to make codecov happy --- causal_testing/testing/causal_effect.py | 4 ---- tests/testing_tests/test_causal_effect.py | 12 +++++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/causal_testing/testing/causal_effect.py b/causal_testing/testing/causal_effect.py index 5f1eae3f..a9e36d6b 100644 --- a/causal_testing/testing/causal_effect.py +++ b/causal_testing/testing/causal_effect.py @@ -114,8 +114,6 @@ class Positive(SomeEffect): Currently only single values are supported for the test value""" def apply(self, res: CausalTestResult) -> bool: - if res.ci_valid() and not super().apply(res): - return False if len(res.test_value.value) > 1: raise ValueError("Positive Effects are currently only supported on single float datatypes") if res.test_value.type in {"ate", "coefficient"}: @@ -130,8 +128,6 @@ class Negative(SomeEffect): Currently only single values are supported for the test value""" def apply(self, res: CausalTestResult) -> bool: - if res.ci_valid() and not super().apply(res): - return False if len(res.test_value.value) > 1: raise ValueError("Negative Effects are currently only supported on single float datatypes") if res.test_value.type in {"ate", "coefficient"}: diff --git a/tests/testing_tests/test_causal_effect.py b/tests/testing_tests/test_causal_effect.py index dd7272f4..f5ea212a 100644 --- a/tests/testing_tests/test_causal_effect.py +++ b/tests/testing_tests/test_causal_effect.py @@ -232,7 +232,7 @@ def test_invalid_ci_range(self): def test_invalid_ci_atol(self): with self.assertRaises(ValueError): - ExactValue(1000, ci_low=1001, ci_high=1002, atol=0.05) + ExactValue(1000, ci_low=999, ci_high=1001, atol=50) def test_invalid(self): test_value = TestValue(type="invalid", value=pd.Series(5.05)) @@ -295,6 +295,16 @@ def test_someEffect_fail(self): self.assertFalse(SomeEffect().apply(ctr)) self.assertTrue(NoEffect().apply(ctr)) + def test_someEffect_None(self): + test_value = TestValue(type="ate", value=pd.Series(0)) + ctr = CausalTestResult( + estimator=self.estimator, + test_value=test_value, + confidence_intervals=None, + effect_modifier_configuration=None, + ) + self.assertEquals(SomeEffect().apply(ctr), None) + def test_someEffect_str(self): test_value = TestValue(type="ate", value=0) ctr = CausalTestResult( From 192cfca35e69ae51dbae85140395ff4980b376eb Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Fri, 25 Apr 2025 15:34:48 +0100 Subject: [PATCH 8/8] Fixed test --- tests/testing_tests/test_causal_effect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testing_tests/test_causal_effect.py b/tests/testing_tests/test_causal_effect.py index f5ea212a..89d02ae1 100644 --- a/tests/testing_tests/test_causal_effect.py +++ b/tests/testing_tests/test_causal_effect.py @@ -303,7 +303,7 @@ def test_someEffect_None(self): confidence_intervals=None, effect_modifier_configuration=None, ) - self.assertEquals(SomeEffect().apply(ctr), None) + self.assertEqual(SomeEffect().apply(ctr), None) def test_someEffect_str(self): test_value = TestValue(type="ate", value=0)