Skip to main content

Smart Publisher - CLI/API framework based on SmartSwitch

Project description

Smart Publisher Logo

smpub - Smart Publisher

CLI/API framework based on SmartSwitch

PyPI version Tests codecov Python 3.10+ License: MIT Documentation Part of Genro-Libs LLM Docs


Build CLI and API applications with automatic command dispatch using SmartSwitch.

What is smpub?

The Problem

When you write a Python library, you typically need to provide multiple interfaces:

  • Pythonic API - Import and use directly in code
  • CLI interface - Command-line usage for scripts and users
  • HTTP/API - Web access, integrations, remote calls

Traditionally, this means writing three different interfaces with lots of boilerplate code.

The Solution

smpub (Smart Publisher) offers an elegant approach:

  1. Write your library once using SmartSwitch for method dispatch
  2. Get three interfaces automatically: Python, CLI, and HTTP/API

SmartSwitch provides an elegant Pythonic dispatch system using decorators. smpub takes that dispatch system and automatically transforms it into CLI commands and HTTP endpoints.

Key Concept

Pythonic dispatch (SmartSwitch) → Automatic CLI + HTTP (smpub)

One codebase, three interfaces:

# 1. Your library (uses SmartSwitch for elegant dispatch)
from smartswitch import Switcher

class MyService:
    api = Switcher(prefix='my_')

    @api
    def my_operation(self, param: str):
        """Process a parameter."""
        return {"result": param}

# 2. Publishing layer (uses smpub) - just ~20 lines!
from smartpublisher import Publisher

class MyApp(Publisher):
    def on_init(self):
        self.publish("service", MyService())

Result: Your service is now accessible three ways:

# Python API (direct import)
from myapp import MyService
service = MyService()
service.my_operation("test")
# CLI (automatic)
python myapp.py service operation test

# HTTP API (automatic)
curl http://localhost:8000/service/operation -d '{"param": "test"}'
# Plus OpenAPI/Swagger at /docs

Why SmartSwitch?

SmartSwitch provides an elegant Pythonic dispatch system with:

  • Clean decorator syntax (@api)
  • Plugin chain for cross-cutting concerns (logging, validation, transactions)
  • Type-safe method routing
  • Composable behavior

When you use SmartSwitch, your code is already well-structured for dispatch. smpub simply transforms that dispatch into multiple interfaces.

Learn more: See how a real application uses SmartSwitch plugins in the Demo Shop documentation (SQL database with transaction management, validation, and format negotiation).

Features

  • 🎯 Publisher Pattern - Register handlers and expose them via CLI/API
  • 🔀 SmartSwitch Integration - Rule-based function dispatch
  • 💻 CLI Generation - Automatic command-line interface
  • Pydantic Validation - Automatic type validation and conversion
  • 🎨 Interactive Mode - Optional Textual TUI for parameter prompting
  • 🌐 HTTP/API Mode - FastAPI with OpenAPI/Swagger UI
  • 📝 Registry System - Local/global app registration

Installation

pip install smartpublisher

# With HTTP support
pip install smartpublisher[http]

Quick Start

Workflow

1. Write your code with SmartSwitch → 2. Create Publisher → 3. Get CLI + HTTP API

1. Write Your Service (with SmartSwitch)

from typing import Literal
from smartswitch import Switcher

class AccountHandler:
    # If using __slots__, include 'smpublisher'
    __slots__ = ('accounts', 'smpublisher')
    api = Switcher(prefix='account_')

    def __init__(self):
        self.accounts = {}

    @api
    def account_add(self, name: str, smtp_host: str, smtp_port: int = 587,
                    username: str = "", use_tls: bool = True,
                    auth_method: Literal["plain", "login", "oauth2"] = "plain"):
        """Add a new mail account."""
        self.accounts[name] = {"smtp_host": smtp_host, "smtp_port": smtp_port,
                              "username": username, "use_tls": use_tls}
        return {"success": True, "account": self.accounts[name]}

    @api
    def account_list(self):
        """List all accounts."""
        return {"count": len(self.accounts), "accounts": list(self.accounts.values())}

class MailHandler:
    # If using __slots__, include 'smpublisher'
    __slots__ = ('account_handler', 'messages', 'smpublisher')
    api = Switcher(prefix='mail_')

    def __init__(self, account_handler):
        self.account_handler = account_handler
        self.messages = []

    @api
    def mail_send(self, account: str, to: str, subject: str, body: str,
                  priority: Literal["low", "normal", "high"] = "normal",
                  html: bool = False):
        """Send an email message."""
        message = {"account": account, "to": to, "subject": subject, "body": body}
        self.messages.append(message)
        return {"success": True, "message_id": len(self.messages)}

2. Create Publisher (with smpub)

from smartpublisher import Publisher

class MailApp(Publisher):
    def on_init(self):
        self.account = AccountHandler()
        self.mail = MailHandler(self.account)
        # Publish handlers - that's it!
        self.publish('account', self.account)
        self.publish('mail', self.mail)

if __name__ == "__main__":
    app = MailApp()
    app.run()  # Auto-detect CLI or HTTP mode

3. Use It - Direct Execution

CLI Mode (direct execution):

# Add mail account
python mailapp.py account add work smtp.gmail.com 587 user@work.com

# Send email
python mailapp.py mail send work recipient@example.com "Hello" "Message body"

# Interactive mode (prompts for parameters)
python mailapp.py mail send --interactive

HTTP Mode (automatic):

# Start server (no CLI args = HTTP mode)
python mailapp.py
# Opens Swagger UI at http://localhost:8000/docs

# Call API
curl -X POST http://localhost:8000/mail/send \
  -H "Content-Type: application/json" \
  -d '{"account": "work", "to": "user@example.com", "subject": "Hello", "body": "Message"}'

4. Optional: Register for Global Access

Register your app to use it from anywhere:

# Register app
smpub register mailapp ~/projects/mailapp

# Now use from anywhere
smpub run mailapp account list
smpub serve mailapp  # Start HTTP server

# List registered apps
smpub list

# Unregister
smpub unregister mailapp

When to use registry?

  • You have multiple apps and want to switch between them
  • You want to use your app from any directory
  • You're building reusable tools for your team

Documentation

Main Documentation

For complete framework documentation, visit smartpublisher.readthedocs.io.

Topics covered:

  • Publisher and handler patterns
  • Registry system (register/run apps)
  • CLI command structure
  • HTTP/API mode with FastAPI
  • Type validation with Pydantic
  • Interactive mode with Textual TUI

Real-World Example

For a complete example showing SmartSwitch plugins, database adapters, and advanced patterns, see:

Demo Shop Documentation - E-commerce library with:

  • SQL database system with adapters (SQLite/PostgreSQL)
  • Table managers with CRUD operations
  • SmartSwitch plugin chain (Logging, Pydantic, DbOp)
  • Transaction management
  • Format negotiation (JSON, Markdown, HTML)
  • Published in ~20 lines with smpub

The demo shows how a well-structured SmartSwitch application becomes trivial to publish.

Part of Genro-Libs Family

smpub is part of the Genro-Libs toolkit, a collection of general-purpose Python developer tools.

Related Projects:

  • smartswitch - Rule-based function dispatch (used by smpub)
  • gtext - Text transformation tool

Requirements

  • Python 3.10+
  • smartswitch >= 0.1.0
  • pydantic >= 2.0
  • textual >= 0.41.0 (optional, for interactive mode)

Development

git clone https://github.com/genropy/smartpublisher.git
cd smartpublisher
pip install -e ".[dev]"
pytest

License

MIT License - see LICENSE file for details.

Links

Project details


Download files

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

Source Distribution

smartpublisher-0.3.0.tar.gz (45.7 kB view details)

Uploaded Source

Built Distribution

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

smartpublisher-0.3.0-py3-none-any.whl (28.9 kB view details)

Uploaded Python 3

File details

Details for the file smartpublisher-0.3.0.tar.gz.

File metadata

  • Download URL: smartpublisher-0.3.0.tar.gz
  • Upload date:
  • Size: 45.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for smartpublisher-0.3.0.tar.gz
Algorithm Hash digest
SHA256 bbf1698944a5dac696e4372a0fc52e8e43e255d0544f59a5526b5fda97935675
MD5 546f9adcade98f0e4db3de8fa6bf172c
BLAKE2b-256 f0965f2661406951e50fc3f50e45a0fdb34c68960a8b98acfc2c34162a29ec94

See more details on using hashes here.

Provenance

The following attestation bundles were made for smartpublisher-0.3.0.tar.gz:

Publisher: publish.yml on genropy/smartpublisher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file smartpublisher-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: smartpublisher-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 28.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for smartpublisher-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 81bfe30ce9eca7bf7dc7854d220ea0e868f13f70a93103e4eab844bcc5f0e5dd
MD5 1243215f05acf06c5c48d5acef00c521
BLAKE2b-256 9921b55b1b69adfb41a31350747f0744f03b28dfb4721ed3a20e356b21867a5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for smartpublisher-0.3.0-py3-none-any.whl:

Publisher: publish.yml on genropy/smartpublisher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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