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
10 changes: 6 additions & 4 deletions .claude/commands/new-pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ Scaffold a new pattern module for $ARGUMENTS.
- `README.md` — frontmatter with `id: <group>/<slug>`, all schema keys present,
`verdict:` left as `use-with-care` with a `TODO` caveat; a ~10-line front door
mapping the folders.
- `__init__.py` re-exporting from `pattern/`; `pattern/__init__.py` +
`pattern/<slug>.py` with a typed stub.
- `__init__.py` and `pattern/__init__.py` holding ONLY as-alias re-export
lines (`from .pattern.<slug> import X as X` / `from .<slug> import X as X`
— no docstrings, no `__all__`); `pattern/<slug>.py` with a typed stub.
- `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/__init__.py` and `examples/demo/` (`__init__.py`, `__main__.py` with a
typed `main() -> None` + script guard that imports from `...pattern`).
- `examples/__init__.py` and `examples/demo/__init__.py` both completely
empty; `examples/demo/__main__.py` with a typed `main() -> None` + script
guard that imports from `...pattern`.
- `tests/test_<slug>.py` with one failing `test_todo` marked
`xfail(reason="unit not yet written")`.
3. Run `make check` and report the result. Note: the catalog loader will fail the
Expand Down
91 changes: 0 additions & 91 deletions .github/code-review.md

This file was deleted.

4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ patterns/<group>/<slug>/
- Everything import-safe (no side effects at import); mini-projects run via
`uv run python -m patterns.<group>.<slug>.examples.<project>`.
- Tests assert behavior, never just "it runs"; load-bearing claims get the
mutation treatment (`.github/code-review.md`).
mutation treatment (mutate the code, prove the suite fails, revert).
- Examples must genuinely build on `pattern/` — the loader and a catalog test
enforce the structure and the import; reviewers reject token imports.
- Full type hints; `mypy --strict` must pass.
Expand All @@ -49,6 +49,8 @@ patterns/<group>/<slug>/
`replace=True`); ordered collections append freely.
- `ParamSpec` only where a wrapper callable is returned; identity typing otherwise.
- Never `None` as a cache sentinel; immutability guards recurse into containers.
- `__init__.py` is empty unless it is the unit's public-API re-export file
(`from .pattern.x import Y as Y` — the as-alias form); never `__all__`.

## Frontmatter schema (the MCP server indexes this — keep it valid)

Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ patterns/<group>/<slug>/
- Everything import-safe (no side effects at import); mini-projects run via
`uv run python -m patterns.<group>.<slug>.examples.<project>`.
- Tests assert behavior, never just "it runs"; load-bearing claims get the
mutation treatment (`.github/code-review.md`).
mutation treatment (mutate the code, prove the suite fails, revert).
- Examples must genuinely build on `pattern/` — the loader and a catalog test
enforce the structure and the import; reviewers reject token imports.
- Full type hints; `mypy --strict` must pass.
Expand All @@ -49,6 +49,8 @@ patterns/<group>/<slug>/
`replace=True`); ordered collections append freely.
- `ParamSpec` only where a wrapper callable is returned; identity typing otherwise.
- Never `None` as a cache sentinel; immutability guards recurse into containers.
- `__init__.py` is empty unless it is the unit's public-API re-export file
(`from .pattern.x import Y as Y` — the as-alias form); never `__all__`.

## Frontmatter schema (the MCP server indexes this — keep it valid)

Expand Down
3 changes: 2 additions & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ takes only reviewed milestone merges. CI (3.11/3.12/3.13) must pass.

- Full type hints; import-safe modules (no side effects at import).
- Tests assert behavior, not "it runs" — and load-bearing claims get the
mutation treatment (see [.github/code-review.md](../.github/code-review.md)).
mutation treatment (mutate the code, prove the suite fails, revert). Reviews
are severity-ordered; machines own style, humans argue design.
- Mini-projects use realistic domains, no Foo/Bar.
- Prose: one page, problem-first, no UML, no history lessons. The classic
(GoF) form lives in `docs/fundamentals.md` as an annotated listing.
1 change: 0 additions & 1 deletion patterns/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""Pattern catalog: one directory per pattern unit."""
1 change: 0 additions & 1 deletion patterns/behavioral/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""behavioral patterns."""
15 changes: 3 additions & 12 deletions patterns/behavioral/chain_of_responsibility/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
"""Chain of Responsibility — public API.

>>> from patterns.behavioral.chain_of_responsibility import Chain
"""

from patterns.behavioral.chain_of_responsibility.pattern import (
Chain,
Handler,
UnhandledRequestError,
)

__all__ = ["Chain", "Handler", "UnhandledRequestError"]
from .pattern.chain import Chain as Chain
from .pattern.chain import Handler as Handler
from .pattern.chain import UnhandledRequestError as UnhandledRequestError
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""Mini-projects demonstrating the Chain of Responsibility in practice."""
Original file line number Diff line number Diff line change
@@ -1,15 +0,0 @@
"""Support-ticket escalation built on the Chain of Responsibility.

Run it: ``uv run python -m patterns.behavioral.chain_of_responsibility.examples.ticket_escalation``
"""

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

__all__ = ["Resolution", "Ticket", "build_escalation_chain", "route"]
12 changes: 3 additions & 9 deletions patterns/behavioral/chain_of_responsibility/pattern/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
"""The Chain of Responsibility pattern, importable as library code."""

from patterns.behavioral.chain_of_responsibility.pattern.chain import (
Chain,
Handler,
UnhandledRequestError,
)

__all__ = ["Chain", "Handler", "UnhandledRequestError"]
from .chain import Chain as Chain
from .chain import Handler as Handler
from .chain import UnhandledRequestError as UnhandledRequestError
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

import pytest

from patterns.behavioral.chain_of_responsibility.examples.ticket_escalation import (
Ticket,
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


def ticket(severity: int, tags: frozenset[str] = frozenset(), id_: str = "T-1") -> Ticket:
Expand Down
11 changes: 3 additions & 8 deletions patterns/behavioral/command/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
"""Command — public API.

>>> from patterns.behavioral.command import UndoStack, Undoable
"""

from patterns.behavioral.command.pattern import Action, Undoable, UndoStack

__all__ = ["Action", "UndoStack", "Undoable"]
from .pattern.commands import Action as Action
from .pattern.commands import Undoable as Undoable
from .pattern.commands import UndoStack as UndoStack
1 change: 0 additions & 1 deletion patterns/behavioral/command/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""Mini-projects demonstrating the Command pattern in practice."""
13 changes: 0 additions & 13 deletions patterns/behavioral/command/examples/editor_undo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +0,0 @@
"""A text editor's undo/redo built on the Command pattern.

Run it: ``uv run python -m patterns.behavioral.command.examples.editor_undo``
"""

from patterns.behavioral.command.examples.editor_undo.editing import (
delete_span,
insert_text,
replace_span,
)
from patterns.behavioral.command.examples.editor_undo.models import Document

__all__ = ["Document", "delete_span", "insert_text", "replace_span"]
12 changes: 3 additions & 9 deletions patterns/behavioral/command/pattern/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
"""The Command pattern, importable as library code."""

from patterns.behavioral.command.pattern.commands import (
Action,
Undoable,
UndoStack,
)

__all__ = ["Action", "UndoStack", "Undoable"]
from .commands import Action as Action
from .commands import Undoable as Undoable
from .commands import UndoStack as UndoStack
4 changes: 2 additions & 2 deletions patterns/behavioral/command/tests/test_editor_undo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

from __future__ import annotations

from patterns.behavioral.command.examples.editor_undo import (
Document,
from patterns.behavioral.command.examples.editor_undo.editing import (
delete_span,
insert_text,
replace_span,
)
from patterns.behavioral.command.examples.editor_undo.models import Document
from patterns.behavioral.command.pattern import UndoStack


Expand Down
31 changes: 7 additions & 24 deletions patterns/behavioral/interpreter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
"""Interpreter — public API.

>>> from patterns.behavioral.interpreter import Interpreter, safe_eval
"""

from patterns.behavioral.interpreter.pattern import (
MAX_DEPTH,
Expr,
Interpreter,
Operation,
Resolver,
Value,
safe_eval,
)

__all__ = [
"MAX_DEPTH",
"Expr",
"Interpreter",
"Operation",
"Resolver",
"Value",
"safe_eval",
]
from .pattern.rules import MAX_DEPTH as MAX_DEPTH
from .pattern.rules import Expr as Expr
from .pattern.rules import Interpreter as Interpreter
from .pattern.rules import Operation as Operation
from .pattern.rules import Resolver as Resolver
from .pattern.rules import Value as Value
from .pattern.safe_eval import safe_eval as safe_eval
1 change: 0 additions & 1 deletion patterns/behavioral/interpreter/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""Mini-projects demonstrating the Interpreter pattern in practice."""
11 changes: 0 additions & 11 deletions patterns/behavioral/interpreter/examples/flag_rules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +0,0 @@
"""A feature-flag rules engine built on the Interpreter pattern.

Run it: ``uv run python -m patterns.behavioral.interpreter.examples.flag_rules``
"""

from patterns.behavioral.interpreter.examples.flag_rules.engine import (
OPERATIONS,
FlagEngine,
)

__all__ = ["OPERATIONS", "FlagEngine"]
28 changes: 7 additions & 21 deletions patterns/behavioral/interpreter/pattern/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
"""The Interpreter pattern, importable as library code."""

from patterns.behavioral.interpreter.pattern.rules import (
MAX_DEPTH,
Expr,
Interpreter,
Operation,
Resolver,
Value,
)
from patterns.behavioral.interpreter.pattern.safe_eval import safe_eval

__all__ = [
"MAX_DEPTH",
"Expr",
"Interpreter",
"Operation",
"Resolver",
"Value",
"safe_eval",
]
from .rules import MAX_DEPTH as MAX_DEPTH
from .rules import Expr as Expr
from .rules import Interpreter as Interpreter
from .rules import Operation as Operation
from .rules import Resolver as Resolver
from .rules import Value as Value
from .safe_eval import safe_eval as safe_eval
2 changes: 1 addition & 1 deletion patterns/behavioral/interpreter/tests/test_flag_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from patterns.behavioral.interpreter.examples.flag_rules import FlagEngine
from patterns.behavioral.interpreter.examples.flag_rules.engine import FlagEngine
from patterns.behavioral.interpreter.pattern import Expr, Value

FLAGS: dict[str, Expr] = {
Expand Down
10 changes: 2 additions & 8 deletions patterns/behavioral/iterator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
"""Iterator — public API.

>>> from patterns.behavioral.iterator import iterate_pages
"""

from patterns.behavioral.iterator.pattern import PageFetcher, iterate_pages

__all__ = ["PageFetcher", "iterate_pages"]
from .pattern.paging import PageFetcher as PageFetcher
from .pattern.paging import iterate_pages as iterate_pages
1 change: 0 additions & 1 deletion patterns/behavioral/iterator/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
"""Mini-projects demonstrating the Iterator pattern in practice."""
Original file line number Diff line number Diff line change
@@ -1,9 +0,0 @@
"""A paginated API client built on the Iterator pattern.

Run it: ``uv run python -m patterns.behavioral.iterator.examples.paginated_client``
"""

from patterns.behavioral.iterator.examples.paginated_client.backend import FakeBackend
from patterns.behavioral.iterator.examples.paginated_client.client import ArticleClient

__all__ = ["ArticleClient", "FakeBackend"]
7 changes: 2 additions & 5 deletions patterns/behavioral/iterator/pattern/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
"""The Iterator pattern, importable as library code."""

from patterns.behavioral.iterator.pattern.paging import PageFetcher, iterate_pages

__all__ = ["PageFetcher", "iterate_pages"]
from .paging import PageFetcher as PageFetcher
from .paging import iterate_pages as iterate_pages
Loading
Loading