Source code for dnppy.textio.ioconfig

from text_data import text_data
import os
import ast


[docs]class ioconfig(text_data): """ An ioconfig object is an extension to the text_data_class it has the same methods of text_data_class, plus an add_param function and simplified ``write()``, and ``read()`` methods for making visually formatted csv files so users can edit config files directly. It is used to generate "config" files, lists of important inputs to a set of complex functions. Allows you to save inputs and call them over and over again to avoid tedious input definitions, also facilitates good record keeping by keeping a hard file with a summary of all inputs alongside any outputs that might have been generated. When a param has been added or imported, its value may be accessed with .. code-block:: python ioconfig_object['param_name'] :param input_filepath: Optional filepath to read/write this ioconfig object to/from. If you do not provide a filepath here, you can provide one when invoking the ``read()`` and ``write()`` methods. """ def __init__(self, input_filepath = None): """ overrides parents __init__ """ self.headers = ["param_name", "param_type", "param_value"] self.row_data = [] # standard text data object row_data formating self.conf_dict = {} # config dict of {param_name: param_value} self.name_len = 1 # number of characters reserved for param names self.type_len = 16 # number of characters reserved for param types if input_filepath and os.path.exists(input_filepath): self.read(input_filepath) def __getitem__(self, index): """ Overrides parent __getitem__. Causes the following external syntax to behave identically .. code-blocK:: python param = ioconfig_object.conf_dict["param_name"] param = ioconfig_object["param_name"] :param index: the key for conf_dict :return value: the value corresponding to input key """ return self.conf_dict[index] def __iter__(self): """ functions as a generator to iterate through an ioconfig object """ for row in self.row_data: yield row[0].strip()
[docs] def add_param(self, param_names, param_values): """ Adds parameters to the ioconfig object :param param_names: A string, the name of the parameter :param param_values: the value of the parameter. May be any built in datatype. (bool, int, str, list, long, etc) when a param has been added or imported, its value may be accessed with .. code-block:: python ioconfig_object['param_name'] """ # avoid indexing errors by handling list inputs differently if isinstance(param_names, list): for i,param in enumerate(param_names): # make sure columns are wide enough for visual readability if len(param) > self.name_len: self.name_len = len(param) entry = [param_names[i], str(type(param_values[i])), param_values[i]] self.row_data.append(entry) else: entry = [param_names, str(type(param_values)), param_values] self.row_data.append(entry) return
[docs] def write(self, filepath): """ Prepares the row data with nice visual formatting then calls the ``text_data.write_csv`` method. :param filepath: filepath to write csv to. (.txt, .csv, etc) """ # create write_rows variable with extra spaces for easy reading of csv write_headers = [self.headers[0].ljust(self.name_len), self.headers[1].ljust(self.type_len), self.headers[2]] write_rows = [] for row in self.row_data: write_rows.append([row[0].ljust(self.name_len), row[1].ljust(self.type_len), row[2]]) write_tdo = text_data(headers = write_headers, row_data = write_rows) write_tdo.write_csv(filepath, delim = " ; ") return
[docs] def read(self, filepath): """ Reads the contents of a csv file generated by ``ioconfig.write()``, interprets and formats each of the variables to the state it was before exporting. Once finished, this the ioconfig object will have all its standard attributes including ``conf_dict``. :param filepath: filepath to a csv or txt file generated by the ``ioconfig.write`` method. """ self.read_csv(filepath, delim = " ; ") for i, row in enumerate(self.row_data): param_name = row[0].strip() # allow display width to adjust to longest parameter name if len(param_name) > self.name_len: self.name_len = len(param_name) self.row_data[i][2] = self._interp(row[1], row[2]) self.conf_dict[param_name] = row[2] # prints a summary of the read operation print("Read from config file '{0}'".format(filepath)) print("{0} : Values".format("Keys".ljust(self.name_len))) for key, value in self.conf_dict.iteritems(): print("{0} : {1}".format(key.ljust(self.name_len),value)) return
[docs] def _interp(self, in_type, in_value): """ allows interpretation of config values based on type """ in_type = in_type.strip() if "str" in in_type: return str(in_value) else: try: return ast.literal_eval(in_value) except: raise TypeError("could not interpret input'{0}'".format(in_type)) # testing area
if __name__ == "__main__": test_names = ["test long title for just one single str", "test_bool", "test_float", "test_int", "test_long", #"test_complex", "test_list", "test_dict", "test_tuple"] test_vals = ["some test string", True, 1.12345, 1, 1000000000000000000, #1 + 1j, ["a","b",75,"d"], {"string_key" : 0, 1: "string_value"}, (1, 2)] conf = ioconfig() conf.add_param(test_names, test_vals) conf.write("test_data/conf_test.txt") conf.write_json("test_data/conf_test.json", row_wise = True) del conf conf = ioconfig("test_data/conf_test.txt")