from .Gadget import Gadget
from collections import OrderedDict
from fnmatch import filter
import os
import h5py
import numpy as np
import pathlib
[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 i, w in enumerate(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 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)
[docs]
def get_git_revision(base_path=None, short=False):
"""
retrieve git hash for a given directory or the used contrast installation
"""
if base_path is None:
base_path = pathlib.Path(__file__).resolve().parents[1]
git_dir = pathlib.Path(base_path) / '.git'
try:
with (git_dir / 'HEAD').open('r') as head:
ref = head.readline().split(' ')[-1].strip()
with (git_dir / ref).open('r') as git_hash:
result = git_hash.readline().strip()
except FileNotFoundError:
# this folder won't exist for a non-editable installation
return ''
if short:
result = result[:8]
return result
def get_uncommitted_git_changes(base_path=None):
if base_path is None:
base_path = pathlib.Path(__file__).resolve().parents[1]
result = []
if not os.path.exists(base_path / '.git'):
# if not installed editable, this is probably not a git repo
return result
with os.popen(f'git -C {base_path} ls-files -m -o --exclude-from=.gitignore') as stream:
output = stream.read().split('\n')
for x in output:
if x != '':
result.append(x)
return result