Skip to content

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+:

$ pip install dosi-engine
$ python -c "import dosi_engine; print(dosi_engine.__version__)"
0.2.1

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.