Skip to content

Custom Python per field

The python field type runs a small Python snippet per row and uses the return value as the field’s value. Use it when none of the built-in types fit — think industry-specific identifiers, inter-field arithmetic, or values pulled from a workspace file.

Quick example

A field that returns an “internal customer ID” combining a fixed prefix, a country code from a sibling field, and a 6-digit sequential number:

def value(rng, row, dm):
seq = dm.counter("customer_seq").next() # workspace-wide counter
country = row["country"] # already-generated sibling
return f"CUST-{country}-{seq:06d}"

In the field editor, pick Type → Python, paste the code, and the live preview runs it.

The function signature

def value(rng, row, dm):
...
return <some value>
ParameterWhat it is
rngA seeded random.Random instance. Use this for reproducibility.
rowA dict of all fields generated before this one in the template.
dmDataMaker context: dm.counter(), dm.workspace_file(), dm.template().

The return value is serialised as JSON — strings, numbers, booleans, lists, dicts, None, and ISO-formatted dates all work.

Field order matters

row only contains fields generated before this one. In the template builder, drag the Python field below any siblings it reads.

If you need to read a field that comes later, use a derived field instead — derived fields run in a second pass.

What dm exposes

dm.counter(name)

A workspace-wide monotonic counter. Useful for sequential IDs that survive across generations.

dm.counter("orders").next() # 1, 2, 3, ...
dm.counter("orders").peek() # current without incrementing
dm.counter("orders").reset() # back to 1 (rare; usually only in scenarios)

dm.workspace_file(path)

Read a file uploaded to the workspace. Useful for pulling from a CSV reference table.

import csv
def value(rng, row, dm):
with dm.workspace_file("currency_rates.csv").open("r") as f:
rates = {r["code"]: float(r["rate"]) for r in csv.DictReader(f)}
return round(row["amount_usd"] * rates[row["currency"]], 2)

Workspace files are project-scoped — see Scenarios → Workspace files for upload mechanics.

dm.template(name_or_id)

Generate one row from another template, inline. Useful when the simple nested-template field can’t express what you need.

def value(rng, row, dm):
if row["country"] in ("DE", "AT", "CH"):
return dm.template("Address (DACH)").generate_one()
return dm.template("Address (Generic)").generate_one()

Limits

  • Max execution time per call: 2 seconds. Longer-running logic belongs in a scenario, not a per-field Python.
  • Standard library only. No pip install from inside a field. If you need third-party packages, use a scenario.
  • Stateless across rows except via dm.counter(). Don’t use module-level globals.

When to reach for a scenario instead

If your field logic needs:

  • A network call (REST or SAP),
  • Multi-row coordination (referential integrity),
  • A third-party Python package,
  • More than 2s of compute,

use a scenario. Scenarios run in a fuller Python environment, support pip packages, and have proper logs and retries.