Workflow Model

The workflow model is the typed counterpart for a workflow’s input variables — conceptually analogous to the ECM model for DMS objects, but a dedicated lightweight implementation (no DMS query / system behaviour).

A model class is built at runtime from the workflow definition (workflow_model_by_name()) or generated as a .py file (ecm-generate-workflow-models). An instance holds the set variable values and serialises itself into the DataFields format the server expects when starting.

The workflow model is optional — a convenience layer for typed, discoverable access. A process can be started without any model: start_process() also accepts variables as a plain Mapping[str, str] (or no variables at all). Example:

ecm.workflow.start_process(
    user=user, workflow="test", client_type="#OSECM_Client#",
    variables={"StringVar": "Hello"},   # plain mapping, no model needed
)

For non-string variables (numbers, dates, lists, records) without a model, see RawWorkflowVariable in start_process().

1. Model classes

ECMWorkflowModel

Base class of a generated workflow model. Input variables are typed attributes; an instance is created with them as keyword arguments.

ECMWorkflowRecordModel

Base class for a nested record model. Record variables map to their own fully typed subclasses (recursively, including record-in-record and lists of records).

from ecmind_blue_client.ecm import ECM

ecm = ECM(client)
user = ecm.workflow.organisation_user_by_login("admin")

Model = ecm.workflow.workflow_model_by_name("test", user, "#OSECM_Client#")

record = Model.record_model("TestRecordVar")(
    StringField="x", IntegerField=1, StringListField=["a"],
)
instance = Model(StringVar="Hello", IntegerVar=42, TestRecordVar=record)

By default only the input (INOUT) variables are exposed. include_internal=True (on workflow_model_by_name / make_workflow_model) also exposes internal fields.

2. Type mapping

Each variable maps to a native Python type:

Server type Python type

STRING

str

INTEGER_SAFE

int

FLOAT_SAFE

float

DATE_SAFE

date

DATETIME_SAFE

datetime

TIME_SAFE

time

ListType

list[…]

RecordType

typed ECMWorkflowRecordModel nested class

The _SAFE suffix is an enaio variant tag and is mapped to the base type. Unknown base types fall back to str.

3. Using instances

Model(**values)

Creates an instance with the input variables as keyword arguments. Unknown names raise TypeError.

Attribute access

Values are read and set as attributes (instance.StringVar = "x"). Only declared input variables are settable.

Model.record_model("<name>")

Returns the typed ECMWorkflowRecordModel class for a record variable, used to build record values.

instance.to_variables()

Serialises the set values into the start_process(variables=…) mapping. Unset variables are omitted. Called internally by start_process() when a model instance is passed.

Value formats verified against the enaio® server: scalars (including integer/float/date/time) are sent as <WFVar><String>VALUE</String></WFVar> — the server converts them. Datetime expects a Unix epoch timestamp. Lists render as <List><ListItem Id="…" Selection="0"><STRING>…</STRING></ListItem></List>, records as <Record><Member Name="…">…</Member></Record> (all members). The model encapsulates these details — they need not be built by hand.

4. Schema data model

The schema parsed internally by workflow_model_by_name() is also directly accessible (e.g. via Model.schema) and consists of frozen dataclasses:

ECMWorkflowVariableSchema
  • variables (tuple[ECMWorkflowVariable, …]) — all variables in document order

  • inputs() — only the start-input (INOUT) variables

ECMWorkflowVariable
  • name (str) — variable name (also the DataField id when starting)

  • type (ECMWorkflowVariableType) — scalar base type (placeholder STRING for records)

  • is_list (bool) — a list of its element type

  • is_record (bool) — the element type is a record

  • record_members (tuple[ECMWorkflowRecordMember, …]) — record members when is_record

  • is_input (bool) — start-input variable (INOUT)

ECMWorkflowRecordMember
  • name, type, is_list, is_record, record_members — as above; recursive

ECMWorkflowVariableType

Enum of the scalar base types: STRING, INTEGER, FLOAT, DATE, DATETIME, TIME (each with its corresponding Python type as the value).

5. Building models from a schema

make_workflow_model(schema, name="WorkflowModel", *, include_internal=False) creates an ECMWorkflowModel subclass at runtime from a parsed ECMWorkflowVariableSchema. workflow_model_by_name() is the usual entry point on top of it; make_workflow_model is useful when the schema is already available otherwise (e.g. from your own wfm.GetWorkflow XML via ECMWorkflowModelParser).

6. See also