chore: add PyPI publishing infrastructure for wren-core-py (#1496)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jax Liu
2026-04-01 11:25:23 +08:00
committed by GitHub
co-authored by Claude Opus 4.6
parent c7e7133d65
commit 760aac4e78
5 changed files with 205 additions and 14 deletions
+3
View File
@@ -2,6 +2,9 @@
name = "wren-core-py"
version = "0.1.0"
edition = "2021"
description = "Python bindings for Wren Engine semantic layer (wren-core)"
license = "Apache-2.0"
repository = "https://github.com/Canner/wren-engine"
include = ["/src", "pyproject.toml", "Cargo.toml", "Cargo.lock"]
[lib]
+53 -10
View File
@@ -1,6 +1,32 @@
# Wren Core Python binding
# Wren Core Python Binding
This is a python binding for [wren-core](../wren-core). It uses [PyO3](https://github.com/PyO3/pyo3) to build the required wheel for [ibis-server](../ibis-server/).
Python bindings for [wren-core](../wren-core), the Rust semantic engine behind [Wren Engine](https://github.com/Canner/wren-engine). Built with [PyO3](https://github.com/PyO3/pyo3) and [Maturin](https://github.com/PyO3/maturin).
Wren Engine translates SQL queries through a semantic layer (MDL - Modeling Definition Language) and executes them against 22+ data sources (PostgreSQL, BigQuery, Snowflake, etc.).
## Installation
```bash
pip install wren-core-py
```
Requires Python >= 3.11.
## Quick Start
```python
from wren_core import SessionContext, to_manifest
# Load an MDL manifest from a base64-encoded JSON string
base64_mdl_json = "<your-base64-encoded-mdl-json>"
manifest = to_manifest(base64_mdl_json)
# Create a session context for query planning
ctx = SessionContext(manifest, remote_functions=[])
# Transform a SQL query through the semantic layer
planned_sql = ctx.transform_sql("SELECT * FROM my_model")
```
## Developer Guide
@@ -11,14 +37,31 @@ This is a python binding for [wren-core](../wren-core). It uses [PyO3](https://g
- Install [poetry](https://github.com/python-poetry/poetry)
- Install [casey/just](https://github.com/casey/just)
### Test and build
After install `casey/just`, you can use the following command to build or test:
- Execute `just install` to create Python venv and install dependencies.
- **Important**: Before testing Python, you need to build the Rust package by running `just develop`.
- Use `just test-rs` to test Rust only, and `just test-py` to test Python only.
- Use `just test` to test Rust and Python.
- Execute `just build` to build the Python package. You can find the wheel in the `target/wheels/` directory.
### Test and Build
After installing `casey/just`, you can use the following commands:
- `just install` — Create Python venv and install dependencies.
- `just develop` — Build the Rust package for local development (**required before running Python tests**).
- `just test-rs` — Run Rust tests only.
- `just test-py` — Run Python tests only.
- `just test` — Run both Rust and Python tests.
- `just build` — Build the Python wheel. Output goes to `target/wheels/`.
### Coding Style
Format via `just format`
Format via `just format`.
### Publishing
See `scripts/publish.sh` for local publishing to PyPI/TestPyPI:
```bash
./scripts/publish.sh --build # Build wheel only
./scripts/publish.sh --test # Build + publish to TestPyPI
./scripts/publish.sh # Build + publish to PyPI
```
## License
Apache-2.0
+1 -1
View File
@@ -150,4 +150,4 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = ">=3.11"
content-hash = "038d17d7d6e90435edd346fa7552b6dcc7193d0f4b1a257e8b0da8c2720fe2bd"
content-hash = "3560f376f36040614abcd7694537b1de69e8fda39be75a63b213c2c2c857541f"
+24 -3
View File
@@ -1,13 +1,34 @@
[project]
name = "wren-core-py"
classifiers = ["Programming Language :: Python :: 3.11"]
version = "0.1.0"
description = "Python bindings for Wren Engine semantic layer (wren-core)"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
authors = [{ name = "Wren AI", email = "contact@getwren.ai" }]
keywords = ["sql", "semantic-layer", "data-modeling", "analytics", "wren", "wrenai", "datafusion"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Rust",
"Topic :: Database",
"Topic :: Software Development :: Libraries :: Python Modules",
]
[project.urls]
Homepage = "https://www.getwren.ai/"
Repository = "https://github.com/Canner/wren-engine"
Issues = "https://github.com/Canner/wren-engine/issues"
[tool.poetry]
name = "wren-core-py"
version = "0.1.0"
description = ""
authors = ["Canner <dev@cannerdata.com>"]
description = "Python bindings for Wren Engine semantic layer (wren-core)"
authors = ["Wren AI <contact@getwren.ai>"]
[tool.poetry.dependencies]
python = ">=3.11"
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
#
# Build and publish wren-core-py 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:
# - Rust toolchain (rustup, cargo)
# - maturin (pip install maturin)
# - twine (pip install twine)
#
# Environment variables (optional):
# MATURIN_ARGS — extra args passed to maturin build (e.g. "--target x86_64-unknown-linux-gnu")
#
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 ---
for cmd in cargo maturin; do
if ! command -v "$cmd" &>/dev/null; then
echo "Error: '$cmd' is not installed." >&2
exit 1
fi
done
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 Cargo.toml ---
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
echo "==> Building wren-core-py v${VERSION}"
# --- Clean previous dist ---
rm -rf "$DIST_DIR"
mkdir -p "$DIST_DIR"
# --- Build wheel ---
echo "==> Running maturin build --release"
maturin build --release --out "$DIST_DIR" ${MATURIN_ARGS:-}
# --- Build sdist ---
echo "==> Running maturin sdist"
maturin sdist --out "$DIST_DIR"
# --- 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-core-py"
else
echo "==> Publishing to PyPI"
fi
echo ""
twine upload --repository "$REPOSITORY" "$DIST_DIR"/*
echo ""
echo "==> Done! Published wren-core-py v${VERSION} to ${REPOSITORY}"