Source code for contrast.utils

from .Gadget import Gadget
from collections import OrderedDict
from fnmatch import filter
import h5py
import numpy as np


[docs]def list_to_table(lst, titles, margins=3, sort=True): """ Formats a table from a nested list, where the first index is the row. """ if sort: lst = sorted(lst) result = '' if not hasattr(margins, '__iter__'): margins = [margins, ] * len(titles) else: margins # establish column widths widths = [] for i in range(len(titles)): widths.append(max([len(titles[i]), ] + [len(row[i]) for row in lst]) + margins[i]) # a base format string for every line linebase = '' for w in widths: linebase += ('%%-%ss' % w) # make the header result += linebase % tuple(titles) + '\n' result += '-' * sum(widths) + '\n' # add the table data for row in lst: result += linebase % tuple(row) + '\n' return result.strip()
[docs]def dict_to_table(dct, titles=('col1', 'col2'), margin=3, sort=True): """ Formats a dict where key:val is str:str into a two column table. """ if sort: dct = OrderedDict({key: dct[key] for key in sorted(dct.keys())}) col1width = max([len(str(s)) for s in dct.keys()] + [len(titles[0])]) col2width = max([len(str(s)) for s in dct.values()] + [len(titles[1])]) width = col1width + col2width + margin baseline = ('%%-%ds' % col1width) + ' ' * margin + ('%%-%ds' % col2width) output = '\n' + baseline % titles + '\n' + '-' * width for key, val in dct.items(): output += '\n' + (baseline % (key, val)) return output
[docs]def str_to_args(line): """ Handy function which splits a list of arguments and keyword arguments, translates names of Gadget instances to actual objects, evaluates expressions that can be evaluated, and accepts the rest as strings. For example, .. ipython:: In [11]: from contrast.motors import DummyMotor In [12]: from contrast.utils import str_to_args In [13]: samx = DummyMotor(name='samx') In [14]: str_to_args("samx hej 1./20") Out[14]: [<contrast.motors.Motor.DummyMotor at 0x7efe164d4f98>, 'hej', 0.05] """ args_in = line.split() args_out = [] kwargs_out = {} gadget_lookup = {g.name: g for g in Gadget.getinstances()} for a in args_in: if '=' in a: key, val = a.split('=') if ('*' in val) or ('?' in val): matching_names = filter(gadget_lookup.keys(), val) kwargs_out[key] = [gadget_lookup[name] for name in matching_names] elif val in gadget_lookup.keys(): kwargs_out[key] = gadget_lookup[val] else: kwargs_out[key] = eval(val) else: if ('*' in a) or ('?' in a): matching_names = filter(gadget_lookup.keys(), a) args_out += [gadget_lookup[name] for name in matching_names] elif a in gadget_lookup.keys(): args_out.append(gadget_lookup[a]) else: try: args_out.append(eval(a)) except NameError: args_out.append(a) return args_out, kwargs_out
[docs]class SpecTable(object): """ A dyamic table, for use when the column titles and one data row are known. """ min_str_len = 12 max_str_len = 12
[docs] def format_pair(self, k, v): """ Return two title strings and a format string corresponding to the k:v pair. """ if isinstance(v, int): data_width = len(str(v)) + 1 header_width = len(str(k)) w = max(data_width, header_width) h = ('%% %us' % w) % k return ' ' * len(h), h, '%%%ud' % w elif k == 'dt': fmt = '%6.3f' return 6 * ' ', '%6s' % k, fmt elif isinstance(v, float): fmt = '% .3e' data_width = len(fmt % 1) header_width = len(str(k)) w = max(data_width, header_width) spaces = ' ' * (w - data_width) h = ('%%%us' % w) % k return ' ' * len(h), h, spaces + fmt elif isinstance(v, dict): results = [self.format_pair(k_, v_) for k_, v_ in v.items()] keys = ' '.join([str(r[-2]) for r in results]) fmts = ' '.join([str(r[-1]) for r in results]) h1 = ('%%.%us' % (len(keys))) % k pl = (len(keys) - len(h1)) // 2 pr = (len(keys) - len(h1)) - pl h1 = '.' * pl + h1 + '.' * pr return h1, keys, fmts elif isinstance(v, h5py.ExternalLink): data_width = len('hdf5-link') header_width = len(str(k)) w = max(data_width, header_width) h = ('%%%us' % w) % k return ' ' * len(h), h, '%%%us' % w elif isinstance(v, h5py.VirtualLayout): data_width = len('hdf5-vds') header_width = len(str(k)) w = max(data_width, header_width) h = ('%%%us' % w) % k return ' ' * len(h), h, '%%%us' % w else: fmt = '%%%u.%us' % (self.min_str_len, self.max_str_len) w = len(fmt % v) h = ('%%%us' % w) % k return ' ' * len(h), h, fmt
[docs] def header_lines(self, dct): """ Takes a dict of {header: value} pairs, and returns a header line. At the same time it calculates the format string for subsequent data lines. """ headers1 = [] headers2 = [] formats = [] for k, v in dct.items(): h1, h2, f = self.format_pair(k, v) headers1.append(h1) headers2.append(h2) formats.append(f) self._line_format = ' '.join(formats) h1 = ' '.join(headers1) h2 = ' '.join(headers2) if h1.strip(): return '\n'.join([h1, h2]) else: return h2
[docs] def fill_line(self, dct): """ Takes a data dict and returns a data line. """ return self._line_format % self.list_values(dct)
def list_values(self, dct): if not hasattr(self, '_line_format'): self.header_lines(dct) vals = [] for v in dct.values(): if isinstance(v, dict): vals += list(self.list_values(v)) elif isinstance(v, h5py.ExternalLink): vals += ['hdf5-link'] elif isinstance(v, h5py.VirtualLayout): vals += ['hdf5-vds'] elif isinstance(v, np.ndarray): vals += [np.array2string(v, threshold=4, edgeitems=1, formatter={'float_kind': lambda x: "%.1e" % x}, separator=',',)] else: vals.append(v) return tuple(vals)