Source code for drymass.cli.config

import pathlib

from . import definitions
from .._version import version

#: DryMass configuration file name
FILE_CONFIG = "drymass.cfg"

[docs]class ConfigFile(object): def __init__(self, path): """DryMass configuration file management Manage configuration file of an experimental data set with restrictions imposed by :data:`drymass.cli.definitions.config`. Parameters ---------- path: str path to the configuration file """ path = pathlib.Path(path).resolve() if path.is_dir(): path = path / FILE_CONFIG self.path = path def __getitem__(self, section): """Get a configuration section Parameters ---------- section: str the configuration section Returns ------- sectiondict: dict the configuration section dictionary """ datadict = self._parse() if section in datadict: return datadict[section] elif section in definitions.config: # return default values secd = {} for kk in definitions.config[section]: secd[kk] = definitions.config[section][kk][0] # write result datadict[section] = secd self._write(datadict) return secd else: raise ValueError("Unknown section title: {}".format(section)) def __setitem__(self, section, sectiondict): """Replace a section in the configuration file Parameters ---------- section: str the section name sectiondict: dict the configuration dictionary Notes ----- The previous content of the configuration section in the configuration file is replaced. """ datadict = self._parse() for key in sectiondict: self._check_value(section, key, sectiondict[key]) datadict[section] = sectiondict self._write(datadict) def _check_value(self, section, key, value): """Check if a section/key/value pair is valid Raises `ValueError` if this is not the case. Returns `None`. """ if section not in definitions.config: raise ValueError("Unknown section title: {}".format(section)) if key not in definitions.config[section]: raise ValueError("Unknown key: {}: {}".format(section, key)) type_func = definitions.config[section][key][1] try: type_func(value) except BaseException: raise ValueError("Wrong dtype: {}: {}={}".format(section, key, value)) def _parse(self): """Return full documentation Returns ------- datadict: dict of dicts Full configuration Notes ----- If a configuration section in self.path is incomplete, then the defaults are be inserted and self.path is overridden. """ if not self.path.exists(): return {} with as fd: data = fd.readlines() outdict = {} for line in data: line = line.strip() if (line.startswith("#") or len(line) == 0): pass elif line.startswith("["): sec = line.strip("[]") outdict[sec] = {} else: key, val = line.split("=") key = key.strip() val = val.strip() # Backwards compatibility: # In 0.1.5, several keys were renamed to reflect pixel units. if sec == "roi" and key in ["dist border", "exclude overlap", "pad border"]: key += " px" key_func = definitions.config[sec][key][1] try: val = key_func(val) except ValueError as e: # This means that the `key_func` has a problem with this # value. To make things transparent, we append information # to the error message. e.args += ('Invalid value in "[{}]: {} = {}"'.format( sec, key, val),) raise outdict[sec][key] = val # Insert default variables where missing must_write = False for sec in outdict: for key in definitions.config[sec]: if key not in outdict[sec]: outdict[sec][key] = definitions.config[sec][key][0] must_write = True if must_write: # Update the configuration file self._write(outdict) return outdict def _write(self, datadict): """Write configuration dictionary Parameters ---------- datadict: dict of dicts the full configuration Notes ----- The configuration key values are converted to the correct dtype before writing using the definitions given in """ keys = sorted(list(datadict.keys())) lines = ["# DryMass version {}".format(version), "# Configuration file documented at: ", "#" + "_file.html", ] for kk in keys: lines.append("") lines.append("[{}]".format(kk)) subkeys = sorted(list(datadict[kk].keys())) for sk in subkeys: value = datadict[kk][sk] typefunc = definitions.config[kk][sk][1] lines.append("{} = {}".format(sk, typefunc(value))) for ii in range(len(lines)): lines[ii] += "\n" with"w") as fd: fd.writelines(lines)
[docs] def remove_section(self, section): """Remove a section from the configuration file""" datadict = self._parse() datadict.pop(section) self._write(datadict)
[docs] def set_value(self, section, key, value): """Set a configuration key value Parameters ---------- section: str the configuration section key: str the configuration key in `section` value: the configuration key value Notes ----- Valid section and key names are defined in """ # load, update, and save sec = self[section] sec[key] = value self[section] = sec