Skip to content

Commit b9ee0dd

Browse files
committed
Logging causal test results
1 parent 48b60d9 commit b9ee0dd

File tree

2 files changed

+27
-22
lines changed

2 files changed

+27
-22
lines changed

causal_testing/json_front/json_class.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from causal_testing.specification.scenario import Scenario
2222
from causal_testing.specification.variable import Input, Meta, Output
2323
from causal_testing.testing.causal_test_case import CausalTestCase
24+
from causal_testing.testing.causal_test_result import CausalTestResult
2425
from causal_testing.testing.causal_test_engine import CausalTestEngine
2526
from causal_testing.testing.estimators import Estimator
2627
from causal_testing.testing.base_test_case import BaseTestCase
@@ -124,28 +125,28 @@ def run_json_tests(self, effects: dict, estimators: dict, f_flag: bool = False,
124125
effect=test.get("effect", "direct"),
125126
)
126127
assert len(test["expected_effect"]) == 1, "Can only have one expected effect."
127-
concrete_tests = [
128-
CausalTestCase(
129-
base_test_case=base_test_case,
130-
expected_causal_effect=next(
131-
effects[effect] for variable, effect in test["expected_effect"].items()
132-
),
133-
estimate_type="coefficient",
134-
effect_modifier_configuration={
135-
self.scenario.variables[v] for v in test.get("effect_modifiers", [])
136-
},
137-
)
138-
]
139-
failures = self._execute_tests(concrete_tests, test, f_flag)
128+
causal_test_case = CausalTestCase(
129+
base_test_case=base_test_case,
130+
expected_causal_effect=next(
131+
effects[effect] for variable, effect in test["expected_effect"].items()
132+
),
133+
estimate_type="coefficient",
134+
effect_modifier_configuration={
135+
self.scenario.variables[v] for v in test.get("effect_modifiers", [])
136+
},
137+
)
138+
failed, result = self._execute_test_case(causal_test_case=causal_test_case, test=test, f_flag=f_flag)
139+
result = ('\n ').join(str(result).split("\n"))
140140
msg = (
141141
f"Executing test: {test['name']} \n"
142-
+ f" {concrete_tests[0]} \n"
143-
+ f" {failures}/{len(concrete_tests)} failed for {test['name']}"
142+
+ f" {causal_test_case} \n"
143+
+ f" {result}==============\n"
144+
+ f" Result: {'FAILED' if failed else 'Passed'}"
144145
)
145146
else:
146147
abstract_test = self._create_abstract_test_case(test, mutates, effects)
147148
concrete_tests, dummy = abstract_test.generate_concrete_tests(5, 0.05)
148-
failures = self._execute_tests(concrete_tests, test, f_flag)
149+
failures, details = self._execute_tests(concrete_tests, test, f_flag)
149150

150151
msg = (
151152
f"Executing test: {test['name']} \n"
@@ -173,7 +174,8 @@ def run_json_tests(self, effects: dict, estimators: dict, f_flag: bool = False,
173174
treatment_value=test["treatment_value"],
174175
estimate_type=test["estimate_type"],
175176
)
176-
if self._execute_test_case(causal_test_case=causal_test_case, test=test, f_flag=f_flag):
177+
failed, result = self._execute_test_case(causal_test_case=causal_test_case, test=test, f_flag=f_flag)
178+
if failed:
177179
result = "failed"
178180
else:
179181
result = "passed"
@@ -189,13 +191,15 @@ def run_json_tests(self, effects: dict, estimators: dict, f_flag: bool = False,
189191

190192
def _execute_tests(self, concrete_tests, test, f_flag):
191193
failures = 0
194+
details = []
192195
if "formula" in test:
193196
self._append_to_file(f"Estimator formula used for test: {test['formula']}")
194197
for concrete_test in concrete_tests:
195-
failed = self._execute_test_case(concrete_test, test, f_flag)
198+
failed, result = self._execute_test_case(concrete_test, test, f_flag)
199+
details.append(result)
196200
if failed:
197201
failures += 1
198-
return failures
202+
return failures, details
199203

200204
def _json_parse(self):
201205
"""Parse a JSON input file into inputs, outputs, metas and a test plan"""
@@ -213,7 +217,7 @@ def _populate_metas(self):
213217
for meta in self.scenario.variables_of_type(Meta):
214218
meta.populate(self.data)
215219

216-
def _execute_test_case(self, causal_test_case: CausalTestCase, test: Iterable[Mapping], f_flag: bool) -> bool:
220+
def _execute_test_case(self, causal_test_case: CausalTestCase, test: Iterable[Mapping], f_flag: bool) -> (bool, CausalTestResult):
217221
"""Executes a singular test case, prints the results and returns the test case result
218222
:param causal_test_case: The concrete test case to be executed
219223
:param test: Single JSON test definition stored in a mapping (dict)
@@ -249,7 +253,7 @@ def _execute_test_case(self, causal_test_case: CausalTestCase, test: Iterable[Ma
249253
)
250254
failed = True
251255
logger.warning(" FAILED- expected %s, got %s", causal_test_case.expected_causal_effect, result_string)
252-
return failed
256+
return failed, causal_test_result
253257

254258
def _setup_test(
255259
self, causal_test_case: CausalTestCase, test: Mapping, conditions: list[str] = None

causal_testing/testing/causal_test_result.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
from typing import Any
55
from dataclasses import dataclass
6+
import pandas as pd
67

78
from causal_testing.testing.estimators import Estimator
89
from causal_testing.specification.variable import Variable
@@ -87,7 +88,7 @@ def ci_high(self):
8788

8889
def ci_valid(self) -> bool:
8990
"""Return whether or not the result has valid confidence invervals"""
90-
return self.ci_low() and self.ci_high()
91+
return self.ci_low() and (not pd.isnull(self.ci_low())) and self.ci_high() and (not pd.isnull(self.ci_high()))
9192

9293
def summary(self):
9394
"""Summarise the causal test result as an intuitive sentence."""

0 commit comments

Comments
 (0)