Creating tasks

This guide explains how to create tasks that can be orchestrated by purjo using either traditional Robot Framework keyword libraries or a more advanced pure Python approach.

Basic task (Robot Framework)

The most common way to define tasks in purjo is by using Robot Framework keyword libraries. This involves creating a Python file with your custom keywords and a .robot file to define the task suite.

Example: The “Hello” task

Here is a basic illustration.

Hello.py (Keyword library)

from robot.api.deco import keyword
from robot.api.deco import library


@library()
class Hello:
    @keyword()
    def hello(self, name: str) -> str:
        return f"Hello {name}!"

This Python file defines a simple Robot Framework library named Hello with one keyword: hello. This keyword takes a name and returns a greeting string.

hello.robot (Task suite)

*** Settings ***
Library    Hello

*** Tasks ***
My Task in Robot
    ${greeting}=    Hello    World
    Log To Console    ${greeting}

The hello.robot file imports the Hello library and defines a task named “My Task in Robot”. This task calls the hello keyword, passes “World” as the name, and logs the returned greeting to the console.

hello.bpmn (BPMN process)

Your BPMN process would then include an external service task that references this Robot Framework task. For instance, a service task with Topic “My Topic in BPMN” might be configured to execute “My Task in Robot” from hello.robot.

Configuration

To map the BPMN topic to the Robot Framework task, you need to configure pyproject.toml.

[tool.purjo.topics."My Topic in BPMN"]
name = "My Task in Robot"
on-fail = "ERROR"
process-variables = true
pythonpath = ["./libs", "./modules"]
  • [tool.purjo.topics."<Topic Name>"]: Defines the configuration for a specific BPMN topic.

  • name: The name of the Robot Framework task (or Python function) to execute.

  • on-fail: Determines the behavior when the task fails (e.g., “ERROR”, “FAIL”). See Variables of a failed task for what a failed task leaves behind.

  • process-variables: If true, process variables are passed to the task. If false, only task scope variables are passed to the task.

  • pythonpath: (Optional) A list of additional paths to add to Robot Framework’s --pythonpath. This allows importing custom libraries and modules from specified directories.

Advanced task (Pure Python)

purjo also supports defining tasks directly in Python, allowing for more complex logic and direct integration with Python’s type hinting and data validation features like Pydantic. This approach can replace the need for a separate .robot file for simple tasks.

Example: A pure Python task

This approach is demonstrated below.

tasks.py (Pure Python task)

from pydantic import BaseModel
from robot.api import logger
from robot.libraries import BuiltIn
from typing import Literal
import json


VariableScope = Literal["BPMN:TASK", "BPMN:PROCESS"]


class InputVariables(BaseModel):
    name: str = "John Doe"


class OutputVariables(BaseModel):
    message: str


def get_variables() -> InputVariables:
    library = BuiltIn.BuiltIn()
    return InputVariables(**library.get_variables(no_decoration=True))


def set_variables(
    variables: OutputVariables, scope: VariableScope = "BPMN:PROCESS"
) -> None:
    library = BuiltIn.BuiltIn()
    try:
        if scope == "BPMN:TASK":
            for name, value in variables.model_dump().items():
{% raw %}
                library._variables.set_bpmn_task(f"${{{name}}}", value)
        else:
            for name, value in variables.model_dump().items():
                library._variables.set_bpmn_process(f"${{{name}}}", value)
{% endraw %}
    except AssertionError:
        logger.info(json.dumps(variables.model_dump(), indent=2))


def main():
    variables = get_variables()
    set_variables(OutputVariables(message=f"Hello, {variables.name}!"))


if __name__ == "__main__":
    from purjo import PythonParser
    from robot import run

    run(__file__, parser=PythonParser("tasks.main"))

Key features:

  • Pydantic Models (InputVariables, OutputVariables): These models enforce strict typing and validation for variables exchanged with the BPMN engine, making your task more robust.

  • get_variables() and set_variables(): Helper functions to easily retrieve input variables from the BPMN process and set output variables back to it.

  • main() Function: Encapsulates the core logic of your task. It retrieves variables, performs operations, and sets new variables.

  • if __name__ == "__main__": Block: This block enables the Python script to be executed directly as a Robot Framework task using purjo’s PythonParser. This means you can specify tasks.main as the Robot Framework task to be executed by your BPMN process, without needing a separate .robot file.

This advanced approach is particularly useful for tasks that are primarily Python-based, requiring minimal or no Robot Framework specific syntax beyond what purjo provides for variable handling.

Configuration

To map the BPMN topic to the Pure Python task, you need to configure pyproject.toml.

[tool.purjo.topics."My Topic in BPMN"]
name = "tasks.main"
on-fail = "FAIL"
process-variables = true
  • name: The name of the Python function to execute, in the format module.function. In this example, tasks.main refers to the main function in tasks.py.

Adding dependencies

When your tasks require external Python libraries (e.g., requests, pandas, PyPDF2), you need to add them to your project’s dependencies. purjo uses uv for dependency management.

To add a dependency, use the uv add command:

$ uv add requests

This command updates your pyproject.toml file and the uv.lock file, ensuring that the dependency is available when your tasks are executed.

Packaging

Once your tasks are ready, you can package them into a robot.zip file using the pur wrap command.

$ pur wrap

This command creates a robot.zip file containing your project files, excluding those specified in .wrapignore (and default exclusions like .git, __pycache__, etc.). This zip file can be deployed to an external worker or used for distribution.

Creating BPMN resources

purjo provides a convenient way to create new BPMN, DMN, and Form files using the pur operaton create command.

$ pur operaton create my-process.bpmn
$ pur operaton create my-decision.dmn
$ pur operaton create my-form.form

This generates template files with unique IDs, ready for editing in any bpmn.io-compatible modeler.