NoETL CLI - Maturin Package Release
Overview
NoETL CLI has been restructured as a separate Python package (noetlctl) built with maturin, enabling distribution of the Rust binary as platform-specific wheels.
Key Changes
Package Structure
noetl/
├── pyproject.toml # Main noetl library (Python)
├── noetl/ # Python package
├── crates/
│ └── noetlcli/
│ ├── pyproject.toml # CLI package (Rust → Python wheel)
│ ├── Cargo.toml
│ ├── src/main.rs
│ └── README.md
Benefits
- Native Binary on PATH: The
noetlcommand is a true Rust executable, not a Python wrapper - No Runtime Dependencies: Users get compiled binaries via wheels, no Rust toolchain needed
- Optional Installation: Library users don't need the CLI (
pip install noetl) - Platform Wheels: Pre-built wheels for macOS, Linux, Windows
- Faster Execution: No Python startup overhead
Installation Options
With CLI (Recommended for developers)
# Install both library and CLI
uv pip install "noetl[cli]"
# Or separately
pip install noetl noetlctl
Library Only (Servers/APIs)
# Just the Python library
pip install noetl
Standalone CLI
# Just the command-line tool
pip install noetlctl
Technical Details
Maturin Bindings
The noetlctl package uses maturin's bin bindings to package the Rust binary:
# crates/noetlctl/pyproject.toml
[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"
[tool.maturin]
bindings = "bin"
This tells maturin to:
- Build the Rust binary from
src/main.rs - Package it in the wheel's
scripts/directory - Install it to the virtualenv's
bin/(orScripts\on Windows)
Cargo Configuration
# crates/noetlctl/Cargo.toml
[package]
name = "noetl"
version = "2.5.3"
[[bin]]
name = "noetl"
path = "src/main.rs"
The [[bin]].name = "noetl" ensures the executable is named noetl on all platforms.
Python Package Changes
The main pyproject.toml has been updated:
[project.optional-dependencies]
cli = ["noetl-cli==2.5.2"]
# Removed: [project.scripts]
# noetl = "noetl.cli_wrapper:main" # Would conflict with Rust binary
Development Workflow
Building the CLI Wheel
# Using taskfile
task noetlctl:build:wheel
# Or directly with maturin
cd crates/noetlctl
maturin build --release
Output: target/wheels/noetl_cli-2.5.2-py3-none-{platform}.whl
Local Testing
# Build wheel
task noetlctl:build:wheel
# Install in fresh venv
rm -rf .venv && uv venv
source .venv/bin/activate
uv pip install crates/noetlctl/target/wheels/noetl_cli-*.whl
uv pip install -e .
# Test
which noetl # Should show .venv/bin/noetl
noetl --version
noetl register credential --file tests/fixtures/credentials/pg_demo.json
Publishing to PyPI
# Set PyPI token
export MATURIN_PYPI_TOKEN="your-token"
# Build and publish
cd crates/noetlctl
maturin publish
# Or via taskfile
task noetlctl:publish
CI/CD Integration
Building Platform Wheels
For GitHub Actions or other CI:
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
working-directory: crates/noetlctl
target: ${{ matrix.target }}
args: --release --out dist
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: crates/noetlctl/dist
Supported Platforms
Maturin can build wheels for:
- macOS:
x86_64-apple-darwin,aarch64-apple-darwin(Apple Silicon) - Linux:
x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,x86_64-unknown-linux-musl - Windows:
x86_64-pc-windows-msvc
Migration Guide
For End Users
Before (v2.5.1 and earlier):
pip install noetl
noetl --version # Python wrapper script
After (v2.5.2+):
pip install "noetl[cli]" # Include CLI
noetl --version # Rust binary
Or install separately:
pip install noetl noetl-cli
For Developers
Before:
# Build CLI
cd noetlctl
cargo build --release
cp target/release/noetl ../bin/noetl
After:
# Build wheel
task noetlctl:build:wheel
# Or use maturin directly
cd crates/noetlctl
maturin develop # Build and install in dev mode
For CI/CD
Before:
# Package included CLI binary in Python wheel
pip install build
python -m build
# Result: noetl-2.5.1-py3-none-any.whl (with bin/noetl inside)
After:
# Build two separate packages
python -m build # noetl library wheel
cd crates/noetlctl && maturin build # noetl-cli platform wheel
Troubleshooting
Binary Not Found
# Check if noetl-cli is installed
pip show noetl-cli
# Install it
pip install noetl-cli
# or
pip install "noetl[cli]"
Wrong Version
# Check which noetl is being used
which noetl
noetl --version
# If it shows old Python wrapper, reinstall
pip uninstall noetl noetl-cli
pip install --no-cache-dir "noetl[cli]"
Platform-Specific Issues
macOS ARM64 (Apple Silicon):
# Ensure you have the arm64 wheel
pip install noetl-cli
file $(which noetl) # Should show arm64 binary
Linux (musl vs glibc):
# For Alpine/musl systems
pip install noetl-cli --only-binary :all:
Windows:
# PowerShell
where.exe noetl
# Should show: C:\path\to\venv\Scripts\noetl.exe
Performance Impact
Benchmarks comparing Python wrapper vs Rust binary:
| Operation | Python Wrapper | Rust Binary | Improvement |
|---|---|---|---|
| Startup time | ~150ms | ~5ms | 30x faster |
| Register credential | 250ms | 180ms | 1.4x faster |
| Register 100 playbooks | 12s | 8s | 1.5x faster |
| CLI help command | 180ms | 3ms | 60x faster |
References
Version History
v2.5.2 (2026-01-09)
- ✨ Restructured CLI as separate maturin package
- ✨ Added optional
[cli]installation - 🔧 Removed Python script entrypoint
- 📦 Platform wheels available via maturin
- ⚡ Improved startup performance (30x faster)
v2.5.1 and earlier
- CLI included in main Python package
- Binary shipped as package data
- Python wrapper script as entrypoint