Version: current

Python

In SAFE you can integrate your own Python functions directly into SAFE. This can be used both in measurement steps, if you for example need to communicate with your own products API, and in processing if you want to use your own analysis.

Preqequisite

Python 3.6 or above must be installed.

Using a Python function in a measurement step

To use a Python function in a measurement step you must drag out the measurement track Python Script onto a step. The track shows you a console which shows you every print statement from your function when the step is started. The Python scripts run BEFORE any recording or output tracks and if more than one Python script is in a step they will run sequentially with a priority based on where the Python Script is placed in the step.

Your Python function can only have one input variable and must return the same variable.

When used in a measurement step, data will be sent to your function as a dictonary like the example below.

user_data = {'step': 1, # the current step number
'repeaterList': [1, 0], # the current repeater count
'success': True} # script success variable (True, False)

You can add key/value pairs to this dict and it will be passed between all the functions you run during a sequence.

Use the 'success' key to tell SAFE if the script ran successfully or not. Returning False will stop the sequence.

Your Python function should be defined as the example function foo below. The file in which your function is, must have a if __name__ == __main__: clause with the content shown in the example below.

caution

It is advised not to make additional function calls or change the code in the in the if __name__ == '__main__': clause. Doing so can cause unexpected behavior.

def foo(user_data):
"""
Example function to be used in a SAFE measurement sequence.
:param user_data: A dictionary to be used throughout a measurement sequence.
:return: user_data: The user_data dictionary
"""
print('Hello world!')
return user_data
if __name__ == '__main__':
import sys
import json
import numpy as np
json_str = sys.stdin.read() # reads the encoded data passed from SAFE
input_data = {k: np.array(v) if type(v) is list else v for k, v in json.loads(json_str).items()} # decode data to numpy arrays
ret = globals()[sys.argv[1]](input_data) # function call
print(json.dumps({k.replace('\'', '"'): v.tolist() if type(v) is np.ndarray else v for k, v in ret.items()})) # encode and print output
### NO PRINTS AFTER THIS LINE ###

Using a Python function in processing

To use a Python function in processing you must drag out the processing block Python Script from the toolbox Scripts. Here you can choose filepath and function name in the attribute dock. When the block is connected to other blocks data will be sent to your function as a dictonary as follows.

import numpy as np
data = {'msg': '',
'fs': 48000,
'xlabel': 'Time',
'ylabel': 'Amplitude',
'X': np.array([[1,1,1],
[2,2,2],
[3,3,3]]),
'Y': np.array([[5,2,5],
[8,3,5],
[9,4,5]])}

Your Python function should be defined as the example foo below. The file in which your function is, must have a if __name__ == __main__: clause with the content shown in the example below.

caution

It is advised not to make additional function calls or change the code in the in the if __name__ == '__main__': clause. Doing so can cause unexpected behavior.

def foo(data):
"""
Example function that works with a SAFE processing block
:param data: is the dictionary of data given to the function by SAFE
:return data: the data dictionary processed by your script
"""
data['Y'][:, 1] = data['Y'][:, 1] + 10 # add 10 to channel 1
return data
if __name__ == '__main__':
import sys
import json
import numpy as np
json_str = sys.stdin.read() # reads the encoded data passed from SAFE
input_data = {k: np.array(v) if type(v) is list else v for k, v in json.loads(json_str).items()} # decode data to numpy arrays
ret = globals()[sys.argv[1]](input_data) # function call
print(json.dumps({k.replace('\'', '"'): v.tolist() if type(v) is np.ndarray else v for k, v in ret.items()})) # encode and print output
### NO PRINTS AFTER THIS LINE ###