Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

duckdb-kql

CI Oracle PyPI Python versions License: MIT Typed

Run Kusto KQL queries on DuckDB, from Python. Pure Python, no server, no JVM.

Status: pre-alpha. The API is settling but not frozen. Coverage is real and measured — see Coverage — and anything outside it raises rather than guessing.

import duckdb_kql

con = duckdb_kql.connect()
con.sql("CREATE TABLE Logs AS SELECT * FROM 'logs.parquet'")

df = duckdb_kql.df(con, """
    Logs
    | where Timestamp > ago(1d) and Level == "Error"
    | summarize Count = count() by bin(Timestamp, 1h), Component
    | sort by Timestamp asc
""")

New here? Start with Getting started.

Install

Install only the layer you need — each adds one dependency.

pip install duckdb-kql              # translate KQL to SQL         (antlr4 only)
pip install 'duckdb-kql[duckdb]'    # ... and run it               (+ duckdb)
pip install 'duckdb-kql[kusto]'     # ... via the Kusto SDK API    (+ pandas)
pip install 'duckdb-kql[all]'       # everything

Python 3.10 or newer. Fully typed — the package ships py.typed, so your type checker sees real types across all three layers (details).

No-runtime-dependency option

Translate at build time and the output has no dependency on this package at all — not even Python. Only your CI machine installs it.

duckdb-kql queries/ -o build/sql/ --check   # fails the build if a .sql is stale

See Build-time translation.

Three layers

Layer Import Needs For
0 duckdb_kql antlr4-python3-runtime KQL text in, DuckDB SQL out. No database involved.
1 duckdb_kql.engine + duckdb Running the translated SQL.
2 duckdb_kql.kusto + pandas A drop-in for azure-kusto-data's KustoClient.

Importing duckdb_kql never imports duckdb, so Layer 0 genuinely installs and runs without a database.

Layer 0 — translate

>>> import duckdb_kql
>>> duckdb_kql.to_sql("print x = 1 + 1")
'SELECT (CAST(1 AS BIGINT) + CAST(1 AS BIGINT)) AS "x"'

>>> duckdb_kql.validate("Logs | where Level ==")
[Diagnostic(span=SourceSpan(line=1, column=21), message="mismatched input '<EOF>' ...")]

Layer 1 — execute

import duckdb_kql

con = duckdb_kql.connect("analytics.duckdb")   # duckdb.connect + TimeZone=UTC
rel = duckdb_kql.kql(con, "StormEvents | summarize n = count() by State")
rel.fetchall()

Layer 2 — the Kusto SDK interface

For code already written against azure-kusto-data: change the import and the connection string, leave the queries alone.

from duckdb_kql.kusto import KustoClient, ClientRequestProperties
from duckdb_kql.kusto.helpers import dataframe_from_result_table

client = KustoClient("analytics.duckdb")
props = ClientRequestProperties()
props.set_parameter("state", user_input)

response = client.execute("Storm", """
    declare query_parameters(state:string);
    StormEvents | where State == state | take 10
""", props)

df = dataframe_from_result_table(response.primary_results[0])

Details, including what it refuses and why: docs/kusto-client.md.

Query parameters

Never build a query by concatenating strings. Declare parameters and pass values; they are bound as values, so the generated SQL contains no caller-controlled text at all.

duckdb_kql.kql(con, """
    declare query_parameters(state:string);
    StormEvents | where State == state
""", {"state": user_input})     # safe whatever user_input contains

Coverage

Measured against the real KQL engine (the Kusto Emulator), not asserted.

Doc-corpus cases matching ground truth 245 of 1036 (0 mismatches)
Azure Monitor's published KQL subset 114 / 119 (96%)
Tabular operators 15 / 41
Scalar functions / aggregates / binary operators 110 / 19 / 33

Supported operators: where, project, project-away, project-rename, extend, summarize, join, mv-expand, distinct, count, sort / order by, take / limit, render; sources print, datatable, range, and tables; plus let and declare query_parameters.

The support matrix lists every operator, function and type — supported or not — with the known limitations and Kusto discrepancies for each. It is generated from the translator's own registries and probed at build time, so it cannot claim support that does not exist.

Why refusal matters

The failure mode this project is built to avoid is not a crash — it is a query that runs and returns a different answer than Kusto would. KQL and SQL look alike in places where they behave differently: % is a mathematical modulo in KQL and takes the dividend's sign in DuckDB; extract's arguments are in the opposite order; KQL weeks start on Sunday; make_datetime truncates where make_timestamp rounds. Every mapping is verified against the emulator rather than inferred from documentation, and where an honest mapping does not exist — hash_xxhash64, datetime_part('nanosecond') — the answer is an error, not an approximation.

Documentation

Document What it covers
Getting started Install, first query, the three layers
KQL support matrix Every operator and function, supported or not, each with its gotchas
Build-time CLI Translating .kql to .sql in CI, to avoid a runtime dependency
API reference Every public function and type
Kusto SDK compatibility What Layer 2 implements, no-ops, and refuses
Azure Monitor profile Coverage against a published KQL subset
docs/TRANSLATION.md Normative KQL→DuckDB mapping spec (R1–R12)
docs/implementation-plan.md Architecture and milestones
docs/test-plan.md Corpus harvesting, oracle, divergence catalog
docs/kql-on-duckdb-landscape.md Survey of existing KQL-on-DuckDB work
docs/implementation-options.md Six approaches considered, with the chosen one
docs/m0-grammar-spike.md Grammar viability result
docs/frequency-scan-results.md What KQL constructs actually get used
docs/licensing.md Third-party licensing review
demo/ Notebook tour of all three layers, with outputs
CONTRIBUTING.md How to add a mapping, and when not to
SECURITY.md Reporting vulnerabilities; what is in scope
Releases What changed, and when

Design

The parser is generated by ANTLR from Microsoft's own Apache-2.0 KQL grammar. Translation targets DuckDB SQL as a chain of CTEs — one per KQL operator — so DuckDB does all execution and optimization, and the generated SQL stays readable.

Development

pip install -e ".[dev]"
pytest

tools/regen_parser.sh        # regenerate the parser (maintainers; needs Java)

The acceptance suite compares against the Kusto Emulator, which runs in Docker; see docs/oracle-harness.md. It is a development and CI tool only — never a runtime dependency, and never redistributed.

License

MIT — see LICENSE. Vendors an Apache-2.0 grammar and MIT-licensed documentation samples; see THIRD-PARTY-NOTICES.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

duckdb_kql-0.0.1.dev2.tar.gz (524.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

duckdb_kql-0.0.1.dev2-py3-none-any.whl (318.6 kB view details)

Uploaded Python 3

File details

Details for the file duckdb_kql-0.0.1.dev2.tar.gz.

File metadata

  • Download URL: duckdb_kql-0.0.1.dev2.tar.gz
  • Upload date:
  • Size: 524.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for duckdb_kql-0.0.1.dev2.tar.gz
Algorithm Hash digest
SHA256 55dbb87d19c106a5e96f7d92baac1123d00d2c73ccddcb41295f6d563af12ee3
MD5 639a86c6c6420c2c0baac01eabb445eb
BLAKE2b-256 6511623821d8dcd27261d79eb91e853ae01748c11a29ae606515b3d7e1198003

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckdb_kql-0.0.1.dev2.tar.gz:

Publisher: release.yml on mmaitre314/duckdb-kql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckdb_kql-0.0.1.dev2-py3-none-any.whl.

File metadata

  • Download URL: duckdb_kql-0.0.1.dev2-py3-none-any.whl
  • Upload date:
  • Size: 318.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for duckdb_kql-0.0.1.dev2-py3-none-any.whl
Algorithm Hash digest
SHA256 52fca3c0d7c6e22e8b6026a4c4a4993df1384e314c7f21888a8bac2035c347e1
MD5 07f087156a98e77325f1c6a588d81dfc
BLAKE2b-256 c2553d2b12cc85fc0b4aec94378e5072c9ced159d1bd35e842c314a1651a0c2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckdb_kql-0.0.1.dev2-py3-none-any.whl:

Publisher: release.yml on mmaitre314/duckdb-kql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.0.15

2 files

0.0.14

2 files

0.0.13

2 files

0.0.12

2 files

0.0.11

2 files

0.0.10

2 files

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

This release

0.0.1.dev2 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page