Skip to content

dpmxl.recordset

Keyed record sets and the natural join every operator uses. See Records and keys.

dpmxl.recordset

Keyed record sets, the value domain of DPM-XL operators.

A selection evaluates to records keyed by its varying components: closed axes that select more than one coordinate (r, c, s) and open key components such as qEBB. Operators combine operands with a natural join on shared keys, so {r0010} = {r0020} under with {c*} compares column by column, and a scalar broadcasts to every record. An operand with a default stands for that default where it lacks a record another operand has.

STANDARD_KEYS module-attribute

STANDARD_KEYS = frozenset({'r', 'c', 's'})

Keys of the closed axes: rows, columns and sheets.

EvaluationError

Bases: Exception

Raised when an expression cannot be evaluated against the data.

For example a type mismatch, an unknown table or incompatible keys. evaluate_rule catches it and returns status error with the message.

UnsupportedError

Bases: EvaluationError

Raised for valid DPM-XL that this evaluator cannot resolve.

Raised when a rule needs an optional provider method (time_shift, {o_...}, {g_...}) that the provider lacks or that returns None, and for a function name the evaluator does not know. evaluate_rule catches it and returns status unsupported.

Record dataclass

Record(value: Value, points: tuple[Any, ...] = ())

One keyed value and the data points it was computed from.

points may nest the operands' point tuples instead of copying them: joins over large open tables would otherwise copy every record's growing point list at each operator. Use unique_points to flatten.

Attributes:

  • value (Value) –

    The record's value.

  • points (tuple[Any, ...]) –

    The data points it was computed from, possibly nested.

value instance-attribute

value: Value

points class-attribute instance-attribute

points: tuple[Any, ...] = ()

Recordset dataclass

Recordset(
    keys: tuple[str, ...],
    records: dict[tuple[Hashable, ...], Record] = dict(),
    default: Record | None = None,
)

Records indexed by a tuple of key values aligned with keys.

A selection with a default keeps it as default: the record of every key the set lacks. combine then fills in the default where another operand has a record, and lookup returns it for a missing key. Per-record operations carry it along (see map), as do where, sub, filter, rename, a time_shift of a date key and an if whose condition has one; get, aggregates and analytic functions drop it.

Attributes:

  • keys (tuple[str, ...]) –

    Key names, such as ("r", "qCPI"); empty for a scalar.

  • records (dict[tuple[Hashable, ...], Record]) –

    Records by key values, aligned with keys.

  • default (Record | None) –

    The record of a key the set lacks, or None when a missing key has no record.

keys instance-attribute

keys: tuple[str, ...]

records class-attribute instance-attribute

records: dict[tuple[Hashable, ...], Record] = field(
    default_factory=dict
)

default class-attribute instance-attribute

default: Record | None = None

is_scalar property

is_scalar: bool

Whether the set has no key components.

scalar classmethod

scalar(
    value: Value, points: tuple[DataPoint, ...] = ()
) -> Recordset

Build a key-less record set holding one value.

Returns:

single

single() -> Record | None

Return the only record of a scalar.

Returns:

  • Record | None –

    Record | None: The record, or None for an empty set.

Raises:

lookup

lookup(binding: Mapping[str, Hashable]) -> list[Record]

Return records consistent with a partial key binding.

Returns:

  • list[Record] –

    list[Record]: Matching records (one when all keys are bound; the

  • list[Record] –

    default when the set lacks that key and has one).

map

map(function: Callable[[Value], Value]) -> Recordset

Apply a function to every value, the default included.

Returns:

  • Recordset ( Recordset ) –

    Same keys, transformed values.

combine

combine(
    operands: Sequence[Recordset],
    function: Callable[[list[Value]], Value],
) -> Recordset

Natural-join operands on shared keys and combine their values.

Records without a partner on a shared key are dropped, unless the operand lacking the partner has a default: it then takes part with its default, as a fact variable with a fallback value does. When every keyed operand has a default, the result has a record for each key any operand with all the keys has, and its own default combines theirs. Operands without any shared key form a cross product, which is only allowed when at most one of them is keyed (scalar broadcast) to avoid accidental explosions.

Returns:

  • Recordset ( Recordset ) –

    Keys in first-seen order across operands.

Raises:

Examples:

>>> def numbers(values, default=None):
...     records = {(key,): Record(value) for key, value in values}
...     return Recordset(("qKEY",), records, default)
>>> def total(values):
...     return sum(values)
>>> left = numbers([("a", 1), ("b", 2)])
>>> right = numbers([("b", 3), ("c", 4)], Record(0))
>>> def values(result):
...     return {key: record.value for key, record in result.records.items()}
>>> values(combine([left, right], total))
{('a',): 1, ('b',): 5}
>>> left.default = Record(0)
>>> values(combine([left, right], total))
{('a',): 1, ('b',): 5, ('c',): 4}

check_structure

check_structure(operands: Sequence[Recordset]) -> None

Enforce DPM-XL 2.2.3.1 for operators over several record sets.

Keyed operands must have exactly the same keys, or one operand's keys (the reference) must be a superset of every other's. Standard keys (r, c, s) shared with the reference must contain the same values: {tT1, r010-020} + {tT1, r030-040} is an error, not empty.

Raises:

iter_points

iter_points(points: Iterable[Any]) -> Iterator[DataPoint]

Flatten nested point tuples (see Record) in order.

Yields:

  • DataPoint ( DataPoint ) –

    Each point, duplicates included.

unique_points

unique_points(
    points: Iterable[Any],
) -> tuple[DataPoint, ...]

Flatten and deduplicate data points by provider reference, keeping order.

Returns:

  • tuple[DataPoint, ...] –

    tuple[DataPoint, ...]: Distinct points.

resolve_key

resolve_key(name: str, keys: Iterable[str]) -> str | None

Resolve a key name written in a rule against available key components.

Rules refer to DPM 2.0 key properties with or without their q prefix (qEBB and EBB) and in any case.

Returns:

  • str | None –

    str | None: The matching key, or None when absent or ambiguous.

Examples:

>>> resolve_key("EBB", ["qEBB", "r"]), resolve_key("qebb", ["qEBB"])
('qEBB', 'qEBB')
>>> resolve_key("CPI", ["r"]) is None
True