Skip to content

Instantly share code, notes, and snippets.

@bzah
Last active February 13, 2023 09:53
Show Gist options
  • Save bzah/90a47040b40b43a36fd4f3d3223038ca to your computer and use it in GitHub Desktop.
Save bzah/90a47040b40b43a36fd4f3d3223038ca to your computer and use it in GitHub Desktop.
Flatten python dictionary and turn it into a RST table
# This code is licensed under the terms of the APACHE 2 License (https://www.apache.org/licenses/LICENSE-2.0.html)
# Copyright (C) 2023 Aoun Abel aoun.abel@gmail.com
from __future__ import annotations
from functools import reduce
def flatten(dico: dict, separator: str = ".") -> dict:
""" Flatten a dictionary by creating a 1 level dict with key assembled using the given separator.
>>> flatten({"a":{"b":2, "c":{"d": 42}},
"o":{"p":42}})
>>> {'a.b': 2, 'a.c.d': 42, 'o.p': 42}
"""
flat_dict = {}
for k, v in dico.items():
if isinstance(v, dict):
f = flatten(v)
for k2, v2 in f.items():
flat_dict[k + separator + k2] = v2
else:
flat_dict[k] = v
return flat_dict
def flatten_level_2(dico: dict):
""" Same as flatten but keep the first dict hierachy.
>>> flatten_level_2(
{"a":{"b":2, "c":{"d": 42}},
"o":{"p":42}})
>>> {'a': {'b': 2, 'c.d': 42}, 'o': {'p': 42}}
"""
for k, v in dico.items():
if isinstance(v, dict):
dico[k] = flatten(v)
else:
dico[k] = v
return dico
def sort_by_key(dico: dict, key: str = "reference"):
"""Return a sorted dictionary, the resulting order is given by the items' `key` value.
"""
filtered = {k: v for k, v in dico.items() if v[key] is not None}
return {k: v for k, v in
sorted(filtered.items(), key=lambda x: x[1].get(key, "zzzz") or "zzzz")}
def filter_relevant_keys(dico: dict, keys: list[str])-> dict:
filtered_dico = {}
for k,v in dico.items():
res = {}
for key in keys:
if key in v.keys():
res.update({key: v[key] })
filtered_dico.update({k: res})
return filtered_dico
def to_rst_table(dico: dict[str, dict[str, str]], key="reference") -> None:
"""Turn a dictionary into a rst table. Not perfect
The output is printed in stdout.
"""
dico = sort_by_key(dico, key)
dico = flatten_level_2(dico)
dico = filter_relevant_keys(dico, [
"reference",
"output.var_name",
"output.standard_name",
"output.cell_methods",
"output.long_name",
"output.units",
"output.proposed_standard_name",
"index_function.name",
"index_function.parameters.reducer.reducer",
])
key_to_max_length_mapper = {}
inner_keys = reduce(lambda x,y : set(x) | set(y), map(lambda d: list(d.keys()), dico.values()))
# get maxes
for inner_key in inner_keys:
current_max = 0
for k, v in dico.items():
val = v.get(inner_key, "")
if len(str(val)) > current_max:
current_max = len(str(val))
key_to_max_length_mapper.update({inner_key: current_max})
# print table
mega_acc = ""
for k in inner_keys:
length = key_to_max_length_mapper.get(k)
end_space = " " * (length - len(k))
mega_acc += f"{k}{end_space} |"
mega_acc+= "\n"
for k, v in dico.items():
string_acc = ""
for k2 in inner_keys:
value = str(v.get(k2, "_") or "_")
length = key_to_max_length_mapper.get(k2)
end_space = " " * (length - len(value))
string_acc += f" {value}{end_space} |"
mega_acc += "\n| " + string_acc
print(mega_acc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment