Using dpm-xl with AI agents¶
This page is for AI coding agents (and the people prompting them) writing
code that uses dpm-xl. It holds the essential API, the contracts that
matter and the mistakes to avoid. Agents working on the dpm-xl repository
should read
AGENTS.md
instead.
Machine-readable documentation, following llmstxt.org:
llms.txt: an index of every page with a one-line description.llms-full.txt: every page, API reference included, as one Markdown file.- Each page as Markdown: replace the trailing
/of a page URL with.md, for exampleguides/provider.md.
The essential API¶
from dpmxl import (
DataPoint,
CellQuery,
MemoryProvider,
TableLayout,
Number, # data
evaluate_rule,
explain,
SelectionCache, # evaluation
parse,
parse_program,
DpmXlSyntaxError, # parsing
references,
tables, # analysis
axis_matcher, # providers
)
| Call | Returns | Raises |
|---|---|---|
evaluate_rule(expression, provider, *, precondition=None, trace=True, cache=None, only_keys=None) |
RuleResult with status, message, outcomes, failures, counts, evaluation, assignments |
Nothing for bad rules or data: those are statuses |
explain(result.evaluation, expression, outcome.key) |
Explanation with summary, filled, difference, gap, direction, left, right, primary, kind |
|
parse(expression) / parse_program(source) |
Expression tree / Program |
DpmXlSyntaxError (message, position, end, pointer()) |
references(tree), tables(tree, provider=None) |
Selections with context applied; table codes | |
dpmxl.columnar.evaluate_rule_columnar(expression, frame_provider, *, precondition=None, cache=None) |
ColumnarResult with status, passed, failed, null, failing_keys, failing_frame |
ColumnarUnsupported: evaluate with evaluate_rule instead |
Statuses: passed, failed, not_applicable, error, unsupported.
A complete, correct example¶
from dpmxl import (
MemoryProvider,
Number,
SelectionCache,
TableLayout,
evaluate_rule,
explain,
)
provider = MemoryProvider(
[TableLayout("C_01.00", rows=("0010", "0020", "0030"), columns=("0010",))],
{
("C_01.00", "0010", "0010", None, ()): Number.of(1204, 0),
("C_01.00", "0020", "0010", None, ()): Number.of(1180, 0),
("C_01.00", "0030", "0010", None, ()): Number.of(31, 0),
},
)
rules = [
(
"v1",
"with {tC_01.00, c0010, interval: true}: {r0010} = {r0020} + {r0030}",
"{v_C_01.00}",
)
]
cache = SelectionCache()
for code, expression, precondition in rules:
result = evaluate_rule(expression, provider, precondition=precondition, cache=cache)
print(code, result.status, result.message or "")
for outcome in result.failures:
print(" ", explain(result.evaluation, expression, outcome.key).summary)
v1 failed
1,204 should equal 1,211 (1,180 + 31): difference 7, at least 5.5 given the reported precision
Contracts¶
- Providers implement
select(query) -> Sequence[DataPoint],table_reported(table) -> bool | Noneandparameter(name) -> Value; optionallyopen_keys,table_group,operation,earlier_report(Connect your data). selectreturns every defined cell of a closed selection, withvalue=Nonefor unreported ones, and one point per reported key combination for open tables (keys inDataPoint.keys). It raisesLookupErrorfor an unknown table.- Numbers are
Number.of(value, decimals)with the fact's XBRLdecimals(Noneor"INF"for exact). Pass strings orDecimal, not floats, for exact values. MemoryProvidervalue keys are(table, row, column, sheet, keys);keysis a tuple of(name, value)pairs for open tables and()for closed ones. Absent coordinates areNone.- Thread safety:
evaluate_ruleandevaluate_rule_columnarmay run concurrently on one report;parse_cached,SelectionCache,FrameCacheandMemoryProvidermay be shared (Run rules in threads).
Common pitfalls¶
| Mistake | Consequence | Do instead |
|---|---|---|
Returning only reported cells from select for a closed table |
default and isnull never apply; presence checks pass wrongly |
Return every defined cell with value=None |
Number.of(0.1, 2) with a float |
Binary float noise in the value | Number.of("0.1", 2) |
Treating not_applicable or null records as failures |
False alarms | Only status == "failed" / outcome.passed is False are failures |
Expecting evaluate_rule to raise on a bad rule |
Errors go unnoticed | Check result.status in {"error", "unsupported"} and result.message |
Calling explain on a trace=False result or a ColumnarResult |
Wrong or no explanation | Re-run evaluate_rule with the default trace=True for failing rules |
Not catching ColumnarUnsupported |
Rules with scripts, time_shift, sets and more crash |
Catch it and call evaluate_rule |
parse on a script with ;, := or <- |
DpmXlSyntaxError |
parse_program |
Writing a<-1 to compare with -1 |
Parsed as a persistent assignment | a < -1 |
{vX} for a filing indicator |
Reads parameter X |
{v_X} tests the filing indicator |
Keywords run together, such as ornot |
One unknown name: a syntax error | Separate words: or not |
A new SelectionCache per rule |
Every selection is read again | One cache per report |
Where to look next¶
- Quick reference: the language and its grammar on one page.
- Language: every construct with its syntax, types, null behaviour, errors and tested examples.
- Concepts: records and keys, null logic, intervals.
- Python API: every public name.