diff --git a/CHANGELOG.md b/CHANGELOG.md
index f55e69d..383e0cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@
 - Use `ImportError` exception instead of `ModuleNotFoundError` which is not
   declared in Python 3.5 [#67][67]
 - Disallow empty JSON path [#68][68]
+- Pass the experiment to each control when requested via the `experiment`
+  parameter of the Python function [#69][69]
 
 [63]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/63
 [64]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/64
@@ -21,6 +23,7 @@
 [66]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/66
 [67]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/67
 [68]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/68
+[69]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/69
 
 ## [1.0.0rc1][] - 2018-11-30
 
diff --git a/chaoslib/control/__init__.py b/chaoslib/control/__init__.py
index 2b4b58c..a9a399b 100644
--- a/chaoslib/control/__init__.py
+++ b/chaoslib/control/__init__.py
@@ -255,7 +255,7 @@ def apply_controls(level: str, experiment: Experiment,
             if provider_type == "python":
                 apply_python_control(
                     level="{}-{}".format(level, scope), control=control,
-                    context=context, state=state,
+                    context=context, state=state, experiment=experiment,
                     configuration=configuration, secrets=secrets)
         except InterruptExecution as c:
             logger.debug(
diff --git a/chaoslib/control/python.py b/chaoslib/control/python.py
index 80cc607..977bb27 100644
--- a/chaoslib/control/python.py
+++ b/chaoslib/control/python.py
@@ -73,7 +73,7 @@ def validate_python_control(control: Control):
                                   mod=mod_name, name=name))
 
 
-def apply_python_control(level: str, control: Control,
+def apply_python_control(level: str, control: Control, experiment: Experiment,
                          context: Union[Activity, Experiment],
                          state: Union[Journal, Run, List[Run]] = None,
                          configuration: Configuration = None,
@@ -104,6 +104,9 @@ def apply_python_control(level: str, control: Control,
     if "state" in sig.parameters:
         arguments["state"] = state
 
+    if "experiment" in sig.parameters:
+        arguments["experiment"] = experiment
+
     func(context=context, **arguments)
 
 

Pass th experiment to all controls
Currently, only the current context (steady-state, method, activity...) is passed down to a control fonction. We should also pass the experiment as it contains a larger context that may be useful as well.

Ideally this should go into 1.0.0rc2
diff --git a/tests/fixtures/controls/dummy_with_experiment.py b/tests/fixtures/controls/dummy_with_experiment.py
new file mode 100644
index 0000000..17a6d61
--- /dev/null
+++ b/tests/fixtures/controls/dummy_with_experiment.py
@@ -0,0 +1,69 @@
+import os
+from typing import Any, Callable, Dict, List, Union
+
+from chaoslib.types import Activity, Configuration, \
+    Experiment, Hypothesis, Journal, Run, Secrets, Settings
+
+value_from_config = None
+
+
+def configure_control(config: Configuration, secrets = Secrets):
+    global value_from_config
+    print(config)
+    value_from_config = config.get("dummy-key", "default")
+
+
+def cleanup_control():
+    global value_from_config
+    value_from_config = None
+
+
+def before_experiment_control(context: Experiment, **kwargs):
+    context["before_experiment_control"] = True
+
+
+def after_experiment_control(context: Experiment, state: Journal, **kwargs):
+    context["after_experiment_control"] = True
+    state["after_experiment_control"] = True
+
+
+def before_hypothesis_control(experiment: Experiment, context: Hypothesis, **kwargs):
+    context["before_hypothesis_control"] = True
+    context["has_experiment_before"] = experiment is not None
+
+
+def after_hypothesis_control(experiment: Experiment, context: Hypothesis,
+                             state: Dict[str, Any], **kwargs):
+    context["after_hypothesis_control"] = True
+    state["after_hypothesis_control"] = True
+    context["has_experiment_after"] = experiment is not None
+
+
+def before_method_control(context: Experiment, **kwargs):
+    context["before_method_control"] = True
+
+
+def after_method_control(context: Experiment, state: List[Run], **kwargs):
+    context["after_method_control"] = True
+    state.append("after_method_control")
+
+
+def before_rollback_control(context: Experiment, **kwargs):
+    context["before_rollback_control"] = True
+
+
+def after_rollback_control(context: Experiment, state: List[Run], **kwargs):
+    context["after_rollback_control"] = True
+    state.append("after_rollback_control")
+
+
+def before_activity_control(experiment: Experiment, context: Activity, **kwargs):
+    context["before_activity_control"] = True
+    context["has_experiment_before"] = experiment is not None
+
+
+def after_activity_control(experiment: Experiment, context: Activity,
+                           state: Run, **kwargs):
+    context["after_activity_control"] = True
+    state["after_activity_control"] = True
+    context["has_experiment_after"] = experiment is not None
diff --git a/tests/fixtures/experiments.py b/tests/fixtures/experiments.py
index 738293a..1f69ff4 100644
--- a/tests/fixtures/experiments.py
+++ b/tests/fixtures/experiments.py
@@ -225,6 +225,10 @@ ExperimentWithControls = {
     ]
 }
 
+
+ExperimentWithControlAccessingExperiment = deepcopy(ExperimentWithControls)
+ExperimentWithControlAccessingExperiment["controls"][0]["provider"]["module"] = "fixtures.controls.dummy_with_experiment"
+
 ExperimentCanBeInterruptedByControl = deepcopy(ExperimentWithControls)
 ExperimentCanBeInterruptedByControl["controls"] = [
     {
diff --git a/tests/test_control.py b/tests/test_control.py
index 1f3789e..dc6fd4b 100644
--- a/tests/test_control.py
+++ b/tests/test_control.py
@@ -227,3 +227,18 @@ def test_validate_python_control_needs_a_module():
                 "type": "python"
             }
         })
+
+
+def test_controls_can_access_experiment():
+    exp = deepcopy(experiments.ExperimentWithControlAccessingExperiment)
+    exp["dry"] = True
+
+    hypo = exp.get("steady-state-hypothesis")
+    run_experiment(exp)
+    assert hypo["has_experiment_before"] is True
+    assert hypo["has_experiment_after"] is True
+
+    activities = get_all_activities(exp)
+    for activity in activities:
+        assert activity["has_experiment_before"] is True
+        assert activity["has_experiment_after"] is True
\ No newline at end of file

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-sugar
3.7
requirements.txt requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi @ file:///croot/certifi_1671487769961/work/certifi
-e git+https://github.com/chaostoolkit/chaostoolkit-lib.git@aa66ce7803dbe4603295f497ca8809ca4d37ac65#egg=chaostoolkit_lib
chardet==3.0.4
coverage==7.2.7
exceptiongroup==1.2.2
hvac==0.7.1
idna==2.7
importlib-metadata==6.7.0
iniconfig==2.0.0
jsonpath-ng==1.7.0
logzero==1.5.0
packaging==24.0
pluggy==1.2.0
ply==3.4
pycodestyle==2.10.0
pyhcl==0.2.3
pytest==7.4.4
pytest-cov==4.1.0
pytest-sugar==1.0.0
PyYAML==3.13
requests==2.20.1
requests-mock==1.11.0
six==1.17.0
termcolor==2.3.0
tomli==2.0.1
typing_extensions==4.7.1
urllib3==1.24.3
zipp==3.15.0

name: chaostoolkit-lib
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - chardet==3.0.4
      - coverage==7.2.7
      - exceptiongroup==1.2.2
      - hvac==0.7.1
      - idna==2.7
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - jsonpath-ng==1.7.0
      - logzero==1.5.0
      - packaging==24.0
      - pluggy==1.2.0
      - ply==3.4
      - pycodestyle==2.10.0
      - pyhcl==0.2.3
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-sugar==1.0.0
      - pyyaml==3.13
      - requests==2.20.1
      - requests-mock==1.11.0
      - setuptools==40.6.2
      - six==1.17.0
      - termcolor==2.3.0
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - urllib3==1.24.3
      - zipp==3.15.0
prefix: /opt/conda/envs/chaostoolkit-lib

tests/test_control.py::test_controls_can_access_experiment
tests/test_control.py::test_initialize_controls_will_configure_a_control tests/test_control.py::test_initialize_controls_will_cleanup_a_control tests/test_control.py::test_controls_are_applied_before_and_after_experiment tests/test_control.py::test_controls_are_applied_before_and_but_not_after_experiment tests/test_control.py::test_controls_are_applied_not_before_and_but_after_experiment tests/test_control.py::test_controls_may_interrupt_experiment tests/test_control.py::test_controls_are_applied_before_and_after_hypothesis tests/test_control.py::test_controls_are_applied_before_and_after_method tests/test_control.py::test_controls_are_applied_before_and_after_rollbacks tests/test_control.py::test_controls_are_applied_before_and_after_activities tests/test_control.py::test_no_controls_get_applied_when_none_defined tests/test_control.py::test_automatic_goes_deep_down_the_tree tests/test_control.py::test_not_automatic_does_not_go_deep_down_the_tree tests/test_control.py::test_validate_python_control_must_be_loadable tests/test_control.py::test_validate_python_control_needs_a_module
chaoslib/control/python.py CHANGELOG.md chaoslib/control/__init__.py
chaoslib/control/python.py CHANGELOG.md chaoslib/control/__init__.py