daitum-model

daitum_model — Model and formula generation for the Daitum platform.

A model consists of three main parts: the model definition, model configuration, and UI definition.

  • The model definition contains tables, named values (calculations and parameters), and fields. These elements either contain static data or can be dynamic, such as calculations and calculated fields. Calculated fields and named values use a custom modelling language which is loosely based on Microsoft Excel.

  • The model configuration specifies the optimisation parameters, such as decision variables, objectives, and constraints. It also sets up the algorithm configuration, data stores and data processors.

  • The UI definition specifies the user interface components and functionality that will be visible when the model is uploaded to the platform.

This package covers the model definition, and also provides all formula functions via daitum_model.formulas.

Usage:

from daitum_model import ModelBuilder, DataType, formulas

model = ModelBuilder()
table = model.add_data_table("Jobs", key_column="ID")
cost = table.add_data_field("Cost", DataType.DECIMAL)
is_valid = formulas.NOT(formulas.ISBLANK(cost))
class BaseDataType(*args, **kwargs)[source]

Structural protocol shared by every data type used in the model: DataType, ObjectDataType and MapDataType.

isinstance checks against this protocol are supported, but production code should generally prefer the concrete classes when behaviour differs.

is_array()[source]
Return type:

bool

to_array()[source]
Return type:

BaseDataType

from_array()[source]
Return type:

BaseDataType

class DataType(*values)[source]

Enumeration representing various data types.

This enumeration is used to specify different data types that can be used in calculations, parameters, or tables within a model.

INTEGER = 'INTEGER'

Integer data type.

DECIMAL = 'DECIMAL'

Decimal data type.

STRING = 'STRING'

String data type.

BOOLEAN = 'BOOLEAN'

Boolean data type.

DATE = 'DATE'

Date data type.

DATETIME = 'DATETIME'

Datetime data type.

TIME = 'TIME'

Time data type.

INTEGER_ARRAY = 'INTEGER_ARRAY'

Array of INTEGER data type.

DECIMAL_ARRAY = 'DECIMAL_ARRAY'

Array of DECIMAL data type.

STRING_ARRAY = 'STRING_ARRAY'

Array of STRING data type.

BOOLEAN_ARRAY = 'BOOLEAN_ARRAY'

Array of BOOLEAN data type.

DATE_ARRAY = 'DATE_ARRAY'

Array of DATE data type.

DATETIME_ARRAY = 'DATETIME_ARRAY'

Array of DATETIME data type.

TIME_ARRAY = 'TIME_ARRAY'

Array of TIME data type.

NULL = 'NULL'

Used to identify BLANK() formulae. Should never be used explicitly in models

is_array()[source]
Return type:

bool

to_array()[source]
Return type:

DataType

from_array()[source]
Return type:

DataType

class ObjectDataType(source_table, is_array=False)[source]

A composite data type used for references to other Tables.

__init__(source_table, is_array=False)[source]
Parameters:
  • source_table (_TableBase) – The table this data type references.

  • is_array (bool) – Whether this is an OBJECT_ARRAY type rather than a singular OBJECT.

is_array()[source]

Checks if the data type is an array.

Returns:

True if the data type is an array, otherwise False.

Return type:

bool

to_array()[source]

Converts an object type to an object array type.

Returns:

The array equivalent of the data type.

Return type:

ObjectDataType

Raises:

ValueError – If the data type is already an array.

from_array()[source]

Converts an object array type to a singular object type.

Returns:

The singular (non-array) equivalent of the data type.

Return type:

ObjectDataType

Raises:

ValueError – If the data type is not an array.

class MapDataType(data_type, source_table)[source]

A composite data type used to represent key-value maps into other Tables.

Raises:

TypeError – If the data type is an array type.

__init__(data_type, source_table)[source]
Parameters:
  • data_type (DataType) – The primitive value type stored in the map. Must not be an array type.

  • source_table (_TableBase) – The table whose rows act as keys for this map.

Raises:

TypeError – If data_type is an array variant.

property data_type: DataType

The primitive data type of the map values.

Returns:

The primitive data type.

Return type:

DataType

is_array()[source]

Always False. Used to simplify array checks without having to check if a data type is a MapDataType

Returns:

False

Return type:

bool

to_array()[source]

Always raises. Mirrors from_array() so callers can treat MapDataType uniformly with DataType and ObjectDataType without isinstance checks.

Raises:

ValueError – Always — map data types cannot be arrays.

Return type:

MapDataType

from_array()[source]

Always raises an error. Used to simplify array checks without having to check if a data type is a MapDataType.

Returns:

The singular (non-array) equivalent of the data type.

Return type:

MapDataType

Raises:

ValueError – Always, as map data types cannot be an array.

class SortDirection(*values)[source]

Enumeration representing the possible sorting options for a SortKey in a DerivedTable.

ASCENDING = 'ASCENDING'

Ascending sort direction.

DESCENDING = 'DESCENDING'

Descending sort direction.

class AggregationMethod(*values)[source]

Enumeration listing the possible aggregation methods for aggregated fields.

BLANK = 'BLANK'

Returns a typed null for the target field without aggregating values. Allowed DataTypes: any type. Return DataTypes: same as the allowed type.

COUNT = 'COUNT'

Counts the number of non-null input items and returns that count. Result type is INTEGER irrespective of the source item type. Allowed DataTypes: any type. Return DataTypes: INTEGER.

SUM = 'SUM'

Sums numeric inputs. For array targets, performs element-wise sum across arrays. Allowed DataTypes: INTEGER, DECIMAL, INTEGER_ARRAY, DECIMAL_ARRAY. Return DataTypes: same as the allowed type.

MIN = 'MIN'

Returns the minimum (by natural ordering) of the inputs. Allowed DataTypes: any comparable scalar type (INTEGER, DECIMAL, STRING, BOOLEAN, DATE, TIME, DATETIME) and other comparable values. Not intended for arrays. Return DataTypes: same as the allowed type.

MAX = 'MAX'

Returns the maximum (by natural ordering) of the inputs. Allowed DataTypes: any comparable scalar type (INTEGER, DECIMAL, STRING, BOOLEAN, DATE, TIME, DATETIME) and other comparable values. Not intended for arrays. Return DataTypes: same as the allowed type.

AVERAGE = 'AVERAGE'

Calculates the arithmetic mean of numeric inputs and returns a DECIMAL value. Allowed DataTypes: INTEGER, DECIMAL. Return DataTypes: DECIMAL.

FIRST = 'FIRST'

Returns the first input value encountered (typed), or null if none. Allowed DataTypes: any type. Return DataTypes: same as the allowed type.

LAST = 'LAST'

Returns the last input value encountered (typed), or null if none. Allowed DataTypes: any type. Return DataTypes: same as the allowed type.

EQUAL = 'EQUAL'

If all input values are equal, returns that value; otherwise returns typed null. Allowed DataTypes: any type. Return DataTypes: same as the allowed type.

AND = 'AND'

Logical AND over boolean inputs. Nulls are treated as false by booleanValue() conversion. Allowed DataTypes: BOOLEAN. Return DataTypes: same as the allowed type.

OR = 'OR'

Logical OR over boolean inputs. Nulls are treated as false by booleanValue() conversion. Allowed DataTypes: BOOLEAN. Return DataTypes: same as the allowed type.

ARRAY = 'ARRAY'

Collects input items into an array of the target element type, preserving order. Allowed DataTypes: any non-array types except MapDataType (e.g., INTEGER, DECIMAL, STRING, BOOLEAN, DATE, TIME, DATETIME, OBJECT) Return DataTypes: the corresponding array type of the allowed type. (e.g., INTEGER_ARRAY, DECIMAL_ARRAY, STRING_ARRAY, BOOLEAN_ARRAY, DATE_ARRAY, TIME_ARRAY, DATETIME_ARRAY, OBJECT_ARRAY)

REFERENCE = 'REFERENCE'

Creates an OBJECT_ARRAY of references from row ids provided by the evaluation engine. Allowed DataTypes: any type. Return DataTypes: OBJECT_ARRAY for a specific table.

INTERSECTION = 'INTERSECTION'

Computes the set intersection across array inputs and returns an array result. Allowed DataTypes: any scalar or array type. Return DataTypes: the array of the scalar type when scalar target is provided, or the same array type when the target is already an array.

UNION = 'UNION'

Computes the set union of inputs. If inputs are arrays, unions their elements; if inputs are scalars, unions individual values.. Allowed DataTypes: any scalar or array type. Return DataTypes: the array of the scalar type when scalar target is provided, or the same array type when the target is already an array.

class JoinType(*values)[source]

The type of join used by a JoinCondition to combine rows from two tables.

LEFT = 'LEFT'

Keep every row from the left table; attach matching right-table values where they exist, and leave the right-side cells blank otherwise.

Example — joining Orders (3 rows) to Customers (2 rows) on Orders.customer_id == Customers.id:

Orders               Customers
order_id  cust_id    cust_id  name
--------  -------    -------  -----
1         A          A        Alice
2         B          C        Carol
3         D

LEFT result (3 rows -- one per Orders row):
order_id  cust_id  name
--------  -------  -------
1         A        Alice
2         B        <blank>
3         D        <blank>
RIGHT = 'RIGHT'

Keep every row from the right table; attach matching left-table values where they exist, and leave the left-side cells blank otherwise. Mirror image of LEFT.

Same source tables as the LEFT example:

RIGHT result (2 rows -- one per Customers row):
order_id  cust_id  name
--------  -------  -----
1         A        Alice
<blank>   C        Carol
INNER = 'INNER'

Keep only rows where the join condition matches on both sides. Unmatched rows from either table are dropped.

Same source tables as the LEFT example:

INNER result (1 row -- only A matches on both sides):
order_id  cust_id  name
--------  -------  -----
1         A        Alice
FULL = 'FULL'

Keep every row from both tables. Where a row has no match on the other side, the missing cells are blank. Equivalent to a LEFT join unioned with a RIGHT join.

Same source tables as the LEFT example:

FULL result (4 rows -- 3 from Orders + 1 unmatched Customer):
order_id  cust_id  name
--------  -------  -------
1         A        Alice
2         B        <blank>
3         D        <blank>
<blank>   C        Carol
CROSS = 'CROSS'

Pair every row from the left table with every row from the right table (the Cartesian product). A CROSS join has no match fields: pass neither left_field nor right_field to the JoinCondition (supplying either raises ValueError).

Same source tables as the LEFT example:

CROSS result (6 rows -- 3 Orders x 2 Customers):
order_id  cust_id  name
--------  -------  -----
1         A        Alice
1         A        Carol
2         B        Alice
2         B        Carol
3         D        Alice
3         D        Carol
class Severity(*values)[source]

Enumeration of validation severity levels.

INFO = 'Info'
WARNING = 'Warning'
ERROR = 'Error'
CRITICAL = 'Critical'
class ModelBuilder[source]

Top-level entry point for building a Daitum model.

A model holds tables and named values (calculations and parameters). Build one incrementally with the add_* factory methods, then call write_to_file() to emit the JSON output.

__init__()[source]

Initialise an empty model with no tables, calculations, or parameters.

add_calculation(id, formula, model_level=False)[source]

Add a Calculation to the model.

Parameters:
  • id (str) – Unique identifier for the calculation. Must not collide with any existing calculation or parameter id.

  • formula (Operand | float | int | bool | str) – The expression. A Formula or any value accepted by CONST() (number, bool, or string), which is wrapped automatically.

  • model_level (bool) – If True, the calculation is evaluated once for the whole model. If False (the default) it is scenario-level.

Return type:

Calculation

Returns:

The newly added Calculation.

Raises:

ValueError – If a calculation or parameter with the same id already exists in the model.

add_parameter(id, data_type, value, model_level=False)[source]

Add a Parameter to the model.

Parameters:
  • id (str) – Unique identifier for the parameter.

  • data_type (BaseDataType) – Data type of the parameter — a DataType, ObjectDataType, or MapDataType.

  • value (Any) – Initial value. Must be compatible with data_type.

  • model_level (bool) – If True, the parameter is shared across all scenarios. If False (the default) it is scenario-level.

Return type:

Parameter

Returns:

The newly added Parameter.

add_tracking_group(name)[source]

Declare a change-tracking group.

Tag fields, parameters, and calculations with the returned group (via set_tracking_groups) to include them in baselines that capture it.

Parameters:

name (str) – Unique identifier for the tracking group.

Return type:

TrackingGroup

Returns:

The newly declared TrackingGroup.

Raises:

ValueError – If a tracking group with the same name already exists.

add_baseline(name, tracking_groups, auto_capture=AutoCapture.NONE)[source]

Declare a baseline — a named point in time that snapshots tracking groups.

Parameters:
  • name (str) – Unique identifier for the baseline.

  • tracking_groups (list[str | TrackingGroup]) – The tracking groups (or their names) this baseline captures.

  • auto_capture (AutoCapture) – Platform milestone that triggers an automatic capture, or NONE (the default) for manual capture only.

Return type:

Baseline

Returns:

The newly declared Baseline.

Raises:

ValueError – If a baseline with the same name already exists.

add_data_table(id)[source]

Add a DataTable to the model.

A data table holds raw imported rows and is the only table type that supports decision variables.

Parameters:

id (str) – Unique identifier for the table. Must not collide with any existing table id.

Return type:

DataTable

Returns:

The newly added DataTable. Use its add_data_field / add_calculated_field / set_key_column methods to populate it.

Raises:

ValueError – If a table with the same id already exists.

add_derived_table(id, source_table, group_by=None, filter_field=None)[source]

Add a DerivedTable to the model.

A derived table is a grouped, filtered, and/or sorted view of an existing source table.

Parameters:
  • id (str) – Unique identifier for the derived table.

  • source_table (Table) – The table whose rows the derived table draws from.

  • group_by (list[Field] | None) – Optional fields to group rows by. When supplied, non-group fields must be added with an AggregationMethod.

  • filter_field (Field | None) – Optional BOOLEAN field on source_table; only rows where it is True are kept.

Return type:

DerivedTable

Returns:

The newly added DerivedTable.

Raises:

ValueError – If a table with the same id already exists.

add_joined_table(id, join_conditions)[source]

Add a JoinedTable to the model.

A joined table is the result of joining two or more tables on a list of JoinCondition rows.

Parameters:
  • id (str) – Unique identifier for the joined table.

  • join_conditions (list[JoinCondition]) – One condition per joined table pairing. The JoinType of each condition controls how unmatched rows are handled. A CROSS condition pairs every left row with every right row and takes no match fields.

Return type:

JoinedTable

Returns:

The newly added JoinedTable.

Raises:

ValueError – If a table with the same id already exists.

add_union_table(id, source_tables)[source]

Add a UnionTable to the model.

A union table stacks rows from multiple source tables. Pass a UnionSource instead of a bare Table when the source schema does not line up with the union table’s fields.

Parameters:
  • id (str) – Unique identifier for the union table.

  • source_tables (list[Table | UnionSource]) – The tables (or wrapped UnionSource instances) whose rows are stacked.

Return type:

UnionTable

Returns:

The newly added UnionTable.

Raises:

ValueError – If a table with the same id already exists.

set_partial_evaluation_allowed(partial_evaluation_allowed=True)[source]

Toggle partial evaluation for this model.

When enabled (the default), the platform re-evaluates only the calculations affected by a change rather than the whole model, which speeds up UI rendering. Disable only if a model has dependencies that the partial evaluator cannot track correctly.

Parameters:

partial_evaluation_allowed (bool) – True to allow partial evaluation.

set_data_validation_rule(named_value)[source]

Gate optimisation on a boolean named value.

Optimisation is allowed only while named_value evaluates to True. When it is False and the UI definition specifies a validation screen, the user is redirected there on attempting to start optimisation.

Parameters:

named_value (Parameter | Calculation) – A Parameter or Calculation of type BOOLEAN.

Raises:

ValueError – If named_value is not of boolean data type.

get_tables()[source]

Return every table that has been added to the model, in insertion order.

Return type:

list[Table]

get_table(id)[source]

Return the table with the given id.

Parameters:

id (str) – Identifier of the table to look up.

Return type:

Table

Returns:

The matching Table.

Raises:

ValueError – If no table with that id exists in the model.

get_named_value(id)[source]

Return the named value (parameter or calculation) with the given id.

Parameters:

id (str) – Identifier of the named value to look up.

Return type:

Parameter | Calculation

Returns:

The matching Parameter or Calculation. Parameters are searched first, so a parameter is returned if both exist with the same id (which add_parameter / add_calculation would normally prevent).

Raises:

ValueError – If no named value with that id exists in the model.

get_validation_state()[source]

Return (and lazily build) a calculation summarising current validity.

The calculation evaluates to the highest SEVERITY_RANK among every field, parameter, and calculation whose __invalid__ formula is currently True, or 0 when nothing is invalid. Useful as the gating value for set_data_validation_rule().

The result is registered in the model under the id __validation_state__. Subsequent calls return the already-registered calculation without rebuilding it, so call this only after every validator has been attached.

Return type:

Calculation | Parameter

Returns:

A model-level Calculation whose integer value is the highest severity rank of any currently-invalid entity.

classmethod read_from_file(model_directory)[source]

Reconstruct a live ModelBuilder from the canonical Daitum directory layout.

The inverse of write_to_file(). Reads model-definition.json and the scenario- and model-level named-values.json files from disk, then delegates to read_from_dict() to do the actual decoding.

Parameters:

model_directory (str | PathLike[str]) – The directory previously written by write_to_file().

Return type:

ModelBuilder

Returns:

A ModelBuilder equivalent to the one that produced the files.

classmethod read_from_dict(definition, named_values=None)[source]

Reconstruct a live ModelBuilder from already-parsed JSON dicts.

The dict-level inverse of build(). Rebuilds the tables, calculations, and parameters from definition, then restores each parameter’s value from the named_values payloads. The returned builder is fully re-editable (decoding routes through the add_* factories) and exposes the populated LoadContext via load_context for a configuration or UI load to consume.

Parameters:
  • definition (dict[str, Any]) – The dict produced by build() (model-definition.json).

  • named_values (list[dict[str, Any]] | None) – Parsed named-values.json payloads (each a {"values": {...}} dict) supplying parameter values. May be omitted when no values are needed.

Return type:

ModelBuilder

Returns:

A ModelBuilder equivalent to the one that produced the dict.

property load_context

The LoadContext populated by read_from_file().

None on a builder that was constructed directly rather than loaded.

write_to_file(model_directory)[source]

Serialise the model into the canonical Daitum directory layout.

Writes three files under model_directory, creating it if it does not exist:

  • model-definition.json — the full model definition from build().

  • scenarios/Initial/named-values.json — scenario-level named values (those added with model_level=False).

  • model-data/named-values.json — model-level named values (those added with model_level=True).

Parameters:

model_directory (str | PathLike[str]) – Destination directory. Parents are created as needed.

Return type:

None

build()[source]

Build the JSON-compatible dict representation of the model.

Change-tracking declarations are validated here (see _validate_tracking()). The trackingGroupDefinitions and baselineDefinitions keys are only emitted when at least one tracking group or baseline has been declared, so untracked models are unaffected.

Return type:

dict[str, Any]

Returns:

A dict suitable for json.dump containing calculationDefinitions, parameterDefinitions, tableDefinitions, optimisationCheckNamedValue, partialEvaluationAllowed and, when present, the change-tracking definition maps.

Raises:

ValueError – If a change-tracking declaration is invalid.

to_named_value_dict(model_level)[source]

Build the JSON-compatible dict of parameter values for one scope.

Parameters:

model_level (bool) – When True, include only model-level parameters (written to model-data/named-values.json). When False, include only scenario-level parameters (written to scenarios/Initial/named-values.json).

Return type:

dict[str, Any]

Returns:

{"values": {parameter_id: value_dict, ...}}.

class Table(id)[source]

The base class for all table types.

This class defines the core structure and behavior of a table, including field management and relationships with derived tables.

A table also satisfies the Operand contract: passed into a formula function it behaves as an OBJECT_ARRAY operand whose rendered string is its id (so LOOKUP/ROWS/FILTER/INDEX accept a bare table with no special-casing). Note that table[field] (column access) is a distinct operator from Operand.__getitem__() (member access) — it renders table[field] with brackets, never the dot form — so __getitem__() is overridden below rather than inherited.

property key_column: str | None

The key column field ID used for object references, or None if not set.

property validation_group: str | None

The validation group identifier, or None if not assigned to a group.

property display_name: str

The human-readable display name for this table. Defaults to the table ID.

set_key_column(key_column)[source]

Sets the key column for this table. Returns self.

Return type:

Table

set_id_field(id_field)[source]

Sets the id field for this table. Returns self.

Return type:

Table

set_model_level(model_level)[source]

Sets whether this table is model-level. Returns self.

Return type:

Table

set_validation_group(group)[source]

Sets the validation group for this table. Returns self.

Return type:

Table

set_display_name(name)[source]

Sets the display name for this table. Returns self.

Return type:

Table

set_export_as_key_column(export_as_key=True)[source]
Configures the table to export its key column instead of the row number when generating

reports. Returns self.

Parameters:
  • export_as_key (bool) – If True, the table’s key column is exported.

  • False (If)

  • True. (the row number is exported instead. Defaults to)

Return type:

Table

initialise_field(id, data_type)[source]

Registers a placeholder field with the given ID and data type.

Use this when a field must exist before its final definition is known — for example, when using PREV or NEXT, or to resolve circular dependencies in combo fields. The placeholder will be automatically replaced when add_calculated_field or add_combo_field is later called with the same id.

Parameters:
  • id (str) – The unique ID of the field.

  • data_type (BaseDataType) – The data type of the field.

Returns:

The placeholder field, which can be referenced in formulas.

Return type:

DataField

add_data_field(id, data_type)[source]

Adds a data field to the table.

This method should be implemented by subclasses and is not valid for the base Table class.

Raises:

NotImplementedError – Always raised since this method is not applicable to Table.

Return type:

DataField

add_object_reference_field(id, table, is_array=False)[source]

Adds an object reference field to the table.

Parameters:
  • id (str) – The ID of the new field.

  • table (Table) – The table being referenced.

  • is_array (bool) – Whether the object reference is an array.

Returns:

The created object reference field.

Return type:

DataField

add_map_field(id, data_type, table)[source]

Adds a map field to the table.

Parameters:
  • id (str) – The ID of the new field.

  • data_type (DataType) – The underlying data type of the map values.

  • table (Table) – The table field maps into.

Returns:

The created map field.

Return type:

DataField

add_calculated_field(id, formula, order_index=None, description=None)[source]

Adds a CalculatedField to the table.

Parameters:
  • id (str) – The ID of the calculated field.

  • formula (Operand | float | int | bool | str) – The formula used to compute the field value.

  • order_index (int | None) – The order index of the field.

  • description (str | None) – Description of the field.

Returns:

The created CalculatedField object.

Return type:

CalculatedField

get_field(id)[source]

Retrieves a field from the table.

Parameters:

id (str) – The ID of the field to retrieve.

Returns:

The field object matching the given ID.

Return type:

Field

Raises:

ValueError – If the field does not exist in the table.

get_fields()[source]

Retrieves all fields in the table.

Returns:

A sequence of fields contained in the table.

Return type:

Sequence[Field]

to_string()[source]

Render this table as a formula operand — its id (an OBJECT_ARRAY reference).

Return type:

str

to_data_type()[source]

The data type of this table used as an operand: an OBJECT_ARRAY over itself.

Return type:

BaseDataType

get_validation_state()[source]

Build a calculated field representing the maximum severity rank among all currently-invalid fields in this table.

For each field with validators, COUNT(table[field__invalid__severity], True) > 0 is used to check whether any row is invalid at that severity level. The result is a scalar formula — all rows will carry the same value — evaluating to the highest SEVERITY_RANK among failing fields, or 0 when nothing is invalid.

The result is registered in the table as a calculated field named __validation_state__. Subsequent calls return the already-registered field without rebuilding it.

Returns:

A calculated field whose value is the highest severity rank of any currently-invalid field in this table.

Return type:

Field | CalculatedField

class Formula[source]

Abstract base for every structured formula expression.

A formula is its structured expression tree: Constant, the operator nodes (BinaryOperator/UnaryOperator/MemberAccess/ColumnAccess), and every per-function node subclass this base. data_type and formula_string are projections of the tree (how it type-checks and how it is written to JSON), derived from to_data_type() / to_string() rather than stored.

Subclasses implement to_string / to_data_type (from Operand) and children().

children()[source]

The immediate operand children of this formula node.

Return type:

Sequence[Operand]

dependencies()[source]

The reference leaves (Field / Calculation / Parameter / Table) this formula transitively uses.

The returned set is keyed by object identity (Operand defines no value __eq__ / __hash__), so each referenced object appears once. Reference leaves are operands that are not themselves Formula nodes; a child that is a structured formula recurses.

Return type:

set[Operand]

is_equivalent(other)[source]

Whether other is a formula equivalent to this one.

Two formulas are equivalent when they render to the same platform expression and infer the same data type. Because rendering is deterministic (the same node tree always produces the same string, brackets and spacing included), this reliably distinguishes structurally different formulas — e.g. (x + y) - z from x + (y - z) — and is exactly the check the parser round-trip needs (parse(f.to_string())f).

This is a dedicated method rather than an __eq__ override, which would perturb the identity-keyed dependencies() set and the equal_to / not_equal_to operators.

Return type:

bool

property data_type: BaseDataType

The formula’s return data type (a projection of the tree).

property formula_string: str

The rendered platform expression string (a projection of the tree).

build()[source]

Serialise to {"dataType", "formulaString"}.

A custom override: the node’s real state lives in _-prefixed attributes that the default Buildable walk skips, so this emits the two projections explicitly. The data type serialises as its enum value (DataType) or its nested build (ObjectDataType / MapDataType) — matching the legacy output.

Return type:

dict[str, Any]

class Field(id, table, data_type)[source]

Abstract base for a column on a Table.

Use the concrete subclasses DataField, CalculatedField, and ComboField rather than constructing Field directly. Every field has an id, an owning table, and a data_type; optionally an order_index, a description, and zero or more Validator instances (at most one per Severity).

table_id

The owning table’s id.

data_type

The BaseDataType of this field.

order_index: int | None

Order in which this field appears in the table (lower comes first).

description: str | None

Free-text description shown in the UI.

tracking_groups: list[str] | None

Names of the tracking groups this field belongs to (None when untracked).

property table: Table

The Table that owns this field.

set_tracking_groups(groups)[source]

Assign this field to one or more change-tracking groups.

A tracked field requires its table to declare an id_field. Passing an empty list clears tracking.

Parameters:

groups (list[str | TrackingGroup]) – Tracking groups (or their names) this field belongs to.

Return type:

Field

Returns:

This field, for chaining.

set_order_index(idx)[source]

Set the field’s position within its table (lower values come first).

Return type:

Field

set_description(desc)[source]

Set the field’s free-text description.

Return type:

Field

to_string()[source]
Return type:

str

to_data_type()[source]
Return type:

BaseDataType

add_validator(validator)[source]

Attach a Validator to this field.

Each field may carry at most one validator per Severity.

Raises:

ValueError – If a validator with the same severity is already attached.

Return type:

None

get_validation_fields(severity=None)[source]

Return the synthetic validation fields generated for this field’s validators.

Parameters:

severity (Severity | None) – When given, return only the validation fields for that severity. When None, return one ValidationFieldsContainer per attached validator, sorted by ascending severity rank.

Return type:

list[ValidationFieldsContainer] | ValidationFieldsContainer | None

Returns:

A single ValidationFieldsContainer, a list of them, or None if no validator matches.

get_combined_message_field()[source]

Return a single calculated field combining all per-severity messages.

The combined field is a STRING_ARRAY ordered from highest to lowest severity (CRITICAL → ERROR → WARNING → INFO); blank messages are excluded. The field is registered on the table as {id}__message__combined on first call and cached for subsequent calls.

Return type:

Field | None

Returns:

The combined-message field, or None if this field has no validators. When exactly one validator is attached, that validator’s existing message field is returned directly.

class Calculation(id, formula, model_level=False, model=None)[source]

A calculation is one of the three basic objects that make up a V3 Model. It consists of a name, data_type, and a formula.

id

The id or ID of the calculation.

Type:

str

formula

The formula defining the calculation.

Type:

model_generator.structures.Formula

depends_on_decision

Indicates if the calculation depends on a decision.

Type:

bool

model_level

Indicates if the calculation is at the model level.

Type:

bool

required_by_output

Indicates if the calculation is required by the output.

Type:

bool

__init__(id, formula, model_level=False, model=None)[source]
Parameters:
  • id (str) – Unique identifier for this calculation. Must be a valid Python-style identifier.

  • formula (Formula) – The formula that defines the calculated value.

  • model_level (bool) – If True, the calculation is model-level; otherwise scenario-level.

  • model (ModelBuilder | None) – The ModelBuilder this calculation belongs to. Can be set later via ModelBuilder.add_calculation.

property id: str

The unique identifier for this calculation.

set_tracking_groups(groups)[source]

Assign this calculation to one or more change-tracking groups.

Passing an empty list clears tracking. Returns self.

Return type:

Calculation

set_depends_on_decision(depends_on_decision)[source]

Sets whether this calculation depends on a decision variable.

Return type:

Calculation

set_required_by_output(required_by_output)[source]

Sets whether this calculation is required by the output.

Return type:

Calculation

to_string()[source]
Return type:

str

to_data_type()[source]
Return type:

BaseDataType

dependencies()[source]

The reference leaves this calculation’s formula uses (empty for a string-only formula).

Note this is the calculation’s own direct formula dependencies; as a leaf operand a Calculation is itself collected by formulas that reference it (it is not expanded).

Return type:

set[Operand]

add_validator(validator)[source]

Attach a validator to this named value.

Each named value can only have one validator per severity level. Attempting to add another validator with the same severity will raise a ValueError.

Parameters:

validator (Validator) – The validator instance to attach.

Raises:

ValueError – If a validator with the same severity has already been added to this field.

Return type:

None

get_validation_values(severity=None)[source]

Retrieve the validation values associated with this named value’s validators.

Parameters:

severity (Severity | None) – If provided, returns only the validation values for that severity level. If None, returns validation values for all attached validators.

Return type:

list[ValidationValuesContainer] | ValidationValuesContainer | None

Returns:

  • A list of ValidationValuesContainer if severity is None and validators exist.

  • A single ValidationValuesContainer if a validator matching severity is found.

  • None if no validators are attached, or if no validator matches the given severity.

get_combined_message_value()[source]

Returns a single calculated named value that combines all per-severity message values into one array, ordered from highest to lowest severity (CRITICAL → ERROR → WARNING → INFO). Blank messages are excluded from the array.

The resulting value is registered on the model with the ID {id}__message__combined and cached so subsequent calls return the same value without rebuilding it.

Returns:

The combined message calculated value, or None if this named value has no validators.

Return type:

Calculation | Parameter | None

Raises:

NotImplementedError – If this named value has not yet been attached to a model.

class Parameter(id, data_type, value=None, model_level=False)[source]

A parameter is one of the three basic objects that make up a model. It is the simplest of these three objects and consists only of a data_type, a id, as well as optional import_format and model_level.

id

The id or ID of the parameter.

Type:

str

data_type

The type of data that the parameter takes.

Type:

DataType

model_level

Indicates if the parameter is at the model level.

Type:

bool

__init__(id, data_type, value=None, model_level=False)[source]
Parameters:
  • id (str) – Unique identifier for this parameter. Must be a valid Python-style identifier.

  • data_type (BaseDataType) – The data type of the parameter value.

  • value (Any | None) – The initial value of the parameter, or None if not yet set.

  • model_level (bool) – If True, the parameter is model-level; otherwise scenario-level.

property id: str

The unique identifier for this parameter.

set_tracking_groups(groups)[source]

Assign this parameter to one or more change-tracking groups.

Passing an empty list clears tracking. Returns self.

Return type:

Parameter

set_model(model)[source]

Attach this parameter to a ModelBuilder. Returns self.

Return type:

Parameter

set_import_format(import_format)[source]

Sets the import format string for this parameter.

Return type:

Parameter

to_string()[source]
Return type:

str

to_data_type()[source]
Return type:

BaseDataType

to_named_value_dict()[source]

Converts the Parameter object to a dictionary representation for JSON serialisation.

Returns:

A dictionary representation of the Parameter object.

Return type:

dict[str, Any]

add_validator(validator)[source]

Attach a validator to this named value.

Each named value can only have one validator per severity level. Attempting to add another validator with the same severity will raise a ValueError.

Parameters:

validator (Validator) – The validator instance to attach.

Raises:

ValueError – If a validator with the same severity has already been added to this field.

Return type:

None

get_validation_values(severity=None)[source]

Retrieve the validation values associated with this named value’s validators.

Parameters:

severity (Severity | None) – If provided, returns only the validation values for that severity level. If None, returns validation values for all attached validators.

Return type:

list[ValidationValuesContainer] | ValidationValuesContainer | None

Returns:

  • A list of ValidationValuesContainer if severity is None and validators exist.

  • A single ValidationValuesContainer if a validator matching severity is found.

  • None if no validators are attached, or if no validator matches the given severity.

get_combined_message_value()[source]

Returns a single calculated named value that combines all per-severity message values into one array, ordered from highest to lowest severity (CRITICAL → ERROR → WARNING → INFO). Blank messages are excluded from the array.

The resulting value is registered on the model with the ID {id}__message__combined and cached so subsequent calls return the same value without rebuilding it.

Returns:

The combined message calculated value, or None if this named value has no validators.

Return type:

Calculation | Parameter | None

Raises:

NotImplementedError – If this named value has not yet been attached to a model.

class UnionSource(source_table, mapping_key)[source]

A source table in a union. Multiple UnionSource instances in a UnionTable may reference the same underlying table, distinguished by mapping_key.

property source_table: Table
class FieldMapping(union_source)
add_map(field_name, source_field)
build()

Serialise this object to a JSON-compatible dict.

Converts public, non-None instance attributes to camelCase keys. Recursively builds nested Buildable objects, converts Enum values, and serialises date/time/datetime instances as lists of components.

Returns:

The serialised representation.

Return type:

dict[str, Any]

Raises:

TypeError – If an attribute value is of an unsupported type.

property mapping_key: str

mapping_key for this field mapping.

Type:

Returns

property source_table: Table

the source table for this field mapping.

Type:

Returns

class Validator(severity, custom_message=None, custom_summary_message=None)[source]

Abstract base class for field validators.

Validators check field values and generate error messages when validation fails. They can be combined using AND (&) and OR (|) operators to create complex validation rules.

__init__(severity, custom_message=None, custom_summary_message=None)[source]

Initialize a validator.

Parameters:
  • severity (Severity) – The severity level of validation failures (INFO, WARNING, ERROR, CRITICAL).

  • custom_message (Formula | str | None) – Optional custom error message to use instead of the default message.

  • custom_summary_message (str | None) – Optional custom summary error message to use instead of the default summary message.

summary_message: str
invalid(field, table)[source]

Return a formula indicating whether the field is invalid

Return type:

Formula

message(field, table)[source]

Return a formula containing the message if the field is invalid

Return type:

Formula | str

get_summary_message(field)[source]

Return a str containing the summary message if the field is invalid

Return type:

str

class RangeValidator(severity, min_value, max_value)[source]

Validator that checks if a field value is within a specified range.

The range can have a min_value, max_value, or both bounds. Bounds can be static values or dynamic field references.

__init__(severity, min_value, max_value)[source]

Initialize a range validator.

Parameters:
  • severity (Severity) – The severity level of validation failures.

  • min_value (int | float | Operand | None) – Minimum allowed value, or None for no lower bound.

  • max_value (int | float | Operand | None) – Maximum allowed value, or None for no upper bound.

allow_blank: bool
min_bound_type: BoundType
max_bound_type: BoundType
set_allow_blank(allow_blank)[source]

Sets whether blank values are considered valid.

Return type:

RangeValidator

set_custom_message(custom_message)[source]

Sets a custom error message to use instead of the default.

Return type:

RangeValidator

set_custom_summary_message(custom_summary_message)[source]

Sets a custom summary error message to use instead of the default.

Return type:

RangeValidator

set_min_bound_type(min_bound_type)[source]

Sets whether the lower bound is inclusive or exclusive.

Return type:

RangeValidator

set_max_bound_type(max_bound_type)[source]

Sets whether the upper bound is inclusive or exclusive.

Return type:

RangeValidator

property min_value: int | float | Operand | None

The minimum bound value, or None if unbounded.

property max_value: int | float | Operand | None

The maximum bound value, or None if unbounded.

invalid(field, table)[source]

Return a formula indicating whether the field value or named value is outside the valid range.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula

Returns:

A Formula that evaluates to True if the field or named value is invalid, False otherwise.

message(field, table)[source]

Return a formula containing the validation error message.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula | str

Returns:

A Formula containing an error message describing the validation failure.

get_summary_message(field)[source]

Return a string of the summary error message.

Parameters:

field (Operand) – The field or named value to validate.

Return type:

str

Returns:

A string of the summary error message describing the validation failure.

class NonBlankValidator(severity, custom_message=None, custom_summary_message=None)[source]

Validator that checks if a field is not blank.

A field is considered blank if it is empty or null.

invalid(field, table)[source]

Return a formula indicating whether the field or named value is null/empty. If array/map provided, performs the validation on each element of the array/map.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula

Returns:

A Formula that evaluates to True if the field or named value is null/empty, False otherwise.

message(field, table)[source]

Return a formula containing the validation error message.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula | str

Returns:

A Formula containing an error message indicating the field or named value cannot be blank.

get_summary_message(field)[source]

Return a string of the summary error message.

Parameters:

field (Operand) – The field or named value to validate.

Return type:

str

Returns:

A string of the summary error message describing the validation failure.

class UniqueValidator(severity, allow_blank=False, custom_message=None, custom_summary_message=None)[source]

Validator that checks if a field value is unique within the table.

A field is considered invalid if its value appears more than once across all rows in the table for that field.

__init__(severity, allow_blank=False, custom_message=None, custom_summary_message=None)[source]

Initialize a Unique validator.

Parameters:
  • severity (Severity) – The severity level of validation failures.

  • allow_blank (bool) – Whether to allow blank values. Defaults to False.

  • custom_message (Formula | str | None) – Optional custom error message.

  • custom_summary_message (str | None) – Optional custom summary error message.

invalid(field, table)[source]

Return a formula indicating whether the field value is duplicated in the table.

Parameters:
  • field (Operand) – The field to validate. Only valid for primitives.

  • table (Table | None) – The table containing the field.

Return type:

Formula

Returns:

A Formula that evaluates to True if the value appears more than once, False otherwise.

message(field, table)[source]

Return a formula containing the validation error message.

Parameters:
  • field (Operand) – The field to validate.

  • table (Table | None) – The table containing the field.

Return type:

Formula | str

Returns:

A Formula containing an error message indicating the field value must be unique.

get_summary_message(field)[source]

Return a string of the summary error message.

Parameters:

field (Operand) – The field or named value to validate.

Return type:

str

Returns:

A string of the summary error message describing the validation failure.

class ListValidator(severity, values, custom_message=None, custom_summary_message=None)[source]

Validator that checks if a field value is within a provided set of allowed values.

The list of allowed values must be non-empty and all values must share the same data type, consistent with the field being validated.

__init__(severity, values, custom_message=None, custom_summary_message=None)[source]

Initialize a list validator.

Parameters:
  • severity (Severity) – The severity level of validation failures.

  • values (Sequence[Operand | str | int | float | bool]) – The sequence of allowed values. Must be non-empty and all elements must share the same data type.

  • custom_message (Formula | str | None) – Optional custom error message.

  • custom_summary_message (str | None) – Optional custom summary error message.

Raises:

ValueError – If values is empty.

invalid(field, table)[source]

Return a formula indicating whether the field value or named value is not in the allowed set. If array/map provided, performs the validation on each element of the array/map.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula

Returns:

A Formula that evaluates to True if the value is not in the allowed list, False otherwise.

message(field, table)[source]

Return a formula containing the validation error message.

Parameters:
  • field (Operand) – The field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula | str

Returns:

A Formula containing an error message listing the allowed values.

get_summary_message(field)[source]

Return a string of the summary error message.

Parameters:

field (Operand) – The field or named value to validate.

Return type:

str

Returns:

A string of the summary error message describing the validation failure.

class LengthValidator(severity, length, custom_message=None, custom_summary_message=None)[source]

Validator that checks if an array field has a specified number of elements.

Only applicable to array fields. The field is considered invalid if its element count does not equal the expected length.

__init__(severity, length, custom_message=None, custom_summary_message=None)[source]

Initialize a length validator.

Parameters:
  • severity (Severity) – The severity level of validation failures.

  • length (int) – The expected number of elements in the array. Must be non-negative.

  • custom_message (Formula | str | None) – Optional custom error message.

  • custom_summary_message (str | None) – Optional custom summary error message.

Raises:

ValueError – If length is negative.

invalid(field, table)[source]

Return a formula indicating whether the array length does not match the expected length.

Parameters:
  • field (Operand) – The array field or named value to validate. Only valid for arrays.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula

Returns:

A Formula that evaluates to True if the element count differs from the expected length, False otherwise.

message(field, table)[source]

Return a formula containing the validation error message.

Parameters:
  • field (Operand) – The array field or named value to validate.

  • table (Table | None) – The table containing the field. Optional.

Return type:

Formula | str

Returns:

A Formula containing an error message stating the expected array length.

get_summary_message(field)[source]

Return a string of the summary error message.

Parameters:

field (Operand) – The field or named value to validate.

Return type:

str

Returns:

A string of the summary error message describing the validation failure.

class DerivedTable(id, source_table, group_by=None, filter_field=None)[source]

Represents a derived table that is based on another source table and supports grouping, sorting, and filtering.

source_table_id: str
sort_keys: list[_SortKey]
grouping_configuration: _GroupingConfiguration | None
filter_field: str | None
add_source_fields(source_fields=None, include_validators=False)[source]

Adds fields to the current object from the source table or grouping configuration.

This method checks whether the source_fields parameter is provided. If source_fields is None, it adds all fields from the source table or grouped fields (depending on whether the grouping configuration is present). If source_fields is provided, it validates that each field is present in the available fields before adding it.

Parameters:
  • source_fields (list[Field] | None) – A list of Field objects to be added. Defaults to None, for which case all available fields will be added.

  • include_validators (bool) – Whether to propagate validators from source fields to the derived table. Defaults to False.

Raises:

ValueError – If Any field in source_fields is not found in the available fields.

Note

If _grouping_configuration is None, fields are taken from self.source_table._fields. If _grouping_configuration is not None, fields are taken from self.grouping_configuration.group_by_fields.

add_sort_key(field, direction)[source]

Adds a sort key to the derived table.

Parameters:
  • field (Field) – The field to sort by.

  • direction (SortDirection) – The direction in which to sort.

add_aggregated_field(id, source_field, aggregation_method)[source]

Adds an aggregated field to the table.

Parameters:
  • id (str) – The unique identifier for the aggregated field.

  • source_field (Field) – The source field that will be aggregated.

  • aggregation_method (AggregationMethod) – The method used to aggregate the source_field.

Raises:
  • ValueError – If no grouped fields are present in the table.

  • ValueError – If the aggregation method is not valid for the source field’s data type.

Return type:

DataField

class JoinedTable(id, join_conditions)[source]

Represents a table resulting from a join operation.

A JoinedTable is a table that is constructed by joining two or more other tables based on specific join conditions. A join operation combines rows from different tables based on a related field (column) between them. The join_conditions list defines how these tables are connected and which fields from the tables are used for the join.

Joins can be of different types, such as INNER, LEFT, RIGHT, FULL, and CROSS, and they dictate how the rows from the tables are combined and which rows are included in the final result.

A JoinCondition consists of the following:
  • left_table: The left table involved in the join.

  • right_table: The right table involved in the join.

  • join_type: The type of join (e.g., INNER, LEFT, RIGHT, FULL, CROSS).

  • left_field: The field in the left table that is used to match with the right table. Omitted for a CROSS join.

  • right_field: The field in the right table that is used to match with the left table. Omitted for a CROSS join.

A CROSS join takes no match fields and pairs every left row with every right row.

Multiple JoinCondition objects can be specified to represent more complex join scenarios. Each condition defines how a pair of tables are joined, and having multiple conditions allows for joining more than two tables at once, with each pair of tables joined based on the specific conditions defined. When there are multiple JoinCondition objects, the joins are performed in sequence, and the resulting table combines the results of all the joins.

add_table_reference(source_table)[source]

Adds a reference to a table in the JoinedTable.

This method allows for adding a reference field for a source table that is part of the join conditions. If the source table is not part of the join conditions, a ValueError will be raised.

Parameters:

source_table (Table) – The table to be referenced.

Returns:

The reference field for the source table.

Return type:

Field

Raises:

ValueError – If the source table is not present in any of the join conditions.

class JoinCondition(left_table, right_table, join_type, left_field=None, right_field=None)[source]

Represents a condition for joining two tables.

For matching joins (JoinType.LEFT, JoinType.RIGHT, JoinType.INNER, JoinType.FULL) both left_field and right_field must be supplied — they are the fields matched between the two tables. A JoinType.CROSS join pairs every left row with every right row and takes no match fields: left_field and right_field must both be omitted.

property left_table: Table
property left_field: Field | None
property right_table: Table
property right_field: Field | None
exception LoadError[source]

Raised when JSON cannot be decoded into the expected object graph.

class TrackingGroup(name)[source]

A named set of tracked elements.

Fields, parameters, and calculations reference a tracking group by name to opt into change tracking. A group only ever has an effect once a Baseline captures it.

class Baseline(name, tracking_groups, auto_capture=AutoCapture.NONE)[source]

A named point in time that snapshots one or more tracking groups.

Parameters:
  • name (str) – Unique identifier for the baseline.

  • tracking_groups (list[str | TrackingGroup]) – The tracking groups this baseline captures.

  • auto_capture (AutoCapture) – Platform milestone that triggers an automatic capture, or AutoCapture.NONE (the default) for manual capture only.

class AutoCapture(*values)[source]

When the platform should capture a baseline automatically.

NONE = 'NONE'
OPTIMISATION_COMPLETED = 'OPTIMISATION_COMPLETED'