---
id: scripting-python
title: "Python script"
summary: "Write a step in Python. The execute function, module state, flow classes, services with the C# member names, pip packages, the viaducta package for your IDE, and debugging."
audience: user
keywords: "python, script, execute, services, pip, viaducta package, wheel, stubs, CPython, debugging"
---
# Python script

The **Python script** component runs your Python code for every record that reaches it. The host embeds CPython
(3.11 or newer, 3.12 by default), so you use the Python language and the packages you know.

## What you write

Connect the input and output first, then open the editor. The template is generated from the connections:

```python
def execute(metaData: FlowMetaData, inputData: Customer):
    outputData = CustomerDto()
    services.Next(metaData, outputData)
```

`Customer` is the type of the input connection and `CustomerDto` the type of the output connection. Every type of the
flow is a Python class with the same property names (`inputData.Email`). `base64`, `datetime`, `uuid` and the
`viaducta` package are already imported.

## How it runs

- The script runs once when the flow starts. Module-level code runs then, and module-level variables keep their values
  between records.
- For every record the component calls `execute(metaData, inputData)`.
- Each component handles one record at a time, so module state needs no locks.

## Sending records on

`services.Next(metaData, obj)` sends a record to the components connected to `Output`. Call it once, several times or
not at all. `obj` is an instance of a flow class: `CustomerDto()`.

## Values

| Flow type | In Python |
|---|---|
| List | A list-like object: index, `len()`, `in`, iteration, `append`, `extend`, `del` |
| Date | `datetime.datetime` |
| Decimal | `float`; assign a `decimal.Decimal` to keep full precision |

## Flow services

`services` has the same members as `Services` in C#, with the same names. See [Flow services](./services).

```python
api_url = services.Settings.Get("Crm", "ApiUrl")
services.Log.Information("Calling " + api_url)
services.Messaging.UpdateStatusMessage("Last: " + inputData.Email)
```

`print` writes to the host's console. Use `services.Log` or `services.Messaging` to see output in Viaducta.

## Packages

Add pip packages in the flow properties: **References** → **Add** → **Python package (pip)**. They are installed into
the host's Python.

## Your own editor

The designer's Python editor highlights syntax. For completion and type checking, install the `viaducta` package into
the Python of your IDE:

```bash
pip install viaducta-<version>-py3-none-any.whl
```

It has type information for `services` and everything it returns. The host doesn't need it.

## Debugger

Start the flow with **Debug** (Ctrl+F5) and set breakpoints in the editor margin. The debugger stops before a line of
`execute` runs and shows its local variables. Step with F10, continue with F5.

## Errors

An exception that leaves `execute` goes to the flow's error handling, with your script's traceback and the error line
marked in the editor. To report an error and carry on, catch it and call
`services.HandleExceptionAsync(metaData, inputData, ex)`.

## Example

```python
import re

def execute(metaData: FlowMetaData, inputData: Customer):
    if not inputData.Email:
        return  # filtered out
    outputData = CustomerDto()
    outputData.Name = inputData.Name.title()
    outputData.Phone = re.sub(r"\D", "", inputData.Phone or "")
    services.Next(metaData, outputData)
```
