3.5.4 Python Implementation

Image noteNote

Assumes you created the project with  bocca create project demo --language=python.

Edit the evaluate method in the implementation file (also known as ``the impl'') that Bocca has generated for you (by invoking Babel ). Use the bocca edit -i to go directly to each method.

$ bocca edit -i Function evaluate

The editor opens up in the place where the implementation code for evaluate  must be put. You see a default implementation generated by Babel for all user methods: the throwing of an exception which says the method is not yet implemented.

  def evaluate(self, x):
    #
    # sidl EXPECTED INCOMING TYPES
    # ============================
    # double x
    #

    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # double _return
    #

# DO-NOT-DELETE splicer.begin(evaluate)
    #
    # This method has not been implemented
    #

    # DO-DELETE-WHEN-IMPLEMENTING exception.begin(evaluate)
    noImpl = sidl.NotImplementedException.NotImplementedException()
    noImpl.setNote("This method has not been implemented.")
    raise  sidl.NotImplementedException._Exception, noImpl
    # DO-DELETE-WHEN-IMPLEMENTING exception.end(evaluate)
# DO-NOT-DELETE splicer.end(evaluate)

As the comment suggests, this method is ``not implemented'', but some code has been inserted by Babel to make sure an exception is thrown to inform the user if this method is called by mistake. Delete this exception code and substitute an implementation for the PiFunction (i.e., the integral from 0 to 1 of 4/(1 + x2) is an approximation of \bgroup\color{Green}$ \pi$\egroup ).

# DO-NOT-DELETE splicer.begin(evaluate)
    return 4.0 / (1.0 + x * x)
# DO-NOT-DELETE splicer.end(evaluate)

Now in the same file just above the evaluate method, find the second method for the FunctionPort init method:

# DO-NOT-DELETE splicer.begin(init)
    # Do nothing.
    pass
# DO-NOT-DELETE splicer.end(init)

We don't have any initialization in this simple example, so we just eliminate the code that throws the exception when the method is executed.

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Function/demo/Function_Impl.py

Similarly edit the march method in the Integrator with

$ bocca edit -i Integrator march

  def march(self, lowBound, upBound, count):
    #
    # sidl EXPECTED INCOMING TYPES
    # ============================
    # double lowBound
    # double upBound
    # int count
    #

    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # double _return
    #

# DO-NOT-DELETE splicer.begin(march)
    #
    # This method has not been implemented
    #

    # DO-DELETE-WHEN-IMPLEMENTING exception.begin(march)
    noImpl = sidl.NotImplementedException.NotImplementedException()
    noImpl.setNote("This method has not been implemented.")
    raise  sidl.NotImplementedException._Exception, noImpl
    # DO-DELETE-WHEN-IMPLEMENTING exception.end(march)
# DO-NOT-DELETE splicer.end(march)

Again remove this boilerplate exception code and insert an implementation of the Trapezoid rule for integration that uses the FunctionPort :

# DO-NOT-DELETE splicer.begin(march)
    # Use a demo.FunctionPort port with port name odeRHS
    try:
        port = self.d_services.getPort("odeRHS")
    except Exception,e:
        if self.bocca_print_errs:
            print "demo.Integrator: port odeRHS not connected."
        e.args = "demo.Integrator: port odeRHS not connected:\n%s" \
                 % e.args
        raise
    odeRHS = demo.FunctionPort.FunctionPort(port);
    if not odeRHS:
        if self.bocca_print_errs:
            print "demo.Integrator: Error casting port gov.cca.Port " \
                + "to odeRHS type demo.FunctionPort"
        ex = sidl.SIDLException.SIDLException()
        ex.setNote(__name__,0,
                   'Error casting self Port to demo.FunctionPort')
        raise sidl.SIDLException._Exception, ex

    # do the math
    h = (upBound - lowBound) / count
    retval = 0.0
    sum = 0.0
    for i in range(1,count+1):
        sum += odeRHS.evaluate(lowBound + (i - 1) * h)
        sum += odeRHS.evaluate(lowBound + i * h)

    retval = h/2.0 * sum
    self.d_services.releasePort("odeRHS")
    return retval
# DO-NOT-DELETE splicer.end(march)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited:

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Integrator/demo/Integrator_Impl.py

Finally for the Driver component we have to implement the GoPort details to get things going. Bocca will take you to the generated method, which looks like this:

$ bocca edit -i Driver go

  def go(self):
    #
    # sidl EXPECTED RETURN VALUE(s)
    # =============================
    # int _return
    #

    """\
 
Execute some encapsulated functionality on the component. 
Return 0 if ok, -1 if internal error but component may be 
used further, and -2 if error so severe that component cannot
be further used safely.
"""
# DO-NOT-DELETE splicer.begin(go)


# Bocca generated code. bocca.protected.begin(go:boccaGoProlog)
    bocca_status = 0
    # The user's code should set bocca_status 0 if computation proceeded ok.
    # The user's code should set bocca_status -1 if computation failed but might
    # succeed on another call to go(), e.g. when a required port is not yet connected.
    # The user's code should set bocca_status -2 if the computation failed and can
    # never succeed in a future call.
    # The users's code should NOT use return in this function;
    # Exceptions that are not caught in user code will be converted to status 2.

    if bocca_status == 0: # skip this getport if a problem already occured.
        # Use a demo.Integration port with port name integrate 
        try:
            port = self.d_services.getPort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling getPort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg
   
        integrate_fetched = False;
        if not port:
            if self.bocca_print_errs:
                print 'demo.Driver: getPort("integrate") returned nil.'
        else:
            integrate_fetched = True # even if the next cast fails, must release.
            integrate = demo.Integration.Integration(port);
            if not integrate:
                bocca_status = -1
                if self.bocca_print_errs:
                    print "demo.Driver: Error casting port gov.cca.Port to "                        + "integrate type demo.Integration"


    if bocca_status == 0: # all is ok so far and we do the user code, else cleanup and return.
        # user code indents to match this.
# Bocca generated code. bocca.protected.end(go:boccaGoProlog)


        # If this try/catch block is rewritten by the user, we will not change it.
        try:
            try:
                # The user might not require all ports to be connected in all configurations.
                # Each uses port is available as the local variable with the same name.
                # Those that are properly connected will be a value other than None.
                # the proper test for an unavailable port is "if not portinstancename:"


                # BEGIN REMOVE ME BLOCK
                ex = sidl.SIDLException.SIDLException()
                ex.setNote("USER FORGOT TO FILL IN THEIR FUNCTION demo.Driver.go()")
                raise sidl.SIDLException._Exception, ex
                # END REMOVE ME BLOCK

            except sidl.BaseException._Exception, e:
                bocca_status = -2
                if self.bocca_print_errs:
                    (etype, eobj, etb) = sys.exc_info()
                    msg="demo.Driver: Error in go() execution: "+eobj.exception.getNote()
                    print >>sys.stderr,'Exception:', msg
                # if specific exceptions in the user code are tolerable 
                # and restart is ok, bocca_status -1 instead.
                # 2 means the component is so confused that it and probably 
	        # the application should be destroyed.
            except Exception,e:
                bocca_status = -2
                if self.bocca_print_errs:
                    print >> sys.stderr, 'Exception in demo.Driver go():'+str(e)
            except:
                bocca_status = -2
                print >> sys.stderr, 'Unclassified Exception in demo.Driver go()'
        finally:
            # always executed.
            pass
        # This version of TryExceptFinally for compatibility with python 2.3 and up


# Bocca generated code. bocca.protected.begin(go:boccaGoEpilog)
        # end user code.
    # end if bocca_status == 0.

    # release integrate 
    if integrate_fetched:
        integrate_fetched = False
        try:
            self.d_services.releasePort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling releasePort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg


    return bocca_status
# Bocca generated code. bocca.protected.end(go:boccaGoEpilog)


    #
    # This method has not been implemented
    #

# DO-NOT-DELETE splicer.end(go)

Find the REMOVE block within the go method implementation, delete it, and insert the numerical logic needed to use the integrator.IntegratorPort port. Any required local variables should be inserted just before the boccaGoProlog protected block.

The go subroutine will be called by the framework when the component's run button (the name of this particular GoPort instance) is pushed in the GUI. Bocca generates the code to the Integration that the Driver is connected to. We just have to use it to compute the integral and return the proper value for bocca_status.

# DO-NOT-DELETE splicer.begin(go)
# Bocca generated code. bocca.protected.begin(go:boccaGoProlog)
    bocca_status = 0
    # The user's code should set bocca_status 0 if computation proceeded ok.
    # The user's code should set bocca_status -1 if computation failed but might
    # succeed on another call to go(), e.g. when a required port is not yet connected.
    # The user's code should set bocca_status -2 if the computation failed and can
    # never succeed in a future call.
    # The users's code should NOT use return in this function;
    # Exceptions that are not caught in user code will be converted to status 2.

    if bocca_status == 0: # skip this getport if a problem already occured.
        # Use a demo.Integration port with port name integrate 
        try:
            port = self.d_services.getPort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling getPort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg
   
        integrate_fetched = False;
        if not port:
            if self.bocca_print_errs:
                print 'demo.Driver: getPort("integrate") returned nil.'
        else:
            integrate_fetched = True # even if the next cast fails, must release.
            integrate = demo.Integration.Integration(port);
            if not integrate:
                bocca_status = -1
                if self.bocca_print_errs:
                    print "demo.Driver: Error casting port gov.cca.Port to "                        + "integrate type demo.Integration"


    if bocca_status == 0: # all is ok so far and we do the user code, else cleanup and return.
        # user code indents to match this.
# Bocca generated code. bocca.protected.end(go:boccaGoProlog)


        # If this try/catch block is rewritten by the user, we will not change it.
        try:
            try:
                # The user might not require all ports to be connected in all configurations.
                # Each uses port is available as the local variable with the same name.
                # Those that are properly connected will be a value other than None.
                # the proper test for an unavailable port is "if not portinstancename:"
                count = 100000
                lowerBound = 0.0
                upperBound = 1.0

                # operate on the port
                value = integrate.march(lowerBound, upperBound, count)
                print 'Value =', value
            except sidl.BaseException._Exception, e:
                bocca_status = -2
                if self.bocca_print_errs:
                    (etype, eobj, etb) = sys.exc_info()
                    msg="demo.Driver: Error in go() execution: " \
                        + eobj.exception.getNote()
                    print >>sys.stderr,'Exception:', msg
                # if specific exceptions in the user code are tolerable
                # and restart is ok, bocca_status -1 instead.
                # 2 means the component is so confused that it and probably
        # the application should be destroyed.
            except Exception,e:
                bocca_status = -2
                if self.bocca_print_errs:
                    print >> sys.stderr, 'Exception in demo.Driver go():'+str(e)
            except:
                bocca_status = -2
                print >> sys.stderr, 'Unclassified Exception in demo.Driver go()'
        finally:
            # always executed.
            pass
        # This version of TryExceptFinally for compatibility with python 2.3 and up

# Bocca generated code. bocca.protected.begin(go:boccaGoEpilog)
        # end user code.
    # end if bocca_status == 0.

    # release integrate 
    if integrate_fetched:
        integrate_fetched = False
        try:
            self.d_services.releasePort("integrate")
        except sidl.BaseException._Exception, e:
            port = None
            if self.bocca_print_errs:
                (etype, eobj, etb) = sys.exc_info()
                msg="demo.Driver: Error calling releasePort('integrate'): "                    + eobj.exception.getNote()
                print >>sys.stderr,'Exception:', msg


    return bocca_status
# Bocca generated code. bocca.protected.end(go:boccaGoEpilog)
# DO-NOT-DELETE splicer.end(go)

After quitting the editor the state of the source code tree is updated if there are any dependencies on the edited implementation. Usually there are no dependencies on the implementation file, so Bocca does very little after you exit the editor and all you see is the information from the edit command about what file was edited.

/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/demo.Driver/demo/Driver_Impl.py

Now remake your project tree to finish the components:

$ make

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'
# =======================================================================
# No SIDL files in external/sidl, skipping build for external
# =======================================================================
# =======================================================================
# Building in ports/, languages: python
# =======================================================================
 ## Building ports... 
# =======================================================================
# Building in components/clients/, languages: python
# =======================================================================
 ## Building clients... 
# =======================================================================
# Building in components/, languages: python
# =======================================================================

   [s] Building class/component demo.Driver: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Driver.la ... 
   [s] finished libtooling: components/demo.Driver/libdemo.Driver.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Driver_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.Function: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Function.la ... 
   [s] finished libtooling: components/demo.Function/libdemo.Function.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Function_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.Integrator: 
make[3]: `.gencode' is up to date.
   [s] creating class/component library: libdemo.Integrator.la ... 
   [s] finished libtooling: components/demo.Integrator/libdemo.Integrator.la ... 
   [s] building /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/install/share/cca/demo/demo.Integrator_depl.xml ... 
   [s] creating Ccaffeine test script (components/tests/instantiation.gen.rc)... 

   [s] Building class/component demo.emptyComponent: 
make[3]: `.gencode' is up to date.
doing nothing -- library is up-to-date.
Build summary:
SUCCESS building demo.Driver
SUCCESS building demo.Function
SUCCESS building demo.Integrator
### To test instantiation of successfully built components, run 'make check' ###
################ Finished building everything #################
####### You can run some simple tests with 'make check' #######
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'

It is good practice to do a make check at this point:

$ make check

make[1]: Entering directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'
make --no-print-directory --no-builtin-rules -C components check
### Test library load and instantiation for the following languages: python
Running instantiation tests only
Test script: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc
Log file: /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc.log
SUCCESS:
==> Instantiation tests passed for all built components (see /home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo/components/tests/instantiation.gen.rc.log).
make --no-print-directory --no-builtin-rules check-user
make[1]: Leaving directory `/home/bernhold/bassi/project/projectdirs/cca/pde-hands-on/doc/scratch/python/demo'

You should now be able to instantiate these components, assemble them into an application, and run the application, following the same procedures as in Section 2, and get a result that's reasonably close to pi .

David E. Bernholdt [bek] 574-3147 2009-08-21