Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,52 @@
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.black-formatter",
"oderwat.indent-rainbow",
"ms-python.isort",
"ms-python.debugpy",
"ms-python.flake8",
"ms-toolsai.jupyter",
"DavidAnson.vscode-markdownlint",
"GitHub.copilot",
"GitHub.copilot-chat",
"github.copilot",
"github.copilot-chat",
"github.vscode-github-actions",
"mikestead.dotenv",
"ms-python.flake8",
"tamasfe.even-better-toml",
"github.vscode-github-actions"
"tamasfe.even-better-toml"
],
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"editor.defaultFormatter": "ms-python.black-formatter",
"indentRainbow.indicatorStyle": "light",
"editor.linkedEditing": true,
"editor.formatOnSave": true,
"editor.rulers": [
80,
100
],
"editor.guides.bracketPairs": true,
"editor.guides.highlightActiveIndentation": true,
"explorer.sortOrderLexicographicOptions": "upper",
"python.condaPath": "/opt/conda/bin/conda",
"python.defaultInterpreterPath": "/opt/conda/envs/venv/bin/python",
"python.analysis.autoImportCompletions": true,
"python.analysis.typeCheckingMode": "strict",
"python.analysis.diagnosticMode": "workspace",
"explorer.sortOrderLexicographicOptions": "upper",
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"editor.rulers": [
80,
100
],
"terminal.integrated.shell.linux": "/bin/bash",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"[toml]": {
"editor.defaultFormatter": "tamasfe.even-better-toml",
"editor.formatOnSave": true
},
"[markdown]": {
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint",
"editor.wordWrap": "on"
}
}
}
Expand Down
38 changes: 33 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TheCodeCrate's Middlewareable

This package provides a middleware pattern implementation built on top of the [`thecodecrate-pipeline`](https://pypi.org/project/thecodecrate-pipeline/) library.
This package provides a middleware pattern implementation built on top of the [`thecodecrate-pipeline`](https://github.com/thecodecrate/python-pipeline) library.

## Installation

Expand All @@ -21,7 +21,7 @@ A pipeline consists of zero, one, or multiple stages. A pipeline can process a p

This particular implementation is build on top of the `thecodecrate-pipeline` library, which provides a generic pipeline pattern.

The standard processor in _TheCodeCrate's Pipeline_ executes stages in a for-loop manner:
The standard processor in Pipeline executes stages in a for-loop manner:

```python
result = payload
Expand All @@ -32,7 +32,7 @@ for stage in stages:
return result
```

However, this library provides a middleware processor for executing stages in a nested manner:
This library provides a middleware processor for executing stages in a nested manner:

```python
stage3 = lambda payload: payload + 3
Expand All @@ -46,7 +46,35 @@ This is useful for implementing a chain of responsibility, where each stage can

## Usage

You define middleware as callables that accept a `payload` and a `next_call` function:
You define middleware as callables that accept a payload and a `next_call` function:

```python
# Create a middleware pipeline using lambda functions
pipeline = (
MiddlewarePipeline[int]()
.pipe(lambda x, next_call: next_call(x + 1))
.pipe(lambda x, next_call: next_call(x * 2))
.pipe(lambda x, next_call: next_call(x + 3))
)

# Process a payload
result = await pipeline.process(5)
print(f"Result: {result}")
```

This pipeline processes the payload `5` through the following stages:

1. Add 1: `5 + 1 = 6`
2. Multiply by 2: `6 * 2 = 12`
3. Add 3: `12 + 3 = 15`

**Output:**

```plaintext
Result: 15
```

With middlewares, you can include pre-processing and post-processing logic:

```python
# Define middleware functions
Expand Down Expand Up @@ -95,7 +123,7 @@ You can also define middleware as classes by implementing the `MiddlewareStage`

```python
class AddMiddleware(MiddlewareStage[int, int]):
async def __call__(self, payload: int, next_call: MiddlewareNextCall[int, int]) -> int:
async def __call__(self, payload: int, next_call: MiddlewareNextCall) -> int:
print("AddMiddleware - Before")
payload += 3
result = await next_call(payload)
Expand Down
6 changes: 6 additions & 0 deletions docker/local/etc/bash_aliases
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Aliases for GIT shortcuts (https://laracasts.com/series/how-to-contribute-to-open-source/episodes/5)
alias wip='git add . && git commit -m '\''Work in progress'\'
alias nope='git reset --hard && git clean -f -d && git checkout HEAD'

# Alias for publishing the package to pypi
alias clean_dist='rm -rf dist/*'
alias bump='bumpver update --minor'
alias build='clean_dist && python -m build'
alias deploy='twine upload dist/*'
4 changes: 2 additions & 2 deletions jupyter/01-instructions.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 1,
"metadata": {},
"outputs": [
{
Expand All @@ -25,7 +25,7 @@
"from python_middlewareable import MiddlewarePipeline\n",
"\n",
"pipeline = (\n",
" (MiddlewarePipeline[int]())\n",
" MiddlewarePipeline[int]()\n",
" .pipe(lambda x, next_call: next_call(x + 1))\n",
" .pipe(lambda x, next_call: next_call(x * 2))\n",
" .pipe(lambda x, next_call: next_call(x + 3))\n",
Expand Down
Loading