<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<toolkitModel xmlns="http://www.ibm.com/xmlns/prod/streams/spl/toolkit" productVersion="4.3.0.0" xmlns:common="http://www.ibm.com/xmlns/prod/streams/spl/common" xmlns:ti="http://www.ibm.com/xmlns/prod/streams/spl/toolkitInfo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <toolkit name="com.ibm.streamsx.topology.pysamples" requiredProductVersion="4.2" version="1.1.0">
    <description>
    Sample toolkit for Python support.
    This sample demonstrates the usage of operators written in python in a Streams spl application.
    In directory opt/python/streams there are some python modules which implement streams operators.
    There are two spl applications in namespace com.ibm.streamsx.topology.pysamples.apps which use these python operators.
    To build this sample export the environment variable STREAMS_TOPOLOGY_TOOLKIT with the path to your toplogy toolki and 
    execute ant all from the command line.
    If environment variable STREAMS_TOPOLOGY_TOOLKIT not exists the sample is build using the topology toolkit from 
    the streams installation.
  </description>
    <uriTable>
      <uri index="8" value="com.ibm.streamsx.topology.pysamples.primitives/SelectCustomers"/>
      <uri index="6" value="com.ibm.streamsx.topology.pysamples.sources/Range"/>
      <uri index="1" value="com.ibm.streamsx.topology.pysamples.apps/MailSample.spl"/>
      <uri index="10" value="com.ibm.streamsx.topology.pysamples.positional/SimpleFilter"/>
      <uri index="12" value="com.ibm.streamsx.topology.pysamples.positional/AddFirstTwoSecondTwo"/>
      <uri index="7" value="com.ibm.streamsx.topology.pysamples.mail/simplesendmail"/>
      <uri index="5" value="opt/.splpy/icons/python-powered32.gif"/>
      <uri index="14" value="com.ibm.streamsx.topology.pysamples.positional/Lowest"/>
      <uri index="2" value="com.ibm.streamsx.topology.pysamples.apps/NoopSample.spl"/>
      <uri index="9" value="com.ibm.streamsx.topology.pysamples.positional/AddSeq"/>
      <uri index="4" value="opt/.splpy/icons/python-powered16.gif"/>
      <uri index="13" value="com.ibm.streamsx.topology.pysamples.positional/PrintTuple"/>
      <uri index="15" value="com.ibm.streamsx.topology.pysamples.positional/PrintWithTimeIntervals"/>
      <uri index="3" value="com.ibm.streamsx.topology.pysamples.sources/Range37"/>
      <uri index="17" value="com.ibm.streamsx.topology.pysamples.kwargs/DeltaFilter"/>
      <uri index="18" value="com.ibm.streamsx.topology.pysamples.kwargs/ContainsFilter"/>
      <uri index="16" value="com.ibm.streamsx.topology.pysamples.positional/ReturnList"/>
      <uri index="11" value="com.ibm.streamsx.topology.pysamples.positional/Noop"/>
    </uriTable>
    <namespace name="com.ibm.streamsx.topology.pysamples.apps">
      <compositeOp column="18" line="5" name="MailSample" potentialMain="true" public="true" uriIndex="1"/>
      <compositeOp column="18" line="5" name="NoopSample" potentialMain="true" public="true" uriIndex="2"/>
    </namespace>
    <namespace name="com.ibm.streamsx.topology.pysamples.sources">
      <primitiveOp language="Cpp" modelUriIndex="3" name="Range37" public="true">
        <description>
Sample of a function as a source operator.
# Python
    @spl.source()
    def Range37():
        """Sample of a function as a source operator."""
        if sys.version_info.major == 2:
            # zip behaviour differs on Python 2.7
            return iter(zip(range(37)))
        return zip(range(37))

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Free"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="6" name="Range" public="true">
        <description>
Callable: Range

# Python
    @spl.source()
    class Range(object):
        def __init__(self, count):
            self.count = count
    
        def __iter__(self):
            # Use zip to convert the single returned value
            # into a tuple to allow it to be returned to SPL
            if sys.version_info.major == 2:
                # zip behaviour differs on Python 2.7
                return iter(zip(range(self.count)))
            return zip(range(self.count))

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <parameter cardinality="1" expressionMode="AttributeFree" name="count" optional="false" type="">
          <description/>
        </parameter>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Free"/>
      </primitiveOp>
    </namespace>
    <namespace name="com.ibm.streamsx.topology.pysamples.mail">
      <primitiveOp language="Cpp" modelUriIndex="7" name="simplesendmail" public="true">
        <description>
Send a simple email.
# Python
    @spl.for_each(style=position)
    class simplesendmail(object):
        "Send a simple email."
        def __init__(self):
            self.server = smtplib.SMTP('localhost')
    
        def __call__(self, from_addr, to_addrs, msg):
            self.server.sendmail(from_addr, to_addrs, msg)

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>
__SPLPY__INPORT_0__DESCRIPTION__SPLPY__
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
      </primitiveOp>
    </namespace>
    <namespace name="com.ibm.streamsx.topology.pysamples.primitives">
      <primitiveOp language="Cpp" modelUriIndex="8" name="SelectCustomers" public="true">
        <description>
Score customers using a model.
Customers that are a good match are submitted to port 0 ('MATCH')
while customers that are a near match are submitted to port 1 ('NEAR_MATCH').
        
Customers that are not a good or near match are not submitted to any port. 
# Python
    @spl.primitive(output_ports=['MATCH', 'NEAR_MATCH'])
    class SelectCustomers(spl.PrimitiveOperator):
        """Score customers using a model.
        Customers that are a good match are submitted to port 0 ('MATCH')
        while customers that are a near match are submitted to port 1 ('NEAR_MATCH').
                
        Customers that are not a good or near match are not submitted to any port. 
        """
        def __init__(self, match, near_match):
            self.match = match
            self.near_match = near_match
        
        @spl.input_port()
        def customers(self, **tuple_):
            customer_score = self.score(tuple_)
            if customer_score &gt;= self.match:
                self.submit('MATCH', tuple_)
            elif customer_score &gt;= self.near_match:
                self.submit('NEAR_MATCH', tuple_)
    
        def score(self, **customer):
            # Real scoring omitted
            score = random.random()
            return score

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <parameter cardinality="1" expressionMode="AttributeFree" name="match" optional="false" type="">
          <description/>
        </parameter>
        <parameter cardinality="1" expressionMode="AttributeFree" name="near_match" optional="false" type="">
          <description/>
        </parameter>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>
                                    customers
  </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Free">
          <description>
    __SPLPY__OUTPORT_DESCRIPTION__SPLPY__
  </description>
        </outputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Free">
          <description>
    __SPLPY__OUTPORT_DESCRIPTION__SPLPY__
  </description>
        </outputPort>
      </primitiveOp>
    </namespace>
    <namespace name="com.ibm.streamsx.topology.pysamples.positional">
      <primitiveOp language="Cpp" modelUriIndex="9" name="AddSeq" public="true">
        <description>
Add a sequence number as the last attribute.
# Python
    @spl.map()
    class AddSeq(object):
        """Add a sequence number as the last attribute."""
        def __init__(self):
            self.seq = 0
    
        def __call__(self, *tuple_):
            id = self.seq
            self.seq += 1
            return tuple_ + (id,)

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="10" name="SimpleFilter" public="true">
        <description>
Filter tuples only allowing output if the first attribute is less than the second.

Returns the sum of the first two attributes.
# Python
    @spl.map(style='position')
    def SimpleFilter(a,b):
       """
       Filter tuples only allowing output if the first attribute is less than the second.
       
       Returns the sum of the first two attributes.
       """
       if (a &lt; b):
           return a+b,

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="11" name="Noop" public="true">
        <description>
Pass the tuple along without any change.
# Python
    @spl.map()
    def Noop(*tuple_):
        "Pass the tuple along without any change."
        return tuple_

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="12" name="AddFirstTwoSecondTwo" public="true">
        <description>
Add first two and second two attributes.
# Python
    @spl.map(style='position')
    def AddFirstTwoSecondTwo(a,b,c,d):
        "Add first two and second two attributes."
        return a+b,c+d

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="13" name="PrintTuple" public="true">
        <description>
Print each tuple to standard out.
# Python
    @spl.for_each()
    def PrintTuple(*tuple_):
        """Print each tuple to standard out."""
        print(tuple_, flush=True)

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>
__SPLPY__INPORT_0__DESCRIPTION__SPLPY__
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="14" name="Lowest" public="true">
        <description>
Find the lowest value above a threshold in all the remaining attributes.
# Python
    @spl.map(style='position')
    def Lowest(threshold, *values):
        "Find the lowest value above a threshold in all the remaining attributes."
        lm = None
        for v in values:
          if v &gt;= threshold:
              if lm == None:
                 lm = v
              elif v &lt; lm:
                 lm = v
        if lm != None:
             return lm,

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="15" name="PrintWithTimeIntervals" public="true">
        <description>
Print tuples with inter-tuple arrival delay.
# Python
    @spl.for_each()
    class PrintWithTimeIntervals(object):
        "Print tuples with inter-tuple arrival delay."
        def __init__(self):
            self.last = datetime.now()
    
        def __call__(self, *tuple_):
            now = datetime.now()
            iat = now - self.last
            self.last = now
            print(tuple_, " ", iat, " seconds", flush=True)

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>
__SPLPY__INPORT_0__DESCRIPTION__SPLPY__
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="16" name="ReturnList" public="true">
        <description>
Demonstrate returning a list of values, each value is submitted as a tuple.
# Python
    @spl.map(style='position')
    def ReturnList(a,b,c):
        "Demonstrate returning a list of values, each value is submitted as a tuple." 
        return [(a+1,b+1,c+1),(a+2,b+2,c+2),(a+3,b+3,c+3),(a+4,b+4,c+4)]

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by position to the Python callable.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
    </namespace>
    <namespace name="com.ibm.streamsx.topology.pysamples.kwargs">
      <primitiveOp language="Cpp" modelUriIndex="17" name="DeltaFilter" public="true">
        <description>
Drops any tuple that is within a delta of the last tuple for the attribute named `value`.
# Python
    @spl.map()
    class DeltaFilter(object):
        "Drops any tuple that is within a delta of the last tuple for the attribute named `value`."
        def __init__(self, delta):
            self.delta = delta
            self.empty = ()
            self.last_value = None
    
        # Signature has **kwargs parameter which fixes the
        # SPL tuple parameter passing style to be dictionary
        def __call__(self, **tuple_):
            value = tuple_['value']
            if self.last_value is not None:
                if abs(value - self.last_value) &lt;= self.delta:
                    self.last_value = value
                    return None
            self.last_value = value
            # Empty tuple will cause any matching input attributes
            # to be carried across to the output tuple
            return self.empty

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <parameter cardinality="1" expressionMode="AttributeFree" name="delta" optional="false" type="">
          <description/>
        </parameter>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by name to the Python callable using `\*\*kwargs`.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving"/>
      </primitiveOp>
      <primitiveOp language="Cpp" modelUriIndex="18" name="ContainsFilter" public="true">
        <description>
Looks for a string term in any attribute in the tuple.
# Python
    @spl.filter()
    class ContainsFilter(object):
        """
        Looks for a string term in any attribute in the tuple.
        """
        def __init__(self, term):
            self.term = term;
    
        def __call__(self, **tuple_):
            for s in tuple_.values():
                if self.term in str(s):
                    return True
            return False

      </description>
        <images>
          <image size="16" uriIndex="4"/>
          <image size="32" uriIndex="5"/>
        </images>
        <parameter cardinality="1" expressionMode="AttributeFree" name="term" optional="false" type="">
          <description/>
        </parameter>
        <inputPort maxNumPorts="1" minNumPorts="1" optional="false" windowPunctInputMode="Oblivious">
          <description>

           Tuple attribute values are passed by name to the Python callable using `\*\*kwargs`.
                 
        </description>
          <windowPolicy>NonWindowed</windowPolicy>
        </inputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="false" windowPunctOutputMode="Preserving">
          <description>
This filter operator is configurable with one or two output ports. This first output port is mandatory.

This filter operator requires that the stream type of this output port matches the stream type of the input port. This output port receives the tuples that match the filter.
        </description>
        </outputPort>
        <outputPort expressionMode="Nonexistent" maxNumPorts="1" minNumPorts="1" optional="true" windowPunctOutputMode="Preserving">
          <description>
This filter operator is configurable with one or two output ports. This second output port is optional.

This filter operator requires that the stream type of this output port matches the stream type of the input port. This output port, if present, receives the tuples that fail to match the filter.
        </description>
        </outputPort>
      </primitiveOp>
    </namespace>
    <sabFiles>
      <ti:include path="toolkit.xml" root="toolkitDir"/>
      <ti:include path="impl/java/lib/**" root="toolkitDir"/>
      <ti:include path="impl/java/bin/**" root="toolkitDir"/>
      <ti:include path="impl/bin/**" root="toolkitDir"/>
      <ti:include path="impl/lib/**" root="toolkitDir"/>
      <ti:include path="impl/nl/*.dat" root="toolkitDir"/>
      <ti:include path="etc/**" root="toolkitDir"/>
      <ti:include path="lib/**" root="toolkitDir"/>
      <ti:include path="nl/**" root="toolkitDir"/>
      <ti:include path="opt/**" root="toolkitDir"/>
    </sabFiles>
  </toolkit>

</toolkitModel>
