def __init__(self, *args, **kwargs): """ :param args: if given, only the first one is considered, and it becomes the name of the BlackBox :param kwargs: any parameter that is a declared parameter or a forwarded one """ # check that the overrides have proper types # declare_direct_params has to be a classmethod or a staticmethod (as declare_params uses it and it's a # classmethod) for func in [self.__class__.declare_cells, self.__class__.declare_direct_params, self.__class__.declare_forwards]: if type(func) != types.FunctionType: if type(func) != types.MethodType: raise BlackBoxError('The "%s" member of the BlackBox %s ' % (func.__name__, self.__class__.__name__) + 'is not a function.') if func.__self__ is None: raise BlackBoxError('The "%s" function of the BlackBox %s ' % (func.__name__, self.__class__.__name__) + 'needs to be decorated with @classmethod or @staticmethod.') self.niter = kwargs.get('niter', 1) self.__impl = None self.__doc__ = '' self.__params = ecto.Tendrils() self.__inputs = ecto.Tendrils() self.__outputs = ecto.Tendrils() self.__configure(**kwargs) self.__connect() self.__impl.name(self.__class__.__name__) self.__gen_doc() if len(args) > 0: self.__impl.name(args[0])
def config_yaml_for_ecto_cell(cls, header=None): """ Given an ecto cell, generate YAML for all the possibles parameters :param cls: the class of an ecto cell :param header: this is just the name of the cell section. If None, no header is written and no indent is given """ if header: res = '%s:\n' % header indent = ' ' else: res = '' indent = '' res += '%stype: %s\n' % (indent, cls.__name__) res += '%smodule: %s\n' % (indent, cls.__module__) # display the parameters res += '%sparameters:\n' % indent p = ecto.Tendrils() try: cls.declare_params(p) except AttributeError: p = cls.params for tendril_name, tendril in list(p.items()): # Split the doc string to 100 characters line = '%s # ' % indent for word in tendril.doc.split(): if len(line + ' ' + word) > 100: res += line + '\n' line = '%s # %s' % (indent, word) else: line += ' ' + word res += line + '\n' res += '%s %s: %s\n' % (indent, tendril_name, tendril.val) return res
def test_bb2(options): # start is going to be ignored as it is set to 20 by default mm = MyBlackBox2(start=0, step=3, amount1=10, amount2=50) # make sure the declare functions work p = ecto.Tendrils() i = ecto.Tendrils() o = ecto.Tendrils() mm.declare_params(p) mm.declare_io(p, i, o) # run the BlackBox plasm = ecto.Plasm() plasm.insert(mm) options.niter = 5 run_plasm(options, plasm) # final value is start + step*(5-1)+amount1+amount2 assert mm.outputs.value == 92 run_plasm(options, plasm) # final value is start + step*(5+5-1)+amount1+amount2 assert mm.outputs.value == 107
def test_tendrils_serialization(): t = ecto.Tendrils() t.declare("Hello", ecto.Tendril.createT('std::string')) t.declare("Woot", ecto.Tendril.createT('double')) t.Hello = 'World' t.Woot = math.pi ofs = StringIO() t.save(ecto.ostream(ofs)) #grab the string ifs = StringIO(ofs.getvalue()) t_ds = ecto.Tendrils() t_ds.load(ecto.istream(ifs)) print 'loaded:' for key, val in t_ds.iteritems(): print key, val.val assert t_ds.Woot == math.pi assert t_ds.Hello == 'World'
def declare_io(cls, p, i, o): """ This function has the same meaning as in C++ and should NOT be overriden by a child class. :param p: an ecto.Tendrils object for the parameters :param i: an ecto.Tendrils object for the inputs :param o: an ecto.Tendrils object for the outputs """ cell_infos = cls.declare_cells(p) try: _p_forwards, i_forwards, o_forwards = cls.declare_forwards(p) except: raise BlackBoxError('Your declare_forwards needs to return a tuple of 3 dictionaries ' 'of the form:\n' '{"cell_name": "all", "cell_name": [BlackBoxForward1, BlackBoxForward2]}') # go over the two sets of tendrils: i and o for info_tuple in [(i_forwards, i, 'inputs'), (o_forwards, o, 'outputs')]: cell_forwards, tendrils, tendril_type = info_tuple for cell_name, forwards in cell_forwards.items(): cell_info = cell_infos[cell_name] if isinstance(cell_infos[cell_name], _BlackBoxCellInfo): python_class = cell_infos[cell_name].python_class if hasattr(python_class, tendril_type): # get the tendrils from the class if it has them _deep_copy_tendrils_to_tendrils(getattr(python_class, tendril_type), forwards, tendrils) else: # in case the cell has no 'inputs'/'outputs' attribute (e.g. if it is a BlackBox # or a pure Python cell) cell_params = _get_param_tendrils(cell_info, forwards.get(cell_name, {})) cell_tendrils = ecto.Tendrils() if tendril_type == 'inputs': python_class.declare_io(cell_params, cell_tendrils, ecto.Tendrils()) else: python_class.declare_io(cell_params, ecto.Tendrils(), cell_tendrils) _deep_copy_tendrils_to_tendrils(cell_tendrils, forwards, tendrils) else: _deep_copy_tendrils_to_tendrils(getattr(cell_info, tendril_type), forwards, tendrils)
def solidify_forward_declares(self): tendrils = ecto.Tendrils() for cell_name, keys in self.forwards.iteritems(): cell = self.__get_cell(cell_name) ctendrils = getattr(cell, self.tt_key) for key, cell_key in keys: tendrils.declare(key, ctendrils.at(cell_key)) tendrils.at(key).copy_value( self._tendrils.at(key)) #set the cells to parameters. for key, tendril in self._tendrils: if not key in tendrils: tendrils.declare(key, tendril) self._tendrils = tendrils
def test_tendrils(): t = ecto.Tendrils() t.declare("Hello","doc str",6) assert t.Hello == 6 assert t["Hello"] == 6 t.declare("x","a number", "str") assert len(t) == 2 assert t["x"] == "str" assert t.x == "str" #test the redeclare try: t.declare("Hello","new doc", "you") util.fail() except ecto.TendrilRedeclaration, e: print str(e) assert('TendrilRedeclaration' in str(e))
def _get_param_tendrils(cell_info, forwards=None, params=None): """ This function returns the params ecto.Tendrils of a cell but it also overrides the default values with the arguments, in order of priority (from low to high): - the defaults of cell_info - the forwards - any given parameters :param cell_info: a BlackBoxCellInfo object :param forwards: a list of BlackBoxForward or the string 'all' :param params: a dictionary of values to give to the parameters that have no default :return: params Tendrils of a class with values overriden from cell_info or forwards """ if forwards is None: forwards = [] if params is None: params = {} cell_class = cell_info.python_class if hasattr(cell_class, 'params'): # this is a C++ cell visible from Python tendrils = _deep_copy_tendrils(cell_class.params) else: # otherwise, call the declare_params function tendrils = ecto.Tendrils() if issubclass(cell_class, BlackBox): cell_class.declare_params(tendrils, **params) else: cell_class.declare_params(tendrils) # override the values with whatever is in params for key, val in params.items(): if key in tendrils: tendrils.at(key).set(val) # override the values with whatever is in forwards if isinstance(forwards, list): for forward in forwards: if forward.key in tendrils and forward.new_default is not None: tendrils.at(forward.key).set(forward.new_default) # override the values with whatever is in cell_info for key, val in cell_info.params.items(): if key in tendrils: tendrils.at(key).set(val) return tendrils
def _deep_copy_tendrils(tendrils_in, values=None): """ Given some tendrils and their values, deep copy them :param tendrils_in: an ecto.Tendrils() :param values: a dictionary {'tendril_key': tendril_value} if 'tendril_key' is not in 'tendrils_in', it will be ignored :return: a deep copy of 'tendrils_in' with the values from 'values' """ if values is None: values = {} tendrils_out = ecto.Tendrils() for key, tendril in tendrils_in: new_tendril = ecto.Tendril.createT(tendril.type_name) if key in values: new_tendril.set(values[key]) else: new_tendril.copy_value(tendril) new_tendril.doc = tendril.doc tendrils_out.declare(key, new_tendril) return tendrils_out
def __configure(self, **kwargs): """ Private implementation that generates the cells/tendrils inside the BlackBox """ p = ecto.Tendrils() self.declare_direct_params(p) # complete the p using the default values given in **kwargs for key, val in kwargs.items(): if key in p: p.at(key).set(val) try: p_forwards, i_forwards, o_forwards = self.declare_forwards(p) except Exception as e: raise BlackBoxError('Your declare_forwards needs to return a tuple of 3 dictionaries ' 'of the form:\n' '{"cell_name": "all", "cell_name": [BlackBoxForward1, BlackBoxForward2]}: %s' % e) # create the cells cell_infos = self.declare_cells(p) for cell_name, cell_info in cell_infos.items(): # if a full-fledged cell is given, just assign it to the blackbox member right away if not isinstance(cell_info, _BlackBoxCellInfo): setattr(self, cell_name, cell_info) continue cell_tendrils = _get_param_tendrils(cell_info, p_forwards.get(cell_name, []), kwargs) # convert the tendrils to parameters to send to the constructor params = {} for key, tendril in cell_tendrils.items(): params[key] = tendril.val # add the cell to the BlackBox if cell_info.name: setattr(self, cell_name, cell_info.python_class(cell_info.name, **params)) else: setattr(self, cell_name, cell_info.python_class(**params)) # redefine the parameters so that they are linked to tendrils of actual cells self.__params = ecto.Tendrils() self.declare_direct_params(self.__params) for cell_name, forwards in p_forwards.items(): cell = getattr(self, cell_name) _copy_tendrils_to_tendrils(cell.params, forwards, self.__params) # complete the params using the default values given in **kwargs for key, val in kwargs.items(): if key in self.__params: self.__params.at(key).set(val) # redefine the io so that they are linked to tendrils of actual cells self.__inputs = ecto.Tendrils() self.__outputs = ecto.Tendrils() for tendril_type, all_forwards in [('inputs', i_forwards), ('outputs', o_forwards)]: for cell_name, forwards in all_forwards.items(): if not hasattr(self, cell_name): raise BlackBoxError('Cell of name "%s" needs to be ' % cell_name + 'declared in "declare_cells"') cell = getattr(self, cell_name) if not hasattr(cell, tendril_type): raise BlackBoxError('Cell of name "%s" needs has no %s ' % (cell_name, tendril_type)) if tendril_type=='inputs': _copy_tendrils_to_tendrils(cell.inputs, forwards, self.__inputs) else: _copy_tendrils_to_tendrils(cell.outputs, forwards, self.__outputs) # call the configure from the user self.configure(self.__params, self.__inputs, self.__outputs)
def __init__(self, bb, tendril_type): self._tendrils = ecto.Tendrils() self.tt = tendril_type self.tt_key = BlackBoxTendrils.tt_key[self.tt] self.bb = bb self.forwards = {}
#!/usr/bin/env python from object_recognition.common.io.source import _assert_source_interface #test that names have to be correct. try: from ecto import And a = And() _assert_source_interface(a) assert False == "Should not have gotten here." except NotImplementedError,e: assert "Must have an output named K" in str(e) import ecto outputs = ecto.Tendrils() outputs.declare("image","an image", "image image") outputs.declare("depth","a depth map", "depth depth") outputs.declare("K","a camera matrix", "eye(3)") outputs.declare("points3d","A matrix of 3 vectors", "Mat(N,3)") class Source(object): pass kr = Source() kr.outputs = outputs try: _assert_source_interface(kr) assert False == "Should not have gotten here." except NotImplementedError,e: assert "This cells output at K has type boost::python::api::object" in str(e)
def make_tendrils(): ts = ecto.Tendrils() ts.declare('foo', ecto.make_tendril('std::string')) ts.declare('bar', ecto.make_tendril('double')) return ts
#!/usr/bin/env python import ecto ts = ecto.Tendrils() ts.declare('foo', ecto.Tendril.createT('std::string')) ts_pass = ecto.PassthroughTendrils(tendrils=ts) ts.foo = "hello" ts_pass.process() assert ts.foo == "hello" assert ts_pass.outputs.foo == "hello" assert ts_pass.inputs.foo == "hello" ts_pass.inputs.foo = "world" assert ts.foo == "world" assert ts_pass.outputs.foo == "world" assert ts_pass.inputs.foo == "world"