dpmcore.services.scope_calculator

Resolve the data-point scopes and module versions touched by a DPM-XL expression.

ScopeCalculatorService

class dpmcore.services.scope_calculator.ScopeCalculatorService(session)[source]

Bases: object

Calculate operation scopes for DPM-XL expressions.

Determines which module versions are involved in an operation based on table references and precondition items.

Parameters:

session (Session) – An open SQLAlchemy session.

__init__(session)[source]

Build the service bound to session.

Parameters:

session (Session)

Return type:

None

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

Calculate scopes for expression, optionally gated.

Parses the expression, runs OperandsChecking to extract table codes, then delegates to OperationScopeService. precondition_items is the list of precondition variable codes that gate the validation; pass None or [] if the validation has no preconditions.

When precondition_expression is supplied, the gate’s own operands join the resolution by their matching channels — its table codes are unioned into table_codes and its mandatory precondition variable codes into precondition_items (unioned with any the caller passed). The two are not interchangeable: only table_codes resolves through get_from_table_codes, and only precondition_items gets the filing-indicator filter and the 1-14 check. Because a module hosts an intra-module scope only when it supplies every operand, a gate reaching outside the expression’s own modules widens the scope to cross-module, or empties it — which is the honest verdict, since the pair is only evaluable where both halves resolve. That change is reported in warning, and a gate-attributable failure sets error_source to "precondition" with a prefixed message.

The two channels treat a disjunctive gate differently, deliberately. Variable codes are intersected across or branches, so an optional filing indicator does not constrain scope. Table codes come from the gate’s OperandsChecking pass, which does not model boolean structure, so every table the gate mentions is required even when only one branch needs it. That errs toward reporting a wider scope rather than missing a table the pair genuinely needs, and costs nothing on the real dictionary, where no persisted precondition references a table.

Passing no precondition_expression costs nothing: no second scope resolution, no warning, and byte-identical error messages.

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

  • release_id (Optional[int]) – Optional release ID filter.

  • precondition_items (Optional[List[str]]) – Filing-indicator codes gating the validation.

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

  • precondition_expression (Optional[str]) – Optional DPM-XL gate expression. Keyword-only, matching SemanticService.validate, so the pre-existing positional arguments keep their meaning.

Return type:

ScopeResult

calculate_from_tables(table_vids, precondition_items=None, release_id=None, table_codes=None, release_code=None)[source]

Calculate scopes directly from table version IDs.

Return type:

ScopeResult

Parameters:
  • table_vids (List[int])

  • precondition_items (List[str] | None)

  • release_id (int | None)

  • table_codes (List[str] | None)

  • release_code (str | None)

filter_valid_dependency_modules(scope_result, primary_module_vid)[source]

Return module VIDs that co-occur with primary_module_vid.

Only modules that actually appear alongside the primary module in a multi-module scope are valid cross-module partners. This filters out sibling modules that share tables but are not actual cross-module dependencies.

Return type:

Set[int]

Parameters:
detect_cross_module_dependencies(scope_result, primary_module_vid, operation_code=None, release_id=None, time_shifts=None, compute_alternative_deps=True, release_code=None, referenced_variables=None, referenced_tables=None, home_module_tables=None)[source]

Build dependency information for a scope result.

Parameters:
  • scope_result (ScopeResult) – The computed scope result.

  • primary_module_vid (int) – VID of the primary module.

  • operation_code (Optional[str]) – Current operation code (if any).

  • release_id (Optional[int]) – Optional release filter.

  • time_shifts (Optional[Dict[str, str]]) – Optional mapping of table codes to ref-period strings (e.g. {"C_01.00": "T-1Q"}). Tables not present default to "T".

  • compute_alternative_deps (bool) – When True (default) the returned alternative_dependencies is populated from this single scope_result. Aggregating callers that compute alternatives across many scope results should pass False to avoid the per-call work.

  • release_code (Optional[str]) – Optional release code; resolved to release_id via Release.code. Mutually exclusive with release_id.

  • referenced_variables (Optional[Dict[str, str]]) – Optional {datapoint: type_code} of every operand datapoint the operation references, across all modules it spans — home module included. Declared in each dependency module’s variables map (#251).

  • referenced_tables (Optional[Set[str]]) – Optional table codes the operation references. Together with referenced_variables this narrows each dependency module’s declaration to the subset the operation uses (#250); omit both to declare the dependency modules whole.

  • home_module_tables (Optional[Set[str]]) – Optional pre-computed set of table codes owned by the primary (home) module — the same set this method would derive from _get_module_tables(). Callers that iterate this method with a fixed primary_module_vid (per-op dependency detection over a script’s operations) should pass a single pre-computed set to avoid re-running the per-table variable/open-key fetch on every iteration.

Return type:

Dict[str, Any]

Returns a dict with: - intra_instance_validations - cross_instance_dependencies - alternative_dependencies - dependency_modules

detect_alternative_dependencies(scope_results, primary_module_vid, release_id=None, release_code=None, valid_module_uris=None)[source]

Detect disjoint groups of interchangeable external modules.

Two external modules are alternatives only when they are interchangeable dependencies of the same operation (#202): within a single operation’s scopes they each appear as the sole external module alongside the primary, yet never co-exist in one scope. Each ScopeResult is one operation, so candidate pairs are collected per scope result — being the sole external of two different operations does not make two modules alternatives.

Interchangeable pairs are then collapsed into disjoint groups so that when three or more modules are mutually interchangeable they surface as one group rather than every overlapping pair (#242).

Parameters:
  • scope_results (List[ScopeResult]) – One entry per operation.

  • primary_module_vid (int) – VID of the primary module.

  • release_id (Optional[int]) – Optional release filter (validated only).

  • release_code (Optional[str]) – Optional release code (validated only).

  • valid_module_uris (Optional[Set[str]]) – When given, the genuine dependency-module URIs of the script. Pairs referencing a module outside this set are dropped so alternative_dependencies can never name a module absent from dependency_modules (#202 dangling references).

Return type:

List[List[str]]

Returns a list of disjoint groups; each group is a sorted list of two or more interchangeable module URIs, and no module appears in more than one group.

ScopeResult

class dpmcore.services.scope_calculator.ScopeResult(scopes=<factory>, total_scopes=0, is_cross_module=False, module_versions=<factory>, has_error=False, error_message=None, warning=None, error_source=None)[source]

Outcome of a scope calculation.

warning is only ever set when a precondition_expression changed the computed scope. error_source names the half a failure belongs to and is set whenever has_error is true. Neither changes error_message for a call that passes no precondition expression.

Parameters:
  • scopes (list[Any])

  • total_scopes (int)

  • is_cross_module (bool)

  • module_versions (List[int])

  • has_error (bool)

  • error_message (str | None)

  • warning (str | None)

  • error_source (str | None)

scopes: list[Any]
total_scopes: int = 0
is_cross_module: bool = False
module_versions: List[int]
has_error: bool = False
error_message: Optional[str] = None
warning: Optional[str] = None
error_source: Optional[str] = None