CLI Reference

dpmcore provides a command-line interface for common tasks.

pip install dpmcore[cli]

Global options

dpmcore --version    Show the version and exit.
dpmcore --help       Show available commands.

dpmcore migrate

Migrate an Access database into a SQL database.

dpmcore migrate --source <path> --database <url>

Options:

Option

Description

--source PATH

Path to the Access .accdb or .mdb file. (Required)

--database TEXT

SQLAlchemy database URL, e.g. sqlite:///dpm.db or postgresql://user:pass@host/db. (Required)

Examples:

# SQLite
dpmcore migrate --source dpm.accdb --database sqlite:///dpm.db

# PostgreSQL
dpmcore migrate \
    --source /data/dpm.accdb \
    --database postgresql://user:pass@localhost:5432/dpm

# SQL Server
dpmcore migrate \
    --source dpm.accdb \
    --database mssql+pyodbc://user:pass@server/db?driver=ODBC+Driver+17

dpmcore validate

Run a shallow shape + data-sanity check on a database. Reports missing tables, missing columns, and required seed tables that exist but are empty. Designed to be cheap (tens of milliseconds on a real DPM database) — not a deep audit. Comparisons are case-insensitive so the same check works across SQLite, PostgreSQL, and SQL Server.

dpmcore validate --database <url> [--json]

Options:

Option

Description

--database TEXT

SQLAlchemy database URL. (Required)

--json

Emit the result as a JSON document instead of a rich table. Useful for CI/healthcheck scripts.

Exit codes:

  • 0 — schema is valid (all expected tables and columns present and all required seed tables non-empty).

  • 1 — at least one of: missing table, missing column, empty required seed table.

Examples:

# Human-readable output
dpmcore validate --database sqlite:///dpm.db

# JSON output (e.g. for CI)
dpmcore validate --database sqlite:///dpm.db --json

# Use as a healthcheck (in scripts)
dpmcore validate --database "$DB_URL" --json > /dev/null \
    && echo "ok" || echo "schema check failed"

dpmcore update-db

Safely update a DPM database from CSV files or an Access file.

The command loads data into a temporary staging area, validates it, and only then atomically replaces the active database. If any step fails the active database is left untouched.

  • SQLite — data is loaded into a hidden temp file; the target .db file is replaced only after validation passes.

  • PostgreSQL / SQL Server — data is loaded into a temporary staging schema; after validation the staging schema is swapped atomically into the active position.

dpmcore update-db --target <url_or_path>
                  (--access-file PATH | --source-dir PATH) [options]

Options:

Option

Description

--target TEXT

Target database. Accepts a SQLite path (dpm.db, dpm.sqlite, dpm.sqlite3), a SQLite URL (sqlite:///path/to/dpm.db), a PostgreSQL URL (postgresql://user:pass@host/db), or a SQL Server URL (mssql+pyodbc://user:pass@server/db?driver=...). (Required)

--access-file PATH

Path to an Access .accdb or .mdb file. When provided, the Access file is exported to CSV automatically before loading. Mutually exclusive with --source-dir; one is required.

--source-dir PATH

Directory containing pre-exported CSV tables. Mutually exclusive with --access-file; one is required.

--ecb-validations-file PATH

Path to an ECB validations CSV file. When provided, the file is imported after the main migration and before final validation.

--dry-run

Load and validate data without replacing the active database. Useful to check whether new data is valid before committing the update.

--keep-staging

Keep the temporary SQLite file or the staging/backup schemas after the command finishes. Useful for debugging failed updates.

Examples:

# Update a SQLite database from a pre-exported CSV directory
dpmcore update-db --target dpm.db --source-dir ./csv_export

# Update using a SQLite URL
dpmcore update-db --target sqlite:///path/to/dpm.db --source-dir ./csv_export

# Update from an Access file
dpmcore update-db \
    --target dpm.db \
    --access-file /path/to/DPM_v4_2_1.accdb

# Include ECB validations
dpmcore update-db \
    --target dpm.db \
    --source-dir ./csv_export \
    --ecb-validations-file ecb_validations.csv

# Dry run — validate only, do not replace active database
dpmcore update-db --target dpm.db --source-dir ./csv_export --dry-run

# Dry run keeping the staging file for inspection
dpmcore update-db \
    --target dpm.db --source-dir ./csv_export --dry-run --keep-staging

# Update a PostgreSQL database
dpmcore update-db \
    --target postgresql://user:pass@localhost:5432/dpm \
    --source-dir ./csv_export \
    --ecb-validations-file ecb_validations.csv

# Update a SQL Server database
dpmcore update-db \
    --target "mssql+pyodbc://user:pass@server/dpm?driver=ODBC+Driver+17+for+SQL+Server" \
    --source-dir ./csv_export

Exit codes:

  • 0 — update completed successfully (or dry run validated successfully).

  • 1 — update failed; the active database was not modified.

dpmcore export-csv

Export all user tables from a Microsoft Access database to CSV files.

Requires mdb-tools (mdb-tables + mdb-export) to be installed and available in PATH. Tables are exported in parallel (up to 8 workers).

dpmcore export-csv SOURCE [--output-dir PATH]

Arguments / Options:

Argument / Option

Description

SOURCE

Path to the Access .accdb or .mdb file. (Required)

--output-dir PATH

Directory where <TableName>.csv files are written. Created (including parents) if it does not exist. Defaults to data/DPM.

Examples:

# Export to the default directory (data/DPM/)
dpmcore export-csv /path/to/DPM_v4_2_1.accdb

# Export to a custom directory
dpmcore export-csv /path/to/DPM_v4_2_1.accdb --output-dir exports/csv

dpmcore build-meili-json

Build a Meilisearch-ready JSON file containing all DPM operation versions with their scopes, module assignments, operand references, and version history.

The pipeline is: Access → CSV → in-memory SQLite → JSON. When --access-file is supplied the CSV export is handled transparently. --source-dir and --access-file are mutually exclusive; at least one must be supplied.

dpmcore build-meili-json [--source-dir PATH | --access-file PATH]
                         [--ecb-validations-file PATH] [--output PATH]

Options:

Option

Description

--source-dir PATH

Directory containing pre-exported CSV tables. Mutually exclusive with --access-file.

--access-file PATH

Path to an Access .accdb or .mdb file. The file is exported to a temporary CSV directory automatically. Mutually exclusive with --source-dir.

--ecb-validations-file PATH

Optional path to an ECB validations CSV file. When provided, ECB validation versions are imported before building the JSON.

--output PATH

Output JSON file path. Defaults to operations.json.

Examples:

# From a pre-exported CSV directory
dpmcore build-meili-json --source-dir ./csv_export --output operations.json

# Directly from an Access file (CSV export handled transparently)
dpmcore build-meili-json \
    --access-file /path/to/DPM_v4_2_1.accdb \
    --output operations.json

# With optional ECB validations
dpmcore build-meili-json \
    --access-file /path/to/DPM_v4_2_1.accdb \
    --ecb-validations-file ecb_validations.csv \
    --output operations.json

dpmcore serve

Start the dpmcore REST API server.

Note

Requires the server extra: pip install dpmcore[server]

dpmcore serve --database <url> [--host HOST] [--port PORT]

Options:

Option

Description

--database TEXT

SQLAlchemy database URL. (Required)

--host TEXT

Bind host (default: 127.0.0.1).

--port INTEGER

Bind port (default: 8000).

Example:

dpmcore serve --database sqlite:///dpm.db --host 0.0.0.0 --port 8000

dpmcore generate-script

Generate an engine-ready DPM-XL validations script from a set of expressions. Expressions are validated and enriched against the DPM dictionary; the output is a JSON document keyed by the resolved module URI (the same shape produced by the Python ASTGeneratorService and the /api/v1/scripts REST endpoint).

dpmcore generate-script --expressions <file> --module-code <code>
                        --module-version <ver> --database <url>
                        --output <file> [--severity LEVEL] [--release CODE]

Options:

Option

Description

--expressions PATH

Path to a JSON file describing the validations (see below). (Required)

--module-code TEXT

Primary module code, e.g. COREP_Con. (Required)

--module-version TEXT

Primary module version, e.g. 2.0.1. (Required)

--severity TEXT

Global default severity (error / warning / info). Defaults to warning. Per-validation overrides go in the severities map of the input file.

--release TEXT

Release code, e.g. 4.2. When omitted, resolves to the latest release whose window contains the requested module version.

--database TEXT

SQLAlchemy database URL. (Required)

--output PATH

Path to write the generated script JSON. (Required)

Input file format:

The --expressions file is a JSON object. Only expressions is required; preconditions and severities are optional.

{
    "expressions": [
        ["{tC_01.00, r0100, c0010} = {tC_01.00, r0200, c0010}", "v0001"]
    ],
    "preconditions": [
        ["{is_reporting_entity}", ["v0001"]]
    ],
    "severities": {"v0001": "error"}
}

Example:

dpmcore generate-script \
    --expressions ./rules.json \
    --module-code COREP_Con --module-version 2.0.1 \
    --severity warning --release 4.2 \
    --database sqlite:///dpm.db --output ./script.json

dpmcore export-script

Generate engine-ready DPM-XL validations scripts directly from the database, with no --expressions file. Unlike generate-script, the active validations, preconditions and severities for each module version are discovered from OperationScope / OperationScopeComposition / OperationVersion.

dpmcore export-script (--module-code <code> | --all-modules)
                       (--module-version <ver> | --all-versions | --release <code>)
                       --database <url> [--output <path>]

Options:

Option

Description

--module-code TEXT

Primary module code, e.g. COREP_Con. Required unless --all-modules is given.

--module-version TEXT

Primary module version, e.g. 2.0.1. Mutually exclusive with --all-versions and --release; one of the three is required.

--all-modules

Sweep every module in the database, instead of --module-code.

--all-versions

Sweep every active version of the selected module(s), instead of --module-version. Mutually exclusive with --module-version and --release.

--release TEXT

Release code, e.g. 4.2. Mutually exclusive with --module-version and --all-versions: on its own, resolves each selected module to its single version active at this release. One of --module-version, --all-versions, or --release is required.

--database TEXT

SQLAlchemy database URL. (Required)

--output PATH

Where to write the generated script(s). For a single module/version target, a JSON file path (defaults to <module_code>-<module_version>.json in the current directory). When sweeping (--all-modules/--all-versions), a directory to write one <module_code>-<version>.json file per target into (defaults to the current directory).

Example — single target:

dpmcore export-script \
    --module-code COREP_Con --module-version 2.0.1 \
    --database sqlite:///dpm.db --output ./script.json

Examples — bulk export:

# Every version of every module
dpmcore export-script --all-modules --all-versions \
    --database sqlite:///dpm.db --output ./scripts/

# Every version of one module
dpmcore export-script --module-code COREP_Con --all-versions \
    --database sqlite:///dpm.db --output ./scripts/

# Every module, pinned to its version active at one release (no
# --all-versions: exactly one file per module)
dpmcore export-script --all-modules --release 4.2 \
    --database sqlite:///dpm.db --output ./scripts/

A target that fails to resolve is skipped with a warning instead of aborting the whole sweep; the command exits non-zero if any target failed.

Validations the semantic pass rejects are not part of the script, and neither are validations whose precondition falls outside what the engine can evaluate — a gate may only combine filing indicators, parameters and boolean literals with and / or / xor / not. The console reports how many were skipped next to how many were discovered, and lists the reason per validation; the output JSON file itself carries only the enriched script (matching mdpm’s own export shape), so the console is the only place the skipped-validation reasons are reported. A precondition left gating only rejected validations is dropped from the preconditions block rather than shipped with affected_operations the script does not contain.

dpmcore fix-script

Patches known EBA source-data errors into an already-generated script’s JSON, in place. A fixed set of ~30 validations reproduce a source-data error faithfully – an empty/zero default that should be absent, a literal typed Integer where the engine expects Boolean, etc. – because the underlying DPM database data is wrong for them, not because of a generation bug. EBA doesn’t amend already-published releases, so these stay wrong indefinitely; run fix-script after every export-script/generate-script run, not just once. Ported from mdpm’s mdm-fix-json-values.py; see dpmcore.services.script_fixups for the exact list of fixed validations and why each one is wrong at the data level.

dpmcore fix-script --input-path <path> [--bulk]

Options:

Option

Description

--input-path PATH

A single script .json file, or a directory of them with --bulk. (Required)

--bulk

Treat --input-path as a directory and fix every .json file in it, instead of a single file.

Examples:

# A single script file
dpmcore fix-script --input-path ./script.json

# Every script in a directory (e.g. after a bulk export-script sweep)
dpmcore fix-script --input-path ./scripts/ --bulk

Only rewrites a file when something in it actually matched a known issue; prints which validations were patched per file, or reports that no known issues were found.

dpmcore export-calculations

Export a module version’s calculations set as JSON. Where export-script scripts a module’s validations, this exports the operations linked to the module version through OperationOutput – the ones that write into it.

The calculations are parsed as one script, reordered so a calculation always follows the ones it consumes, and serialized with every operand resolved to its datapoints. Two files are written: the export itself, keyed by the module’s EBA taxonomy URI, and a companion datapoint map naming the cell behind every datapoint the calculations reference.

dpmcore export-calculations --module-code <code>
                            --reference-date <YYYY-MM-DD>
                            --database <url>
                            [--publication-date <YYYY-MM-DD>]
                            [--output <path>] [--datapoints-output <path>]

Options:

Option

Description

--module-code TEXT

Module code whose calculations to export, e.g. KRI. (Required)

--reference-date TEXT

Reference date, YYYY-MM-DD. The module version whose reference-date window contains it is the one exported; exactly one must. (Required)

--database TEXT

SQLAlchemy database URL. (Required)

--publication-date TEXT

Publication date stamped into the dpm_release block. Defaults to today.

--output PATH

Where to write the export. Defaults to <module_code>.json in the current directory.

--datapoints-output PATH

Where to write the companion datapoint map. Defaults to <output-base>_datapoints.json.

Example:

dpmcore export-calculations \
    --module-code KRI --reference-date 2026-12-31 \
    --database sqlite:///dpm.db --output ./kri.json

Note

The command needs a database carrying the OperationOutput table, which links an operation to the module version it writes to. That table exists in the EBA SQL Server DPM databases but not in the Access DPM 2.0 distribution, so a migrated Access database reports the omission instead of exporting an empty set.

Cells are read from each table’s live version – open now and already published – rather than from the version effective at the module’s release, matching the EBA pipeline this export feeds. A table version introduced only in a working (Playground) release therefore never contributes datapoints.

dpmcore export-layout

Export annotated table layouts to Excel workbooks. Generates formatted .xlsx files with hierarchical headers, data-point cells, dimensional annotations, and categorisation tooltips.

Note

Requires the export extra: pip install dpmcore[export]

dpmcore export-layout --database <url> (--module <code> | --tables <codes>) [options]

Options:

Option

Description

--database TEXT

SQLAlchemy database URL. (Required)

--module TEXT

Module version code to export (e.g. FINREP9, AE, DORA). Exports all tables in the module.

--tables TEXT

Comma-separated table codes (e.g. F_01.01,F_05.01).

--release TEXT

Release code filter (e.g. 4.2). Defaults to the current (active) release.

--output PATH

Output file path. Defaults to <module>.xlsx or tables.xlsx.

--no-annotate

Disable dimensional annotations below and to the right of the grid.

--no-comments

Disable Excel comments (tooltips) on headers and data cells.

--derive-missing-variables / --no-derive-missing-variables

In a dictionary under construction, some cells exist before their variable has been generated. By default the export fills those in from the table structure — the property and dimensions of the headers bounding the cell — so the workbook shows the data point the cell is meant to hold. Pass --no-derive-missing-variables to leave them empty.

Examples:

# Export all tables in FINREP
dpmcore export-layout \
    --database sqlite:///dpm.db \
    --module FINREP9 \
    --output finrep.xlsx

# Export specific tables
dpmcore export-layout \
    --database sqlite:///dpm.db \
    --tables F_01.01,F_01.02,F_05.01 \
    --output selected.xlsx

# Export for a specific release, no comments (faster)
dpmcore export-layout \
    --database sqlite:///dpm.db \
    --module AE \
    --release 4.2 \
    --no-comments \
    --output ae.xlsx

# Export a module under construction, showing only the cells whose
# variable already exists
dpmcore export-layout \
    --database sqlite:///dpm.db \
    --module AE \
    --no-derive-missing-variables \
    --output ae.xlsx

Output format:

Each generated workbook contains:

  • An Index sheet with a hyperlinked table of contents, one row per worksheet. When the export finds cells whose variable has not been generated yet, it gains a Cells without a variable column counting them for each worksheet

  • One sheet per table (alphabetically sorted) — or one sheet per Z-axis sheet for tables whose cells are sheet-scoped, named <table code> (<sheet code>) and listed individually in the Index — each with:

    • Table title and optional sheet (Z-axis) header

    • Hierarchical column headers with merged cells

    • Row headers with indentation reflecting the hierarchy

    • Data cells showing the variable_id (data point ID), the data type and the sign recorded on the cell (a cell with no sign shows none); excluded cells are greyed out and void cells get a darker grey

    • Data cells whose variable has not been generated yet shaded in pale orange, and the key cells of an open table in that state flagged in their comment; unless --no-derive-missing-variables was passed, both also show the property and dimensions derived from the table structure

    • The possible values of an enumerated cell listed in its comment: every member of the hierarchy that restricts the cell, indented by its position in it and shown as (signature) label. The key columns of an open table carry the same list. A hierarchy too long for an Excel comment is cut short with an ... and N more lines marker

    • Cells reporting a data point that is also reported elsewhere in the workbook (“identities”) highlighted in yellow, with the other locations listed in the cell comment

    • Dimensional annotations below the grid (for column dimensions) and to the right (for row dimensions), colour-coded per dimension

    • Excel comments on headers and cells showing the variable IDs, identities and dimensional categorisations (Dimension = Member)

    • Outline groups for expanding/collapsing hierarchical rows and columns

    • Frozen panes at the data-area origin

dpmcore generate-graph

Build a portable, self-contained HTML dependency graph from a DPM-XL calculations script. The graph shows the execution order of the operations: one node per operation, one arrow per dependency. The output is a single .html file with its rendering libraries (Cytoscape.js + the dagre layout) embedded inline, so it opens offline and can be attached to a ticket or sent to another person as a single file.

``–database URL`` is always required. The engine resolves every selection’s cells against the DPM dictionary, so dependencies are exact in every mode — row/column ranges and wildcards are expanded to the concrete cells they cover, never approximated. Choose the operations to graph with one input source:

  1. a Code,Expression CSV file (the CSV argument);

  2. one or more inline ``-e CODE=EXPRESSION`` operations (handy for a quick, ad-hoc graph without authoring a file); or

  3. neither — read the DPM dictionary directly (filter with --module / --table).

--release selects the release to resolve against (default: the latest).

dpmcore generate-graph CSV --database URL [--release R] [-o OUT] [-t TITLE]
dpmcore generate-graph -e CODE=EXPRESSION [-e ...] --database URL
                       [--release R] [-o OUT] [-t TITLE]
dpmcore generate-graph --database URL [--module C] [--table T]
                       [--release R] [-o OUT] [-t TITLE]

Arguments / Options:

Argument / Option

Description

CSV

Path to the calculations-script CSV.

-e, --expression CODE=EXPRESSION

An inline operation, given as a Code and its DPM-XL expression separated by = (split on the first =). Repeatable.

--database TEXT (required)

SQLAlchemy database URL. The engine resolves every selection’s cells against this dictionary, so dependencies are exact in all modes.

--module TEXT

Dictionary mode only (no CSV / -e): restrict to operations in this module version code.

--table TEXT

Dictionary mode only (no CSV / -e): restrict to operations referencing this table code.

--release TEXT

Release code to resolve against (e.g. 4.2). Defaults to the latest release.

-o, --output PATH

Output HTML path. Defaults to calculations_graph.html.

-t, --title TEXT

Graph title. Defaults to a title derived from the input.

How dependencies are resolved:

The engine expands every selection to the concrete VariableID set it covers — ranges, wildcards and the sheet dimension included — and draws an implicit edge only on an exact variable match, so overlapping ranges never produce a false dependency.

In the CSV and inline modes each <lhs> <- ...: (<rhs>) assignment is resolved against --database at --release: the left-hand selection is the operation’s output and the right-hand side its inputs.

In the dictionary mode the graph is built from the operations already in the DPM dictionary. Those are stored as validations/equalities (with {scope}: {LHS} = {RHS}); for an = operation the left side is the output and the right the inputs. The full dictionary has thousands of operations, so a --module / --table / --release filter is recommended to keep the graph readable.

Input format:

A CSV with a Code,Expression header. Each row is one operation:

  • Code is the bare operation code. It must not start with o — explicit references use that prefix (see below).

  • Expression is a DPM-XL assignment of the form <lhs selection> <- with {default:..., interval:...}: (<rhs expression>). The left-hand side selection is the operation’s output; the right-hand side reads its inputs through selection operators {...}. Because expressions contain commas, quoting the Expression field is recommended; an unquoted expression is still read in full — everything after the first comma is taken as the expression.

Dependencies:

An arrow A -> B is drawn when operation B depends on A:

  • Implicit — B reads a cell that A writes (matched on the engine-resolved VariableID).

  • Explicit — B references A directly via {o<A-code>}.

Operations with no incoming arrow are roots and are shown in a distinct colour. Click a node to see its output cell and full expression; the panel also offers search/filter and Fit / Re-layout controls.

Note

An operation whose selection cannot be resolved (an unknown table, or a grey cell that carries no variable) is not fatal: its node still renders, its unresolved dependencies are skipped, and a warning is printed. Explicit {o<code>} references need no cell resolution and are always drawn.

Examples:

# CSV script, resolved against the dictionary (default output)
dpmcore generate-graph calculations_script.csv \
    --database sqlite:///dpm.db

# Custom output path, title and release
dpmcore generate-graph calculations_script.csv \
    --database sqlite:///dpm.db \
    --release 4.2 \
    -o output/graph.html \
    -t "COREP calculations"

# Inline expressions, no CSV file needed
dpmcore generate-graph \
    -e "calc1={tK_1.00, r0010, c0010} <- {tK_2.00, r0010, c0010}" \
    -e "calc2={tK_3.00, r0010, c0010} <- {tK_1.00, r0010, c0010} + 1" \
    --database sqlite:///dpm.db \
    -o graph.html

# Dictionary mode: graph the operations already in the DPM (one table)
dpmcore generate-graph \
    --database sqlite:///dpm.db \
    --table C_01.00 \
    -o graph.html

Vendored libraries:

The embedded JavaScript (Cytoscape.js, dagre, cytoscape-dagre — all MIT) is vendored under dpmcore/services/calculations_graph/assets/. Their pinned versions, source URLs and update steps are recorded in assets/VENDOR.md.