dpmcore.services.semantic

Semantic validation of DPM-XL expressions against the loaded DPM dictionary. Release-aware: accepts release_id or release_code.

SemanticService

class dpmcore.services.semantic.SemanticService(session)[source]

Bases: object

Validate DPM-XL expressions against the data dictionary.

Parameters:

session (Session) – An open SQLAlchemy session bound to a DPM database.

__init__(session)[source]

Build the service bound to session.

Parameters:

session (Session)

Return type:

None

validate(expression, release_id=None, release_code=None, *, precondition_expression=None, precondition_operation_vid=None)[source]

Full semantic validation of expression and its optional gate.

Returns a SemanticResult — never raises on validation failure.

A referenced parameter’s declared type is also checked against co-scoped operations already in the database (raising 3-8 on a clash). This lookup only runs when the expression actually references a parameter and is scoped in SQL to co-located operations, so it adds no overhead to a parameter-free database.

When precondition_expression is supplied, both halves are validated against the same release, resolved once, and is_valid becomes the verdict for the pairFalse if either half failed, since a row whose gate does not resolve is not evaluable. precondition carries the gate’s own verdict and error_source names the failing half. Two checks then apply that a single expression never sees:

  • The gate is validated as a gate, so its result must be a boolean (2-1). A numeric selection is a valid expression but not a valid precondition.

  • Parameter declarations are cross-checked across the halves (3-8). A gate co-executes with its expression, so a parameter bound across them must declare one type.

The halves are evaluated gate-first, so the per-call state this service publishes (ast, oc_data, oc_tables, oc_parameters, oc_operations_data) describes the main expression when the call returns — what existing consumers of this method already rely on.

Parameters:
  • expression (str) – The DPM-XL expression to validate.

  • release_id (Optional[int]) – Optional release ID filter. When neither this nor release_code is given, defaults to the latest release.

  • release_code (Optional[str]) – Optional release code (mutually exclusive with release_id).

  • precondition_expression (Optional[str]) – Optional DPM-XL gate expression. Keyword-only, and appended after the pre-existing arguments, so validate(expr, 5) still means release_id=5. When None, the result is exactly as before this argument existed: precondition is None and is_valid describes expression alone.

  • precondition_operation_vid (Optional[int]) – Optional VID of a separately persisted OperationVersion gating this one (its precondition_operation_vid self-FK), distinct from precondition_expression. Cross-checked against the current module scope when expression is valid (7-3/7-4/7-5); a VID with nothing to check against is accepted.

Return type:

SemanticResult

is_valid(expression, release_id=None, release_code=None, *, precondition_expression=None)[source]

Quick boolean check, pair-wide when a gate is supplied.

Return type:

bool

Parameters:
  • expression (str)

  • release_id (int | None)

  • release_code (str | None)

  • precondition_expression (str | None)

SemanticResult

class dpmcore.services.semantic.SemanticResult(is_valid, error_message, error_code, expression, results=None, warning=None, parameters=<factory>, precondition=None, error_source=None)[source]

Outcome of a semantic validation.

When a precondition_expression is supplied, is_valid is the verdict for the pair: it is False if either the expression or its gate failed, because a row whose gate does not resolve is not evaluable. The gate’s own independent verdict is precondition; error_source says which half a failure belongs to — "expression", "precondition", or "both" — so attribution never needs string matching. error_message names every failure that occurred, each from the gate prefixed "Precondition: ", and warning merges both halves’ warnings the same way, so a caller reading only the outer result never misses half the story. error_code holds a single value: the expression’s when it failed, otherwise the gate’s.

precondition is None exactly when the caller supplied no gate — never as a way of signalling that one failed. On that nested result error_source is "precondition" whenever it failed, since it describes the gate alone.

Parameters:
is_valid: bool
error_message: Optional[str]
error_code: Optional[str]
expression: str
results: Optional[Any] = None
warning: Optional[str] = None
parameters: tuple[ParameterInfo, ...]
precondition: Optional[SemanticResult] = None
error_source: Optional[str] = None

ParameterInfo

class dpmcore.services.semantic.ParameterInfo(code, declared_type, default=None)[source]

Declared metadata for a parameter referenced by an expression.

This is the runtime-binding contract: dpmcore reports which parameters an expression needs (and their declared types/defaults); the downstream engine resolves and binds their values.

is_set is a derived property (Set prefix of the canonical declared_type), not a stored field, so there is one source of truth for set-ness.

Parameters:
  • code (str)

  • declared_type (str)

  • default (Any)

code: str
declared_type: str
default: Any = None
property is_set: bool

True for the set variants.

The canonical declared_type is SetNumber/SetItem/…; no scalar type name starts with Set, so the prefix is unambiguous.