Skip to main content

duckdb-kql

CI PyPI Python versions

Run Kusto Query Language (KQL) queries on DuckDB in Python. Develop KQL queries locally, run them in unit tests, as part of CI builds, have AI agents verify their work, etc. without the need for network.

import duckdb_kql

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

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

See the demo notebook.

Install

APIs are split into 3 layers to control features and dependencies. Select based on needs.

Layer Install Scenario Dependencies
0 pip install duckdb-kql Translate KQL queries to SQL antlr4 only
1 pip install duckdb-kql[duckdb] Run KQL queries adds duckdb, pytz
2 pip install duckdb-kql[kusto] Run KQL queries via Kusto SDK APIs adds pandas

See Getting started.

To reduce runtime dependencies, translate KQL queries to SQL at build time using the CLI.

duckdb-kql translate -o query.sql query.kql

See Build-time translation.

KustoClient query

Run queries using APIs compatible with Kusto client SDK (azure-kusto-data).

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

client = KustoClient(con)

response = client.execute("NetDefaultDB", """
    Requests
    | where Status >= 500
    | summarize Errors = count() by Service
    | sort by Errors desc
""")

dataframe_from_result_table(table)

See Kusto client.

Local HTTP server

Start a local KQL HTTP server using the CLI.

duckdb-kql serve

Then open https://dataexplorer.azure.com, choose 'Add connection', and enter http://127.0.0.1:31415.

See Kusto server.

Query validation and translation

Use validate() and to_sql() to respectively validate the KQL query and translate it to SQL.

>>> 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>' ...")]

Query parameters

Declare parameters and pass values to defend against query injections.

duckdb_kql.query(con, """
    declare query_parameters(state:string);
    StormEvents | where State == state
""", {"state": user_input})

Scripts

Run several commands at once using scripts. Blank lines separate the statements.

duckdb_kql.script(con, """
    .set-or-replace Errors <| Logs | where Level == "Error"

    .set-or-replace ByComponent <| Errors | summarize n = count() by Component
""")

Also available through the CLI.

duckdb-kql script schema.kql -d logs.duckdb

Cross-cluster queries

Map remote databases to local ones to run queries referencing cross-cluster tables.

duckdb_kql.set_clusters({
    ('cluster1.eastus.kusto.windows.net', 'Customers'): 'Customers',
    ('cluster2.westus.kusto.windows.net', 'Sales'): 'Sales',
})

duckdb_kql.query(con, '''
    cluster('cluster1.eastus.kusto.windows.net').database('Customers').Customers
    | join kind=leftouter (cluster('cluster2.westus.kusto.windows.net').database('Sales').Orders) on CustomerId
    | project-away CustomerId1
''')

Macro expansion and entity groups

Register entity groups to run queries calling macro-expand.

duckdb_kql.set_entity_groups({
    'MyDatabases': ["database('Customers')"]
})

duckdb_kql.query(con, '''
    macro-expand MyDatabases as db ( db.Customers | where Tier == 'Free' ) | count
''')

Stored functions

Register stored functions to run queries calling them against local tables.

duckdb_kql.set_functions([
    'function with (folder = "Tests", docstring = "Reads it") ReadEvents() { Events }',
    'function EventsAbove(x:long = 5) { Events | where Value > x }',
])

duckdb_kql.query(con, '''
    ReadEvents()
    | join kind=inner (EventsAbove(10)) on Value
    | summarize Total = sum(Value)
''')

Pass {None: [...], 'Sales': [...]} to register functions for other attached databases, called as database('Sales').F().

Coverage

Correctness measured against the real KQL engine (the Kusto Emulator).

Doc-corpus cases matching ground truth 355 of 1060 (0 mismatches)
Azure Monitor's published KQL subset 115 / 119 (96%)
Tabular operators 27 / 48
Scalar functions / aggregates / binary operators 115 / 21 / 41

Supported operators: where, project, project-away, project-rename, extend, summarize, join, mv-expand, distinct, count, sort / order by, top, take / limit, union, macro-expand, lookup, parse, parse-where, render; the graph operators make-graph, graph-match, graph-shortest-paths, graph-to-table and graph-mark-components; 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.

Documentation

Document Topics
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
Local Kusto endpoint duckdb-kql serve — query a DuckDB file from the Azure Data Explorer UI
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–R16)
docs/create-database.md Reference notes for .create database, reconstructed from the KQL parser
docs/implementation-plan.md Architecture and milestones
docs/test-plan.md Corpus harvesting, oracle, divergence catalog
docs/code-review/ Review framework: severity scale, reporting format, one checklist per area
docs/maintenance/ Maintenance framework: refactoring gate, technical debt, upgrades, and the metrics that measure them
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 KQL parser is generated by ANTLR from Microsoft's KQL grammar. Translation targets DuckDB SQL as a chain of Common Table Expressions (CTEs), one per KQL operator. DuckDB handles query optimization and execution.

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.

Alternatives

Some other ways to run KQL queries locally:

License

MIT. See LICENSE, THIRD-PARTY-NOTICES.md, and licenses/.

Trademarks

"DuckDB" is a trademark of the DuckDB Foundation. "Kusto", "Azure", and "Azure Data Explorer" are trademarks of Microsoft Corporation. This project is independent and is not affiliated with, endorsed by, or sponsored by either the DuckDB Foundation or Microsoft. Product names are used descriptively, to indicate compatibility.

Metadata

Release files for duckdb-kql 1.0.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for duckdb-kql 1.0.8
File Size Uploaded Provenance
duckdb_kql-1.0.8.tar.gz 1.1 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for duckdb-kql 1.0.8
File Interpreter ABI Platform
duckdb_kql-1.0.8-py3-none-any.whl Python 3 none any Details

Total release size: 1.6 MB

Release files / duckdb_kql-1.0.8.tar.gz

Download URL duckdb_kql-1.0.8.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
ff5757146672cd0b67eea4244518134a352b12a6f0ecc0073c6d0897c43f9250
BLAKE2b-256 checksum
How to use checksums
b6cb91889ebd6e1a48e5ba6370dcbf4ecd3203cc5d4befa01c5aec18984ce7ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / duckdb_kql-1.0.8-py3-none-any.whl

Download URL duckdb_kql-1.0.8-py3-none-any.whl
Size 538.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d87f09d9d4e2127ba54c41d37cd8ca10922ae4e7b7b1a372c3d7982409f6ea80
BLAKE2b-256 checksum
How to use checksums
20660544e9fff7bbb7385b89f6fb4b5b7e7cdbe976e36c6b9dc49bd8a7f89611
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Security for duckdb-kql 1.0.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for duckdb_kql-1.0.8.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.8 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page