Source code for gaitutils.eclipse

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 23 10:59:28 2016

Eclipse (database) hacks.

@author: Jussi (jnu@iki.fi)
"""
import logging
import io
import configobj
from configobj import ConfigObj
from collections import defaultdict

from .numutils import _isint
from .envutils import GaitDataError

logger = logging.getLogger(__name__)


[docs]class FileFilter: """Filter class for configobj. File-like class that will replace strings according to the replace dict below. This is needed for prefiltering before configobj parsing, since configobj will not tolerate lines with neither key nor value (which seem to occasionally appear in Eclipse files). Also deduplicates successive identical lines for same reason. """ replace = {'\n=\n': '\n'} def __init__(self, fname): self.fname = fname
[docs] def read(self): """Read data. ConfigObj seems to use only this method. """ # Eclipse switched from latin-1 to utf-8 at some point... try: self.fp = io.open(self.fname, encoding='utf8') data = self.fp.read() except UnicodeDecodeError: logger.warning(f'Cannot interpret {self.fname} as utf-8, trying latin-1') self.fp = io.open(self.fname, encoding='latin-1') data = self.fp.read() # filter for val, newval in FileFilter.replace.items(): data = data.replace(val, newval) # rm subsequent duplicate lines - a bit cryptic data = '\n'.join(list(dict.fromkeys(data.split('\n')))) return data
[docs] def close(self): self.fp.close()
def _enf_reader(fname_enf): """Return enf reader (ConfigObj instance).""" fp = FileFilter(fname_enf) # do not listify comma-separated values # logger.debug('loading %s' % fname_enf) try: cp = ConfigObj(fp, encoding='utf8', list_values=False, write_empty_values=True) except configobj.ParseError: raise GaitDataError(f'Cannot parse config file {fname_enf}') if 'TRIAL_INFO' not in cp.sections: raise GaitDataError('No trial info in .enf file') return cp
[docs]def get_eclipse_keys(fname_enf, return_empty=False): """Read key/value pairs from enf file. Currently, only keys in the TRIAL_INFO section will be read. Parameters ---------- fname_enf : str The filename. return_empty : bool, optional If True, return also keys without value Returns ------- dict Dict of the eclipse keys and values. """ di = defaultdict(lambda: '') cp = _enf_reader(fname_enf) di.update( {key: val for key, val in cp['TRIAL_INFO'].items() if val != '' or return_empty} ) return di
def _eclipse_forceplate_keys(eclipse_keys): """Filter that returns Eclipse forceplate keys/values as a dict.""" return { key: val for key, val in eclipse_keys.items() if key[:2] == 'FP' and len(key) == 3 and _isint(key[2]) }
[docs]def set_eclipse_keys(fname_enf, eclipse_dict, update_existing=False): """Set key/value pairs in enf file. Keys will be written into the TRIAL_INFO section. Parameters ---------- fname_enf : str The filename. eclipse_dict : dict A dict containing the new key/value pairs. update_existing : bool, optional If True, overwrite existing keys. """ cp = _enf_reader(fname_enf) did_set = False for key, val in eclipse_dict.items(): if key not in cp['TRIAL_INFO'].keys() or update_existing: cp['TRIAL_INFO'][key] = val did_set = True if did_set: logger.debug(f'writing {fname_enf}') # output the config lines; this writes utf8-encoded bytes out = cp.write() # they must be converted to str for writing outu = [str(line, encoding='utf8') + '\n' for line in out] with io.open(fname_enf, 'w', encoding='utf8') as fp: fp.writelines(outu) else: logger.debug('did not set any keys')