diff --git a/invisible_cities/cities/components.py b/invisible_cities/cities/components.py index 1dd26f0c8..5debdaedd 100644 --- a/invisible_cities/cities/components.py +++ b/invisible_cities/cities/components.py @@ -211,10 +211,37 @@ def index_tables(file_out): table.colinstances[colname].create_index() +def dict_to_string(arg : dict, + parent_key : str= ""): + ''' + A function that recusively flattens nested dictionaries and converts the values to strings. + + Each nested key is combined with its parent keys and associated with its respective value + as a string. + + Parameters + ---------- + arg : the dictionary to flatten which can contain nested dictionaries + parent_key : the string containing the prefix to use for keys in the flattened dictionary (default ""). + + Returns + ------- + flat_dict : flattened dictionary containing no nested dictionaries and where all values are strings + ''' + flat_dict = {} + for k, v in arg.items(): + new_key = f"{parent_key}.{k}" if parent_key else k + if isinstance(v, dict): + flat_dict.update(dict_to_string(v, new_key)) + else: + flat_dict[new_key] = str(v) + return flat_dict + + def write_city_configuration( filename : str , city_name: str , args : dict): - args = {k: str(v) for k,v in args.items()} + args = dict_to_string(args) with tb.open_file(filename, "a") as file: df = (pd.Series(args) diff --git a/invisible_cities/cities/components_test.py b/invisible_cities/cities/components_test.py index 3cff8f0b3..655f440f5 100644 --- a/invisible_cities/cities/components_test.py +++ b/invisible_cities/cities/components_test.py @@ -560,6 +560,7 @@ def test_write_city_configuration(config_tmpdir): d = "two strings".split(), e = [1,2,3], f = np.linspace(0, 1, 5), + g = {'a' : 2, 'b' : 3, 'c' : {'alpha' : 5, 'beta' : 10}} ) write_city_configuration(filename, city_name, args) with tb.open_file(filename, "r") as file: @@ -567,10 +568,18 @@ def test_write_city_configuration(config_tmpdir): assert city_name in file.root.config df = pd.read_hdf(filename, "/config/" + city_name).set_index("variable") - for var, value in args.items(): + + # ignoring the nested dictionary + for var, value in list(args.items())[:-1]: assert var in df.index assert str(value) == df.value.loc[var] + # considering just the nested dictionary + assert 'g.a' in df.index and str(args['g']['a']) == df.value.loc['g.a'] + assert 'g.b' in df.index and str(args['g']['b']) == df.value.loc['g.b'] + assert 'g.c.alpha' in df.index and str(args['g']['c']['alpha']) == df.value.loc['g.c.alpha'] + assert 'g.c.beta' in df.index and str(args['g']['c']['beta']) == df.value.loc['g.c.beta'] + def test_copy_cities_configuration(config_tmpdir): filename1 = os.path.join(config_tmpdir, "test_copy_cities_configuration_1.h5")