|
| 1 | +# Callable Script |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | + |
| 8 | +=== "Hera" |
| 9 | + |
| 10 | + ```python linenums="1" |
| 11 | + from typing import List |
| 12 | + |
| 13 | + from pydantic import BaseModel |
| 14 | + |
| 15 | + from hera.shared import global_config |
| 16 | + from hera.workflows import Script, Steps, Workflow, script |
| 17 | + |
| 18 | + # Note, setting constructor to runner is only possible if the source code is available |
| 19 | + # along with dependencies include hera in the image. |
| 20 | + # Callable is a robust mode that allows you to run any python function |
| 21 | + # and is compatible with pydantic. It automatically parses the input |
| 22 | + # and serializes the output. |
| 23 | + global_config.image = "my-image-with-python-source-code-and-dependencies" |
| 24 | + global_config.set_class_defaults(Script, constructor="runner") |
| 25 | + # Runner script constructor is still and experimental feature and we need to explicitly opt in to it |
| 26 | + # Note that experimental features are subject to breaking changes in future releases of the same major version |
| 27 | + global_config.experimental_features["script_runner"] = True |
| 28 | + |
| 29 | + |
| 30 | + # An optional pydantic input type |
| 31 | + # hera can automatically de-serialize argo |
| 32 | + # arguments into types denoted by your function's signature |
| 33 | + # as long as they are de-serializable by pydantic |
| 34 | + # This provides auto-magic input parsing with validation |
| 35 | + # provided by pydantic. |
| 36 | + class Input(BaseModel): |
| 37 | + a: int |
| 38 | + b: str = "foo" |
| 39 | + |
| 40 | + |
| 41 | + # An optional pydantic output type |
| 42 | + # hera can automatically serialize the output |
| 43 | + # of your function into a json string |
| 44 | + # as long as they are serializable by pydantic or json serializable |
| 45 | + # This provides auto-magic output serialization with validation |
| 46 | + # provided by pydantic. |
| 47 | + class Output(BaseModel): |
| 48 | + output: List[Input] |
| 49 | + |
| 50 | + |
| 51 | + @script() |
| 52 | + def my_function(input: Input) -> Output: |
| 53 | + return Output(output=[input]) |
| 54 | + |
| 55 | + |
| 56 | + # Note that the input type is a list of Input |
| 57 | + # hera can also automatically de-serialize |
| 58 | + # composite types like lists and dicts |
| 59 | + @script() |
| 60 | + def another_function(inputs: List[Input]) -> Output: |
| 61 | + return Output(output=inputs) |
| 62 | + |
| 63 | + |
| 64 | + # it also works with raw json strings |
| 65 | + # but those must be explicitly marked as |
| 66 | + # a string type |
| 67 | + @script() |
| 68 | + def str_function(input: str) -> Output: |
| 69 | + # Example function to ensure we are not json parsing |
| 70 | + # string types before passing it to the function |
| 71 | + return Output(output=[Input.parse_raw(input)]) |
| 72 | + |
| 73 | + |
| 74 | + with Workflow(name="my-workflow") as w: |
| 75 | + with Steps(name="my-steps") as s: |
| 76 | + my_function(arguments={"input": Input(a=2, b="bar")}) |
| 77 | + str_function(arguments={"input": Input(a=2, b="bar").json()}) |
| 78 | + another_function(arguments={"inputs": [Input(a=2, b="bar"), Input(a=2, b="bar")]}) |
| 79 | + ``` |
| 80 | + |
| 81 | +=== "YAML" |
| 82 | + |
| 83 | + ```yaml linenums="1" |
| 84 | + apiVersion: argoproj.io/v1alpha1 |
| 85 | + kind: Workflow |
| 86 | + metadata: |
| 87 | + name: my-workflow |
| 88 | + spec: |
| 89 | + templates: |
| 90 | + - name: my-steps |
| 91 | + steps: |
| 92 | + - - arguments: |
| 93 | + parameters: |
| 94 | + - name: input |
| 95 | + value: '{"a": 2, "b": "bar"}' |
| 96 | + name: my-function |
| 97 | + template: my-function |
| 98 | + - - arguments: |
| 99 | + parameters: |
| 100 | + - name: input |
| 101 | + value: '{"a": 2, "b": "bar"}' |
| 102 | + name: str-function |
| 103 | + template: str-function |
| 104 | + - - arguments: |
| 105 | + parameters: |
| 106 | + - name: inputs |
| 107 | + value: '[{"a": 2, "b": "bar"}, {"a": 2, "b": "bar"}]' |
| 108 | + name: another-function |
| 109 | + template: another-function |
| 110 | + - inputs: |
| 111 | + parameters: |
| 112 | + - name: input |
| 113 | + name: my-function |
| 114 | + script: |
| 115 | + args: |
| 116 | + - -m |
| 117 | + - hera.workflows.runner |
| 118 | + - -e |
| 119 | + - examples.workflows.callable_script:my_function |
| 120 | + command: |
| 121 | + - python |
| 122 | + image: my-image-with-python-source-code-and-dependencies |
| 123 | + source: '{{inputs.parameters}}' |
| 124 | + - inputs: |
| 125 | + parameters: |
| 126 | + - name: input |
| 127 | + name: str-function |
| 128 | + script: |
| 129 | + args: |
| 130 | + - -m |
| 131 | + - hera.workflows.runner |
| 132 | + - -e |
| 133 | + - examples.workflows.callable_script:str_function |
| 134 | + command: |
| 135 | + - python |
| 136 | + image: my-image-with-python-source-code-and-dependencies |
| 137 | + source: '{{inputs.parameters}}' |
| 138 | + - inputs: |
| 139 | + parameters: |
| 140 | + - name: inputs |
| 141 | + name: another-function |
| 142 | + script: |
| 143 | + args: |
| 144 | + - -m |
| 145 | + - hera.workflows.runner |
| 146 | + - -e |
| 147 | + - examples.workflows.callable_script:another_function |
| 148 | + command: |
| 149 | + - python |
| 150 | + image: my-image-with-python-source-code-and-dependencies |
| 151 | + source: '{{inputs.parameters}}' |
| 152 | + ``` |
| 153 | + |
0 commit comments