BlackBox

The BlackBox is an encapsulation method for ecto graphs: it behaves like a meta-cell.

Example

Let’s take the plasm from Hello Plasms! but let’s assume that we want to encapsulate it so that it looks like a cell to a user. Let’s use a BlackBox.

#!/usr/bin/env python
import ecto
from ecto.tutorial import Increment, Add
from ecto import BlackBoxCellInfo as CellInfo, BlackBoxForward as Forward

class MyBlackBox(ecto.BlackBox):
    """
    We encapsulate the plasm from the hello_tutorial by exposing the
    start value of 'i2' as a parameter to the BlackBox and forwarding
    the output of the 'add' cell
    """
    @staticmethod
    def declare_cells(_p):
        """
        Implement the virtual function from the base class
        Only cells from which something is forwarded have to be declared
        """
        cells = {}
        # 'i2' has its start value exposed to the user so only a type is given
        cells['i2'] = CellInfo(Increment, name='Inc 2')
        # 'add' is always the same so we could define with a CellInfo(Add, name='Add') or
        # just with an instance
        cells['add'] = Add('Add')

        return cells

    @staticmethod
    def declare_forwards(_p):
        """
        Implement the virtual function from the base class
        """
        # we forward the start parameter of the cells 'i2' but the user will
        # see it as 'start2'
        p = {'i2': [Forward('start',new_key='start2',new_default=20)]}

        # there are no inputs to expose to the user
        i={}

        # we forward all the outputs from add to the user
        o = {'add': 'all'}

        return (p, i, o)

    def configure(self, _p,_i,_o):
        # implicitly, 'add' and 'i2' will be created as they have been declared
        # only 'i1' needs to be defined
        self.i1 = Increment('Inc 1', start=18)

    def connections(self, _p):
        # define the connections like you would for the plasm
        return [ self.i1['output'] >> self.add['a'],
                 self.i2['output'] >> self.add['b'] ]

# create an instance of my BlackBox
my_blackbox = MyBlackBox(start2=18)
# create a plasm that only contains the BlackBox
plasm = ecto.Plasm()
plasm.insert(my_blackbox)
# execute the plasm
plasm.execute(niter=2)

# display the output name 'output' in the outputs of cell 'add'
print my_blackbox.outputs.output

Now, let’s go over the example. We first create a class to encapsulate the plasm.

class MyBlackBox(ecto.BlackBox):
    """
    We encapsulate the plasm from the hello_tutorial by exposing the
    start value of 'i2' as a parameter to the BlackBox and forwarding
    the output of the 'add' cell
    """

We know we will forward the parameters of i2 to the user and the output of add. To have declare_io and declare_params work statically, we need to define those cells in declare_cells.

    @staticmethod
    def declare_cells(_p):
        """
        Implement the virtual function from the base class
        Only cells from which something is forwarded have to be declared
        """
        cells = {}
        # 'i2' has its start value exposed to the user so only a type is given
        cells['i2'] = CellInfo(Increment, name='Inc 2')
        # 'add' is always the same so we could define with a CellInfo(Add, name='Add') or
        # just with an instance
        cells['add'] = Add('Add')

        return cells

We also need to define the different forwards

    @staticmethod
    def declare_forwards(_p):
        """
        Implement the virtual function from the base class
        """
        # we forward the start parameter of the cells 'i2' but the user will
        # see it as 'start2'
        p = {'i2': [Forward('start',new_key='start2',new_default=20)]}

        # there are no inputs to expose to the user
        i={}

        # we forward all the outputs from add to the user
        o = {'add': 'all'}

        return (p, i, o)

We also need to define the cells like we would in C++ in configure except some are already known as they were defined in declare_cells.

    def configure(self, _p,_i,_o):
        # implicitly, 'add' and 'i2' will be created as they have been declared
        # only 'i1' needs to be defined
        self.i1 = Increment('Inc 1', start=18)

Finally, we need to define the connections like we would in the plasm:

    def connections(self, _p):
        # define the connections like you would for the plasm
        return [ self.i1['output'] >> self.add['a'],
                 self.i2['output'] >> self.add['b'] ]

If we execute that BlackBox, we get the same as when running the plasm:

No module named PySide.QtCore
42

Python definition

Here is the full Python definition and what members you are supposed to override.

class ecto.BlackBox(*args, **kwargs)[source]

The BlackBox may be used as an encapsulation idiom within ecto, to declare reusable plasms.

A BlackBox is a meta-cell. 3 functions need to be implemented when inheriting. declare_fowards: defines the inputs/outputs/parameters that are forwarded to the inner cells. declare_cells: declare_io and declare_params should not be overriden but in order to have them work statically, information about the inner cells have to be given in declare_cells. declare_direct_params: a BlackBox can have its own parameters and this is where they are declared

cell()[source]

Return an instance of the cell that backs this BlackBox. Useful for ecto.If, or other places that expect a cell

configure(p, i, o)[source]

This function has the same meaning as in C++ and can be overriden by a child class.

This function should be used to allocate all cells internal to a BlackBox

Parameters:
  • p – an ecto.Tendrils object for the parameters
  • i – an ecto.Tendrils object for the inputs
  • o – an ecto.Tendrils object for the outputs
connections(p)[source]

This function has to be overriden by a child class.

Parameters:p – an already filled ecto.Tendrils for the parameters that can be used to decide on certain connections
Returns:an iterable of tendril connections.
classmethod declare_cells(p)[source]

This function can be overriden by a child class.

Given some parameters, define the characteristics of the cells.

Parameters:p – an ecto.Tendrils() object
Returns:a dictionary of the form: {‘cell_name’: BlackBoxCellInfo_call, ‘cell_name’: cell_instance}
static declare_direct_params(p)[source]

This function can be overriden by a child class.

This function declares normal parameters for the BlackBox, i.e. you need to declare them using p.declare(‘key_name’, ‘key_docs’, default_value) like you would in a normal Python cell.

If you want to have your cell expose different parameters according to different parameters sent to the constructor of the BlackBox, you can make this function non-static. declare_params and declare_io (that are static) might then fail if called statically but they are not used to build a BlackBox.

Parameters:p – an ecto.Tendrils() object
classmethod declare_forwards(_p)[source]

This function can be overriden by a child class.

Parameters:_p – an ecto.Tendrils object from which some logic can be done to know what to forward. This function will be called after declare_direct_params which fills ‘p’ with BlackBox specific parameters (non-forwarded)
Returns:a tuple of three dictionaries definining the params/input/output forwarded to/from the inner cells. It has the format: {‘cell_name’: ‘all’, ‘cell_name’: [BlackBoxForward_call1, BlackBoxForward_call2]}
classmethod declare_io(p, i, o)[source]

This function has the same meaning as in C++ and should NOT be overriden by a child class.

Parameters:
  • p – an ecto.Tendrils object for the parameters
  • i – an ecto.Tendrils object for the inputs
  • o – an ecto.Tendrils object for the outputs
classmethod declare_params(p, **kwargs)[source]

This method should NOT be overridden by a child class.

This function returns the parameter tendrils but as there are two kinds (namely the BlackBox ones defined in “declare_direct_params” and the forwarded parameters), there are two levels of parameters. If you just call the function with no kwargs, you get the default parametes. But if you know the parameters you will send to your BlackBox constructor, call declare_params with it and you will have a “runtime estimate” of your parameters.

Parameters:
  • p – an ecto.Tendrils() object
  • kwargs – anything sent to the constructor of the BlackBox
classmethod inspect(*args, **kwargs)[source]

This emulates the inspect method that each ecto cell has, which creates a light version of the cell, where the default values for p,i,o are acceptable.

More Examples

Here are a few more examples from the official ecto tests in test/scripts/test_blackbox: