Skip to main content

Envoxy Platform Framework

Project description

Envoxy Platform Framework

Tests Security Quality Python Code style: ruff Pre-commit

Envoxy is a service platform framework + uWSGI‑based daemon that unifies messaging, persistence, background processing and an opinionated ORM layer. One install gives you structured modules, connectors, conventions and a packaged migration workflow.

📋 Table of Contents

🚀 Quick Start

# Install the framework and uWSGI server
pip install envoxy envoxyd

# Create a new project structure
mkdir my-service && cd my-service

# Create your application (run.py)
# See usage examples below

# Start the uWSGI server
envoxyd --http :8080 --set conf=/path/to/envoxy.json

📦 Installation

Framework Only (Pure Python)

pip install envoxy

This installs the Envoxy framework with all Python dependencies for building services.

With uWSGI Server (Manylinux Binary)

pip install envoxyd

This installs:

  • The envoxy framework (as a dependency)
  • A pre-built envoxyd binary (uWSGI with dynamic Python 3.12 linking)
  • All shared libraries bundled for portability

Note: envoxyd is Linux-only. For development on macOS/Windows, use the framework with your own WSGI server.

Development Installation

# Clone the repository
git clone https://github.com/habitio/envoxy.git
cd envoxy

# Create virtual environment
python3.12 -m venv venv
source venv/bin/activate

# Install in development mode
pip install -e .[dev]

# Install pre-commit hooks
pre-commit install

See CONTRIBUTING.md for detailed development setup.

💡 Usage Examples

PostgreSQL with ORM

from envoxy.db.orm import EnvoxyBase
from sqlalchemy import Column, String

class Product(EnvoxyBase):
    name = Column(String(255), nullable=False)

# Table name: aux_products
# Columns: id, name, created, updated, href

Redis Cache

from envoxy import redisc

# Set value
redisc.set("server_key", "my_key", {"a": 1, "b": 2})

# Get value
val = redisc.get("server_key", "my_key")

# Direct client access
client = redisc.client('server_key')
client.hgetall('my_hash')

MQTT Messaging

from envoxy import mqttc

# Publish
mqttc.publish('server_key', '/v3/topic/channel',
              {"data": "test"}, no_envelope=True)

# Subscribe
def callback(data):
    print(f"Received: {data}")

mqttc.subscribe('server_key', '/v3/topic/channels/#', callback)

CouchDB

from envoxy import couchdbc

# Find documents
docs = couchdbc.find(
    db="server_key.db_name",
    fields=["id", "field2"],
    params={"id": "1234", "field1__gt": "2345"}
)

# Get document
doc = couchdbc.get("005r9odyj...", db="server_key.db_name")

🐳 Docker Support (Development Only)

Local Development Environment

For local development and testing, a Docker Compose setup is available:

cd docker/dev
docker-compose up -d

This starts:

  • PostgreSQL database
  • Redis cache
  • pgAdmin (PostgreSQL GUI)
  • RedisInsight (Redis GUI)

Note: For production deployments, use the envoxyd wheel from PyPI instead of Docker images.

See docker/dev/README.md for development environment documentation.

🔧 Development

Run Tests

# All tests
make test

# Unit tests only
make test-unit

# With coverage
make test-cov

Code Quality

# Lint and format
make lint
make format

# Type checking
make type-check

# Run all CI checks locally
make ci-local

Build Documentation

# Build system documentation
cat docs/BUILD.md

# CI/CD pipeline documentation
cat docs/CI-CD.md

# Testing guide
cat tests/README.md

📦 Publishing Releases

Publishing to TestPyPI (Testing)

TestPyPI is used to test package distribution before publishing to production PyPI.

1. Update Version Numbers

Update the version in both package files:

# Edit pyproject.toml for envoxy
vim pyproject.toml  # Update version = "0.6.10"

# Edit vendors/pyproject.toml for envoxyd
vim vendors/pyproject.toml  # Update version = "0.5.10"

2. Commit and Push Version Changes

git add pyproject.toml vendors/pyproject.toml
git commit -m "chore: Bump version to 0.6.10 / 0.5.10"
git push origin main

3. Automatic TestPyPI Publishing

When you push to main branch, both workflows automatically trigger:

  • envoxy-publish.yml: Builds pure Python wheel → publishes to TestPyPI
  • envoxyd-manylinux.yml: Builds manylinux wheel → publishes to TestPyPI

No manual workflow trigger needed! Every push to main automatically publishes to TestPyPI for testing.

4. Test Installation from TestPyPI

# Create a fresh virtual environment
python3.12 -m venv test-env
source test-env/bin/activate

# Install from TestPyPI (note: --extra-index-url needed for dependencies)
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ envoxy
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ envoxyd

# Verify installation
python -c "import envoxy; print(envoxy.__version__)"
envoxyd --version

# Test basic functionality
python -c "from envoxy.db.orm import EnvoxyBase; print('Import successful')"

Publishing to PyPI (Production)

Production releases require manual workflow dispatch to prevent accidental publishes.

1. Ensure Version is Updated

Make sure pyproject.toml and vendors/pyproject.toml have the correct version numbers and are pushed to main.

2. Create and Push Git Tag

# Create annotated tag (recommended for documentation)
git tag -a v0.6.10 -m "Release version 0.6.10

- Feature: Description of major features
- Fix: Description of bug fixes
- Chore: Infrastructure updates
"

# Push the tag to GitHub
git push origin v0.6.10

Note: Pushing a tag will trigger the workflows to build the packages, but NOT publish to production PyPI.

3. Manual Production Publishing

After pushing the tag and verifying the builds succeeded:

For envoxy (pure Python wheel):

  1. Go to GitHub Actions
  2. Select Build and publish envoxy (pure Python) workflow
  3. Click "Run workflow"
  4. Select the tag (e.g., v0.6.10) from the branch dropdown
  5. Click "Run workflow"

This will publish to production PyPI at https://pypi.org/project/envoxy/

For envoxyd (manylinux binary):

  1. Go to GitHub Actions
  2. Select Build and publish envoxyd (manylinux) workflow
  3. Click "Run workflow"
  4. Select the tag (e.g., v0.6.10) from the branch dropdown
  5. Click "Run workflow"

This will publish to production PyPI at https://pypi.org/project/envoxyd/

4. Verify Production Release

# Install from production PyPI
pip install --upgrade envoxy envoxyd

# Verify versions
pip show envoxy envoxyd

5. Monitor Release

Versioning Guidelines

Follow Semantic Versioning:

  • Major version (1.0.0): Breaking changes
  • Minor version (0.6.0): New features, backward compatible
  • Patch version (0.6.1): Bug fixes, backward compatible

Both envoxy and envoxyd should be versioned together to maintain compatibility:

# Example: Major release
envoxy: 1.0.0
envoxyd: 1.0.0

# Example: Feature release
envoxy: 0.7.0
envoxyd: 0.6.0  # Only if envoxyd has no changes

Troubleshooting

Build fails on GitHub Actions:

  • Check workflow logs in Actions tab
  • Verify all tests pass: make test
  • Ensure dependencies are up to date

TestPyPI/PyPI upload fails:

  • Verify TEST_PYPI_API_TOKEN and PYPI_API_TOKEN secrets are set in repository settings
  • Check if version already exists (PyPI doesn't allow re-uploading same version)
  • Ensure package name is available

envoxyd binary doesn't run:

  • Check RPATH is correct: patchelf --print-rpath $(which envoxyd)
  • Verify shared libraries are bundled: auditwheel show wheelhouse/*.whl
  • Test in clean manylinux container: docker run -it quay.io/pypa/manylinux_2_28_x86_64 bash

📚 Documentation

Core capabilities

  • ZeroMQ / UPnP integration ("Zapata")
  • MQTT / AMQP (RabbitMQ) messaging
  • Celery task dispatch
  • CouchDB & PostgreSQL connectors (direct + SQLAlchemy helpers)
  • Redis cache / key‑value utilities
  • Packaged Alembic migrations & CLI (envoxy-alembic)
  • Opinionated ORM conventions (automatic naming, audit columns, index safety)

Recent additions

  • EnvoxyBase declarative base (prefix + pluralization + audit fields)
  • Idempotent mapper listeners (populate id/created/updated/href)
  • Bundled Alembic config (alembic.ini + env.py) with model auto‑discovery
  • Session helpers: session_scope, transactional

Why

Reduce boilerplate per service, enforce naming consistency across a fleet and make migrations / messaging predictable and safe.

ORM conventions

EnvoxyBase is the unified model base.

Automatic rules:

  • Table prefix: aux_
  • Pluralized class names (with curated exceptions)
  • Audit columns injected: id, created, updated, href
  • Index names rewritten with framework prefix
  • Audit values populated by idempotent listeners

Why aux_? The core Envoxy platform is designed around a ZeroMQ data-layer for primary domain entities. The SQLAlchemy layer is intentionally a secondary/auxiliary persistence mechanism for sidecar tables: caches, denormalized projections, integration state, small feature flags, ephemeral join helpers—NOT the canonical domain records.

The aux_ prefix:

  • Visibly segregates auxiliary tables from core platform data-layer storage.
  • Prevents future naming collisions if a core table later lands in RDBMS form.
  • Makes auditing / cleanup simpler (drop or archive all aux_ tables safely).
  • Signals that schemas can evolve faster with fewer cross‑service guarantees.

Guidelines:

  • Keep business‑critical source-of-truth entities in the primary data-layer.
  • Use ORM aux_ tables for performance, enrichment, or transient coordination.
  • Avoid back‑writing from aux_ tables into the core pipeline except via explicit integration processes.

Minimal model:

from envoxy.db.orm import EnvoxyBase
from sqlalchemy import Column, String

class Product(EnvoxyBase):
    name = Column(String(255), nullable=False)

metadata = EnvoxyBase.metadata  # for Alembic autogenerate

Benefits: consistent naming, fewer conflicts, less boilerplate. More: docs/HOWTO-migrations.md, docs/POSTGRES.md.

Migrations (packaged Alembic)

Run migrations without copying config.

CLI:

envoxy-alembic revision -m "create product table" --autogenerate
envoxy-alembic upgrade head

Module form:

python -m envoxy.tools.alembic.alembic current

Features: packaged config, model discovery, sqlite path normalization, baseline versions. CI helper: python -m envoxy.tools.check_migrations <versions_dir>. Docs: docs/HOWTO-migrations.md.

Daemon & packaging

envoxyd boots service modules via embedded customized uWSGI.

Install (Make):

make install

Docker:

# Development: Quick start with docker-compose (recommended)
cd docker/dev && docker-compose up -d

# Or build builder images manually
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
  -t envoxy-ubuntu:24.04 -f docker/builder/ubuntu-24.04.Dockerfile .

# Production runtime image
docker build -t envoxy:runtime -f docker/runtime/Dockerfile .

See docker/README.md for detailed Docker documentation.

Run:

envoxyd --http :8080 --set conf=/path/to/confs/envoxy.json

Build packages:

make packages

Manual (example):

# Using tools/build.sh (recommended)
./tools/build.sh packages

# Or manually with Python 3.12
python3.12 setup.py sdist bdist_wheel
cd vendors && python3.12 setup.py sdist bdist_wheel
twine upload dist/*

Details: docs/ENVOXYD.md.

Project scaffold

envoxy-cli --create-project --name my-container

Docker (mount volumes):

docker run -it -d -p 8080:8080 \
  -v /path/to/project:/home/envoxy \
  -v /path/to/plugins:/usr/envoxy/plugins envoxy

PostgreSQL (direct connector)

Read-only queries:

from envoxy import pgsqlc
rows = pgsqlc.query("db_name", "select * from sample_table where id = 1;")

Writes: use the ORM (SQLAlchemy) via PgDispatcher.sa_manager() and models. Direct insert() on the raw client is no longer supported by design.

CouchDB

Find:

from envoxy import couchdbc
docs = couchdbc.find(
    db="server_key.db_name",
    fields=["id", "field2"],
    params={"id": "1234", "field1__gt": "2345"}
)

Get:

doc = couchdbc.get("005r9odyj...", db="server_key.db_name")

Redis

from envoxy import redisc
redisc.set("server_key", "my_key", {"a": 1, "b": 2})
val = redisc.get("server_key", "my_key")
client = redisc.client('server_key'); client.hgetall('my_hash')

MQTT

Publish:

from envoxy import mqttc
mqttc.publish('server_key', '/v3/topic/channel', {"data": "test"}, no_envelope=True)

Subscribe:

from envoxy import mqttc
mqttc.subscribe('server_key', '/v3/topic/channels/#', callback)

on_event class:

from envoxy import on
from envoxy.decorators import log_event

@on(endpoint='/v3/topic/channels/#', protocols=['mqtt'], server='server_key')
class MqttViewCtrl(View):
    @log_event
    def on_event(self, data, **kw):
        do_stuff(data)

Low‑level client example: docs/MQTT.md.

Core Documentation

How-To Guides

Additional Resources

🤝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for:

  • Development setup instructions
  • Code style guidelines
  • Testing requirements
  • Pull request process
  • Release workflow

📝 License

See LICENSE for details.

🔗 Links


Made with ❤️ by the Envoxy team

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

envoxy-0.6.21.tar.gz (82.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

envoxy-0.6.21-py3-none-any.whl (91.0 kB view details)

Uploaded Python 3

File details

Details for the file envoxy-0.6.21.tar.gz.

File metadata

  • Download URL: envoxy-0.6.21.tar.gz
  • Upload date:
  • Size: 82.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for envoxy-0.6.21.tar.gz
Algorithm Hash digest
SHA256 ba5e6cbf39a9bf0e68aa5f79bf1e1b1b099a08f448f3c1cabb7541d75ecbe231
MD5 440f471b351efc212ed4026aa7987d6f
BLAKE2b-256 01cc3b76e69e87ed60430143e8f23b777407d2fb1ac439719f0b991541201388

See more details on using hashes here.

File details

Details for the file envoxy-0.6.21-py3-none-any.whl.

File metadata

  • Download URL: envoxy-0.6.21-py3-none-any.whl
  • Upload date:
  • Size: 91.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for envoxy-0.6.21-py3-none-any.whl
Algorithm Hash digest
SHA256 e8b170f2b188e57222a4e0caa2a28b15f046405e462294c3efc52afb5c97b55e
MD5 48879f449b06f9896481118cef25bcef
BLAKE2b-256 4bac5df0542a6fa449dfc9e6df737764bceda9ac74a90a4acab85ff30938a296

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page