Plummy 💧
A lightweight, modern Python micro-framework for building clean, testable, and scalable event-driven applications using a Chain of Responsibility and Ports and Adapters (Hexagonal) architecture.
Overview
Plummy provides a set of simple, reusable building blocks to help you structure your application according to Domain-Driven Design (DDD) and Hexagonal Architecture principles. It's designed to keep your core business logic (the "hexagon") pure and isolated from external technical details like SQS, APIs, or databases (the "adapters").
The core idea is to build your application as a pipeline of independent, single-responsibility handlers that pass an event down a chain, allowing each handler to decide if it should process the event.
Key Features
- Clean Architecture: Enforces a clear separation between your domain, application, and infrastructure layers.
- Decoupled Components: Uses protocols (Ports) and dependency injection to ensure your business logic is independent of external technologies.
- Functional & Testable: Encourages writing business logic as simple, pure functions that are easy to unit test.
- Flexible Pipelines: Built around a Chain of Responsibility pattern to create extensible event-processing pipelines.
Installation
Install plummy directly from PyPI:
pip install plummy
How to Use Plummy
Here's how to build a simple event-processing pipeline with plummy.
1. Define Your Business Logic (Pure Functions)
First, write your business logic as simple, standalone functions. These functions should have no knowledge of the plummy framework.
# your_app/services.py
# A function to check if the event should be handled
def can_process_new_order(data: dict) -> bool:
return data.get("type") == "NEW_ORDER"
# A function that contains the core business logic
def process_new_order(data: dict) -> dict:
print(f"Processing order {data['order_id']}...")
data["status"] = "PROCESSED"
return data
2. Adapt Your Logic into a Processor
Use the FunctionalProcessor adapter to package your functions into a component that the framework can understand.
# your_app/processors.py
from plummy import FunctionalProcessor
from .services import can_process_new_order, process_new_order
# Adapt your functions into a "Processor"
order_processor = FunctionalProcessor(
can_handle=can_process_new_order,
process=process_new_order
)
3. Assemble the Pipeline with Handlers
Use StepHandler to create a "step" in your pipeline for each processor. Then, link the steps together.
# your_app/pipeline.py
from plummy.handlers import StepHandler
from .processors import order_processor
# ... import other processors for other steps
# Create a pipeline step for each processor
order_processing_step = StepHandler(processor=order_processor)
# another_step = StepHandler(processor=another_processor)
# Link them together to form the chain
pipeline_start = order_processing_step
# order_processing_step.set_next(another_step)
# The 'pipeline_start' is now your application's entry point.
4. Run the Pipeline
Pass your event data to the start of the pipeline.
# your_app/main.py
from .pipeline import pipeline_start
def main_entry_point(event: dict):
"""This could be your AWS Lambda handler or an API endpoint."""
return pipeline_start.handle(event)
# --- Example ---
new_order_event = {"type": "NEW_ORDER", "order_id": "123"}
result = main_entry_point(new_order_event)
print(result)
# Output: {'type': 'NEW_ORDER', 'order_id': '123', 'status': 'PROCESSED'}
🚀 Development & Contribution
Follow these steps to set up the plummy project for local development.
Prerequisites
- Python 3.10+
- uv (recommended) or pip
Setup Instructions
1. Create and Activate the Virtual Environment
Navigate to the project root and run:
uv venv
source .venv/bin/activate
2. Install Dependencies
Install the project in editable mode, including all development dependencies:
uv pip install -e ".[dev]"
3. Running Tests
To run the full test suite, use pytest:
pytest
License
This project is licensed under the MIT License.
Metadata
Release files for plummy 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| plummy-0.1.1.tar.gz | 5.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| plummy-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 11.8 kB
Release files / plummy-0.1.1.tar.gz
| Download URL | plummy-0.1.1.tar.gz |
|---|---|
| Size | 5.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d8288348e1686872fdf0ab296bcfc4f50d788cbe6a92c55fb4a439e23f108e14
|
|
BLAKE2b-256 checksum How to use checksums |
c675e0573333a18ac9b68b0fafcb359ef68c03df2e9f0d5e5b7d1a02cd7b606a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2025.
Transparency logRelease files / plummy-0.1.1-py3-none-any.whl
| Download URL | plummy-0.1.1-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35c1938cf5c5193a1e3db8e747ec82e86f28235dc6d7d4a3a6568e76e30592ea
|
|
BLAKE2b-256 checksum How to use checksums |
dd87102f3db37448a4019b14cf72c3324ad72e6fb61668eb73d651d14b242d0d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2025.
Transparency log