Python
The python runtime allows you to run generic python function within the platform.
The runtime introduces a function of kind python and three task of kind job, serve and build.
Prerequisites
Python version and libraries:
python >= 3.9digitalhub-runtime-python
The package is available on PyPI:
python -m pip install digitalhub-runtime-python
HOW TO
With the python runtime you can use the function's run() method to execute a python function you have defined.
The python runtime execution workflow follows roughly these steps:
- Define somewhere a python function.
- Create a
Functionobject in the platform and execute the function'srun()method. - The runtime collects the inputs specified in the function as SDK objects (
Dataitem,Artifact,Model). - It fetches the function source code and import the function handler.
- It composes the parameters for the handler function.
- It executes the function and map the outputs as SDK objects or as simple results.
Python function definition
You can declare a generic python function as usual with the def keyword.
There are some restriction that must be applied when defining the function:
- The argument
projectis reserved. The runtime overrides the function parameters and assign to theprojectargument aProjectobject, used as SDK context. With theProjectobject you can manipulate entities likeArtifact,Dataitem, etc. If you provide aprojectargument into the function and use it as a nonProjectobject, you will probably get an error. If you define theprojectargument into your functions signature, you can use theprojectvariable asProjectobject. - The arguments
contextandeventsare reserved in remote execution. These arguments are reserved fornucliocontextandeventsfunction parameters. If you define these arguments into your functions signature, you can use thecontextandeventsvariables asnucliocontextandeventsobjects. - If some arguments of the function refer to some SDK objects, they must be mapped inside the run's
inputsparameter. Other arguments of the function can be mapped inside the run'sparameterparameter. More on that on the Parameters composition section. - You may or may not decorate your function with the
@handlerdecorator you can import from thedigitalhub_runtime_pythonpackage. If you decorate your function and return something, you need to map the outputs in the decorator and in the run'soutputsparameter. More on that on the Parameters composition section.
Function definition example
from digitalhub_runtime_python import handler
# 1. Simple function that returns a string
def func1():
return "hello world"
# 2. Decorated function that returns a string
# If you decorate your function and return something, you need to map the outputs
# in the decorator and in the run's `outputs` parameter
@handler(outputs=["result"])
def func2():
return "hello world"
# 3. Function with project argument
def func3(project):
# allowed use of project variable
project.log_artifact(name="example",
kind="artifact",
source_path="/path/to/file")
# not allowed use of project variable
project.some_method_not_from_sdk() # Probably there will be an error
# 4. Function with context and events arguments
def func4(context, events):
# allowed use of context and events variables in remote execution
context.logger.info("Some log")
# 5. Function with mixed input arguments
def func5(di: Dataitem, param1: str):
# di refers to a Dataitem object, so it must be mapped
# into runs inputs paramaters
# param1 is a string, it must be mapped into runs input parameters
Parameters composition
Inputs
To properly pass the parameters you need to your function, you must map them in the function.run() method.
Ther are some rules you need to follow:
- If you expect one of your arguments to be a
Dataitem/Artifact/Modelobject, you need to explicit the reference to the object into the run'sinputsparameter using the argument name as key and the object key as value.
# Define your function and declare di argument as Dataitem
def func(di: Dataitem):
# do something with di
# Create a dataitem
sdk_dataitem = sdk.new_dataitem(...)
# Reference the di argument as key and the dataitem key as value
sdk_function.run(inputs={"di": sdk_dataitem.key})
- Other function arguments must be mapped inside the run's
parameterparameter.
# Define your function and declare di argument as Dataitem
def func(di: Dataitem, param1: str):
# do something with di
# Create a dataitem
sdk_dataitem = sdk.new_dataitem(...)
# Reference the di argument as key and the dataitem key as value
sdk_function.run(inputs={"di": sdk_dataitem.key},
parameter={"param1": "some value"})
Outputs
The outputs of the function must be mapped inside the run's outputs parameter if you return something and you decorate your function.
from digitalhub_runtime_python import handler
@handler(outputs=["result", "other_result"])
def func(di: Dataitem, param1: str):
# do something with di
return "some value", "some other value"
sdk_function.run(inputs={"di": sdk_dataitem.key},
parameter={"param1": "some value"},
outputs={"result": "named_result",
"other_result": "named_other_result"})
Function
The python runtime introduces a function of kind python.
Function parameters
| Name | Type | Description | Default |
|---|---|---|---|
| project | str | Project name | required (if creating from library) |
| name | str | Name that identifies the object | required |
| kind | str | Kind of the object | required (must be python) |
| uuid | str | ID of the object in form of UUID | None |
| description | str | Description of the object | None |
| git_source | str | Remote git source for object | None |
| labels | list[str] | List of labels | None |
| embedded | bool | Flag to determine if object must be embedded in project | True |
| code_src | str | URI pointer to source code | None |
| code | str | Source code (plain text) | None |
| base64 | str | Source code (base64 encoded) | None |
| handler | str | Function entrypoint | None |
| lang | str | Source code language (hint) | None |
| init_function | str | Init function for remote nuclio execution | None |
| python_version | str | Python version to use, must be one of: PYTHON3_9PYTHON3_10PYTHON3_11 |
None |
| image | str | Image where the function will be executed | None |
| base_image | str | Base image used to build the image where the function will be executed | None (required when using build task) |
| requirements | list | Requirements list to be installed in the image where the function will be executed | None |
Source
Source code can be specified with code_src as an URI. It can have three different type of schema:
| schema | value | description |
|---|---|---|
| None | "path/to/file.ext" | Local file path |
| git+https | "git+https://github.com/some-user/some-repo" | Remote git repository |
| zip+s3 | "zip+s3://some-bucket/some-key.zip" | Remote zip s3 archive |
Function example
import digitalhub_core as dh
# From project ...
function = project.new_function(name="python-function",
kind="python",
code_src="main.py",
handler="function",
python_version="PYTHON3_9")
# .. or from sdk
function = dh.new_function(project="my-project",
name="python-function",
kind="python",
code_src="main.py",
handler="function",
python_version="PYTHON3_9")
Task
The python runtime introduces three tasks of kind job, serve and build that allows you to run a python function execution, serving a function as a service or build a docker image where the function is executed.
A Task is created with the run() method, so it's not managed directly by the user. The parameters for the task creation are passed directly to the run() method, and may vary depending on the kind of task.
Task parameters
| Name | Type | Description | Default | Kind specific |
|---|---|---|---|---|
| action | str | Task action. Must be one of: jobservebuild |
required | |
| node_selector | list[dict] | Node selector | None | |
| volumes | list[dict] | List of volumes | None | |
| resources | dict | Resources restrictions | None | |
| affinity | dict | Affinity | None | |
| tolerations | list[dict] | Tolerations | None | |
| envs | list[dict] | Env variables | None | |
| secrets | list[str] | List of secret names | None | |
| backoff_limit | int | Backoff limit | None | job |
| instructions | list[str] | Build instructions to be executed as RUN instructions in Dockerfile. Example: apt install git -y |
None | build |
| replicas | int | Number of replicas | None | serve |
| service_type | str | Service type. Must be one of: ClusterIPLoadBalancerNodePort |
NodePort |
serve |
Task example
run = function.run(
action="job",
backoff_limit=1,
)
Run
The Run object is, similar to the Task, created with the run() method.
The run's parameters are passed alongside the task's ones.
Run parameters
| Name | Type | Description | Default |
|---|---|---|---|
| loacal_execution | bool | Flag to indicate if the run will be executed locally | False |
| inputs | dict | Input entity key. | None |
| outputs | dict | Outputs mapped. | None |
| parameters | dict | Extra parameters for a function. | None |
Run example
run = function.run(
action="job",
inputs={
"dataitem": dataitem.key
},
outputs={
"dataitem": "mapped-name",
"label": "some-label"
}
)