Skip to main content
Archived

This project has been archived by its maintainers, and is no longer receiving any updates.

PredQL

PredQL (Predictive Query Language) is a Python framework for writing compact, expressive predictive queries over relational data, especially for Relational Deep Learning.

It lets you write shorter, more expressive queries by abstracting temporal joins and complex aggregations.

🧠 Features

  • 🎯 ANTLR-based Parser

    • Lexer and parser for PredQL syntax
  • 🌳 Structured parse-tree visitor

    • Converts parsed queries into normalized dictionaries with source positions.
  • 🔍 Semantic validation

    • Schema-aware query validation with error reporting.
  • 🔀 Two converters

    • 📌 SConverter for static prediction queries.
    • ⏰ TConverter for temporal prediction queries with timestamp windows.
  • ⚙️ Dual output mode

    • execute=False returns generated SQL.
    • execute=True executes SQL and returns a Table object.

⚙️ Installation

Install PredQL via pip:

pip install predql

🚀 Quickstart

1. Build your database as RelBench Database object or use simplified PredQL version

# path to classes
from predql.base import Database, Table

2. Static query with SConverter

from predql.converter import SConverter

converter = SConverter(db)

predql_query = """
    PREDICT COUNT_DISTINCT(votes.* 
        WHERE votes.votetypeid == 2)
    FOR EACH posts.* WHERE posts.PostTypeId == 1
                       AND posts.OwnerUserId IS NOT NULL
                       AND posts.OwnerUserId != -1;
"""

# SQL only
sql_query = converter.convert(predql_query, execute=False)

# execute and get Table(fk, label)
table = converter.convert(predql_query, execute=True)

3. Temporal query with TConverter

import pandas as pd
from predql.converter import TConverter

timestamps = pd.Series(...) # define timestamps for which prediction must be made
converter = TConverter(db, timestamps)

# also, it is possible to update prediction timestamps later without recreating converter
converter.set_timestamps(new_timestamps)

predql_query = """
    PREDICT COUNT_DISTINCT(votes.* 
        WHERE votes.votetypeid == 2, 0, 91, DAYS)
    FOR EACH posts.* WHERE posts.PostTypeId == 1
                       AND posts.OwnerUserId IS NOT NULL
                       AND posts.OwnerUserId != -1;
"""

# SQL only
sql_query = converter.convert(predql_query, execute=False)

# execute and get Table(fk, timestamp, label)
table = converter.convert(predql_query, execute=True)

📐 Query Language

📌 Static query design

PREDICT <aggregation | expression | table.column> [RANK TOP K | CLASSIFY]
FOR EACH <entity_table>.<primary_key>
[WHERE <static_condition | static_nested_expression>];

⏰ Temporal query shape

PREDICT <aggregation | temporal_expression> [RANK TOP K | CLASSIFY]
FOR EACH <entity_table>.<primary_key> [WHERE <static_condition | static_nested_expression>]
[ASSUMING <temporal_condition | temporal_nested_expression>]
[WHERE <temporal_condition | temporal_nested_expression>];

🧮 Aggregations

Function Meaning Condition-Compatible
AVG average ✅
MAX maximum ✅
MIN minimum ✅
SUM sum ✅
COUNT non-null count ✅
COUNT_DISTINCT distinct count ✅
FIRST earliest value by time ✅
LAST latest value by time ✅
LIST_DISTINCT list of distinct values ❌

🧭 Temporal window rules

  • Window format: <start>, <end>, <measure_unit>.
  • Supported units: YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS.
  • Window semantics are half-open: (start, end].
  • PREDICT/WHERE: start and end must be non-negative.
  • ASSUMING: start and end must be non-positive.
  • start must be strictly less than end.

🏗️ Architecture

PredQL Query String
    ↓
[Lexer] -> Tokens
    ↓
[Parser] -> Parse Tree
    ↓
[Visitor] -> Structured Dictionary
    ↓
[Validator] -> Semantic Checks
    ↓
[Converter] -> SQL Query
    ↓ (optional execute=True)
[DuckDB] -> Result Table

🔧 Development

Install uv

  • macOS & Linux
wget -qO- https://astral.sh/uv/install.sh | sh
  • Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Install dependencies

uv sync --all-extras

Regenerate parser files

If you modify lexer or parser grammar files (*.g4), regenerate ANTLR outputs from the repo root:

./regenerate_parser.sh

Run tests

pytest

Run linter

ruff check .

Metadata

Release files for predql 0.1.0

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

Source distribution (sdist)

Source distribution for predql 0.1.0
File Size Uploaded Provenance Actions
predql-0.1.0.tar.gz 77.9 kB With provenance Details for predql-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for predql 0.1.0
File Interpreter ABI Platform Actions
predql-0.1.0-py3-none-any.whl Python 3 none any Details for predql-0.1.0-py3-none-any.whl

Total release size: 166.3 kB

Release files / predql-0.1.0.tar.gz

Download URL predql-0.1.0.tar.gz
Size 77.9 kB
Tags Source
SHA-256 checksum
How to use checksums
1cd5c378915764cd4fd916e60a5c128fa64d2bdc8b67bb87c5596c8371e71a00
BLAKE2b-256 checksum
How to use checksums
67803248d16ff1d527814d1eb8c29898c78b08a53f61f8e4ae86bdd124027eaa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Apr 6, 2026.

Transparency log

Release files / predql-0.1.0-py3-none-any.whl

Download URL predql-0.1.0-py3-none-any.whl
Size 88.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f0d397eca1b5632568f2f5671eecd38ef29cadb326ab0297171a511728e3dc69
BLAKE2b-256 checksum
How to use checksums
5d48a968495d95fa3b9b471419a5a01fbc4f8ea154525c40f72b2fe8d6e9be1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Apr 6, 2026.

Transparency log

Security for predql 0.1.0

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 predql-0.1.0.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 Apr 6, 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.

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