Skip to main content

dpm-xl

A Python parser and evaluator for DPM-XL, the expression language of EBA validation rules and similar checks. The core has no dependencies; the optional columnar extra adds a polars evaluator for reports with millions of open-table rows.

from dpmxl import evaluate_rule, explain

expression = (
    "with {tC_01.00, c*, default: 0, interval: true}: {r0010} = {r0020} + {r0030}"
)
result = evaluate_rule(expression, provider, precondition="{v_C_01.00}")
for outcome in result.failures:
    print(explain(result.evaluation, expression, outcome.key).summary)
# 1,204 should equal 1,211 (1,180 + 31): difference 7, at least 5.5 given the
# reported precision

The package does not read report files and knows nothing about a particular DPM release. Data comes through a small provider protocol (see below), so the same evaluator works against an xBRL-CSV upload, a database, or test fixtures.

dpm-xl is an independent project, not affiliated with or endorsed by the European Banking Authority.

Modules

Module Purpose
dpmxl.parser Tokenizer and recursive-descent parser. Nodes keep source spans.
dpmxl.ast Expression tree, selections, axis selectors and item literals.
dpmxl.values Number with interval tolerance, comparison and formatting.
dpmxl.recordset Keyed record sets and the natural join used by every operator.
dpmxl.evaluator Evaluation, preconditions and per-record outcomes.
dpmxl.explain Fills a failing record's formula with operand values.
dpmxl.references Static selections (with with context applied) and {v_…} templates.
dpmxl.provider DataProvider protocol and the in-memory MemoryProvider.
dpmxl.columnar The same semantics on polars frames (optional columnar extra).
dpmxl.cli dpm-xl check and dpm-xl eval.

Supported language

  • with {context} [where …]: body, nested contexts replacing inherited parts.
  • Selections {tTABLE, r…, c…, s…, default: v, interval: b} with single codes, inclusive ranges (r0010-0050), lists ((c0010, c0030)) and wildcards.
  • {v_TABLE} filing-indicator tests and {vName} report parameters.
  • Literals: numbers, 4.5%, "text"/'text', #2026-12-31#, true/false, null, items [eba_qEC:qx01].
  • Operators + - * /, = != <> < <= > >=, in {…}, not, and, or, xor, if … then … [else …] endif.
  • Aggregates sum, count, avg, min, max, median (and the specification's min_aggr/max_aggr spellings) with group by; scalar abs, isnull, nvl, len, match, min/max with several operands, exp, ln, sqrt, power; filter(data, condition).
  • Clauses [where …], [get key], [sub key = value], [rename a to b].

time_shift needs the previous reporting period and is reported as unsupported. Every distinct EBA rule and precondition expression in releases 3.4–4.4 parses, except two source expressions with typos (trueendif, ornot), which are reported as syntax errors.

Semantics

  • Records and keys. A selection yields one record per data point. Its key holds every closed axis that selects more than one coordinate (r, c, s; an axis that is not written counts when the table has several coordinates on it) plus open key components such as qEBB. Binary operators natural-join on shared keys; a scalar broadcasts. Operands with unrelated keys are an error.
  • Missing facts take the selection's default; with no default they are null. Providers must therefore return every defined cell of a closed selection, reported or not.
  • Interval arithmetic. With interval: true, numbers follow the Eurofiling interval arithmetic functions (iaf:*, version 1.1.1) that EBA validation rules are based on. A fact reported with decimals = d stands for value ± 0.5·10^-d (INF is exact; constants and defaults are exact). Sums and differences add thresholds; products use |A·δB| + |B·δA| + δA·δB; quotients take the largest deviation of the four endpoint quotients (skipping a zero divisor); abs and negation keep the threshold; min and max keep the chosen value's threshold. a = b holds when |a − b| ≤ δa + δb (the intervals overlap), a ≤ b when a − b ≤ δa + δb, a ≥ b when a ≥ b − (δa + δb), and likewise for the strict comparisons. With interval: false facts are exact. Explanations report each side's interval and the gap: how far apart the closest values within those intervals still are.
  • Null. Null propagates through arithmetic, comparisons and functions (except isnull and nvl). and/or/not use three-valued (Kleene) logic. A record whose result is null is "not evaluated", never a failure. Division by zero is a run-time error, as the specification requires.
  • Conditionals. if takes the else branch when the condition is null; without else, a Boolean then yields true where the condition is false or null. The result has the condition's record structure; branch keys the condition lacks widen it, so each condition record applies to every branch record sharing its keys (the columnar evaluator hands that case to the reference evaluator).
  • Aggregates over no records are null, except count, which is 0; count counts non-null values. max and min also order dates, text and items by their text (ISO dates in date order, items by category and code), as presence checks expect; Booleans, and numbers mixed with other values in one group, are an error.
  • Clauses. [get key] omits records whose fact is null; a where or sub inside a with body overrides the context's clause on the same key. Booleans order false < true.
  • Key names in where, group by, sub and get match with or without the DPM 2.0 q prefix and ignore case (EBB finds qEBB).
  • Items compare by code and category, ignoring the eba_ prefix and a category missing on either side.
  • Preconditions make a rule not_applicable unless they yield at least one true record.

A RuleResult has status passed, failed, not_applicable, error (syntax, unknown table, type mismatch) or unsupported, plus one Outcome per record with the data points it used.

These semantics follow the EBA DPM-XL language specification v0.9 (operators and data model documents) and the Eurofiling interval arithmetic functions. Where the specification is ambiguous or contradicts itself (sum of no records, count over nulls, key-name aliases, the radius formulas for products and quotients), the choice above is the one that avoids false failures.

Columnar evaluation

dpmxl.columnar.evaluate_rule_columnar(expression, provider) evaluates a rule on polars frames from a FrameProvider (select_frame(query) returns one row per data point with k:<key> columns and the num, thr, txt, flag value columns). Values are exact Decimal(38, 12), keys are joined like recordset.combine, and a FrameCache shares selections across rules within a row budget. Anything the module does not implement, including arithmetic that would overflow, raises ColumnarUnsupported so the caller falls back to the reference evaluator. tests/test_columnar.py checks both evaluators agree case by case. PointsFrameProvider adapts any DataProvider.

Provider contract

class DataProvider(Protocol):
    def select(self, query: CellQuery) -> Sequence[DataPoint]: ...
    def table_reported(self, table: str) -> bool | None: ...
    def parameter(self, name: str) -> Value: ...

select resolves the table and axis selectors (axis_matches and normalize_code implement range and code matching) and returns all defined cells of the closed axes with value=None where nothing was reported. For an open table it returns one point per reported key combination, with the key components in DataPoint.keys. DataPoint.ref is an opaque identity that comes back in outcomes, so a caller can highlight cells.

CLI

dpm-xl check rules.json            # parse every expression/precondition in a rule list
dpm-xl check "with {tC_01.00}: {r0010} >= 0" --references
dpm-xl eval "with {tC_01.00, c0010, default: 0, interval: true}: {r0010} = {r0020} + {r0030}" data.json

data.json holds tables (code, rows, columns, sheets, open_keys), facts (table, row, column, sheet, keys, value, decimals, type), reported and parameters.

Development

uv sync
uv run pytest
uv run ruff check . && uv run ruff format --check . && uv run ty check

tests/data/eba_expressions.txt is a sample of about 300 EBA rule expressions covering every construct above. Every line must parse.

Metadata

Release files for dpm-xl 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dpm-xl 0.1.0
File Size Uploaded Provenance
dpm_xl-0.1.0.tar.gz 56.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dpm-xl 0.1.0
File Interpreter ABI Platform
dpm_xl-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 117.1 kB

Release files / dpm_xl-0.1.0.tar.gz

Download URL dpm_xl-0.1.0.tar.gz
Size 56.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4cb798fc72909ec1dde00e89d49f6ad91fc0df658027087a119ec5ea30a2bc9d
BLAKE2b-256 checksum
How to use checksums
ee4de1b82090c474731d448c94b01666b4995e6b58dd21b052d9ef10481b51c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / dpm_xl-0.1.0-py3-none-any.whl

Download URL dpm_xl-0.1.0-py3-none-any.whl
Size 61.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
13e760071e4a280b7a3fa5316dfa2e999a2379db2a71e901561b192c9144dfbf
BLAKE2b-256 checksum
How to use checksums
9855167a59562b45ffe37a65a3b8d3b7e37aef4d146c9b6e02709aea21d7f0ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for dpm-xl 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page