# coding=utf-8
# Copyright (c) 2013, 2017, System Engineering Software Society
# 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 System Engineering Software Society 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 SYSTEM ENGINEERING SOFTWARE SOCIETY 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.
"""
A collection of examples that illustrates a number of details that are
important in order to create nodes for Sympathy of Data. The usage of content
in this file should be combined with the Node Writing Tutorial.
"""
import time
import numpy as np
from sympathy.api import node as synode
from sympathy.api.nodeconfig import Port, Ports, deprecated_node
from sympathy.utils.parameter_helper import (
CustomParameterHandler, MyCustomWidgetBuildingVisitor)
from sympathy.api.exceptions import sywarn
[docs]@deprecated_node('1.5.0', 'All parameters example')
class Example1(synode.Node):
"""
This node includes all available configuration options for initialising
parameters that can be controlled by the users through a configuration GUI.
The GUI is automatically generated by the platform through defined
connections between data types and different GUI widgets.
Another functionality shown by this node is how the platform
defined methods verify_parameters and adjust_parameters can
be used.
The example demonstrates how to set up an outgoing Table. This Table can
be used as input for the Example2 node.
:Inputs: None
:Outputs:
**Output** : Table
Table file with a dataset named 'k'. The dataset
consists of the values 1-99.
:Configuration: All types of configuration options
:Opposite node: None
:Ref. nodes: :ref:`Example2`, :ref:`Example3`, :ref:`Error Example`
"""
name = 'Example1'
description = 'Example Node'
icon = 'example.svg'
nodeid = 'org.sysess.sympathy.examples.example1'
author = 'Alexander Busck <alexander.busck@sysess.org>'
copyright = '(C)2011-2012 System Engineering Software Society'
version = '1.0'
outputs = Ports([Port.Table('Output Table', name='port1')])
# TODO fix labels on groups and pages
parameters = synode.parameters()
delay_group = parameters.create_group('delay', label='Delay Group')
delay_group.set_float('delay',
label='Delay',
description='Delay in seconds',
value=0.050)
examples_group = parameters.create_group('examples', label='Examples')
scalars_page = examples_group.create_page('scalars', label='Scalars')
scalars_page.set_float('stringfloat',
label='Float in a line edit',
description='A float',
value=0.1234)
scalars_page.set_float('spinfloat',
label='Float in a spinbox',
description='A float',
value=0.1234,
editor=synode.Util.bounded_decimal_spinbox_editor(
0.0, 4.0, 0.1, 4).value())
scalars_page.set_integer('stringinteger',
label='Integer in a line edit',
description='An integer',
value=1234,
editor=synode.Util.bounded_lineedit_editor(
0, 2000).value())
scalars_page.set_integer('spininteger',
label='Integer in a spinbox',
description='An integer',
value=1234,
editor=synode.Util.bounded_spinbox_editor(
0, 2000, 10).value())
string_page = examples_group.create_page('strings', label='Strings')
string_page.set_string('lineedit',
label='String in a line edit',
description='Text on a single line')
string_page.set_string('filename',
label='String as filename',
description='A filename including path if needed',
value='test.text',
editor=synode.Util.filename_editor(
['Image files (*.png *.xpm *.jpg)',
'Text files (*.txt)',
'Any files (*)']).value())
string_page.set_string('directory',
label='String as directory name',
description='A directory including path if needed',
value='MyDirectory',
editor=synode.Util.directory_editor().value())
logics_page = examples_group.create_page('logics', label='Logics')
logics_page.set_boolean('boolflag',
label='Boolean',
description=('A boolean flag indicating true or '
'false'),
value=True)
lists_page = examples_group.create_page('lists', label='Lists')
lists_page.set_list('combo',
label='Combo Box',
description='A combo box',
value=[1],
plist=['First option',
'Second option',
'Third option'],
editor=synode.Util.combo_editor().value())
lists_page.set_list('alist',
label='List View',
description='A list',
value=[2],
plist=['First option',
'Second option',
'Third option'],
editor=synode.Util.list_editor().value())
multilist_editor = synode.Util.selectionlist_editor('multi')
multilist_editor.set_attribute('alternatingrowcolors', False)
lists_page.set_list('multilist',
label='List View with multiselect',
description='A list with multiselect',
value=[0, 2],
plist=['Element1', 'Element2', 'Element3'],
editor=multilist_editor.value())
controllers = synode.controller(
when=synode.field('boolflag', 'checked'),
action=synode.field('strings', 'enabled')
)
def __init__(self):
super(Example1, self).__init__()
def verify_parameters(self, node_context):
"""Verify parameters"""
# Fail if delay is larger than 0.2 seconds.
if node_context.parameters['delay']['delay'].value > 0.2:
return False
return True
def adjust_parameters(self, node_context):
"""Adjust parameters"""
params = node_context.parameters
params['examples']['lists']['alist'].list = (
['My', 'Programmatically', 'Generated', 'List'])
return node_context
def custom_parameters(self, node_context):
return CustomParameterHandler, MyCustomWidgetBuildingVisitor
def execute(self, node_context):
"""Execute node"""
delay = node_context.parameters['delay']['delay'].value
data = []
for k in range(1, 100):
self.set_progress(float(k))
time.sleep(delay)
data.append(k)
# Create a recarray from list
# Write table to output file
tablefile = node_context.output['port1']
tablefile.set_column_from_array('k', np.array(data))
[docs]@deprecated_node('1.5.0', 'Read/write example')
class Example2(synode.Node):
"""
The node demonstrates how to create ports for receiving a Table
and dispatching an ADAF.
:Inputs:
**Port1** : Table
Table with incoming data. For example from Example1.
:Outputs:
**Port3** : ADAF
ADAF with the data from incoming Table stored in the metadata
container.
:Configuration:
:Opposite node: None
:Ref. nodes:
:ref:`Example1`, :ref:`Example3`, :ref:`Example5`, :ref:`Error Example`
"""
name = 'Example2'
description = 'Example Node'
icon = 'example.svg'
nodeid = 'org.sysess.sympathy.examples.example2'
author = 'Alexander Busck <alexander.busck@sysess.org>'
copyright = '(C)2011-2012 System Engineering Software Society'
version = '1.0'
inputs = Ports([Port.Table('Input Table', name='port1')])
outputs = Ports([Port.ADAF('Output ADAF', name='port3')])
parameters = synode.parameters()
parameters.set_float('delay',
label='Delay',
description='Delay in seconds',
value=0.05)
def __init__(self):
super(Example2, self).__init__()
def execute(self, node_context):
"""Execute node"""
tablefile = node_context.input['port1']
try:
data_array = tablefile.get_column_to_array('k')
except KeyError:
sywarn("Empty output will be produced if input has no column 'k'.")
data_array = []
new_data = []
for k in data_array:
self.set_progress(float(k))
time.sleep(node_context.parameters['delay'].value)
new_data.append(k + 1)
# Write an ADAF file.
adaffile = node_context.output['port3']
adaffile.meta.create_column('k', np.array(new_data), {})
[docs]@deprecated_node('1.5.0')
class Example3(synode.Node):
"""
Example3 demonstrates the identity function, the incoming ADAF is
passed through the node. Instead of creating a new ADAF for the
output a link is created between the input and output with the following
line::
out_datafile.source(in_datafile)
:Inputs:
**Input** : ADAF
ADAF with incoming data. For example from Example2.
:Outputs:
**Port3** : ADAF
ADAF where the data is linked to the input ADAF.
:Ref. nodes:
:ref:`Example1`, :ref:`Example2`, :ref:`Example3`, :ref:`Error Example`
"""
name = 'Example3'
description = 'Example Node'
icon = 'example.svg'
nodeid = 'org.sysess.sympathy.examples.example3'
author = 'Alexander Busck <alexander.busck@sysess.org>'
copyright = '(C)2011-2012,2015 System Engineering Software Society'
version = '1.0'
inputs = Ports([Port.ADAF('Input ADAF', name='port1')])
outputs = Ports([Port.ADAF('Output ADAF', name='port3')])
def __init__(self):
super(Example3, self).__init__()
def execute(self, node_context):
in_datafile = node_context.input['port1']
out_datafile = node_context.output['port3']
# Create links in the output file to the data in the input file.
out_datafile.source(in_datafile)
[docs]@deprecated_node('1.5.0')
class Example4(synode.Node):
"""This node performs a test of the paths added to the Python paths."""
name = 'Example4'
description = 'Test Node'
icon = 'example.svg'
nodeid = 'org.sysess.sympathy.examples.example4'
author = 'Alexander Busck <alexander.busck@sysess.org>'
copyright = '(C)2011-2012 System Engineering Software Society'
version = '1.0'
# Deprecated because it doesn't work.
outputs = Ports([Port.ADAF('Output ADAF', name='port3')])
def __init__(self):
super(Example4, self).__init__()
def execute(self, node_context):
"""Execute node"""
import pythonpathtest # noqa
[docs]@deprecated_node('1.5.0', 'Output Example')
class Example5(synode.Node):
"""
Example5 demonstrates the configuration for multiple ports on the output
side of the node. The configuration for multiple input ports is analogous
to this example.
During execution the node let the incoming Table pass through to the
outputs by setting up links.
:Inputs:
**Port0** : Table
Table with incoming data. For example from Example1.
:Outputs:
**Output0** : Table
Table where the data is linked to the input Table.
**Output1** : Table
Table where the data is linked to the input Table.
:Configuration:
:Opposite node: None
:Ref. nodes:
:ref:`Example1`, :ref:`Example2`, :ref:`Example3`, :ref:`Error Example`
"""
name = 'Example5'
description = 'Example Node'
icon = 'example.svg'
nodeid = 'org.sysess.sympathy.examples.example5'
author = 'Alexander Busck <alexander.busck@sysess.org>'
copyright = '(C)2011-2012 System Engineering Software Society'
version = '1.0'
inputs = Ports([Port.Table('Input Table', name='port0')])
outputs = Ports([
Port.Table('Output Table 1', name='port0'),
Port.Table('Output Table 2', name='port1')])
def __init__(self):
super(Example5, self).__init__()
def execute(self, node_context):
"""Execute node"""
tablefile = node_context.input['port0']
out_datafile1 = node_context.output['port0']
out_datafile2 = node_context.output['port1']
out_datafile1.source(tablefile)
out_datafile2.source(tablefile)