Instance-scoped routing engine for Python with hierarchical handlers and composable plugins
Project description
Genro Routes
Genro Routes is a transport-agnostic routing engine that decouples method routing from how those methods are exposed. Define your handlers once, then expose them via HTTP, CLI, WebSocket, or any other transport layer.
The routing logic lives in your application objects - the transport adapter (like genro-asgi for HTTP) simply maps external requests to router entries.
Why Transport-Agnostic?
Traditional web frameworks tightly couple routing to HTTP. Genro Routes separates these concerns:
| Layer | Responsibility |
|---|---|
| genro-routes | Method registration, hierarchies, plugins, introspection |
| Transport adapter | Protocol handling, request/response mapping |
This separation enables:
- Same handlers, multiple transports - Expose your API via HTTP and CLI without duplication
- Runtime introspection - Query available routes, generate documentation, build admin UIs
- Testability - Test business logic without HTTP overhead
- Flexibility - Swap transports without changing application code
Use Cases
- HTTP APIs - Via genro-asgi adapter
- Internal services - Direct method invocation with plugin pipeline
- CLI tools - Map commands to router entries
- Admin dashboards - Runtime introspection for dynamic UIs
Key Features
- Instance-scoped routers - Each object instantiates its own routers (
Router(self, ...)) with isolated state. - Friendly registration -
@route(...)accepts explicit names, auto-strips prefixes, and supports custom metadata. - Simple hierarchies -
attach_instance(child, name="alias")connects RoutingClass instances with path access (parent.api.node("child/method")). - Plugin pipeline -
BasePluginprovideson_decore/wrap_handlerhooks and plugins inherit from parents automatically. - Runtime configuration -
routing.configure()applies global or per-handler overrides with wildcards and returns reports ("?"). - Built-in plugins -
logging,pydantic,auth,env, andopenapiplugins are included out of the box. - Full coverage - The package ships with a comprehensive test suite and no hidden compatibility layers.
Quick Example
from genro_routes import RoutingClass, Router, route
class OrdersAPI(RoutingClass):
def __init__(self, label: str):
self.label = label
self.api = Router(self, name="orders")
@route("orders")
def list(self):
return ["order-1", "order-2"]
@route("orders")
def retrieve(self, ident: str):
return f"{self.label}:{ident}"
@route("orders")
def create(self, payload: dict):
return {"status": "created", **payload}
orders = OrdersAPI("acme")
print(orders.api.node("list")()) # ["order-1", "order-2"]
print(orders.api.node("retrieve")("42")) # acme:42
overview = orders.api.nodes()
print(overview["entries"].keys()) # dict_keys(['list', 'retrieve', 'create'])
Hierarchical Routing
Build nested service structures with path access:
class UsersAPI(RoutingClass):
def __init__(self):
self.api = Router(self, name="api")
@route("api")
def list(self):
return ["alice", "bob"]
class Application(RoutingClass):
def __init__(self):
self.api = Router(self, name="api")
self.users = UsersAPI()
# Attach child service
self.api.attach_instance(self.users, name="users")
app = Application()
print(app.api.node("users/list")()) # ["alice", "bob"]
# Introspect hierarchy
info = app.api.nodes()
print(info["routers"].keys()) # dict_keys(['users'])
Learn by Example
We provide a comprehensive gallery of examples in the examples/ directory:
- Standard Faker - Explicit routing and Pydantic validation.
- Magic Faker - Dynamic mapping of library methods at runtime.
- Syntax Highlighting - Creating a service wrapper around the Pygments library.
- Auth & Roles - Implementing role-based access control.
- Service Composition - Building complex apps from independent modules.
Read our guide on Why wrap a library with Genro-Routes? for more specialized insights.
Installation
pip install genro-routes
For development:
git clone https://github.com/genropy/genro-routes.git
cd genro-routes
pip install -e ".[all]"
For the Lazy: RoutingClassAuto
Don't want to create a router explicitly? Use RoutingClassAuto - it creates a "main" router automatically:
from genro_routes import RoutingClassAuto, route
class SimpleAPI(RoutingClassAuto):
@route() # No router name needed!
def hello(self):
return "Hello, World!"
api = SimpleAPI()
api.default_router.node("hello")() # "Hello, World!"
The auto-created router is named "main" and stored internally to avoid conflicts with your attributes.
Core Concepts
Router- Runtime router bound directly to an object viaRouter(self, name="api")@route("name")- Decorator that marks bound methods for the router with the matching nameRoutingClass- Mixin that tracks routers per instance and exposes theroutingproxyRoutingClassAuto- LikeRoutingClassbut auto-creates a "main" router if none definedBasePlugin- Base class for creating plugins withon_decoreandwrap_handlerhooksobj.routing- Proxy exposed by every RoutingClass that provides helpers likeget_router(...)andconfigure(...)for managing routers/plugins without polluting the instance namespace.RouterNode- Callable wrapper returned bynode(), withpath,error,doc,metadataproperties.NotFound/NotAuthenticated/NotAuthorized/NotAvailable- Exceptions for routing errors (not found, auth required, auth denied, capabilities missing)
Pattern Highlights
- Explicit naming + prefixes -
@route("api", name="detail")andRouter(self, prefix="handle_")separate method names from public route names. - Explicit instance hierarchies -
self.api.attach_instance(self.child, name="alias")connects RoutingClass instances with parent tracking and auto-detachment. - Branch routers -
Router(self, branch=True)creates pure organizational nodes without handlers. - Built-in and custom plugins -
Router(self, ...).plug("logging"),Router(self, ...).plug("pydantic"), or custom plugins. - Runtime configuration -
routing.configure("api:logging/_all_", enabled=False)applies targeted overrides with wildcards or batch updates. - Lazy binding - Routers auto-bind on first use; no explicit
bind()call needed.
Documentation
- Full Documentation - Complete guides, tutorials, and API reference
- Quick Start - Get started in 5 minutes
- FAQ - Common questions and answers
Testing
Genro Routes ships with a comprehensive test suite:
PYTHONPATH=src pytest --cov=src/genro_routes --cov-report=term-missing
All examples in documentation are verified by the test suite.
Repository Structure
genro-routes/
├── src/genro_routes/
│ ├── core/ # Core router implementation
│ │ ├── base_router.py # BaseRouter (plugin-free runtime)
│ │ ├── router.py # Router (with plugin support)
│ │ ├── decorators.py # @route decorator
│ │ └── routing.py # RoutingClass mixin
│ └── plugins/ # Built-in plugins
│ ├── logging.py # LoggingPlugin
│ ├── pydantic.py # PydanticPlugin
│ ├── auth.py # AuthPlugin
│ ├── env.py # EnvPlugin
│ └── openapi.py # OpenAPIPlugin
├── tests/ # Comprehensive test suite
└── docs/ # Documentation (Sphinx)
Project Status
Genro Routes is currently in beta. The core API is stable with complete documentation.
- Python Support: 3.10, 3.11, 3.12, 3.13
- License: Apache 2.0
Current Limitations
- Instance methods only - Routers assume decorated functions are bound methods (no static/class method or free function support)
- Minimal plugin system - Intentionally simple; advanced features must be added manually
Roadmap
- genro-asgi - ASGI adapter for HTTP exposure (in development)
- Additional plugins (async, storage, audit trail, metrics)
- CLI adapter for command-line exposure
- Example applications and use cases
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
Apache License 2.0 - see LICENSE for details.
Origin
This project was originally developed as "smartroute" under MIT license and has been renamed and relicensed.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file genro_routes-0.14.0.tar.gz.
File metadata
- Download URL: genro_routes-0.14.0.tar.gz
- Upload date:
- Size: 2.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f0c2be9d66f5673f157ce4d8d474e7559852e63db6a4b8cadbd781114caea29
|
|
| MD5 |
6d30723d94a7e7f1e69a0c473b3d514e
|
|
| BLAKE2b-256 |
c65e61e448b9944c0fa3e46ee43f5bd561ecef517897c0ca4ef407455ef951b3
|
Provenance
The following attestation bundles were made for genro_routes-0.14.0.tar.gz:
Publisher:
publish.yml on genropy/genro-routes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
genro_routes-0.14.0.tar.gz -
Subject digest:
7f0c2be9d66f5673f157ce4d8d474e7559852e63db6a4b8cadbd781114caea29 - Sigstore transparency entry: 1110693068
- Sigstore integration time:
-
Permalink:
genropy/genro-routes@e1db6781bbc7c184c43481594077b3195b804626 -
Branch / Tag:
refs/tags/v0.14.0 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1db6781bbc7c184c43481594077b3195b804626 -
Trigger Event:
push
-
Statement type:
File details
Details for the file genro_routes-0.14.0-py3-none-any.whl.
File metadata
- Download URL: genro_routes-0.14.0-py3-none-any.whl
- Upload date:
- Size: 61.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f84a28beea44d26359b1e3c95ffa0b194522e1e8d52ba0342520083d1eb95372
|
|
| MD5 |
0e9aed0c4c36e649c98764a66a5a5fc2
|
|
| BLAKE2b-256 |
25fac3c86aef7dee55302be18954c27acc653108c1b30aec493fb75f9cad35aa
|
Provenance
The following attestation bundles were made for genro_routes-0.14.0-py3-none-any.whl:
Publisher:
publish.yml on genropy/genro-routes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
genro_routes-0.14.0-py3-none-any.whl -
Subject digest:
f84a28beea44d26359b1e3c95ffa0b194522e1e8d52ba0342520083d1eb95372 - Sigstore transparency entry: 1110693092
- Sigstore integration time:
-
Permalink:
genropy/genro-routes@e1db6781bbc7c184c43481594077b3195b804626 -
Branch / Tag:
refs/tags/v0.14.0 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1db6781bbc7c184c43481594077b3195b804626 -
Trigger Event:
push
-
Statement type: