# Python Processing (Custom Operator)

Write Python logic to transform upstream data into the structure needed by later nodes.

Use it for field transformations, text calculations, or other code-based processing. Create Python code through the custom operator entry. After publishing, it appears by its operator name in the custom node list.

## Create a Python operator

In the workflow editor's node panel, select **New Operator**, choose **Python Code** as the implementation, and set usage to **General Workflow**.

| Setting | Description |
| --- | --- |
| Name | Display name, such as Text Length Counter |
| Identifier | Letters, digits, and underscores; must not start with a digit, for example `text_counter` |
| Description | Explain the accepted input and returned result |
| Language | Python |
| Handler | Default: `main.handle`, corresponding to the `handle` function |
| Version | Operator version; creation form default: `v1` |
| Input schema | Field names, types, required fields, and descriptions |
| Output schema | Returned fields, types, required fields, and descriptions |
| Code | Python function matching the input and output definitions |

Describe each field to make bindings easier to understand. Publish the operator, then select it and its version from the custom node list.

## Write the handler

Ordinary workflows use this signature:

```python
def handle(workspace_id, sdk, input):
    return {"length": len(input["text"])}
```

- `workspace_id`: workspace where the code runs.
- `sdk`: Python SDK client provided by the runtime.
- `input`: input dictionary passed by the workflow.

Use `return` for a dictionary matching the output schema. Use `print` for logs. Values must be JSON-serializable, such as strings, numbers, lists, and objects.

## Bind inputs and outputs

Inputs are validated against the input schema before execution, and results against the output schema afterward. Missing fields, incorrect types, code exceptions, or unserializable output cause the node to fail.

If the input field is `text`, bind upstream parsed text to it. A file ID is a reference and is not automatically converted into file contents; parse the file first when text is needed.

Downstream nodes bind directly to returned fields. In this example, `length` provides the character count.

## Example: count text characters

1. Create Text Length Counter with identifier `text_counter` and handler `main.handle`.
2. Add a required string input `text`, described as the text to process.
3. Add a required integer output `length`, described as the character count.
4. Use the code above and publish the operator.
5. Add it to a workflow, bind upstream text, and inspect `length` in the run result.

For `{"text": "Hello MOI"}`, the function returns `{"length": 9}`. This is Python string length, not bytes or model tokens.

## Runtime requirements

The Python custom operator execution service must be enabled. If the node cannot be scheduled, ask an administrator to check the service.

Code runs on the server and uses its installed dependencies and accessible files. Server settings control network access and execution timeout.

## Related pages

- [Code processing](index.md)
- [SQL Processing](sql-processing.md)
- [Variables and data flow](../../variables-and-data.md)
- [Run and debug](../../run-debug.md)
