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
2 changes: 1 addition & 1 deletion .claude/commands/new-pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Scaffold a new pattern module for $ARGUMENTS.
- `docs/fundamentals.md`, `docs/implementation.md`, `docs/examples.md` — each a
heading plus a `TODO` line naming what belongs there (classic-form contrast in
fundamentals; never use the word "naive").
- `examples/demo/__main__.py` with a typed `main() -> None` + script guard
- `examples/demo/main.py` with a typed `main() -> None` + script guard
that imports from `...pattern`. Create NO other `__init__.py` — empty ones
are banned (PEP 420 namespace packages); the loader rejects them.
- `tests/test_<slug>.py` with one failing `test_todo` marked
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ patterns/<group>/<slug>/
│ ├── implementation.md# introducing it into a real system: smell, steps, idioms, pitfalls
│ └── examples.md # cited EXTERNAL usages: stdlib, OSS, articles
├── examples/ # runnable mini-projects that import pattern/
│ └── <project>/ # realistic domain, no Foo/Bar; __main__.py + modules
│ └── <project>/ # realistic domain, no Foo/Bar; main.py + modules
└── tests/ # isolated: test_<named>.py + test_<project>.py
```

No other `__init__.py` exist — namespace packages (PEP 420) carry the rest;
the loader rejects empty ones.

- Everything import-safe (no side effects at import); mini-projects run via
`uv run python -m patterns.<group>.<slug>.examples.<project>`.
`uv run python -m patterns.<group>.<slug>.examples.<project>.main`.
- Tests assert behavior, never just "it runs"; load-bearing claims get the
mutation treatment (mutate the code, prove the suite fails, revert).
- Examples must genuinely build on `pattern/` — the loader and a catalog test
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ patterns/<group>/<slug>/
│ ├── implementation.md# introducing it into a real system: smell, steps, idioms, pitfalls
│ └── examples.md # cited EXTERNAL usages: stdlib, OSS, articles
├── examples/ # runnable mini-projects that import pattern/
│ └── <project>/ # realistic domain, no Foo/Bar; __main__.py + modules
│ └── <project>/ # realistic domain, no Foo/Bar; main.py + modules
└── tests/ # isolated: test_<named>.py + test_<project>.py
```

No other `__init__.py` exist — namespace packages (PEP 420) carry the rest;
the loader rejects empty ones.

- Everything import-safe (no side effects at import); mini-projects run via
`uv run python -m patterns.<group>.<slug>.examples.<project>`.
`uv run python -m patterns.<group>.<slug>.examples.<project>.main`.
- Tests assert behavior, never just "it runs"; load-bearing claims get the
mutation treatment (mutate the code, prove the suite fails, revert).
- Examples must genuinely build on `pattern/` — the loader and a catalog test
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ patterns/structural/decorator/
from patterns.structural.decorator import retry, logged
```

Run any mini-project: `uv run python -m patterns.structural.decorator.examples.resilient_client`
Run any mini-project: `uv run python -m patterns.structural.decorator.examples.resilient_client.main`

Give it to your agents (MCP server with search, runnable examples, and
pattern recommendations):
Expand Down
2 changes: 1 addition & 1 deletion docs/how-to-read-this-repo.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ from patterns.behavioral.chain_of_responsibility import Chain
```

```bash
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.main
```

## Where to start
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/chain_of_responsibility/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ chain is callables in a list, not objects with successor pointers.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ resolution = chain.handle_or(ticket, triage(ticket))
step above to support-ticket routing — run it with:

```bash
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation
uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

import pytest

from patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.__main__ import main
from patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.handlers import (
build_escalation_chain,
route,
)
from patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.main import main
from patterns.behavioral.chain_of_responsibility.examples.ticket_escalation.models import Ticket


Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/command/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ the whole pattern until commands need undo, logs, or metadata.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.command.examples.editor_undo
uv run python -m patterns.behavioral.command.examples.editor_undo.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/command/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ Both grow unbounded and neither can answer "what exactly did the user do?".
text editor — insert/delete/replace with undo, redo, and a session log:

```bash
uv run python -m patterns.behavioral.command.examples.editor_undo
uv run python -m patterns.behavioral.command.examples.editor_undo.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/interpreter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ most little-language needs; grammar-as-data covers the rest.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.interpreter.examples.flag_rules
uv run python -m patterns.behavioral.interpreter.examples.flag_rules.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/interpreter/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ feature-flag engine — rules as data, per-user evaluation, hostile input
rejected:

```bash
uv run python -m patterns.behavioral.interpreter.examples.flag_rules
uv run python -m patterns.behavioral.interpreter.examples.flag_rules.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/iterator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ Traverse elements without exposing storage — lazily when it matters.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.iterator.examples.paginated_client
uv run python -m patterns.behavioral.iterator.examples.paginated_client.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/iterator/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ million records.
step to an article API client with an observably lazy fetch log:

```bash
uv run python -m patterns.behavioral.iterator.examples.paginated_client
uv run python -m patterns.behavioral.iterator.examples.paginated_client.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/mediator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ for god-object drift.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.mediator.examples.checkout_form
uv run python -m patterns.behavioral.mediator.examples.checkout_form.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/mediator/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ assert form.payment_options == ("card", "cod")
country/shipping/payment with cascading resets and submit gating:

```bash
uv run python -m patterns.behavioral.mediator.examples.checkout_form
uv run python -m patterns.behavioral.mediator.examples.checkout_form.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/memento/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ state and the pattern is nearly free.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.memento.examples.config_checkpoints
uv run python -m patterns.behavioral.memento.examples.config_checkpoints.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/memento/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,5 @@ every step: atomic validate-or-reject batches, LIFO undo, and a named
"before-upgrade" checkpoint. Run it with:

```bash
uv run python -m patterns.behavioral.memento.examples.config_checkpoints
uv run python -m patterns.behavioral.memento.examples.config_checkpoints.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import pytest

from patterns.behavioral.memento.examples.config_checkpoints.__main__ import main
from patterns.behavioral.memento.examples.config_checkpoints.editor import ConfigEditor
from patterns.behavioral.memento.examples.config_checkpoints.main import main
from patterns.behavioral.memento.examples.config_checkpoints.models import (
InvalidConfigError,
ServiceConfig,
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/observer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ list; the only real design decisions are order and failure policy.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.observer.examples.order_events
uv run python -m patterns.behavioral.observer.examples.order_events.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/observer/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@ one pipeline, four independent subscribers, a down webhook quarantined to a
dead-letter list while the rest keep working. Run it with:

```bash
uv run python -m patterns.behavioral.observer.examples.order_events
uv run python -m patterns.behavioral.observer.examples.order_events.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/observer/tests/test_order_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from patterns.behavioral.observer.examples.order_events.__main__ import main
from patterns.behavioral.observer.examples.order_events.main import main
from patterns.behavioral.observer.examples.order_events.subscribers import (
AuditLog,
EmailNotifier,
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ class-per-state only pays at real size.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.state.examples.order_lifecycle
uv run python -m patterns.behavioral.state.examples.order_lifecycle.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/state/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,5 @@ step: an eight-row table, three data guards, refusal of a too-late cancel, and
the audit log printed at the end. Run it with:

```bash
uv run python -m patterns.behavioral.state.examples.order_lifecycle
uv run python -m patterns.behavioral.state.examples.order_lifecycle.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/state/tests/test_order_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import pytest

from patterns.behavioral.state import IllegalTransitionError
from patterns.behavioral.state.examples.order_lifecycle.__main__ import main
from patterns.behavioral.state.examples.order_lifecycle.lifecycle import build_lifecycle
from patterns.behavioral.state.examples.order_lifecycle.main import main
from patterns.behavioral.state.examples.order_lifecycle.models import (
Order,
OrderAction,
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/strategy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ the registry below is for families that grow.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.strategy.examples.promotions
uv run python -m patterns.behavioral.strategy.examples.promotions.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/strategy/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ checkout pricing — three registered rules, a best-rule engine, and a
comparison report:

```bash
uv run python -m patterns.behavioral.strategy.examples.promotions
uv run python -m patterns.behavioral.strategy.examples.promotions.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/strategy/tests/test_promotions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from patterns.behavioral.strategy.examples.promotions.__main__ import main
from patterns.behavioral.strategy.examples.promotions.main import main
from patterns.behavioral.strategy.examples.promotions.models import LineItem, Order
from patterns.behavioral.strategy.examples.promotions.rules import best_promo, due, promotion
from patterns.behavioral.strategy.pattern import StrategyRegistry
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/template_method/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ that hand them to you.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.template_method.examples.report_pipeline
uv run python -m patterns.behavioral.template_method.examples.report_pipeline.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/template_method/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ step above to sales reporting — one spine, CSV and Markdown variants derived
from a baseline:

```bash
uv run python -m patterns.behavioral.template_method.examples.report_pipeline
uv run python -m patterns.behavioral.template_method.examples.report_pipeline.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from patterns.behavioral.template_method.examples.report_pipeline.__main__ import main
from patterns.behavioral.template_method.examples.report_pipeline.main import main
from patterns.behavioral.template_method.examples.report_pipeline.models import Sale
from patterns.behavioral.template_method.examples.report_pipeline.pipeline import (
build_csv_report,
Expand Down
2 changes: 1 addition & 1 deletion patterns/behavioral/visitor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ the subclass form survives at stdlib boundaries (`ast.NodeVisitor`).
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.behavioral.visitor.examples.doc_exporters
uv run python -m patterns.behavioral.visitor.examples.doc_exporters.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/visitor/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,5 @@ above to a document tree — Markdown, plain-text, and word-count operations
over five node types the operations never edit:

```bash
uv run python -m patterns.behavioral.visitor.examples.doc_exporters
uv run python -m patterns.behavioral.visitor.examples.doc_exporters.main
```
2 changes: 1 addition & 1 deletion patterns/behavioral/visitor/tests/test_doc_exporters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import pytest

from patterns.behavioral.visitor import Operation, UnhandledNodeError
from patterns.behavioral.visitor.examples.doc_exporters.__main__ import main, sample_document
from patterns.behavioral.visitor.examples.doc_exporters.exporters import (
markdown,
plain_text,
word_count,
)
from patterns.behavioral.visitor.examples.doc_exporters.main import main, sample_document
from patterns.behavioral.visitor.examples.doc_exporters.nodes import (
BulletList,
CodeBlock,
Expand Down
2 changes: 1 addition & 1 deletion patterns/creational/abstract_factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ consistent with each other.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.creational.abstract_factory.examples.report_renderer
uv run python -m patterns.creational.abstract_factory.examples.report_renderer.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ quarterly report through the `MARKDOWN` and `HTML` families — same client
code, both outputs:

```bash
uv run python -m patterns.creational.abstract_factory.examples.report_renderer
uv run python -m patterns.creational.abstract_factory.examples.report_renderer.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from patterns.creational.abstract_factory.examples.report_renderer.__main__ import Q3
from patterns.creational.abstract_factory.examples.report_renderer.main import Q3
from patterns.creational.abstract_factory.examples.report_renderer.renderer import render
from patterns.creational.abstract_factory.examples.report_renderer.report import (
Report,
Expand Down
2 changes: 1 addition & 1 deletion patterns/creational/builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ genuinely staged.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.creational.builder.examples.sql_select_builder
uv run python -m patterns.creational.builder.examples.sql_select_builder.main
```
2 changes: 1 addition & 1 deletion patterns/creational/builder/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,5 @@ three analytics queries — including a conditionally-narrowed one — and runs
them against a real in-memory sqlite database:

```bash
uv run python -m patterns.creational.builder.examples.sql_select_builder
uv run python -m patterns.creational.builder.examples.sql_select_builder.main
```
2 changes: 1 addition & 1 deletion patterns/creational/factory_method/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ Java with the serial numbers filed off.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.creational.factory_method.examples.feed_client
uv run python -m patterns.creational.factory_method.examples.feed_client.main
```
2 changes: 1 addition & 1 deletion patterns/creational/factory_method/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ class StrictClient(FeedClient): # or per-subclass; factory_slot because
subclass, by instance, and by a test double — run it with:

```bash
uv run python -m patterns.creational.factory_method.examples.feed_client
uv run python -m patterns.creational.factory_method.examples.feed_client.main
```
2 changes: 1 addition & 1 deletion patterns/creational/prototype/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ with a `clone()` protocol; tweak frozen products with `dataclasses.replace`.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.creational.prototype.examples.report_job_templates
uv run python -m patterns.creational.prototype.examples.report_job_templates.main
```
2 changes: 1 addition & 1 deletion patterns/creational/prototype/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ rush = menu.create("nightly-sales", fmt="csv") # fresh, tweaked, template safe
scheduler shape above, end to end — run it with:

```bash
uv run python -m patterns.creational.prototype.examples.report_job_templates
uv run python -m patterns.creational.prototype.examples.report_job_templates.main
```
2 changes: 1 addition & 1 deletion patterns/creational/singleton/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ seam for tests.
| [`tests/`](tests/) | Behavioral tests for the pattern and the mini-project |

```bash
uv run python -m patterns.creational.singleton.examples.app_config
uv run python -m patterns.creational.singleton.examples.app_config.main
```
2 changes: 1 addition & 1 deletion patterns/creational/singleton/docs/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,5 @@ with lazy build, cached reads, env re-read after reset, and an injected
mapping for tests — run it with:

```bash
uv run python -m patterns.creational.singleton.examples.app_config
uv run python -m patterns.creational.singleton.examples.app_config.main
```
2 changes: 1 addition & 1 deletion patterns/modern/async_producer_consumer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ Fan I/O-bound work out to N workers over a bounded queue — backpressure by
| [`tests/`](tests/) | Behavioral tests for the pool and the mini-project |

```bash
uv run python -m patterns.modern.async_producer_consumer.examples.feed_fetcher
uv run python -m patterns.modern.async_producer_consumer.examples.feed_fetcher.main
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

import pytest

from patterns.modern.async_producer_consumer.examples.feed_fetcher.__main__ import main
from patterns.modern.async_producer_consumer.examples.feed_fetcher.fetcher import (
fetch_all,
summarize,
)
from patterns.modern.async_producer_consumer.examples.feed_fetcher.main import main
from patterns.modern.async_producer_consumer.examples.feed_fetcher.models import Feed
from patterns.modern.async_producer_consumer.pattern import Shutdown

Expand Down
2 changes: 1 addition & 1 deletion patterns/modern/context_manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ Pair acquire with release on every exit path, structurally — Python's RAII.
| [`tests/`](tests/) | Behavioral tests for both managers and the mini-project |

```bash
uv run python -m patterns.modern.context_manager.examples.atomic_deploy
uv run python -m patterns.modern.context_manager.examples.atomic_deploy.main
```
Loading
Loading