Skip to content

Commit bdc1c33

Browse files
committed
Add extra saving functions
1 parent eaf1712 commit bdc1c33

File tree

2 files changed

+141
-4
lines changed

2 files changed

+141
-4
lines changed

skm_pyutils/config.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import os
55
import sys
66
from pprint import pprint
7-
87
import yaml
98

109

@@ -144,23 +143,26 @@ def normalise_path(pth):
144143
exec(contents, {}, metadata)
145144
except Exception as e:
146145
import traceback
146+
147147
print("QUITTING: An error occurred reading {}".format(path))
148148
traceback.print_exc()
149149
exit(-1)
150150
metadata = {k.lower(): v for (k, v) in metadata.items()}
151151
return metadata
152152

153+
153154
def read_yaml(path):
154-
with open(path, 'r') as stream:
155-
parsed_yaml=yaml.safe_load(stream)
155+
with open(path, "r") as stream:
156+
parsed_yaml = yaml.safe_load(stream)
156157
return parsed_yaml
157158

158159

159160
def read_json(path):
160-
with open(path, 'r') as stream:
161+
with open(path, "r") as stream:
161162
parsed_json = json.load(stream)
162163
return parsed_json
163164

165+
164166
def split_dict(in_dict, index):
165167
"""
166168
Grab the value at index from each list in the dictionary.
@@ -183,3 +185,58 @@ def split_dict(in_dict, index):
183185
if isinstance(value, list):
184186
new_dict[key] = value[index]
185187
return new_dict
188+
189+
def convert_dict_to_string(in_dict, name):
190+
"""
191+
Convert the underlying parameters dictionary to string.
192+
193+
Can be useful for printing or writing to a file.
194+
Does not overwrite default __str__ as the output is quite verbose.
195+
196+
Parameters
197+
----------
198+
in_dict : dict
199+
Input dictionary
200+
201+
Returns
202+
-------
203+
str
204+
The string representation of the dict.
205+
206+
"""
207+
208+
def _val_to_str(val):
209+
"""
210+
Convert a value to a string.
211+
212+
One caveat, if a string is passed, it returns
213+
the original string wrapped in quotes.
214+
215+
Parameters
216+
----------
217+
val : object
218+
The value to convert
219+
220+
Returns
221+
-------
222+
str
223+
The value as a string.
224+
225+
"""
226+
return f"'{val}'" if isinstance(val, str) else val
227+
228+
out_str = ""
229+
out_str += name + " = {\n"
230+
for k, v in in_dict.items():
231+
out_str += f"\t{_val_to_str(str(k))}:"
232+
if isinstance(v, dict):
233+
out_str += "\n\t\t{\n"
234+
for k2, v2 in v.items():
235+
out_str += "\t\t {}: {},\n".format(
236+
_val_to_str(str(k2)), _val_to_str(v2)
237+
)
238+
out_str += "\t\t},\n"
239+
else:
240+
out_str += f" {_val_to_str(v)},\n"
241+
out_str += "\t}"
242+
return out_str

skm_pyutils/save.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Utilities for saving structures to disk."""
22
import csv
33
import os
4+
from typing import Union
45

56
import numpy as np
67

@@ -134,3 +135,82 @@ def save_dicts_to_csv(filename, in_dicts, do_sort=True):
134135

135136
except Exception as e:
136137
log_exception(e, "When {} saving to csv".format(filename))
138+
139+
140+
def data_dict_from_attr_list(
141+
input_item, attr_list: list, friendly_names: Union["list[str]", None] = None
142+
):
143+
"""
144+
From a list of attributes, return a dictionary.
145+
146+
Each item in attr_list should be a tuple containing
147+
attributes, keys, or None.
148+
The elements of the tuple are then accessed iteratively, like
149+
item.tuple_el1.tuple_el2...
150+
If the element is an attribute, it is directly retrieved.
151+
If the element is a key in a dictionary, that is retrieved.
152+
If the element is None, it indicates a break.
153+
(This last option can be used to get functions without calling them,
154+
or to get a full dictionary instead of pulling out the key, value pairs.)
155+
156+
The output also depends on what is retrieved, if a dictionary or a function.
157+
Functions are called with no arguments.
158+
Dictionaries have key value pairs, that are stored in the output dictionary.
159+
Both of these can be avoided by passing the last element of the tuple as None.
160+
161+
As an example:
162+
item.results = {"addition": {"1 + 1": 2}}
163+
item.data.running_speed = [0.5, 1.4, 1.5]
164+
attr_list = [("results", "addition", None)]
165+
this_fn(attr_list) = {"results_addition": {"1 + 1" = 2}}
166+
attr_list = [("results", "addition"), ("data", "running_speed")]
167+
this_fn(attr_list) = {"1 + 1": 2, "data_running_speed": [0.5, 1.4, 1.5]}
168+
169+
Parameters
170+
----------
171+
input_item : Any
172+
The item to get data attributes from.
173+
attr_list : list
174+
The list of attributes to retrieve.
175+
friendly_names : list of str, optional
176+
What to name each retrieved attribute, (default None).
177+
Must be the same size as attr_list or None.
178+
179+
Returns
180+
-------
181+
dict
182+
The retrieved attributes.
183+
184+
Raises
185+
------
186+
ValueError
187+
attr_list and friendly_names are not the same size.
188+
189+
"""
190+
if friendly_names is not None and len(friendly_names) != len(attr_list):
191+
raise ValueError("friendly_names and attr_list must be the same length")
192+
193+
data_out = {}
194+
for i, attr_tuple in enumerate(attr_list):
195+
item = input_item
196+
for a in attr_tuple:
197+
if a is None:
198+
break
199+
item = (
200+
getattr(item, a) if isinstance(a, str) and hasattr(item, a) else item[a]
201+
)
202+
if callable(item):
203+
item = item()
204+
if isinstance(item, dict):
205+
for key, value in item.items():
206+
data_out[key] = value
207+
else:
208+
non_none_attrs = [x for x in attr_tuple if x is not None]
209+
if friendly_names is None:
210+
key = "_".join(non_none_attrs)
211+
else:
212+
key = friendly_names[i]
213+
if key is None:
214+
key = "_".join(non_none_attrs)
215+
data_out[key] = item
216+
return data_out

0 commit comments

Comments
 (0)