Skip to content
This repository was archived by the owner on May 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
98 changes: 98 additions & 0 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Publish wren-core-py 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-wheels:
name: Build wheel — ${{ matrix.os }} (${{ matrix.target }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux x86_64
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
# Linux aarch64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
# macOS x86_64
- os: macos-13
target: x86_64-apple-darwin
# macOS arm64
- os: macos-latest
target: aarch64-apple-darwin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify workflow syntax and runner labels
actionlint -color -oneline .github/workflows/pypi-publish.yml

Repository: Canner/wren-engine

Length of output: 856


Invalid macOS runner label will break the wheel matrix.

Line 34 uses macos-13, which is not a valid GitHub Actions hosted runner label, so that job will fail to start.

💡 Proposed fix
-          - os: macos-13
+          - os: macos-15-intel
             target: x86_64-apple-darwin
@@
-          - os: macos-latest
+          - os: macos-15
             target: aarch64-apple-darwin
🧰 Tools
🪛 actionlint (1.7.11)

[error] 34-34: label "macos-13" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2025-vs2026", "windows-2022", "windows-11-arm", "ubuntu-slim", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26-large", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xlarge", "macos-14-large", "macos-14", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pypi-publish.yml around lines 34 - 38, The job matrix uses
an invalid runner label "macos-13" for the x86_64 job (the entry paired with
target: x86_64-apple-darwin); update that runner label to a valid hosted runner
such as "macos-latest" (or "macos-12") so the workflow can start correctly—i.e.,
replace the "macos-13" value with a supported label next to the
x86_64-apple-darwin target.

# Windows x86_64
- os: windows-latest
target: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Build wheel
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
manylinux: auto
working-directory: wren-core-py
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.target }}
path: wren-core-py/dist/*.whl

build-sdist:
name: Build sdist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
working-directory: wren-core-py
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: sdist
path: wren-core-py/dist/*.tar.gz

publish:
name: Publish to ${{ github.event.inputs.target || 'testpypi' }}
needs: [build-wheels, build-sdist]
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.target || 'testpypi' }}
url: ${{ github.event.inputs.target == 'pypi' && 'https://pypi.org/project/wren-core-py/' || 'https://test.pypi.org/project/wren-core-py/' }}
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true

- 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/
3 changes: 3 additions & 0 deletions wren-core-py/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
62 changes: 52 additions & 10 deletions wren-core-py/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
# 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
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")
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Developer Guide

Expand All @@ -11,14 +36,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
27 changes: 24 additions & 3 deletions wren-core-py/pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
123 changes: 123 additions & 0 deletions wren-core-py/scripts/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/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"
twine check "$DIST_DIR"/* 2>/dev/null || {
if [[ "$MODE" == "build" ]]; then
echo "Warning: twine not available for validation (build-only mode)"
else
exit 1
fi
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validation failures are masked in --build mode.

This block treats any twine check failure as “twine not available” when MODE=build, so real metadata/package errors can pass silently.

💡 Proposed fix
-echo "==> Validating with twine check"
-twine check "$DIST_DIR"/* 2>/dev/null || {
-    if [[ "$MODE" == "build" ]]; then
-        echo "Warning: twine not available for validation (build-only mode)"
-    else
-        exit 1
-    fi
-}
+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
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wren-core-py/scripts/publish.sh` around lines 95 - 101, The current block
runs `twine check "$DIST_DIR"/*` and treats any failure as "twine not available"
when MODE=build, which masks real validation errors; change the logic to first
detect whether the `twine` command exists (e.g., via `command -v twine` or
checking exit status 127) and only suppress validation in build mode when
`twine` is genuinely missing; if `twine` exists but `twine check` returns
non-zero, always treat that as a validation failure (exit non-zero) regardless
of MODE, and if `twine` is missing and MODE==build emit the warning you already
have. Reference: the `twine check` invocation, the `MODE` variable and
`DIST_DIR` glob in the failing block.


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}"
Loading