Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/wren-pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Publish wren-engine to PyPI

permissions:
contents: read
id-token: write # Required for trusted publishing (OIDC)

on:
workflow_dispatch:
inputs:
target:
description: "Publish target"
required: true
default: "testpypi"
type: choice
options:
- testpypi
- pypi

jobs:
build:
name: Build distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install build tool
run: pip install build

- name: Build sdist and wheel
run: python -m build
working-directory: wren

- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: dist
path: wren/dist/

publish:
name: Publish to ${{ github.event.inputs.target || 'testpypi' }}
needs: build
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.target || 'testpypi' }}
url: ${{ github.event.inputs.target == 'pypi' && 'https://pypi.org/project/wren-engine/' || 'https://test.pypi.org/project/wren-engine/' }}
steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: List artifacts
run: ls -lhR dist/

- name: Publish to ${{ github.event.inputs.target }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: ${{ github.event.inputs.target == 'testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
packages-dir: dist/
46 changes: 38 additions & 8 deletions wren/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
# wren-engine

[![PyPI version](https://img.shields.io/pypi/v/wren-engine.svg)](https://pypi.org/project/wren-engine/)
[![Python](https://img.shields.io/pypi/pyversions/wren-engine.svg)](https://pypi.org/project/wren-engine/)
[![License](https://img.shields.io/pypi/l/wren-engine.svg)](https://github.com/Canner/wren-engine/blob/main/LICENSE)

Wren Engine CLI and Python SDK — semantic SQL layer for 20+ data sources.

Translate natural SQL queries through an MDL (Modeling Definition Language) semantic layer and execute them against your database.
Translate natural SQL queries through an [MDL (Modeling Definition Language)](https://docs.getwren.ai/) semantic layer and execute them against your database. Powered by [Apache DataFusion](https://datafusion.apache.org/) and [Ibis](https://ibis-project.org/).

## Installation

```bash
pip install wren-engine[mysql] # MySQL
pip install wren-engine[postgres] # PostgreSQL
pip install wren-engine[duckdb] # DuckDB (local files)
pip install 'wren-engine[memory]' # Schema & query memory (LanceDB)
pip install 'wren-engine[all]' # All connectors + memory
pip install wren-engine # Core (DuckDB included)
pip install wren-engine[postgres] # PostgreSQL
pip install wren-engine[mysql] # MySQL
pip install wren-engine[bigquery] # BigQuery
pip install wren-engine[snowflake] # Snowflake
pip install wren-engine[clickhouse] # ClickHouse
pip install wren-engine[trino] # Trino
pip install wren-engine[mssql] # SQL Server
pip install wren-engine[databricks] # Databricks
pip install wren-engine[redshift] # Redshift
pip install wren-engine[spark] # Spark
pip install wren-engine[athena] # Athena
pip install wren-engine[oracle] # Oracle
pip install 'wren-engine[memory]' # Schema & query memory (LanceDB)
pip install 'wren-engine[all]' # All connectors + memory
```

Requires Python 3.11+.

## Quick start

**1. Create `~/.wren/mdl.json`** — your semantic model:
Expand Down Expand Up @@ -86,10 +102,12 @@ with WrenEngine(manifest_str, DataSource.mysql, {"host": "...", ...}) as engine:

---

## Running tests
## Development

```bash
just install-dev
just install-dev # Install with dev dependencies
just lint # Ruff format check + lint
just format # Auto-fix
```

| Command | What it runs | Docker needed |
Expand All @@ -99,3 +117,15 @@ just install-dev
| `just test-postgres` | PostgreSQL connector tests | Yes |
| `just test-mysql` | MySQL connector tests | Yes |
| `just test` | All tests | Yes |

## Publishing

```bash
./scripts/publish.sh # Build + publish to PyPI
./scripts/publish.sh --test # Build + publish to TestPyPI
./scripts/publish.sh --build # Build only
```

## License

Apache-2.0
3 changes: 2 additions & 1 deletion wren/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ description = "Wren Engine CLI and Python SDK — semantic SQL layer for 20+ dat
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
keywords = ["wrenai", "wren", "sql", "semantic", "mdl", "datafusion"]
authors = [{ name = "Wren AI", email = "contact@getwren.ai" }]
keywords = ["wrenai", "wren", "sql", "semantic", "semantic-layer", "mdl", "datafusion", "data-modeling", "analytics", "database", "cli", "sdk", "python"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
Expand Down
117 changes: 117 additions & 0 deletions wren/scripts/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env bash
#
# Build and publish wren-engine to PyPI or TestPyPI.
#
# Usage:
# ./scripts/publish.sh # build + publish to PyPI
# ./scripts/publish.sh --test # build + publish to TestPyPI
# ./scripts/publish.sh --build # build only (no publish)
#
# Prerequisites:
# - uv (https://docs.astral.sh/uv/)
# - twine (pip install twine) — only needed for publish
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
DIST_DIR="$PROJECT_DIR/dist"

MODE="publish" # publish | test | build
REPOSITORY="pypi"

while [[ $# -gt 0 ]]; do
case "$1" in
--test)
MODE="test"
REPOSITORY="testpypi"
shift
;;
--build)
MODE="build"
shift
;;
-h|--help)
echo "Usage: $0 [--test | --build | -h]"
echo ""
echo " (no flag) Build and publish to PyPI"
echo " --test Build and publish to TestPyPI"
echo " --build Build only, no publish"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done

cd "$PROJECT_DIR"

# --- Check prerequisites ---
if ! command -v uv &>/dev/null; then
echo "Error: 'uv' is not installed. See https://docs.astral.sh/uv/" >&2
exit 1
fi

if [[ "$MODE" != "build" ]]; then
if ! command -v twine &>/dev/null; then
echo "Error: 'twine' is not installed. Run: pip install twine" >&2
exit 1
fi
fi

# --- Read version from __init__.py ---
VERSION=$(sed -nE 's/^__version__\s*=\s*"([^"]+)".*/\1/p' src/wren/__init__.py | head -n1)
if [[ -z "$VERSION" ]]; then
echo "Error: failed to parse __version__ from src/wren/__init__.py" >&2
exit 1
fi
echo "==> Building wren-engine v${VERSION}"

# --- Clean previous dist ---
rm -rf "$DIST_DIR"

# --- Build sdist + wheel ---
echo "==> Running uv build"
uv build

# --- List artifacts ---
echo ""
echo "==> Built artifacts:"
ls -lh "$DIST_DIR"

# --- Validate ---
echo ""
echo "==> Validating with twine check"
if command -v twine &>/dev/null; then
twine check "$DIST_DIR"/*
elif [[ "$MODE" == "build" ]]; then
echo "Warning: twine not installed; skipping validation in build-only mode"
else
echo "Error: 'twine' is not installed. Run: pip install twine" >&2
exit 1
fi

if [[ "$MODE" == "build" ]]; then
echo ""
echo "==> Build complete. Artifacts in: $DIST_DIR"
exit 0
fi

# --- Publish ---
echo ""
if [[ "$REPOSITORY" == "testpypi" ]]; then
echo "==> Publishing to TestPyPI"
echo " After upload, install with:"
echo " pip install --index-url https://test.pypi.org/simple/ wren-engine"
else
echo "==> Publishing to PyPI"
fi
echo ""

twine upload --repository "$REPOSITORY" "$DIST_DIR"/*

echo ""
echo "==> Done! Published wren-engine v${VERSION} to ${REPOSITORY}"
2 changes: 1 addition & 1 deletion wren/src/wren/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Wren — semantic SQL layer for 20+ data sources."""

__version__ = "0.0.1"
__version__ = "0.1.0"

from wren.engine import WrenEngine
from wren.model.data_source import DataSource
Expand Down
8 changes: 8 additions & 0 deletions wren/src/wren/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,14 @@ def _print_result(table, output: str) -> None:
typer.echo(str(table))


@app.command()
def version():
"""Print the wren-engine version."""
from wren import __version__ # noqa: PLC0415

typer.echo(f"wren-engine {__version__}")


try:
import lancedb # noqa: PLC0415, F401
import sentence_transformers # noqa: PLC0415, F401
Expand Down
Loading