command.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 '''Python interface to the wire-cell command.
3 
4 Configuration:
5 
6 * WC file is a wire-cell configuration file in JSON format.
7 
8 * WC JSON is the contents of a WC file.
9 
10 * A configlist is the Python data structure representing a WC JSON
11  string. It is a list of dictionaries with keys "type", "name" and
12  "data" which holds a type-specific data structure.
13 
14 * A configdict is a dictionary keyed by tuple(type,name) with a value
15  that of the corresponding "data" value.
16 
17 The C++ Wire Cell components which are configurable provide a default,
18 hard-coded configuration "data" structure.
19 
20 '''
21 from collections import defaultdict
22 import json
23 import subprocess
24 
25 class Config:
26 
27  formats = 'wcjson wcfile configlist configdict'.split()
28 
29  def __init__(self, **kwds):
30  self._cfg = defaultdict(dict)
31  self.load(**kwds)
32 
33  def load(self, **kwds):
34  for form in self.formats:
35  obj = kwds.get(form,None)
36  if not obj: continue
37  meth = getattr(self, 'load_'+form)
38  meth(obj)
39 
40  def load_wcjson(self, string):
41  cl = json.loads(string)
42  self.load_configlist(cl)
43 
44  def load_wcfile(self, filename):
45  self.load_wcjson(open(filename).read())
46 
47  def load_configlist(self, cfglist):
48  for d in cfglist:
49  self.load_one(d['type'], d.get('name',''), d['data'])
50 
51  def load_configdict(self, cfgdict):
52  for (t,n),d in self._cfg.items():
53  self.load_one(t,n,d)
54 
55  def get(self, type, name=''):
56  return self._cfg[(type,name)]
57 
58  def load_one(self, type, name, data):
59  val = self.get(type,name)
60  val.update(data)
61  self._cfg[(type,name)] = val
62 
63 
64  def merge(self, other):
65  '''
66  Merge other into copy of self and return new Config object
67  '''
68  ret = Config()
69  for (t,n),d in self._cfg.items():
70  ret.load_one(t,n,d)
71  if other:
72  for (t,n),d in other._cfg.items():
73  ret.load_one(t,n,d)
74  return ret
75 
76  def wcjson(self):
77  '''
78  Return wire-cell compatible JSON representation.
79  '''
80  dat = list()
81  for (t,n),d in self._cfg.items():
82  dat.append(dict(type=t, name=n, data=d))
83  return json.dumps(dat)
84 
85  def __str__(self):
86  return self.wcjson()
87 
88 class WireCell:
89  '''Python interface to wire-cell executable.
90 
91  Beware, this trusts its input! In particular do not let
92  <executable> be set by untrusted sources.
93  '''
94 
95  default_plugins = ['WireCellAlg', 'WireCellGen', 'WireCellApps', 'WireCellTbb']
96 
97  def __init__(self, executable='wire-cell', **kwds):
98  self.prog = executable
99  self.plugins = kwds.pop('plugins', self.default_plugins)
100  self.config = Config(**kwds)
101  self.app = kwds.get('app',None)
102 
103  def cmdline(self, app=None):
104  '''
105  Return command line string
106  '''
107  parts = ['%s -c /dev/stdin' % self.prog]
108  parts += ['-p %s'%p for p in self.plugins]
109  app = app or self.app
110  if app:
111  parts.append('-a %s' % app)
112  return ' '.join(parts)
113 
114  def __call__(self, app=None, config=None):
115  '''Run wire-cell.
116 
117  If app is not given then fall back to one given to constructor.
118 
119  If any config is given it is merged with any given to constructor.
120 
121  '''
122  cmd = self.cmdline(app)
123  #print 'CMD:\n%s'%cmd
124  cfg = self.config.merge(config).wcjson()
125  #print 'CFG:\n%s'%cfg
126  proc = subprocess.Popen(cmd, shell=True,
127  stdin = subprocess.PIPE,
128  stdout = subprocess.PIPE,
129  stderr = subprocess.PIPE)
130  out,err= proc.communicate(cfg)
131  #print 'OUT:\n%s'%out
132  #print 'ERR:\n%s'%err
133  return out,err
134 
135  def component_configlist(self, *components):
136  '''
137  Return a config list giving configuration for components
138  '''
139  config = Config()
140  config.load_one("ConfigDumper","", data=dict(components = components))
141  o,e = self("ConfigDumper", config=config)
142  return json.loads(o)
143 
def load_wcfile(self, filename)
Definition: command.py:44
def load_one(self, type, name, data)
Definition: command.py:58
def __call__(self, app=None, config=None)
Definition: command.py:114
def load_configlist(self, cfglist)
Definition: command.py:47
int open(const char *, int)
Opens a file descriptor.
def load_configdict(self, cfgdict)
Definition: command.py:51
def cmdline(self, app=None)
Definition: command.py:103
def merge(self, other)
Definition: command.py:64
def load(self, kwds)
Definition: command.py:33
def __init__(self, kwds)
Definition: command.py:29
def get(self, type, name='')
Definition: command.py:55
def load_wcjson(self, string)
Definition: command.py:40
int read(int, char *, size_t)
Read bytes from a file descriptor.
void split(std::string const &s, char c, OutIter dest)
Definition: split.h:35
def component_configlist(self, components)
Definition: command.py:135
def __init__(self, executable='wire-cell', kwds)
Definition: command.py:97