Source code for ecto.opts

#
# Copyright (c) 2011, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of the Willow Garage, Inc. nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
'''
Set of helper functions for ecto scripts, that expose a few common args for
the schedulers.
'''

import ecto

[docs]def use_ipython(options, sched, plasm, locals={}): '''Launch a plasm using ipython, and a scheduler of choice. Keyword arguments: options -- are from scheduler_options sched -- is an already initialized scheduler for plasm. plasm -- The graph to execute locals -- are a dictionary of locals to forward to the ipython shell, use locals() ''' #expose the locals to the ipython prompt. for key, val in locals.items(): vars()[key] = val sched.prepare_jobs(options.niter) print "Scheduler ready to run. To execute for some number of microseconds, type:" print "sched.run(1000)" import IPython if IPython.__version__ < '0.11': from IPython.Shell import IPShellEmbed #the argv is important so that the IPShellEmbed doesn't use the global #Also fancy colors!!!! ipython_argv = ['-prompt_in1', 'Input <\\#>', '-colors', 'LightBG'] ipshell = IPShellEmbed(ipython_argv) ipshell() else: from IPython import embed embed() # this call anywhere in your program will start IPython
[docs]def run_plasm(options, plasm, locals={}): ''' Run the plasm given the options from the command line parser. :param options: The command line, preparsed options object. It is assumed that you have filled this object using scheduler_options. :param plasm: The plasm to run. :param locals: Any local variables that you would like available to the iPython shell session. ''' if options.graphviz: ecto.view_plasm(plasm) if len(options.dotfile) > 0: print >> open(options.dotfile, 'wt'), plasm.viz() if len(options.logfile) > 0: ecto.log_to_file(options.logfile) if options.gui: from ecto.gui import gui_execute gui_execute(plasm) else: sched = ecto.Scheduler(plasm) if options.ipython: use_ipython(options, sched, plasm, locals) else: sched.execute(options.niter) if options.stats: print sched.stats()
class CellFactory(object): '''A factory for cells that are created from command line args.''' def __init__(self, CellType, CellProtoType, prefix=None): ''' cellType a type of ecto cell to create prefix the prefix used by the parser ''' self.cellType = CellType self.cellProtoType = CellProtoType self.prefix = prefix def __call__(self, args, cellname=''): ''' args from a parser where cell_options was used to add arguments. cellname option cellname ''' params = {} prototype = self.cellProtoType for key, value in args.__dict__.iteritems(): if not self.prefix or key.startswith(self.prefix + '_'): if self.prefix: p = ''.join(key.split(self.prefix + '_')[:]) else: p = key if p not in prototype.params.keys(): continue t = type(prototype.params[p]) if 'values' in t.__dict__ and type(value) != t and type(value) == str: params[p] = t.names[value] else: params[p] = t(value) nkwargs = () if len(cellname) > 0: nkwargs = (cellname,) #tuple return self.cellType(*nkwargs, **params)
[docs]class CellYamlFactory(object): '''A factory to go between cells and YAML files :param CellOrCellType: The prototype to base the factory off of. :type CellOrCellType: Cell Class, or Cell Instance :param prefix: The top level key for the parameters dict for this factory :type prefix: str ''' def __init__(self, CellOrCellType, prefix): cell_type, cell = _cell_type_instance(CellOrCellType) self.cell_type = cell_type self.cell = cell self.prefix = prefix params = cell.params c = {} for x in params: c[x.key()] = x.data().get() c[x.key() + '__doc__'] = x.data().doc self.params = c
[docs] def dump(self, stream=None): '''Dump YAML for this factory. :param stream: A stream like object to print the YAML to. :returns: The string YAML representation of the prototype used to initialize the factory. ''' from yaml import dump return dump({self.prefix:self.params}, default_flow_style=False, stream=stream)
[docs] def load(self, parsed, cell_name=''): '''Create a cell from a parsed bit of YAML. :param parsed: A dictionary that has been parsed from a YAML file. :param cell_name: will be used as the cell's instance name. :returns: A brand new instance of a cell, modeled after whatever is in the YAML ''' params = parsed[self.prefix] nkwargs = () params_clean = {} for x in self.cell.params: if x.key() in params: params_clean[x.key()] = params[x.key()] if len(cell_name) > 0: nkwargs = (cell_name,) #tuple cell = self.cell_type(*nkwargs, **params_clean) return cell
def _cell_type_instance(CellOrCellType): c = CellOrCellType cell_type = CellOrCellType if isinstance(cell_type, object.__class__): c = cell_type.inspect() else: cell_type = c.__class__ # print "....", (cell_type, c) return (cell_type, c)
[docs]def cell_options(parser, CellType, prefix=None): '''Creates an argument parser group for any cell. CellType may be either a __class__ type, or an instance object. ''' group = parser.add_argument_group('%s options' % prefix) cell_type, cell = _cell_type_instance(CellType) params = cell.params for x in params: if prefix: dest = '%s_%s' % (prefix, x.key()) else: dest = x.key() tendril_type = type(x.data().val) if 'values' in tendril_type.__dict__: choices = tendril_type.names.keys() tendril_type = str else: choices = None kwargs = dict(metavar='%s' % dest.upper(), dest=dest, type=tendril_type, default=x.data().val, help=x.data().doc + ' ~ (default: %(default)s)' ) if tendril_type is type(True): if x.data().val: kwargs = dict(dest=dest, help=x.data().doc + ' Disables %s' % dest, action='store_false') dest = '%s_disable' % dest else: kwargs = dict(dest=dest, help=x.data().doc + ' Enables %s' % dest, action='store_true') dest = '%s_enable' % dest if choices: kwargs['choices'] = choices kwargs['help'] = kwargs['help'] + ' (choices: %(choices)s)' group.add_argument('--%s' % dest, **kwargs) factory = CellFactory(cell_type, cell, prefix) return factory
[docs]def scheduler_options(parser, default_niter=0, default_shell=False, default_graphviz=False): '''Creates an argument parser for ecto schedulers. Operates inplace on the given parser object. ''' ecto_group = parser.add_argument_group('Ecto runtime parameters') ecto_group.add_argument('--niter', metavar='ITERATIONS', dest='niter', type=int, default=default_niter, help='''Run the graph for niter iterations. 0 means run until stopped by a cell or external forces. (default: %(default)s)''' ) ecto_group.add_argument('--shell', dest='ipython', action='store_const', const=True, default=default_shell, help=''''Bring up an ipython prompt, and execute asynchronously.(default: %(default)s) ''' ) ecto_group.add_argument('--gui', dest='gui', action='store_true', help='Bring up a gui to help execute the plasm.' ) ecto_group.add_argument('--logfile', metavar='LOGFILE', dest='logfile', type=str, default='', help='''Log to the given file, use tail -f LOGFILE to see the live output. May be useful in combination with --shell''' ) ecto_group.add_argument('--graphviz', dest='graphviz', action='store_const', const=True, default=default_graphviz, help='Show the graphviz of the plasm. (default: %(default)s)' ) ecto_group.add_argument('--dotfile', dest='dotfile', type=str, default='', help='''Output a graph in dot format to the given file. If no file is given, no output will be generated. (default: %(default)s)''' ) ecto_group.add_argument('--stats', dest='stats', action='store_const', const=True, default=default_graphviz, help='Show the runtime statistics of the plasm.')
[docs]def doit(plasm, description="An ecto graph.", locals={}, args=None, default_niter=0, default_shell=False, default_graphviz=False): ''' doit is a short hand for samples, that is a combination of a call to scheduler_options, and then run_plasm. This function in not intended to allow customization of parameter parsing. If this is needed please call scheduler_options and run_plasm yourself. :param args: If this is None, default to using the sys.argv args, otherwise this overrides it. :param locals: May be used to forward any local variables to the ipython shell. Suggest either vars() or locals() to do this. :param default_shell: Override :param default_graphviz: Override ''' import argparse parser = argparse.ArgumentParser(description=description) scheduler_options(parser, default_niter=default_niter, default_shell=default_shell, default_graphviz=default_graphviz) options = parser.parse_args(args=args) run_plasm(options, plasm, locals)
if __name__ == '__main__': import ecto.ecto_test as ecto_test import yaml import argparse parser = argparse.ArgumentParser(description='My awesome program thing.') parser.add_argument('-i,--input', metavar='IMAGE_FILE', dest='imagefile', type=str, default='', help='an image file to load.') scheduler_options(parser, default_niter=2) multiply_factory = cell_options(parser, ecto_test.Multiply, prefix='mult') const_factory = cell_options(parser, ecto.Constant(value=0.50505), prefix='const') #parser.print_help() options = parser.parse_args() c = const_factory(options) m = multiply_factory(options) cyaml = CellYamlFactory(c, 'const') print cyaml.dump() c = cyaml.load(yaml.load(cyaml.dump())) pr = ecto_test.Printer() plasm = ecto.Plasm() plasm.connect(c[:] >> m[:], m[:] >> pr[:] ) run_plasm(options, plasm, locals=vars())