Source code for tidypath.fmt

"""
Encode dictionaries in strings and decode them. Useful for automatically asigning filenames.
"""
import numpy as np
import os

##############################################################################################################################
"""                                                  I. Getopt utils                                                       """
##############################################################################################################################

[docs]def encoder(x, ndigits=2, iterables=(list, tuple, np.ndarray), iterable_maxsize=3): """x -> string version of x""" if isinstance(x, float): if x == int(x): return str(int(x)) else: return str(round(x, ndigits=ndigits)).replace('.', '--') elif isinstance(x, int): return str(x) elif callable(x): return x.__name__ elif isinstance(x, dict): if len(x) >= iterable_maxsize: return "{}-values".format(str(len(x))) else: return dict_to_id(x, ndigits=ndigits, join_char="-") elif isinstance(x, iterables): if len(x) >= iterable_maxsize: return "{}-values".format(str(len(x))) else: return '-'.join([encoder(sub_x) for sub_x in x]) else: return str(x)
[docs]def decoder(x, iterables=(list, tuple, np.ndarray)): """string version of x -> x""" if x.lower() == "none": return None elif x.lower() == "false": return False elif x.lower() == "true": return True elif "--" in x: return float(x.replace("--", ".")) elif isinstance(x, iterables): return [decoder(sub_x) for sub_x in x] else: try: return int(x) except: return x
[docs]def getopt_printer(opts): """Prints getopt input in a readable way.""" print('\n'.join(f'{opt} => {arg}' for opt, arg in (("Args", "Values"), *opts)))
[docs]def dict_to_id(*args, ndigits=2, join_char="_", **kwargs): """Generate ID of the form k1-v1_k2-v2... for k_i, v_i keys and values of the dictionary d or the kwargs.""" key_formatter = lambda k: k.replace("_", "-") d = args[0] if len(args) > 0 else kwargs return join_char.join([f"{key_formatter(k)}-{encoder(d[k], ndigits=ndigits)}" for k in sorted(d.keys())])
[docs]def id_to_dict(identifier): """Inverse of dict_to_id.""" s = identifier.split("/")[-1] # retain filename only s = os.path.splitext(s)[0] # remove extension d = {} for split in s.split("_"): var_value = split.split("-") if len(var_value) > 1: if "" in var_value: # value is a float var_value_arr = np.array(var_value) idx_dot = np.argwhere(var_value_arr == "")[0, 0] key_idx = 0 if idx_dot == 2 else slice(0, idx_dot-2) d["-".join(var_value[key_idx])] = decoder(f"{var_value_arr[idx_dot-1]}--{var_value_arr[idx_dot+1]}") else: d["-".join(var_value[:-1])] = decoder(var_value[-1]) return d
[docs]def id_updater(filename, update_dict, mode="add"): """ Modifies filename by updating the underlying dict. Attrs: - filename: id to be modified - update_dict: dict to use for updating the id. if update_dict={} => filename rearranged according to other_utils.dict_to_id. - mode: - "add": add update_dict to the id. - "delete": delete update_dict from the id. Returns modified filename. """ split_dirs = filename.split("/") parentDir = "/".join(split_dirs[:-1]) file = split_dirs[-1] d = id_to_dict(file) if mode == "add": d.update(update_dict) elif mode == "delete": d = {k: v for k, v in d.items() if k not in update_dict.keys()} var_values = [part.split("-") for part in file.split("_")] init = "_".join([part[0] for part in var_values if len(part) == 1]) ext = os.path.splitext(file)[1] new_filename = os.path.join(parentDir, f"{init}_{dict_to_id(d)}{ext}") return new_filename
[docs]def id_renamer(update_dict, parentDir, key=None, mode="add"): """ Modifies id of files in parentDir by updating the underlying dict. Attrs: - update_dict: dict to use for updating the id - parentDir: folder where files are located. - key: string contained in the file for it to be modified. - mode: - "add": add update_dict to the id. - "delete": delete update_dict from the id. Returns #modified files. NOTE: If update_dict={} => filenames will be rearranged according to other_utils.dict_to_id. """ r = 0 for file in os.listdir(parentDir): if key is None or key in file: old_filename = os.path.join(parentDir, file) new_filename = id_updater(old_filename, update_dict, mode=mode) os.rename(old_filename, new_filename) r += 1 return r