Python3 actions and triggers¶
Python is one of the most used programming language in the world. Ryax supports actions and triggers written in python 3.
Here, we will describe what a ryax python action is, what it consists of, as well as some technical functionalities made available.
You can found examples of python actions and triggers here.
General¶
An action or a trigger require at least 2 files: the python code in a .py
file, and the Ryax metadata file: ryax_metadata.yaml
.
If the action has some external dependencies (ex: pandas
, tensorflow
), it needs a standard requirements.txt
file with those dependencies listed on separate lines in plain text.
You can also add a logo to your action, to be more easily seen in the webui. This logo must be at most 250x250px
, and be in either jpg
or png
format.
Dependencies¶
Python dependencies¶
In a typical python3 program, you might need to install some dependencies for your program to work.
The common approach is to have a file requirements.txt
with a list of all actions needed.
Ryax will look at this file in the root of the action to know the external python libraries that are required by your code.
If your code does not have any external dependencies, you can omit this file.
Windows users must be careful because windows sometimes adds a .txt resulting in a requirements.txt.txt
.
A requirements.txt
file consists of a list of python dependencies, one per line.
You can add version constraints to be sure that you use the right version of your dependency:
pandas
tensorflow==1.3.0
pillow>=7.0.0
You can look for all available python dependencies in Pypi.
Binary dependencies¶
If you have non-python dependencies (called “binary dependencies”), you can specify them in the dependencies
field of the ryax_metadata.yaml
file.
It is possible that some python actions require a binary dependency to work, like opencv
.
You can look for all supported dependencies, and their version, here. Some binaries might not work as Ryax run your code in a containerized and secured environement.
Metadata file¶
To describe your action, you need a ryax_metadata.yaml
file that contains a high-level description of your action and the inputs/outputs.
The file ryax_metadata.yaml
follow the YAML standard that is equivalent to json
in many aspects.
Here is an example:
apiVersion: "ryax.tech/v2.0"
kind: Processor
spec:
id: tfdetection
human_name: Tag objects
description: "Tag detected objects on images using Tensorflow"
type: python3
version: "1.0"
logo: mylogo.png
inputs:
- help: Model name
human_name: Model name
name: model
type: enum
enum_values:
- ssdlite_mobilenet_v2_coco_2018_05_09
- mask_rcnn_inception_v2_coco_2018_01_28
default_value: ssdlite_mobilenet_v2_coco_2018_05_09
- help: An image to be tagged; in any format accepted by OpenCV
human_name: Image
name: image
type: file
outputs:
- help: Path of the tagged image
human_name: Tagged image
name: tagged_image
type: file
Some explanation on the fileds:
kind
to tell the kind of the action: a source, a processor or, a publisher?id
unique name of the actionversion
unique version of the actionhuman_name
a short name, readable by a humandescription
a description of the actiontype
the programming languagelogo
optional, a relative path to a logo file.
inputs
and outputs
contain the list of all the inputs and outputs of this action. Here, the name
is the name in your python program, while the human_name
is to display in the webUI.
The complete list of all fields is available here as a JSON Schema.
TODO: add json schema. {.error}
The code¶
Ryax know how to call your code by importing a python code and starting a specific function in it.
Depending on the kind
of the action, we use 2 different filenames:
ryax_handler.py
for processors and publishersryax_run.py
for sources
When creating a action, Ryax will copy all the files that are in the action directory. Thus, if you split your code in multiple files and use some resource files, they will be copied into the action.
Actions¶
The ryax_handler.py
file should contain a handle
method that takes a dict
as first parameter and returns a dict
or a list
of dict
.
def handle(request):
a = request["an_integer_input"]
a = a + 42
return {
"output1": "value",
"output2": a,
}
By looking at this code, we can guess that this actions has at least an input called an_integer_input
(an integer), and has 2 outputs: output1
and output2
.
Ryax should know about these by describing them in the ryax_metadata.yaml
file.
If the function returns a dict
, it should contains an entry for all outputs of the action, with a valid value.
If the function returns a list
of dict
, the dict
s should contains an entry for all outputs of the action, with a valid value.
If the list does not have any element, it means that the workflow will end here. You can use this feature to create filters, that stops the execution of the workflow under specific conditions.
If the list has more than one element, it means that the following actions in the workflow will execute each element independently. For example, this feature can be used to analyze an image faster by spliting the input image into several smaller images.
Triggers¶
ryax_run.py
is the file to write your python code for a source.
This script must contain a run
function that takes 2 paramaters:
a dict
containing the inputs and
an instance of the RyaxSourceProtocol
class.
import asyncio
from ryax_wrapper import RyaxSourceProtocol #optional import
async def run(service: RyaxSourceProtocol, input_values: dict) -> None:
while True:
text = source.inputs_values["input1"]
source.create_run({"output1": "hello "+text})
await asyncio.sleep(1)
In this particular case, we are creating an execution every second.
We can guess that this action has 1 input called input1
and 1 output called output1
.
Ryax should know about these by describing them in the ryax_metadata.yaml
file.
Here is the interface of RyaxSourceProtocol
:
class RyaxRunStatus(Enum):
DONE = 1
ERROR = 2
class RyaxSourceProtocol(metaclass=abc.ABCMeta):
async def create_run_error(self) -> None:
await self.create_run({}, status=RyaxRunStatus.ERROR)
@abc.abstractmethod
async def create_run(
self,
data: dict,
running_time: float = 0.001,
status: RyaxRunStatus = RyaxRunStatus.DONE,
) -> None:
...
def get_output_definitions(self) -> Dict[str, Any]:
...
Migrating from v1 to v2.0¶
Most of the specifications stay the same, except the following.
ryax_metadata.yaml
changes:
apiVersion: "ryax.tech/v2.0"
kind
changes:Gateways
is nowSource
,Functions
is nowProcessor
,Publishers
is nowPublisher
spec.detail
becomesspec.description
The requirements.txt
is now completly standard.
handler.py
has to be renamed ryax_handler.py
.
run.py
has to be renamed ryax_run.py
.
Also, the content has to be changed, we do not use a class anymore.
You have to use a run
function has explained in the documentation above.
If the ryax_metadata.yaml
file contains unknown fields, an error is thrown.