Skip to content

Python script ​

Runs your own Python code (CPython embedded through pythonnet) for every message that reaches the component. Use it for transformations or when you need Python packages installed on the host.

Pins ​

PinKindTypesDescription
InputinputanyThe data from the previous component. Its type is the type of the input connection.
OutputoutputanyWhatever the script passes to services.Next. The template creates an object of the output connection's type.

Configuration ​

FieldTypeDefaultDescription
Scriptcode (Python)emptyThe user script: a function execute(metaData, inputData) plus any imports, functions and classes you need. Empty means the generated template is used.

Behaviour ​

  • Before your code the component generates a Python class for every type of the flow (same class and property names as in the flow, e.g. inputData.Name), the classes FlowMetaData, NoInputData, AnyInputData and ViaFileInfo, and the global services. base64, datetime, uuid and the viaducta package are already imported. This part is hidden in the editor; your code starts with the #viaducta.python.code marker, and the line numbers of errors and of the debugger are the lines of your script.

  • The script is executed once when the flow starts (module-level code runs then); for every message the component calls execute(metaData, inputData), where inputData already is an instance of the input connection's class (NoInputData when nothing is connected). Module-level variables keep their values between messages. Messages are processed one at a time per component.

  • The generated template:

    python
    def execute(metaData: FlowMetaData, inputData: Customer):
        outputData = CustomerDto()
        services.Next(metaData, outputData)

    CustomerDto is the output connection's type; without an output connection the template calls services.Next(metaData, inputData).

  • services is the component's flow service (IFlowService) with the C# member names, the same services a C# script has: services.Log, services.Messaging, services.Settings, services.Component, services.Flow, services.Profiler, services.Batches, services.Storage, services.Repository and the rest. The viaducta package (see Notes) gives the editor their types.

  • services.Next(metaData, obj) sends obj to the components connected to Output; obj must be an instance of one of the generated flow classes. It can be called zero, one or many times. services.Next(metaData, obj, connectionId) sends to one connection only. The next components run on a separate task, so Next returns before they finish.

  • Frequently used services:

    • services.Log.Information("...") (also Debug, Warning, Error, Fatal) writes to the flow log.
    • services.Messaging.Information("...") (also Warning, Error, Trace) writes to the designer console; UpdateStatusMessage("..."), UpdateProgress(0.5) (0 to 1), StopProgress() and Clear() update the component.
    • services.Settings.Get("Package", "Name") reads an expression setting.
    • services.Component.Id / .Name; services.Profiler.UpdateRecordsProduced(services.Component.Id, 1).
    • services.Batches.Begin(metaData, "label") opens a batch: with services.Batches.Begin(metaData, fileName) as batch: send the records with batch.MetaData and call batch.Complete(); leaving the block without Complete() fails the batch.
    • services.HandleExceptionAsync(metaData, inputData, ex) hands a caught exception to the flow's error handling and carries on.
  • List properties are ViaProxyArray objects: index, len(), in, iteration, append, extend, assignment by index and del are written through to the .NET list. Date properties are returned as datetime.datetime. Decimal properties are returned as float and accept float, int and decimal.Decimal (a Decimal keeps its full precision).

  • Leading tabs are converted to 4 spaces before execution; don't mix tabs and spaces differently inside a block.

  • An exception that leaves execute goes to the flow's error handling as PythonScriptException: the message is ValueError: ..., the stack trace is the Python traceback from your code on, and the error line is marked in the editor.

  • In debug mode the script is traced line by line while execute runs: the debugger stops before a line runs and shows its local variables (flow objects and other .NET objects as .NET objects, Python values as a dump of at most 1000 values). Module-level code is not traced.

Notes ​

  • Editor support: the viaducta package (viaducta-<version>-py3-none-any.whl, built with the Viaducta.Python project) contains type stubs for services and everything it returns. Install it into the Python of your editor (pip install viaducta-...whl) for completion and type checking outside the designer. The host doesn't need it: the component brings its own copy and puts it first on sys.path.
  • print output goes to the host's stdout, not to the designer; use services.Messaging.Information or services.Log.
  • The Python configured as Python.RuntimeDll (default python312.dll, 3.11 or newer) must be available on the host; extra packages must be installed into that Python.
  • The Python engine is shared by the whole host process: it starts once and stays up until the process ends, stopping a component only releases its own module.
  • The template is generated from the connections that exist when it is created; connect first, then open the editor (or clear the script).

Example ​

Input connection type Customer, output connection type CustomerDto:

python
#viaducta.python.code
import re

def execute(metaData: FlowMetaData, inputData: Customer):
    if not inputData.Email:
        return  # filter: nothing is sent on
    outputData = CustomerDto()
    outputData.Name = inputData.Name.title()
    outputData.Phone = re.sub(r"\D", "", inputData.Phone or "")
    services.Messaging.UpdateStatusMessage("Last: " + inputData.Email)
    services.Next(metaData, outputData)

Database reader → Python script → Json serializer → File writer

Viaducta documentation