Tutorial

This is a tutorial for creating an Anduril component using the Python API. You can also use the API from scripts passed to the PythonEvaluator component. See the components documentation for more information. It is assumed that you should know the basics in Python and writing Anduril component.xml files.

Importing the API

The API can be found from python directory under your Anduril home directory. This should be included in your Python path in order for any of the Python components to work. You should be able to import the Anduril Python API by:

import anduril

Importing component arguments

If you are writing a component and want an easy way to import all the arguments passed to your compnent, i.e. input ports, output ports and parameters, you can simply import the anduril.args module.

The arguments are read to namespace of the module as they appear in the component.xml file. In case of collision with the arguments of different types, the arguments can be accessed with names starting with “param_”, “input_”, and “output_”.

The input/output ports arguments contain the file names where the data can be read or written (except for arrays, which are described below). The parameters are automatically converted to the data type indicated in the component.xml file. That is, strings are Python string, bools are Python boolean objects etc.

Simple example component

Lets write a component which takes a number as input and writes another number which is a sum of the input and an offset given as a parameter.

The component.xml file for this component looks like this:

<component>
  <name>NumberOffset</name>
  <version>1.0</version>
  <doc>Adds offset to data.</doc>
  <launcher type="python">
      <argument name="file" value="numberoffset.py" />
  </launcher>
  <requires URL="http://www.python.org/" type="manual">python</requires>
  <inputs>
    <input name="data" type="TextFile"></input>
  </inputs>
  <outputs>
    <output name="result" type="TextFile"></output>
  </outputs>
  <parameters>
    <parameter name="offset" type="float" default="0.1"></parameter>
  </parameters>
</component>

The Python script doing the work, numberoffset.py, would start by importing the arguments:

from anduril.args import *

After this we need to read in the number from the input port named “data”:

data_file=open(data,'r')
original_number=float(data_file.read())

The offset is already loaded as float to the “offset” parameter so the calculation is simple:

new_number=original_number + offset

Finally we write the new number to the result port:

result_file=open(result,'w')
result_file.write(str(new_number))

Reading and writing CSV files

If your input or output ports are of CSV type, you should use TableReader and TableWriter to handle them. This way you can easily write CVS files in a dialect which is understood by other components, and helps you to avoid the most common pitfalls in parsing the CSV files produced by the other components.

The TableReader instances are iterable objects which by default return dictionary objects with column names as keys and data on each row as values. For example, consider the following table:

"index" "data"
1       "one"
2       "two"

The TableReader could be used in the following way:

from anduril import *
table=TableReader(table_filename)
for row in table:
  print row

which would print:

{'data': 'one', 'index': 1}
{'data': 'two', 'index': 2}

The same table could be written with the TableWriter class:

from anduril import *
table=TableWriter(table_filename,fieldnames=["index","data"])
table.writerow([1,"one"])
table.writerow([2,"two"])

A convenience function pair exists to work with pandas data frames:

df = anduril.PandasReader(input_filename)
df['absCol'] = df['Column1'].abs()
anduril.PandasWriter(df, output_filename)

Arrays

When input/output ports which are arrays are imported with the anduril.args module they are not give as file names but are automatically converted into OrderedDict and AndurilOutputArray objects.

For example, component reading an array and writing the same array to an output port would look like this:

from anduril import *
for key,filename in input_array_port_name.items():
  output_array_port_name.write(key,filename)

Logs, errors and temporary dirs

Writing to the log and error streams is possible with anduril.args.write_log and anduril.args.write_error functions. The temporary directory which is created for each component instance can be accessed through the anduril.args.tempdir variable.