From d397313626e38c58afceb6a6020a8ba2500b7075 Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Wed, 3 Jul 2024 10:30:16 +0200 Subject: [PATCH 1/6] enable setting nested dicts directly in plugin config --- garak/_config.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/garak/_config.py b/garak/_config.py index 982fcc322..1d66e19c3 100644 --- a/garak/_config.py +++ b/garak/_config.py @@ -7,6 +7,7 @@ # logging should be set up before config is loaded +from collections import defaultdict from dataclasses import dataclass import importlib import logging @@ -60,11 +61,13 @@ class TransientConfig(GarakSubConfig): run = GarakSubConfig() plugins = GarakSubConfig() reporting = GarakSubConfig() -plugins.probes = {} -plugins.generators = {} -plugins.detectors = {} -plugins.buffs = {} -plugins.harnesses = {} + +nested_dict = lambda: defaultdict(nested_dict) +plugins.probes = nested_dict() +plugins.generators = nested_dict() +plugins.detectors = nested_dict() +plugins.buffs = nested_dict() +plugins.harnesses = nested_dict() reporting.taxonomy = None # set here to enable report_digest to be called directly buffmanager = BuffManager() From f69b8bf188aceb0870b96c0a51e2535bfa52be42 Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Wed, 3 Jul 2024 14:57:52 +0200 Subject: [PATCH 2/6] update default type for config nodes --- garak/_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/garak/_config.py b/garak/_config.py index 1d66e19c3..2bfa2a0f3 100644 --- a/garak/_config.py +++ b/garak/_config.py @@ -90,7 +90,7 @@ def _set_settings(config_obj, settings_obj: dict): def _combine_into(d: dict, combined: dict) -> None: for k, v in d.items(): if isinstance(v, dict): - _combine_into(v, combined.setdefault(k, {})) + _combine_into(v, combined.setdefault(k, nested_dict)) else: combined[k] = v return combined @@ -99,7 +99,7 @@ def _combine_into(d: dict, combined: dict) -> None: def _load_yaml_config(settings_filenames) -> dict: global config_files config_files += settings_filenames - config = {} + config = nested_dict() for settings_filename in settings_filenames: with open(settings_filename, encoding="utf-8") as settings_file: settings = yaml.safe_load(settings_file) From 32c2848b14881f083dcdc9192c33b0257301d092 Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Wed, 3 Jul 2024 15:08:14 +0200 Subject: [PATCH 3/6] ref obj not func --- garak/_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/garak/_config.py b/garak/_config.py index 2bfa2a0f3..1b43fe8ab 100644 --- a/garak/_config.py +++ b/garak/_config.py @@ -90,7 +90,7 @@ def _set_settings(config_obj, settings_obj: dict): def _combine_into(d: dict, combined: dict) -> None: for k, v in d.items(): if isinstance(v, dict): - _combine_into(v, combined.setdefault(k, nested_dict)) + _combine_into(v, combined.setdefault(k, nested_dict())) else: combined[k] = v return combined From 74e1370cfa21c5802ceaeb21b79e6e2bc15f9cc3 Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Wed, 3 Jul 2024 15:21:03 +0200 Subject: [PATCH 4/6] add nested config test --- tests/test_config.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_config.py b/tests/test_config.py index 48aac5226..784dc8e73 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -623,3 +623,8 @@ def test_report_prefix_with_hitlog_no_explode(): assert os.path.isfile("kjsfhgkjahpsfdg.report.jsonl") assert os.path.isfile("kjsfhgkjahpsfdg.report.html") assert os.path.isfile("kjsfhgkjahpsfdg.hitlog.jsonl") + + +def test_nested(): + _config.plugins.generators["a"]["b"]["c"]["d"] = "e" + assert _config.plugins.generators["a"]["b"]["c"]["d"] == "e" \ No newline at end of file From d251988d4a2884e587fada6b3239e1eb28a5555c Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Thu, 4 Jul 2024 15:41:45 +0200 Subject: [PATCH 5/6] crystallise plugins config after load --- garak/_config.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/garak/_config.py b/garak/_config.py index 1b43fe8ab..3e0a618f9 100644 --- a/garak/_config.py +++ b/garak/_config.py @@ -55,6 +55,7 @@ class TransientConfig(GarakSubConfig): starttime_iso = None + transient = TransientConfig() system = GarakSubConfig() @@ -62,7 +63,19 @@ class TransientConfig(GarakSubConfig): plugins = GarakSubConfig() reporting = GarakSubConfig() +def _lock_config_as_dict(): + global plugins + for plugin_type in ('probes', 'generators', 'buffs', 'detectors', 'harnesses'): + setattr(plugins, plugin_type, _crystallise(getattr(plugins, plugin_type))) + +def _crystallise(d): + for k in d.keys(): + if isinstance(d[k], defaultdict): + d[k] = _crystallise(d[k]) + return dict(d) + nested_dict = lambda: defaultdict(nested_dict) + plugins.probes = nested_dict() plugins.generators = nested_dict() plugins.detectors = nested_dict() @@ -158,6 +171,7 @@ def load_config( logging.debug("Loading configs from: %s", ",".join(settings_files)) _store_config(settings_files=settings_files) + _lock_config_as_dict() loaded = True From cec0079750410fcb3e380779309cbde862256823 Mon Sep 17 00:00:00 2001 From: Leon Derczynski Date: Fri, 5 Jul 2024 11:34:03 +0200 Subject: [PATCH 6/6] reset config before doing nested test (in case it's been converted to dict) --- garak/_config.py | 11 ++++++++--- tests/test_config.py | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/garak/_config.py b/garak/_config.py index 3e0a618f9..10aa270fe 100644 --- a/garak/_config.py +++ b/garak/_config.py @@ -16,6 +16,8 @@ from typing import List import yaml +DICT_CONFIG_AFTER_LOAD = False + version = -1 # eh why this is here? hm. who references it system_params = ( @@ -55,7 +57,6 @@ class TransientConfig(GarakSubConfig): starttime_iso = None - transient = TransientConfig() system = GarakSubConfig() @@ -63,17 +64,20 @@ class TransientConfig(GarakSubConfig): plugins = GarakSubConfig() reporting = GarakSubConfig() + def _lock_config_as_dict(): global plugins - for plugin_type in ('probes', 'generators', 'buffs', 'detectors', 'harnesses'): + for plugin_type in ("probes", "generators", "buffs", "detectors", "harnesses"): setattr(plugins, plugin_type, _crystallise(getattr(plugins, plugin_type))) + def _crystallise(d): for k in d.keys(): if isinstance(d[k], defaultdict): d[k] = _crystallise(d[k]) return dict(d) + nested_dict = lambda: defaultdict(nested_dict) plugins.probes = nested_dict() @@ -171,7 +175,8 @@ def load_config( logging.debug("Loading configs from: %s", ",".join(settings_files)) _store_config(settings_files=settings_files) - _lock_config_as_dict() + if DICT_CONFIG_AFTER_LOAD: + _lock_config_as_dict() loaded = True diff --git a/tests/test_config.py b/tests/test_config.py index 0e988ca2a..b431c7c24 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -625,5 +625,7 @@ def test_report_prefix_with_hitlog_no_explode(): def test_nested(): + importlib.reload(_config) + _config.plugins.generators["a"]["b"]["c"]["d"] = "e" - assert _config.plugins.generators["a"]["b"]["c"]["d"] == "e" \ No newline at end of file + assert _config.plugins.generators["a"]["b"]["c"]["d"] == "e"