Python API¶
The dosi-engine wheel puts Dosi in your Python process as the module
dosi_engine: the same compiler, connectors and error contract as the
CLI and the REST API, with DuckDB and every warehouse
driver built in.
Install¶
Needs Python 3.12+:
Example¶
from dosi_engine import Engine, QueryError
engine = Engine(model_path="model.yaml")
engine.metrics() # [{"name": "revenue", "kind": "aggregate", ...}, ...]
engine.compile(
{"metrics": ["revenue"], "group_by": [{"field": "orders.status"}]},
dialect="snowflake",
) # {"dialect": "snowflake", "sql": "SELECT ...", ...}
engine.execute(
{"metrics": ["revenue"], "group_by": [{"field": "orders.status"}],
"order_by": [{"key": "status"}]},
db_path="orders.duckdb",
) # {"columns": [...], "rows": [{"status": ..., "revenue": ...}], "row_count": 3, ...}
try:
engine.compile({"metrics": ["revenu"]})
except QueryError as e:
e.code, e.candidates # ("unknown_metric", ["revenue", "order_count", ...])
Queries and results are the same JSON as dosi --format json and the
REST API: a query dict here is the request body there.
Engine¶
Engine(...) loads, validates and compiles one model, and raises ModelError
if any of that fails. One engine serves concurrent calls; compile and execute
release the GIL.
| Argument | Meaning |
|---|---|
model_path / model_text |
The model, as a file (or a directory read as a catalog) or as YAML text |
connections |
Warehouse connections as a dict, in the connections file vocabulary. The module never reads a connections file itself |
pool_size |
Connection-pool cap per connection (default 8) |
mode |
"datus" (default) honours the Datus extensions; "basic" is strict standard Apache Ossie |
ontology_path / ontology_text, mapping_path / mapping_text |
An ontology and its mapping, keyword-only |
| Method | Returns |
|---|---|
metrics(), datasets(), dimensions(metric=None) |
The model's metrics, datasets and dimensions |
metric(name), dataset(name) |
One of them in full, like dosi show |
compile(query, dialect=None, connection=None, pretty=False) |
The SQL for a metric query, without running it |
execute(query, dialect=None, connection=None, timeout_secs=None, db_path=None) |
The query's rows |
compile_select(...), select(...) |
The same for a detail query |
explain(query), explain_select(query) |
The logical plan, as text |
attribute(request, ...) |
Why a metric changed between two periods; see Metric attribution |
lineage(redact_sql=False) |
The lineage graph; see Metric lineage |
describe(name=None), paths(source, target) |
The ontology's concepts and the paths between them |
warnings |
Construction warnings, such as extensions ignored in basic mode |
execute without connection runs on the connection marked default: true
when there is one, else on local DuckDB: the db_path file, or an in-memory
database. compile, execute, select and attribute also take a SQL
policy; see SQL policy providers.
Errors¶
Every error is a subclass of OsiError and carries the same code,
candidates and hint as the CLI and REST JSON: ModelError when a model
does not load, QueryError for a query that cannot be planned, ExecuteError
for a failure in the warehouse. The codes are listed in
Errors.
What the installed engine supports¶
Module constants report what this build implements: the same content as
dosi info. A tool that generates models reads them before it chooses which
Datus extension keys to write.
| Name | Content |
|---|---|
__version__ |
The engine version, such as '0.2.1' |
SPEC_VERSION |
The Apache Ossie core spec version, such as '0.2.0.dev0' |
DATUS_EXT_VERSION |
The Datus extension version, such as '1.12' |
DATUS_EXT |
Every Datus extension key, with the version that introduced it and what ignoring it costs; see Extension versions |
DIALECTS |
The SQL dialects compile accepts |
CONNECTION_TYPES |
The connection type values connections accepts |
DATUS_AUTHORING_CONTRACT, DATUS_AUTHORING_CONTRACT_DIGEST |
The full contract for writing a model, and its digest |
Agent integrations take the authoring contract from the installed engine instead of keeping a copy of their own:
import dosi_engine
prompt_yaml = dosi_engine.render_datus_authoring_spec()
digest = dosi_engine.DATUS_AUTHORING_CONTRACT_DIGEST
The contract is dialect-neutral: pass the active SQL dialect to the agent separately, since it depends on the datasource and not on the engine. The digest stays the same while the contract does, so it can key a prompt cache.
dosi_engine.validate(model_text, mode="datus") checks model text without
building an engine. It never raises for problems in the model; it returns
{"valid", "issues", "compile_errors", "warnings", ...}.
Coming from datus_osi_engine¶
The package was previously named datus-osi-engine (module
datus_osi_engine); it is now dosi-engine (module dosi_engine). The
environment variables and the connections file were renamed with it:
OSI_* became DOSI_*, ./osi-connections.yaml became
./dosi-connections.yaml, and ~/.config/osi/ became ~/.config/dosi/.
The old file paths are still found as fallbacks; the old environment
variables are not.