Skip to content

Commit d673d0a

Browse files
Merge pull request #198 from CITCOM-project/json_optional_data_path
Json optional data path
2 parents aa90884 + e390c3e commit d673d0a

File tree

4 files changed

+68
-15
lines changed

4 files changed

+68
-15
lines changed

causal_testing/json_front/json_class.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ def setup(self, scenario: Scenario):
8181
# Populate the data
8282
if self.input_paths.data_paths:
8383
self.data = pd.concat([pd.read_csv(data_file, header=0) for data_file in self.input_paths.data_paths])
84+
if len(self.data) == 0:
85+
raise ValueError(
86+
"No data found, either provide a path to a file containing data or manually populate the .data "
87+
"attribute with a dataframe before calling .setup()"
88+
)
8489
self._populate_metas()
8590

8691
def _create_abstract_test_case(self, test, mutates, effects):

causal_testing/specification/metamorphic_relation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def generate_metamorphic_relations(dag: CausalDAG) -> list[MetamorphicRelation]:
253253
return metamorphic_relations
254254

255255

256-
if __name__ == "__main__": # pragma: no cover
256+
if __name__ == "__main__": # pragma: no cover
257257
logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO)
258258
parser = argparse.ArgumentParser(
259259
description="A script for generating metamorphic relations to test the causal relationships in a given DAG."

docs/source/frontends/json_front_end.rst

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,38 @@ JSON Frontend
33
The JSON frontend allows Causal Tests and parameters to be specified in JSON to allow for tests to be quickly written
44
whilst retaining the flexibility of the Causal Testing Framework (CTF).
55

6+
basic workflow
7+
--------------
8+
The basic workflow of using the JSON frontend is as follows:
9+
10+
#. Specify your test cases in the JSON format (more details below)
11+
#. Create your DAG in a dot file
12+
#. Initialise the JsonUtility class in python with a path of where you want the outputs saved
13+
#. Set the paths pointing the Json class to your json file, dag file and optionally your data file (see data section below) using the :func:`causal_testing.json_front.json_class.JsonUtility.set_paths` method
14+
#. Run the :func:`causal_testing.json_front.json_class.JsonUtility.setup` method providing your scenario
15+
#. Run the :func:`causal_testing.json_front.json_class.JsonUtility.run_json_tests` method, which will execute the test cases provided by the JSON file.
16+
17+
Example Walkthrough
18+
-------------------
619
An example is provided in `examples/poisson` which will be walked through in this README to better understand
720
the framework
821

922
run_causal_tests.py
10-
-------------------
23+
*******************
1124
`examples/poisson/run_causal_tests.py <https://github.com/CITCOM-project/CausalTestingFramework/blob/main/examples/poisson/run_causal_tests.py>`_
1225
contains python code written by the user to implement scenario specific features
1326
such as:
14-
1. Custom Estimators
15-
2. Causal Variable specification
16-
3. Causal test case outcomes
17-
4. Meta constraint functions
18-
5. Mapping JSON distributions, effects, and estimators to python objects
27+
28+
#. Custom Estimators
29+
#. Causal Variable specification
30+
#. Causal test case outcomes
31+
#. Meta constraint functions
32+
#. Mapping JSON distributions, effects, and estimators to python objects
1933

2034
Use case specific information is also declared here such as the paths to the relevant files needed for the tests.
2135

2236
causal_tests.json
23-
-----------------
37+
*****************
2438
`examples/poisson/causal_tests.json <https://github.c#om/CITCOM-project/CausalTestingFramework/blob/main/examples/poisson/causal_tests.json>`_ contains python code written by the user to implement scenario specific features
2539
is the JSON file that allows for the easy specification of multiple causal tests. Tests can be specified two ways; firstly by specifying a mutation lke in the example tests with the following structure:
2640
Each test requires:
@@ -45,7 +59,9 @@ The second method of specifying a test is to specify the test in a concrete form
4559
#. skip
4660

4761
Run Commands
48-
------------
62+
************
63+
This example uses the Argparse utility built into the JSON frontend, which allows the frontend to be run from a commandline interface as shown here.
64+
4965
To run the JSON frontend example from the root directory of the project, use::
5066

5167
python examples\poisson\run_causal_tests.py --data_path="examples\poisson\data.csv" --dag_path="examples\poisson\dag.dot" --json_path="examples\poisson\causal_tests.json
@@ -59,4 +75,17 @@ Secondly a log file is produced, by default a file called `json_frontend.log` is
5975

6076
The behaviour of where the log file is produced and named can be altered with the --log_path argument::
6177

62-
python examples\poisson\run_causal_tests.py -f --data_path="examples\poisson\data.csv" --dag_path="examples\poisson\dag.dot" --json_path="examples\poisson\causal_tests.json --log_path="example_directory\logname.log"
78+
python examples\poisson\run_causal_tests.py -f --data_path="examples\poisson\data.csv" --dag_path="examples\poisson\dag.dot" --json_path="examples\poisson\causal_tests.json --log_path="example_directory\logname.log"
79+
80+
81+
Runtime Data
82+
----------
83+
84+
There are currently 2 methods to inputting your runtime data into the JSON frontend:
85+
86+
#. Providing one or more file paths to `.csv` files containing your data
87+
#. Setting a dataframe to the .data attribute of the JsonUtility instance, this must be done before the setup method is called.
88+
89+
90+
91+

tests/json_front_tests/test_json_class.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from statistics import StatisticsError
44
import scipy
55

6-
76
from causal_testing.testing.estimators import LinearRegressionEstimator
87
from causal_testing.testing.causal_test_outcome import NoEffect, Positive
98
from tests.test_helpers import remove_temp_dir_if_existent
@@ -99,7 +98,7 @@ def test_f_flag(self):
9998
effects = {"NoEffect": NoEffect()}
10099
mutates = {
101100
"Increase": lambda x: self.json_class.scenario.treatment_variables[x].z3
102-
> self.json_class.scenario.variables[x].z3
101+
> self.json_class.scenario.variables[x].z3
103102
}
104103
estimators = {"LinearRegressionEstimator": LinearRegressionEstimator}
105104
with self.assertRaises(StatisticsError):
@@ -148,7 +147,7 @@ def test_run_json_tests_from_json(self):
148147
effects = {"NoEffect": NoEffect()}
149148
mutates = {
150149
"Increase": lambda x: self.json_class.scenario.treatment_variables[x].z3
151-
> self.json_class.scenario.variables[x].z3
150+
> self.json_class.scenario.variables[x].z3
152151
}
153152
estimators = {"LinearRegressionEstimator": LinearRegressionEstimator}
154153

@@ -178,7 +177,7 @@ def test_generate_tests_from_json_no_dist(self):
178177
effects = {"NoEffect": NoEffect()}
179178
mutates = {
180179
"Increase": lambda x: self.json_class.scenario.treatment_variables[x].z3
181-
> self.json_class.scenario.variables[x].z3
180+
> self.json_class.scenario.variables[x].z3
182181
}
183182
estimators = {"LinearRegressionEstimator": LinearRegressionEstimator}
184183

@@ -208,7 +207,7 @@ def test_formula_in_json_test(self):
208207
effects = {"Positive": Positive()}
209208
mutates = {
210209
"Increase": lambda x: self.json_class.scenario.treatment_variables[x].z3
211-
> self.json_class.scenario.variables[x].z3
210+
> self.json_class.scenario.variables[x].z3
212211
}
213212
estimators = {"LinearRegressionEstimator": LinearRegressionEstimator}
214213

@@ -241,6 +240,26 @@ def test_run_concrete_json_testcase(self):
241240
temp_out = reader.readlines()
242241
self.assertIn("FAILED", temp_out[-1])
243242

243+
def test_no_data_provided(self):
244+
example_test = {
245+
"tests": [
246+
{
247+
"name": "test1",
248+
"mutations": {"test_input": "Increase"},
249+
"estimator": "LinearRegressionEstimator",
250+
"estimate_type": "ate",
251+
"effect_modifiers": [],
252+
"expected_effect": {"test_output": "NoEffect"},
253+
"skip": False,
254+
}
255+
]
256+
}
257+
json_class = JsonUtility("temp_out.txt", True)
258+
json_class.set_paths(self.json_path, self.dag_path)
259+
260+
with self.assertRaises(ValueError):
261+
json_class.setup(self.scenario)
262+
244263
def tearDown(self) -> None:
245264
remove_temp_dir_if_existent()
246265

0 commit comments

Comments
 (0)