diff --git a/.claude/commands/new-pattern.md b/.claude/commands/new-pattern.md index 5211221..d903a1c 100644 --- a/.claude/commands/new-pattern.md +++ b/.claude/commands/new-pattern.md @@ -11,13 +11,15 @@ Scaffold a new pattern module for $ARGUMENTS. - `README.md` — frontmatter with `id: /`, 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/.py` with a typed stub. + - `__init__.py` and `pattern/__init__.py` holding ONLY as-alias re-export + lines (`from .pattern. import X as X` / `from . import X as X` + — no docstrings, no `__all__`); `pattern/.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_.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 diff --git a/.github/code-review.md b/.github/code-review.md deleted file mode 100644 index b5714c9..0000000 --- a/.github/code-review.md +++ /dev/null @@ -1,91 +0,0 @@ -# Code review standards - -The reviewer's contract for this repo — and a reusable checklist for any -Python team. - -## Layer 0: machines argue about style, humans argue about design - -These run in CI; a human review comment about anything they cover is wasted: - -| Tool | Standard it enforces | -|---|---| -| `ruff check` + `ruff format` | PEP 8, import order, bugbear/simplify/pyupgrade rule packs — each rule documented at [docs.astral.sh/ruff/rules](https://docs.astral.sh/ruff/rules/) | -| `mypy --strict` | PEP 484 typing, no untyped defs, no implicit Any | -| `pytest` + coverage | behavior, not just "it imports" | -| `python -m design_patterns.readme_table --check` | docs can't drift from code | - -Worth adding for security-sensitive work: `bandit` (SAST) and `pip-audit` -(dependency CVEs). Note: bandit flags every `assert` (B101) — in pytest -tests that's idiomatic, not a finding. - -## Layer 1: the written standards behind the tools - -- **PEP 8** (style) · **PEP 257** (docstrings) · **PEP 20** (design sensibility) -- **Google Python Style Guide** — the most common team-level extension -- This repo's own bar: [CLAUDE.md](../CLAUDE.md) (unit template, frontmatter - schema) and [docs/verdicts.md](../docs/verdicts.md) - -## Layer 2: what human reviewers actually check - -Severity-ordered — block on CRITICAL/HIGH, note MEDIUM: - -**CRITICAL** -- Injection: user input reaching `eval`/`exec`, SQL strings, `subprocess` with `shell=True` -- Unsafe deserialization: `pickle.loads`/`yaml.load` on data crossing a trust boundary -- Secrets in code - -**HIGH** -- `assert` as a runtime guard (vanishes under `python -O`) -- Mutable default arguments; shared mutable module state -- Swallowed exceptions (`except: pass`), or `except Exception` hiding real errors -- Resources without context managers; missing cleanup on the error path -- Thread-safety claims the code doesn't earn (unguarded lazy init, shared caches) -- Unbounded recursion/loops on user-controlled input - -**MEDIUM** -- Work at import time (I/O, big computation) — see `patterns/python/global_object` -- `isinstance` traps (`bool` passes `int` checks), `is` vs `==` on sentinels -- API honesty: docstrings/comments that promise more than the code delivers -- A design pattern where a language feature suffices — check the catalog's verdict first - -## Reference sources for reviewers (MCP) - -- **This repo's own MCP server** — `claude mcp add design-patterns -- uv run --directory python-design-patterns-mcp`. `recommend_pattern` answers "should this be a Singleton?" with python-patterns.guide's verdicts and caveats; `get_pattern` serves the reference implementation to compare against. -- **Context7 MCP** — current library/framework docs, for "is this the right API usage?" questions. -- **python-patterns.guide** — the prose authority behind this catalog's verdicts. - -## House rules (settled during the v2 migration, enforced in review) - -- Name-keyed registries and caretakers refuse silent duplicates: `ValueError` - unless `replace=True`. Ordered collections where repeats are meaningful — - chains, signals — append freely; `functools.singledispatch`'s own overwrite - behavior is inherited, noted not fought. -- `ParamSpec` typing only where a wrapper callable is returned - (`structural/decorator` is the precedent); registries that return callables - unchanged use plain identity typing. -- Never use `None` as a cache sentinel — a factory may legitimately return - `None` and it must still cache once (`LazyProxy._MISSING` precedent). - Immutability guards recurse into containers: a tuple holding a list is - mutable where it counts (`InternPool` precedent). -- Every unit's `examples/` must genuinely build on its `pattern/` package — - an AST import check enforces the import; reviewers judge token imports - (an annotation-only import that vanishes at runtime does not count). -- Frontmatter stays stable; deliberate caveat improvements are allowed and - called out in review. - -## Mutation discipline - -Reading a diff is not verification. For any load-bearing claim — a shutdown -discipline, a durability promise, a security guard, an "import does no work" -assertion — apply the mutation that would falsify it (swap the operator, -collapse the branch, make the write non-atomic) and confirm the suite fails. -During the v2 migration this caught four real defects that reading alone did -not: an untestable shutdown switch, a sqlite adapter that never committed, a -fixture that erased its own evidence, and a runtime-erased annotation import. -If the mutant survives, the finding is the missing test, not the mutation. - -## Review etiquette - -- Cite the rule or the file, not taste ("B008: mutable default" beats "I don't like this"). -- One approval pass = one severity sweep top-down; don't drip-feed. -- The author of a change never approves it. diff --git a/AGENTS.md b/AGENTS.md index c1fc42b..88b55a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ patterns/// - Everything import-safe (no side effects at import); mini-projects run via `uv run python -m patterns...examples.`. - 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. @@ -49,6 +49,8 @@ patterns/// `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) diff --git a/CLAUDE.md b/CLAUDE.md index 18876e5..6af2aed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,7 +38,7 @@ patterns/// - Everything import-safe (no side effects at import); mini-projects run via `uv run python -m patterns...examples.`. - 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. @@ -49,6 +49,8 @@ patterns/// `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) diff --git a/docs/contributing.md b/docs/contributing.md index 6a9d26d..c7ddd01 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -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. diff --git a/patterns/__init__.py b/patterns/__init__.py index c2468b6..e69de29 100644 --- a/patterns/__init__.py +++ b/patterns/__init__.py @@ -1 +0,0 @@ -"""Pattern catalog: one directory per pattern unit.""" diff --git a/patterns/behavioral/__init__.py b/patterns/behavioral/__init__.py index 51eeff6..e69de29 100644 --- a/patterns/behavioral/__init__.py +++ b/patterns/behavioral/__init__.py @@ -1 +0,0 @@ -"""behavioral patterns.""" diff --git a/patterns/behavioral/chain_of_responsibility/__init__.py b/patterns/behavioral/chain_of_responsibility/__init__.py index eebf149..5c09c6e 100644 --- a/patterns/behavioral/chain_of_responsibility/__init__.py +++ b/patterns/behavioral/chain_of_responsibility/__init__.py @@ -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 diff --git a/patterns/behavioral/chain_of_responsibility/examples/__init__.py b/patterns/behavioral/chain_of_responsibility/examples/__init__.py index dc47780..e69de29 100644 --- a/patterns/behavioral/chain_of_responsibility/examples/__init__.py +++ b/patterns/behavioral/chain_of_responsibility/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Chain of Responsibility in practice.""" diff --git a/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py b/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py index fd4aa0e..e69de29 100644 --- a/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py +++ b/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py @@ -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"] diff --git a/patterns/behavioral/chain_of_responsibility/pattern/__init__.py b/patterns/behavioral/chain_of_responsibility/pattern/__init__.py index 33c6b88..9121055 100644 --- a/patterns/behavioral/chain_of_responsibility/pattern/__init__.py +++ b/patterns/behavioral/chain_of_responsibility/pattern/__init__.py @@ -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 diff --git a/patterns/behavioral/chain_of_responsibility/tests/test_ticket_escalation.py b/patterns/behavioral/chain_of_responsibility/tests/test_ticket_escalation.py index 240a897..e83e4da 100644 --- a/patterns/behavioral/chain_of_responsibility/tests/test_ticket_escalation.py +++ b/patterns/behavioral/chain_of_responsibility/tests/test_ticket_escalation.py @@ -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: diff --git a/patterns/behavioral/command/__init__.py b/patterns/behavioral/command/__init__.py index 7e3f1f0..74046f6 100644 --- a/patterns/behavioral/command/__init__.py +++ b/patterns/behavioral/command/__init__.py @@ -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 diff --git a/patterns/behavioral/command/examples/__init__.py b/patterns/behavioral/command/examples/__init__.py index 8971b23..e69de29 100644 --- a/patterns/behavioral/command/examples/__init__.py +++ b/patterns/behavioral/command/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Command pattern in practice.""" diff --git a/patterns/behavioral/command/examples/editor_undo/__init__.py b/patterns/behavioral/command/examples/editor_undo/__init__.py index 34f60f2..e69de29 100644 --- a/patterns/behavioral/command/examples/editor_undo/__init__.py +++ b/patterns/behavioral/command/examples/editor_undo/__init__.py @@ -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"] diff --git a/patterns/behavioral/command/pattern/__init__.py b/patterns/behavioral/command/pattern/__init__.py index e304667..a6714cb 100644 --- a/patterns/behavioral/command/pattern/__init__.py +++ b/patterns/behavioral/command/pattern/__init__.py @@ -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 diff --git a/patterns/behavioral/command/tests/test_editor_undo.py b/patterns/behavioral/command/tests/test_editor_undo.py index c35f15c..8c392c4 100644 --- a/patterns/behavioral/command/tests/test_editor_undo.py +++ b/patterns/behavioral/command/tests/test_editor_undo.py @@ -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 diff --git a/patterns/behavioral/interpreter/__init__.py b/patterns/behavioral/interpreter/__init__.py index 49952a8..9cd063f 100644 --- a/patterns/behavioral/interpreter/__init__.py +++ b/patterns/behavioral/interpreter/__init__.py @@ -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 diff --git a/patterns/behavioral/interpreter/examples/__init__.py b/patterns/behavioral/interpreter/examples/__init__.py index 64c563c..e69de29 100644 --- a/patterns/behavioral/interpreter/examples/__init__.py +++ b/patterns/behavioral/interpreter/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Interpreter pattern in practice.""" diff --git a/patterns/behavioral/interpreter/examples/flag_rules/__init__.py b/patterns/behavioral/interpreter/examples/flag_rules/__init__.py index beba8b7..e69de29 100644 --- a/patterns/behavioral/interpreter/examples/flag_rules/__init__.py +++ b/patterns/behavioral/interpreter/examples/flag_rules/__init__.py @@ -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"] diff --git a/patterns/behavioral/interpreter/pattern/__init__.py b/patterns/behavioral/interpreter/pattern/__init__.py index b221163..64864a3 100644 --- a/patterns/behavioral/interpreter/pattern/__init__.py +++ b/patterns/behavioral/interpreter/pattern/__init__.py @@ -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 diff --git a/patterns/behavioral/interpreter/tests/test_flag_rules.py b/patterns/behavioral/interpreter/tests/test_flag_rules.py index 97491f5..7864a2f 100644 --- a/patterns/behavioral/interpreter/tests/test_flag_rules.py +++ b/patterns/behavioral/interpreter/tests/test_flag_rules.py @@ -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] = { diff --git a/patterns/behavioral/iterator/__init__.py b/patterns/behavioral/iterator/__init__.py index 146d335..b4d8623 100644 --- a/patterns/behavioral/iterator/__init__.py +++ b/patterns/behavioral/iterator/__init__.py @@ -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 diff --git a/patterns/behavioral/iterator/examples/__init__.py b/patterns/behavioral/iterator/examples/__init__.py index e50b2ee..e69de29 100644 --- a/patterns/behavioral/iterator/examples/__init__.py +++ b/patterns/behavioral/iterator/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Iterator pattern in practice.""" diff --git a/patterns/behavioral/iterator/examples/paginated_client/__init__.py b/patterns/behavioral/iterator/examples/paginated_client/__init__.py index fdf8cc6..e69de29 100644 --- a/patterns/behavioral/iterator/examples/paginated_client/__init__.py +++ b/patterns/behavioral/iterator/examples/paginated_client/__init__.py @@ -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"] diff --git a/patterns/behavioral/iterator/pattern/__init__.py b/patterns/behavioral/iterator/pattern/__init__.py index 40d9240..6130fd6 100644 --- a/patterns/behavioral/iterator/pattern/__init__.py +++ b/patterns/behavioral/iterator/pattern/__init__.py @@ -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 diff --git a/patterns/behavioral/iterator/tests/test_paginated_client.py b/patterns/behavioral/iterator/tests/test_paginated_client.py index 025a045..4d257e1 100644 --- a/patterns/behavioral/iterator/tests/test_paginated_client.py +++ b/patterns/behavioral/iterator/tests/test_paginated_client.py @@ -4,10 +4,8 @@ import itertools -from patterns.behavioral.iterator.examples.paginated_client import ( - ArticleClient, - FakeBackend, -) +from patterns.behavioral.iterator.examples.paginated_client.backend import FakeBackend +from patterns.behavioral.iterator.examples.paginated_client.client import ArticleClient def _backend(count: int = 30, page_size: int = 5) -> FakeBackend: diff --git a/patterns/behavioral/mediator/__init__.py b/patterns/behavioral/mediator/__init__.py index 4982c15..f637691 100644 --- a/patterns/behavioral/mediator/__init__.py +++ b/patterns/behavioral/mediator/__init__.py @@ -1,8 +1,2 @@ -"""Mediator — public API. - ->>> from patterns.behavioral.mediator import Field, Form -""" - -from patterns.behavioral.mediator.pattern import Field, Form - -__all__ = ["Field", "Form"] +from .pattern.form import Field as Field +from .pattern.form import Form as Form diff --git a/patterns/behavioral/mediator/examples/__init__.py b/patterns/behavioral/mediator/examples/__init__.py index c8350a9..e69de29 100644 --- a/patterns/behavioral/mediator/examples/__init__.py +++ b/patterns/behavioral/mediator/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Mediator pattern in practice.""" diff --git a/patterns/behavioral/mediator/examples/checkout_form/__init__.py b/patterns/behavioral/mediator/examples/checkout_form/__init__.py index fcf8726..e69de29 100644 --- a/patterns/behavioral/mediator/examples/checkout_form/__init__.py +++ b/patterns/behavioral/mediator/examples/checkout_form/__init__.py @@ -1,12 +0,0 @@ -"""A checkout form built on the Mediator pattern. - -Run it: ``uv run python -m patterns.behavioral.mediator.examples.checkout_form`` -""" - -from patterns.behavioral.mediator.examples.checkout_form.form import CheckoutForm -from patterns.behavioral.mediator.examples.checkout_form.rules import ( - PAYMENTS_BY_SHIPPING, - SHIPPING_BY_COUNTRY, -) - -__all__ = ["PAYMENTS_BY_SHIPPING", "SHIPPING_BY_COUNTRY", "CheckoutForm"] diff --git a/patterns/behavioral/mediator/pattern/__init__.py b/patterns/behavioral/mediator/pattern/__init__.py index c274ca8..ce2cccd 100644 --- a/patterns/behavioral/mediator/pattern/__init__.py +++ b/patterns/behavioral/mediator/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Mediator pattern, importable as library code.""" - -from patterns.behavioral.mediator.pattern.form import Field, Form - -__all__ = ["Field", "Form"] +from .form import Field as Field +from .form import Form as Form diff --git a/patterns/behavioral/mediator/tests/test_checkout_form.py b/patterns/behavioral/mediator/tests/test_checkout_form.py index a6c8f82..769956e 100644 --- a/patterns/behavioral/mediator/tests/test_checkout_form.py +++ b/patterns/behavioral/mediator/tests/test_checkout_form.py @@ -2,7 +2,7 @@ from __future__ import annotations -from patterns.behavioral.mediator.examples.checkout_form import CheckoutForm +from patterns.behavioral.mediator.examples.checkout_form.form import CheckoutForm class TestCheckoutForm: diff --git a/patterns/behavioral/memento/__init__.py b/patterns/behavioral/memento/__init__.py index cc92040..b4d3623 100644 --- a/patterns/behavioral/memento/__init__.py +++ b/patterns/behavioral/memento/__init__.py @@ -1,8 +1,2 @@ -"""Memento — public API. - ->>> from patterns.behavioral.memento import History -""" - -from patterns.behavioral.memento.pattern import History, NoSnapshotError - -__all__ = ["History", "NoSnapshotError"] +from .pattern.history import History as History +from .pattern.history import NoSnapshotError as NoSnapshotError diff --git a/patterns/behavioral/memento/examples/config_checkpoints/__init__.py b/patterns/behavioral/memento/examples/config_checkpoints/__init__.py index 5e8bcac..e69de29 100644 --- a/patterns/behavioral/memento/examples/config_checkpoints/__init__.py +++ b/patterns/behavioral/memento/examples/config_checkpoints/__init__.py @@ -1,13 +0,0 @@ -"""Config editing with validate-or-rollback, built on the Memento pattern. - -Run it: ``uv run python -m patterns.behavioral.memento.examples.config_checkpoints`` -""" - -from patterns.behavioral.memento.examples.config_checkpoints.editor import ConfigEditor -from patterns.behavioral.memento.examples.config_checkpoints.models import ( - InvalidConfigError, - ServiceConfig, - validate, -) - -__all__ = ["ConfigEditor", "InvalidConfigError", "ServiceConfig", "validate"] diff --git a/patterns/behavioral/memento/pattern/__init__.py b/patterns/behavioral/memento/pattern/__init__.py index 594ca1d..1e8cbc9 100644 --- a/patterns/behavioral/memento/pattern/__init__.py +++ b/patterns/behavioral/memento/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Memento pattern, importable as library code.""" - -from patterns.behavioral.memento.pattern.history import History, NoSnapshotError - -__all__ = ["History", "NoSnapshotError"] +from .history import History as History +from .history import NoSnapshotError as NoSnapshotError diff --git a/patterns/behavioral/memento/tests/test_config_checkpoints.py b/patterns/behavioral/memento/tests/test_config_checkpoints.py index 6fcc6f3..2d89135 100644 --- a/patterns/behavioral/memento/tests/test_config_checkpoints.py +++ b/patterns/behavioral/memento/tests/test_config_checkpoints.py @@ -4,12 +4,12 @@ import pytest -from patterns.behavioral.memento.examples.config_checkpoints import ( - ConfigEditor, +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.models import ( InvalidConfigError, ServiceConfig, ) -from patterns.behavioral.memento.examples.config_checkpoints.__main__ import main class TestValidateOrRollback: diff --git a/patterns/behavioral/observer/__init__.py b/patterns/behavioral/observer/__init__.py index 770e6dc..263b01f 100644 --- a/patterns/behavioral/observer/__init__.py +++ b/patterns/behavioral/observer/__init__.py @@ -1,8 +1,3 @@ -"""Observer — public API. - ->>> from patterns.behavioral.observer import Signal -""" - -from patterns.behavioral.observer.pattern import ErrorPolicy, Signal, Subscriber - -__all__ = ["ErrorPolicy", "Signal", "Subscriber"] +from .pattern.signal import ErrorPolicy as ErrorPolicy +from .pattern.signal import Signal as Signal +from .pattern.signal import Subscriber as Subscriber diff --git a/patterns/behavioral/observer/examples/order_events/__init__.py b/patterns/behavioral/observer/examples/order_events/__init__.py index 1f65881..e69de29 100644 --- a/patterns/behavioral/observer/examples/order_events/__init__.py +++ b/patterns/behavioral/observer/examples/order_events/__init__.py @@ -1,22 +0,0 @@ -"""Order events with independent subscribers, built on the Observer pattern. - -Run it: ``uv run python -m patterns.behavioral.observer.examples.order_events`` -""" - -from patterns.behavioral.observer.examples.order_events.models import OrderEvent -from patterns.behavioral.observer.examples.order_events.subscribers import ( - AuditLog, - EmailNotifier, - MetricsCounter, - OrderPipeline, - flaky_webhook, -) - -__all__ = [ - "AuditLog", - "EmailNotifier", - "MetricsCounter", - "OrderEvent", - "OrderPipeline", - "flaky_webhook", -] diff --git a/patterns/behavioral/observer/pattern/__init__.py b/patterns/behavioral/observer/pattern/__init__.py index c0d2a0d..bbe8b6d 100644 --- a/patterns/behavioral/observer/pattern/__init__.py +++ b/patterns/behavioral/observer/pattern/__init__.py @@ -1,5 +1,3 @@ -"""The Observer pattern, importable as library code.""" - -from patterns.behavioral.observer.pattern.signal import ErrorPolicy, Signal, Subscriber - -__all__ = ["ErrorPolicy", "Signal", "Subscriber"] +from .signal import ErrorPolicy as ErrorPolicy +from .signal import Signal as Signal +from .signal import Subscriber as Subscriber diff --git a/patterns/behavioral/observer/tests/test_order_events.py b/patterns/behavioral/observer/tests/test_order_events.py index 6f9bee1..a577d3c 100644 --- a/patterns/behavioral/observer/tests/test_order_events.py +++ b/patterns/behavioral/observer/tests/test_order_events.py @@ -4,14 +4,14 @@ import pytest -from patterns.behavioral.observer.examples.order_events import ( +from patterns.behavioral.observer.examples.order_events.__main__ import main +from patterns.behavioral.observer.examples.order_events.subscribers import ( AuditLog, EmailNotifier, MetricsCounter, OrderPipeline, flaky_webhook, ) -from patterns.behavioral.observer.examples.order_events.__main__ import main def wired_pipeline() -> tuple[OrderPipeline, EmailNotifier, MetricsCounter, AuditLog]: diff --git a/patterns/behavioral/state/__init__.py b/patterns/behavioral/state/__init__.py index cdcb916..4a08d9b 100644 --- a/patterns/behavioral/state/__init__.py +++ b/patterns/behavioral/state/__init__.py @@ -1,8 +1,4 @@ -"""State — public API. - ->>> from patterns.behavioral.state import StateMachine -""" - -from patterns.behavioral.state.pattern import Guard, IllegalTransitionError, StateMachine, Step - -__all__ = ["Guard", "IllegalTransitionError", "StateMachine", "Step"] +from .pattern.machine import Guard as Guard +from .pattern.machine import IllegalTransitionError as IllegalTransitionError +from .pattern.machine import StateMachine as StateMachine +from .pattern.machine import Step as Step diff --git a/patterns/behavioral/state/examples/order_lifecycle/__init__.py b/patterns/behavioral/state/examples/order_lifecycle/__init__.py index 17524a9..e69de29 100644 --- a/patterns/behavioral/state/examples/order_lifecycle/__init__.py +++ b/patterns/behavioral/state/examples/order_lifecycle/__init__.py @@ -1,16 +0,0 @@ -"""An order lifecycle FSM, built on the State pattern. - -Run it: ``uv run python -m patterns.behavioral.state.examples.order_lifecycle`` -""" - -from patterns.behavioral.state.examples.order_lifecycle.lifecycle import ( - LIFECYCLE, - build_lifecycle, -) -from patterns.behavioral.state.examples.order_lifecycle.models import ( - Order, - OrderAction, - OrderStatus, -) - -__all__ = ["LIFECYCLE", "Order", "OrderAction", "OrderStatus", "build_lifecycle"] diff --git a/patterns/behavioral/state/pattern/__init__.py b/patterns/behavioral/state/pattern/__init__.py index 3e070f7..2c03778 100644 --- a/patterns/behavioral/state/pattern/__init__.py +++ b/patterns/behavioral/state/pattern/__init__.py @@ -1,10 +1,4 @@ -"""The State pattern, importable as library code.""" - -from patterns.behavioral.state.pattern.machine import ( - Guard, - IllegalTransitionError, - StateMachine, - Step, -) - -__all__ = ["Guard", "IllegalTransitionError", "StateMachine", "Step"] +from .machine import Guard as Guard +from .machine import IllegalTransitionError as IllegalTransitionError +from .machine import StateMachine as StateMachine +from .machine import Step as Step diff --git a/patterns/behavioral/state/tests/test_order_lifecycle.py b/patterns/behavioral/state/tests/test_order_lifecycle.py index e4575f5..fecfab3 100644 --- a/patterns/behavioral/state/tests/test_order_lifecycle.py +++ b/patterns/behavioral/state/tests/test_order_lifecycle.py @@ -5,13 +5,13 @@ import pytest from patterns.behavioral.state import IllegalTransitionError -from patterns.behavioral.state.examples.order_lifecycle import ( +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.models import ( Order, OrderAction, OrderStatus, - build_lifecycle, ) -from patterns.behavioral.state.examples.order_lifecycle.__main__ import main def order_with_items() -> Order: diff --git a/patterns/behavioral/strategy/__init__.py b/patterns/behavioral/strategy/__init__.py index 1758720..ee3a67c 100644 --- a/patterns/behavioral/strategy/__init__.py +++ b/patterns/behavioral/strategy/__init__.py @@ -1,8 +1,2 @@ -"""Strategy — public API. - ->>> from patterns.behavioral.strategy import StrategyRegistry -""" - -from patterns.behavioral.strategy.pattern import StrategyRegistry, UnknownStrategyError - -__all__ = ["StrategyRegistry", "UnknownStrategyError"] +from .pattern.registry import StrategyRegistry as StrategyRegistry +from .pattern.registry import UnknownStrategyError as UnknownStrategyError diff --git a/patterns/behavioral/strategy/examples/__init__.py b/patterns/behavioral/strategy/examples/__init__.py index d1deeba..e69de29 100644 --- a/patterns/behavioral/strategy/examples/__init__.py +++ b/patterns/behavioral/strategy/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Strategy pattern in practice.""" diff --git a/patterns/behavioral/strategy/examples/promotions/__init__.py b/patterns/behavioral/strategy/examples/promotions/__init__.py index 0c6c7c6..e69de29 100644 --- a/patterns/behavioral/strategy/examples/promotions/__init__.py +++ b/patterns/behavioral/strategy/examples/promotions/__init__.py @@ -1,13 +0,0 @@ -"""A promotions engine built on the Strategy pattern. - -Run it: ``uv run python -m patterns.behavioral.strategy.examples.promotions`` -""" - -from patterns.behavioral.strategy.examples.promotions.models import LineItem, Order -from patterns.behavioral.strategy.examples.promotions.rules import ( - best_promo, - due, - promotion, -) - -__all__ = ["LineItem", "Order", "best_promo", "due", "promotion"] diff --git a/patterns/behavioral/strategy/pattern/__init__.py b/patterns/behavioral/strategy/pattern/__init__.py index 327d105..1b75203 100644 --- a/patterns/behavioral/strategy/pattern/__init__.py +++ b/patterns/behavioral/strategy/pattern/__init__.py @@ -1,8 +1,2 @@ -"""The Strategy pattern, importable as library code.""" - -from patterns.behavioral.strategy.pattern.registry import ( - StrategyRegistry, - UnknownStrategyError, -) - -__all__ = ["StrategyRegistry", "UnknownStrategyError"] +from .registry import StrategyRegistry as StrategyRegistry +from .registry import UnknownStrategyError as UnknownStrategyError diff --git a/patterns/behavioral/strategy/tests/test_promotions.py b/patterns/behavioral/strategy/tests/test_promotions.py index 30cc2f4..596255c 100644 --- a/patterns/behavioral/strategy/tests/test_promotions.py +++ b/patterns/behavioral/strategy/tests/test_promotions.py @@ -4,14 +4,9 @@ import pytest -from patterns.behavioral.strategy.examples.promotions import ( - LineItem, - Order, - best_promo, - due, - promotion, -) 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 diff --git a/patterns/behavioral/template_method/__init__.py b/patterns/behavioral/template_method/__init__.py index 94dcc5a..dadc1fa 100644 --- a/patterns/behavioral/template_method/__init__.py +++ b/patterns/behavioral/template_method/__init__.py @@ -1,8 +1,3 @@ -"""Template Method — public API. - ->>> from patterns.behavioral.template_method import Skeleton -""" - -from patterns.behavioral.template_method.pattern import Skeleton, discard, keep_all - -__all__ = ["Skeleton", "discard", "keep_all"] +from .pattern.skeleton import Skeleton as Skeleton +from .pattern.skeleton import discard as discard +from .pattern.skeleton import keep_all as keep_all diff --git a/patterns/behavioral/template_method/examples/__init__.py b/patterns/behavioral/template_method/examples/__init__.py index 3587ec1..e69de29 100644 --- a/patterns/behavioral/template_method/examples/__init__.py +++ b/patterns/behavioral/template_method/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Template Method pattern in practice.""" diff --git a/patterns/behavioral/template_method/examples/report_pipeline/__init__.py b/patterns/behavioral/template_method/examples/report_pipeline/__init__.py index cb24886..e69de29 100644 --- a/patterns/behavioral/template_method/examples/report_pipeline/__init__.py +++ b/patterns/behavioral/template_method/examples/report_pipeline/__init__.py @@ -1,23 +0,0 @@ -"""A sales-report pipeline built on the Template Method pattern. - -Run it: ``uv run python -m patterns.behavioral.template_method.examples.report_pipeline`` -""" - -from patterns.behavioral.template_method.examples.report_pipeline.models import Sale, Sales -from patterns.behavioral.template_method.examples.report_pipeline.pipeline import ( - build_csv_report, - build_markdown_report, - csv_rows, - drop_refunds, - markdown_table, -) - -__all__ = [ - "Sale", - "Sales", - "build_csv_report", - "build_markdown_report", - "csv_rows", - "drop_refunds", - "markdown_table", -] diff --git a/patterns/behavioral/template_method/pattern/__init__.py b/patterns/behavioral/template_method/pattern/__init__.py index 7870ce7..5918c34 100644 --- a/patterns/behavioral/template_method/pattern/__init__.py +++ b/patterns/behavioral/template_method/pattern/__init__.py @@ -1,9 +1,3 @@ -"""The Template Method pattern, importable as library code.""" - -from patterns.behavioral.template_method.pattern.skeleton import ( - Skeleton, - discard, - keep_all, -) - -__all__ = ["Skeleton", "discard", "keep_all"] +from .skeleton import Skeleton as Skeleton +from .skeleton import discard as discard +from .skeleton import keep_all as keep_all diff --git a/patterns/behavioral/template_method/tests/test_report_pipeline.py b/patterns/behavioral/template_method/tests/test_report_pipeline.py index 2ca4675..e8ca8d1 100644 --- a/patterns/behavioral/template_method/tests/test_report_pipeline.py +++ b/patterns/behavioral/template_method/tests/test_report_pipeline.py @@ -4,15 +4,15 @@ import pytest -from patterns.behavioral.template_method.examples.report_pipeline import ( - Sale, +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, build_markdown_report, csv_rows, drop_refunds, markdown_table, ) -from patterns.behavioral.template_method.examples.report_pipeline.__main__ import main class TestSteps: diff --git a/patterns/behavioral/visitor/__init__.py b/patterns/behavioral/visitor/__init__.py index 8e49dd5..f818c34 100644 --- a/patterns/behavioral/visitor/__init__.py +++ b/patterns/behavioral/visitor/__init__.py @@ -1,8 +1,2 @@ -"""Visitor — public API. - ->>> from patterns.behavioral.visitor import Operation -""" - -from patterns.behavioral.visitor.pattern import Operation, UnhandledNodeError - -__all__ = ["Operation", "UnhandledNodeError"] +from .pattern.dispatch import Operation as Operation +from .pattern.dispatch import UnhandledNodeError as UnhandledNodeError diff --git a/patterns/behavioral/visitor/examples/__init__.py b/patterns/behavioral/visitor/examples/__init__.py index 7fdc4b0..e69de29 100644 --- a/patterns/behavioral/visitor/examples/__init__.py +++ b/patterns/behavioral/visitor/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Visitor pattern in practice.""" diff --git a/patterns/behavioral/visitor/examples/doc_exporters/__init__.py b/patterns/behavioral/visitor/examples/doc_exporters/__init__.py index b03c3fa..e69de29 100644 --- a/patterns/behavioral/visitor/examples/doc_exporters/__init__.py +++ b/patterns/behavioral/visitor/examples/doc_exporters/__init__.py @@ -1,30 +0,0 @@ -"""Document exporters built on the Visitor pattern. - -Run it: ``uv run python -m patterns.behavioral.visitor.examples.doc_exporters`` -""" - -from patterns.behavioral.visitor.examples.doc_exporters.exporters import ( - markdown, - plain_text, - word_count, -) -from patterns.behavioral.visitor.examples.doc_exporters.nodes import ( - Block, - BulletList, - CodeBlock, - Document, - Paragraph, - Section, -) - -__all__ = [ - "Block", - "BulletList", - "CodeBlock", - "Document", - "Paragraph", - "Section", - "markdown", - "plain_text", - "word_count", -] diff --git a/patterns/behavioral/visitor/pattern/__init__.py b/patterns/behavioral/visitor/pattern/__init__.py index c1ad4c2..379d77c 100644 --- a/patterns/behavioral/visitor/pattern/__init__.py +++ b/patterns/behavioral/visitor/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Visitor pattern, importable as library code.""" - -from patterns.behavioral.visitor.pattern.dispatch import Operation, UnhandledNodeError - -__all__ = ["Operation", "UnhandledNodeError"] +from .dispatch import Operation as Operation +from .dispatch import UnhandledNodeError as UnhandledNodeError diff --git a/patterns/behavioral/visitor/tests/test_doc_exporters.py b/patterns/behavioral/visitor/tests/test_doc_exporters.py index 0c674a0..d1504bb 100644 --- a/patterns/behavioral/visitor/tests/test_doc_exporters.py +++ b/patterns/behavioral/visitor/tests/test_doc_exporters.py @@ -5,17 +5,19 @@ import pytest from patterns.behavioral.visitor import Operation, UnhandledNodeError -from patterns.behavioral.visitor.examples.doc_exporters import ( +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.nodes import ( BulletList, CodeBlock, Document, Paragraph, Section, - markdown, - plain_text, - word_count, ) -from patterns.behavioral.visitor.examples.doc_exporters.__main__ import main, sample_document class TestMarkdown: diff --git a/patterns/creational/__init__.py b/patterns/creational/__init__.py index d423003..e69de29 100644 --- a/patterns/creational/__init__.py +++ b/patterns/creational/__init__.py @@ -1 +0,0 @@ -"""creational patterns.""" diff --git a/patterns/creational/abstract_factory/__init__.py b/patterns/creational/abstract_factory/__init__.py index 1506a67..9062a18 100644 --- a/patterns/creational/abstract_factory/__init__.py +++ b/patterns/creational/abstract_factory/__init__.py @@ -1,12 +1,3 @@ -"""Abstract Factory — public API. - ->>> from patterns.creational.abstract_factory import DocumentFamily -""" - -from patterns.creational.abstract_factory.pattern import ( - HTML, - MARKDOWN, - DocumentFamily, -) - -__all__ = ["HTML", "MARKDOWN", "DocumentFamily"] +from .pattern import HTML as HTML +from .pattern import MARKDOWN as MARKDOWN +from .pattern import DocumentFamily as DocumentFamily diff --git a/patterns/creational/abstract_factory/examples/report_renderer/__init__.py b/patterns/creational/abstract_factory/examples/report_renderer/__init__.py index da508e1..e69de29 100644 --- a/patterns/creational/abstract_factory/examples/report_renderer/__init__.py +++ b/patterns/creational/abstract_factory/examples/report_renderer/__init__.py @@ -1,13 +0,0 @@ -"""Quarterly-report rendering built on the Abstract Factory. - -Run it: ``uv run python -m patterns.creational.abstract_factory.examples.report_renderer`` -""" - -from patterns.creational.abstract_factory.examples.report_renderer.renderer import render -from patterns.creational.abstract_factory.examples.report_renderer.report import ( - Report, - Section, - Table, -) - -__all__ = ["Report", "Section", "Table", "render"] diff --git a/patterns/creational/abstract_factory/pattern/__init__.py b/patterns/creational/abstract_factory/pattern/__init__.py index 7391668..9a51727 100644 --- a/patterns/creational/abstract_factory/pattern/__init__.py +++ b/patterns/creational/abstract_factory/pattern/__init__.py @@ -1,9 +1,3 @@ -"""The importable Abstract Factory building block.""" - -from patterns.creational.abstract_factory.pattern.family import ( - HTML, - MARKDOWN, - DocumentFamily, -) - -__all__ = ["HTML", "MARKDOWN", "DocumentFamily"] +from .family import HTML as HTML +from .family import MARKDOWN as MARKDOWN +from .family import DocumentFamily as DocumentFamily diff --git a/patterns/creational/abstract_factory/tests/test_report_renderer.py b/patterns/creational/abstract_factory/tests/test_report_renderer.py index 1d24f72..beee41f 100644 --- a/patterns/creational/abstract_factory/tests/test_report_renderer.py +++ b/patterns/creational/abstract_factory/tests/test_report_renderer.py @@ -2,13 +2,13 @@ from __future__ import annotations -from patterns.creational.abstract_factory.examples.report_renderer import ( +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, Section, Table, - render, ) -from patterns.creational.abstract_factory.examples.report_renderer.__main__ import Q3 from patterns.creational.abstract_factory.pattern import HTML, MARKDOWN from patterns.creational.abstract_factory.tests.test_family import make_recording_family diff --git a/patterns/creational/builder/__init__.py b/patterns/creational/builder/__init__.py index 36c1d75..b024190 100644 --- a/patterns/creational/builder/__init__.py +++ b/patterns/creational/builder/__init__.py @@ -1,8 +1,2 @@ -"""Builder — public API. - ->>> from patterns.creational.builder import SelectBuilder -""" - -from patterns.creational.builder.pattern import Query, SelectBuilder - -__all__ = ["Query", "SelectBuilder"] +from .pattern import Query as Query +from .pattern import SelectBuilder as SelectBuilder diff --git a/patterns/creational/builder/examples/sql_select_builder/__init__.py b/patterns/creational/builder/examples/sql_select_builder/__init__.py index 78c8e1e..e69de29 100644 --- a/patterns/creational/builder/examples/sql_select_builder/__init__.py +++ b/patterns/creational/builder/examples/sql_select_builder/__init__.py @@ -1,13 +0,0 @@ -"""Order analytics over sqlite, with every query built through SelectBuilder. - -Run it: ``uv run python -m patterns.creational.builder.examples.sql_select_builder`` -""" - -from patterns.creational.builder.examples.sql_select_builder.database import seed_orders -from patterns.creational.builder.examples.sql_select_builder.reports import ( - big_orders, - orders_in_region, - top_orders, -) - -__all__ = ["big_orders", "orders_in_region", "seed_orders", "top_orders"] diff --git a/patterns/creational/builder/pattern/__init__.py b/patterns/creational/builder/pattern/__init__.py index 184bcec..25e32ec 100644 --- a/patterns/creational/builder/pattern/__init__.py +++ b/patterns/creational/builder/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The importable Builder building block.""" - -from patterns.creational.builder.pattern.query import Query, SelectBuilder - -__all__ = ["Query", "SelectBuilder"] +from .query import Query as Query +from .query import SelectBuilder as SelectBuilder diff --git a/patterns/creational/builder/tests/test_sql_select_builder.py b/patterns/creational/builder/tests/test_sql_select_builder.py index e4681d5..708a1cd 100644 --- a/patterns/creational/builder/tests/test_sql_select_builder.py +++ b/patterns/creational/builder/tests/test_sql_select_builder.py @@ -2,10 +2,10 @@ from __future__ import annotations -from patterns.creational.builder.examples.sql_select_builder import ( +from patterns.creational.builder.examples.sql_select_builder.database import seed_orders +from patterns.creational.builder.examples.sql_select_builder.reports import ( big_orders, orders_in_region, - seed_orders, top_orders, ) diff --git a/patterns/creational/factory_method/__init__.py b/patterns/creational/factory_method/__init__.py index 48eb12f..94d7203 100644 --- a/patterns/creational/factory_method/__init__.py +++ b/patterns/creational/factory_method/__init__.py @@ -1,11 +1,2 @@ -"""Factory Method — public API. - ->>> from patterns.creational.factory_method import factory_slot -""" - -from patterns.creational.factory_method.pattern import Factory, factory_slot - -__all__ = [ - "Factory", - "factory_slot", -] +from .pattern import Factory as Factory +from .pattern import factory_slot as factory_slot diff --git a/patterns/creational/factory_method/examples/__init__.py b/patterns/creational/factory_method/examples/__init__.py index 16e951e..e69de29 100644 --- a/patterns/creational/factory_method/examples/__init__.py +++ b/patterns/creational/factory_method/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Factory Method's Python forms in practice.""" diff --git a/patterns/creational/factory_method/examples/feed_client/__init__.py b/patterns/creational/factory_method/examples/feed_client/__init__.py index 706f897..e69de29 100644 --- a/patterns/creational/factory_method/examples/feed_client/__init__.py +++ b/patterns/creational/factory_method/examples/feed_client/__init__.py @@ -1,26 +0,0 @@ -"""A feed-client framework built on the unit's ``pattern`` package. - -Run it: ``uv run python -m patterns.creational.factory_method.examples.feed_client`` -""" - -from patterns.creational.factory_method.examples.feed_client.client import ( - DigestClient, - DigestResponse, - FeedClient, - FeedResponse, - StrictClient, - Transport, - parse_strictly, -) -from patterns.creational.factory_method.examples.feed_client.models import Article - -__all__ = [ - "Article", - "DigestClient", - "DigestResponse", - "FeedClient", - "FeedResponse", - "StrictClient", - "Transport", - "parse_strictly", -] diff --git a/patterns/creational/factory_method/pattern/__init__.py b/patterns/creational/factory_method/pattern/__init__.py index 0c02cec..3ddaf4a 100644 --- a/patterns/creational/factory_method/pattern/__init__.py +++ b/patterns/creational/factory_method/pattern/__init__.py @@ -1,8 +1,2 @@ -"""The Factory Method pattern's Python forms, importable as library code.""" - -from patterns.creational.factory_method.pattern.dodges import Factory, factory_slot - -__all__ = [ - "Factory", - "factory_slot", -] +from .dodges import Factory as Factory +from .dodges import factory_slot as factory_slot diff --git a/patterns/creational/factory_method/tests/test_feed_client.py b/patterns/creational/factory_method/tests/test_feed_client.py index 2504d09..8d59242 100644 --- a/patterns/creational/factory_method/tests/test_feed_client.py +++ b/patterns/creational/factory_method/tests/test_feed_client.py @@ -2,7 +2,7 @@ import pytest -from patterns.creational.factory_method.examples.feed_client import ( +from patterns.creational.factory_method.examples.feed_client.client import ( DigestClient, DigestResponse, FeedClient, diff --git a/patterns/creational/prototype/__init__.py b/patterns/creational/prototype/__init__.py index b67e88e..d24886e 100644 --- a/patterns/creational/prototype/__init__.py +++ b/patterns/creational/prototype/__init__.py @@ -1,8 +1,2 @@ -"""Prototype — public API. - ->>> from patterns.creational.prototype import TemplateRegistry -""" - -from patterns.creational.prototype.pattern import Template, TemplateRegistry - -__all__ = ["Template", "TemplateRegistry"] +from .pattern import Template as Template +from .pattern import TemplateRegistry as TemplateRegistry diff --git a/patterns/creational/prototype/examples/__init__.py b/patterns/creational/prototype/examples/__init__.py index f1651ca..e69de29 100644 --- a/patterns/creational/prototype/examples/__init__.py +++ b/patterns/creational/prototype/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Prototype's Python form in practice.""" diff --git a/patterns/creational/prototype/examples/report_job_templates/__init__.py b/patterns/creational/prototype/examples/report_job_templates/__init__.py index f4a7a68..e69de29 100644 --- a/patterns/creational/prototype/examples/report_job_templates/__init__.py +++ b/patterns/creational/prototype/examples/report_job_templates/__init__.py @@ -1,12 +0,0 @@ -"""Report jobs stamped from templates, built on the Prototype's Python form. - -Run it: ``uv run python -m patterns.creational.prototype.examples.report_job_templates`` -""" - -from patterns.creational.prototype.examples.report_job_templates.models import ReportJob -from patterns.creational.prototype.examples.report_job_templates.scheduler import ( - Scheduler, - build_template_menu, -) - -__all__ = ["ReportJob", "Scheduler", "build_template_menu"] diff --git a/patterns/creational/prototype/pattern/__init__.py b/patterns/creational/prototype/pattern/__init__.py index e358512..3df3362 100644 --- a/patterns/creational/prototype/pattern/__init__.py +++ b/patterns/creational/prototype/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Prototype pattern's Python form, importable as library code.""" - -from patterns.creational.prototype.pattern.templates import Template, TemplateRegistry - -__all__ = ["Template", "TemplateRegistry"] +from .templates import Template as Template +from .templates import TemplateRegistry as TemplateRegistry diff --git a/patterns/creational/prototype/tests/test_report_job_templates.py b/patterns/creational/prototype/tests/test_report_job_templates.py index ba40fcf..b5a5c7f 100644 --- a/patterns/creational/prototype/tests/test_report_job_templates.py +++ b/patterns/creational/prototype/tests/test_report_job_templates.py @@ -1,6 +1,6 @@ """Behavioral tests for the report-job mini-project.""" -from patterns.creational.prototype.examples.report_job_templates import Scheduler +from patterns.creational.prototype.examples.report_job_templates.scheduler import Scheduler class TestScheduler: diff --git a/patterns/creational/singleton/__init__.py b/patterns/creational/singleton/__init__.py index 1b4287b..ffe491c 100644 --- a/patterns/creational/singleton/__init__.py +++ b/patterns/creational/singleton/__init__.py @@ -1,8 +1 @@ -"""Singleton — public API (the alternative, really). - ->>> from patterns.creational.singleton import Shared -""" - -from patterns.creational.singleton.pattern import Shared - -__all__ = ["Shared"] +from .pattern import Shared as Shared diff --git a/patterns/creational/singleton/examples/__init__.py b/patterns/creational/singleton/examples/__init__.py index d25c438..e69de29 100644 --- a/patterns/creational/singleton/examples/__init__.py +++ b/patterns/creational/singleton/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Singleton's Python replacement in practice.""" diff --git a/patterns/creational/singleton/examples/app_config/__init__.py b/patterns/creational/singleton/examples/app_config/__init__.py index 98736de..e69de29 100644 --- a/patterns/creational/singleton/examples/app_config/__init__.py +++ b/patterns/creational/singleton/examples/app_config/__init__.py @@ -1,13 +0,0 @@ -"""App configuration behind an accessor, built on the Singleton's replacement. - -Run it: ``uv run python -m patterns.creational.singleton.examples.app_config`` -""" - -from patterns.creational.singleton.examples.app_config.settings import ( - Settings, - get_settings, - load_settings, - reset_settings, -) - -__all__ = ["Settings", "get_settings", "load_settings", "reset_settings"] diff --git a/patterns/creational/singleton/pattern/__init__.py b/patterns/creational/singleton/pattern/__init__.py index 62d5062..21667fc 100644 --- a/patterns/creational/singleton/pattern/__init__.py +++ b/patterns/creational/singleton/pattern/__init__.py @@ -1,5 +1 @@ -"""The Singleton's Python replacement, importable as library code.""" - -from patterns.creational.singleton.pattern.shared import Shared - -__all__ = ["Shared"] +from .shared import Shared as Shared diff --git a/patterns/creational/singleton/tests/test_app_config.py b/patterns/creational/singleton/tests/test_app_config.py index c2fac19..0b1327e 100644 --- a/patterns/creational/singleton/tests/test_app_config.py +++ b/patterns/creational/singleton/tests/test_app_config.py @@ -5,7 +5,7 @@ import pytest -from patterns.creational.singleton.examples.app_config import ( +from patterns.creational.singleton.examples.app_config.settings import ( get_settings, load_settings, reset_settings, diff --git a/patterns/modern/__init__.py b/patterns/modern/__init__.py index e52f98d..e69de29 100644 --- a/patterns/modern/__init__.py +++ b/patterns/modern/__init__.py @@ -1 +0,0 @@ -"""Modern Python patterns beyond the Gang of Four.""" diff --git a/patterns/modern/async_producer_consumer/__init__.py b/patterns/modern/async_producer_consumer/__init__.py index 499f74d..dc4df9a 100644 --- a/patterns/modern/async_producer_consumer/__init__.py +++ b/patterns/modern/async_producer_consumer/__init__.py @@ -1,13 +1,4 @@ -"""Async Producer/Consumer — public API. - ->>> from patterns.modern.async_producer_consumer import WorkerPool -""" - -from patterns.modern.async_producer_consumer.pattern import ( - Processor, - Shutdown, - WorkerPool, - process_all, -) - -__all__ = ["Processor", "Shutdown", "WorkerPool", "process_all"] +from .pattern import Processor as Processor +from .pattern import Shutdown as Shutdown +from .pattern import WorkerPool as WorkerPool +from .pattern import process_all as process_all diff --git a/patterns/modern/async_producer_consumer/examples/__init__.py b/patterns/modern/async_producer_consumer/examples/__init__.py index 07461af..e69de29 100644 --- a/patterns/modern/async_producer_consumer/examples/__init__.py +++ b/patterns/modern/async_producer_consumer/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the async producer/consumer pattern in practice.""" diff --git a/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py b/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py index dd5ce1e..e69de29 100644 --- a/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py +++ b/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py @@ -1,16 +0,0 @@ -"""Feed-fetching pipeline built on the async producer/consumer pool. - -Run it: ``uv run python -m patterns.modern.async_producer_consumer.examples.feed_fetcher`` -""" - -from patterns.modern.async_producer_consumer.examples.feed_fetcher.fetcher import ( - fetch_all, - fetch_entries, - summarize, -) -from patterns.modern.async_producer_consumer.examples.feed_fetcher.models import ( - Feed, - FetchOutcome, -) - -__all__ = ["Feed", "FetchOutcome", "fetch_all", "fetch_entries", "summarize"] diff --git a/patterns/modern/async_producer_consumer/pattern/__init__.py b/patterns/modern/async_producer_consumer/pattern/__init__.py index d397876..751e351 100644 --- a/patterns/modern/async_producer_consumer/pattern/__init__.py +++ b/patterns/modern/async_producer_consumer/pattern/__init__.py @@ -1,10 +1,4 @@ -"""The async producer/consumer pattern, importable as library code.""" - -from patterns.modern.async_producer_consumer.pattern.pool import ( - Processor, - Shutdown, - WorkerPool, - process_all, -) - -__all__ = ["Processor", "Shutdown", "WorkerPool", "process_all"] +from .pool import Processor as Processor +from .pool import Shutdown as Shutdown +from .pool import WorkerPool as WorkerPool +from .pool import process_all as process_all diff --git a/patterns/modern/async_producer_consumer/tests/test_feed_fetcher.py b/patterns/modern/async_producer_consumer/tests/test_feed_fetcher.py index 56651ab..8e975e8 100644 --- a/patterns/modern/async_producer_consumer/tests/test_feed_fetcher.py +++ b/patterns/modern/async_producer_consumer/tests/test_feed_fetcher.py @@ -4,12 +4,12 @@ import pytest -from patterns.modern.async_producer_consumer.examples.feed_fetcher import ( - Feed, +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 FEEDS = [ diff --git a/patterns/modern/context_manager/__init__.py b/patterns/modern/context_manager/__init__.py index ac82640..3812cc0 100644 --- a/patterns/modern/context_manager/__init__.py +++ b/patterns/modern/context_manager/__init__.py @@ -1,8 +1,2 @@ -"""Context Manager — public API. - ->>> from patterns.modern.context_manager import AtomicWrite -""" - -from patterns.modern.context_manager.pattern import AtomicWrite, temporarily - -__all__ = ["AtomicWrite", "temporarily"] +from .pattern import AtomicWrite as AtomicWrite +from .pattern import temporarily as temporarily diff --git a/patterns/modern/context_manager/examples/__init__.py b/patterns/modern/context_manager/examples/__init__.py index eaf1971..e69de29 100644 --- a/patterns/modern/context_manager/examples/__init__.py +++ b/patterns/modern/context_manager/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the context manager pattern in practice.""" diff --git a/patterns/modern/context_manager/examples/atomic_deploy/__init__.py b/patterns/modern/context_manager/examples/atomic_deploy/__init__.py index 2fed0ca..e69de29 100644 --- a/patterns/modern/context_manager/examples/atomic_deploy/__init__.py +++ b/patterns/modern/context_manager/examples/atomic_deploy/__init__.py @@ -1,13 +0,0 @@ -"""Atomic config deployment built on the context manager pattern. - -Run it: ``uv run python -m patterns.modern.context_manager.examples.atomic_deploy`` -""" - -from patterns.modern.context_manager.examples.atomic_deploy.deploy import ( - ReleaseError, - deploy, - no_validation, - require_nonempty, -) - -__all__ = ["ReleaseError", "deploy", "no_validation", "require_nonempty"] diff --git a/patterns/modern/context_manager/pattern/__init__.py b/patterns/modern/context_manager/pattern/__init__.py index 2acc08b..a20a8ee 100644 --- a/patterns/modern/context_manager/pattern/__init__.py +++ b/patterns/modern/context_manager/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The context manager pattern, importable as library code.""" - -from patterns.modern.context_manager.pattern.managers import AtomicWrite, temporarily - -__all__ = ["AtomicWrite", "temporarily"] +from .managers import AtomicWrite as AtomicWrite +from .managers import temporarily as temporarily diff --git a/patterns/modern/context_manager/tests/test_atomic_deploy.py b/patterns/modern/context_manager/tests/test_atomic_deploy.py index a102446..b47ff47 100644 --- a/patterns/modern/context_manager/tests/test_atomic_deploy.py +++ b/patterns/modern/context_manager/tests/test_atomic_deploy.py @@ -6,12 +6,12 @@ import pytest -from patterns.modern.context_manager.examples.atomic_deploy import ( +from patterns.modern.context_manager.examples.atomic_deploy.__main__ import main +from patterns.modern.context_manager.examples.atomic_deploy.deploy import ( ReleaseError, deploy, require_nonempty, ) -from patterns.modern.context_manager.examples.atomic_deploy.__main__ import main V1 = {"app.toml": "retries = 3\n", "logging.toml": "level = 'info'\n"} diff --git a/patterns/modern/dependency_injection/__init__.py b/patterns/modern/dependency_injection/__init__.py index e8ceb59..4b55e3f 100644 --- a/patterns/modern/dependency_injection/__init__.py +++ b/patterns/modern/dependency_injection/__init__.py @@ -1,14 +1,5 @@ -"""Dependency Injection — public API. - ->>> from patterns.modern.dependency_injection import ReminderService -""" - -from patterns.modern.dependency_injection.pattern import ( - Clock, - Invoice, - InvoiceSource, - MailTransport, - ReminderService, -) - -__all__ = ["Clock", "Invoice", "InvoiceSource", "MailTransport", "ReminderService"] +from .pattern import Clock as Clock +from .pattern import Invoice as Invoice +from .pattern import InvoiceSource as InvoiceSource +from .pattern import MailTransport as MailTransport +from .pattern import ReminderService as ReminderService diff --git a/patterns/modern/dependency_injection/examples/__init__.py b/patterns/modern/dependency_injection/examples/__init__.py index f03c5a4..e69de29 100644 --- a/patterns/modern/dependency_injection/examples/__init__.py +++ b/patterns/modern/dependency_injection/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating Dependency Injection in practice.""" diff --git a/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py b/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py index aab3ef7..e69de29 100644 --- a/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py +++ b/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py @@ -1,15 +0,0 @@ -"""Overdue-invoice reminders wired at a real composition root. - -Run it: ``uv run python -m patterns.modern.dependency_injection.examples.invoice_reminders`` -""" - -from patterns.modern.dependency_injection.examples.invoice_reminders.adapters import ( - ConsoleMail, - InMemoryInvoices, -) -from patterns.modern.dependency_injection.examples.invoice_reminders.app import ( - build_service, - sample_invoices, -) - -__all__ = ["ConsoleMail", "InMemoryInvoices", "build_service", "sample_invoices"] diff --git a/patterns/modern/dependency_injection/pattern/__init__.py b/patterns/modern/dependency_injection/pattern/__init__.py index e68885f..4bb2d7c 100644 --- a/patterns/modern/dependency_injection/pattern/__init__.py +++ b/patterns/modern/dependency_injection/pattern/__init__.py @@ -1,11 +1,5 @@ -"""Dependency Injection as importable, typed building blocks.""" - -from patterns.modern.dependency_injection.pattern.service import ( - Clock, - Invoice, - InvoiceSource, - MailTransport, - ReminderService, -) - -__all__ = ["Clock", "Invoice", "InvoiceSource", "MailTransport", "ReminderService"] +from .service import Clock as Clock +from .service import Invoice as Invoice +from .service import InvoiceSource as InvoiceSource +from .service import MailTransport as MailTransport +from .service import ReminderService as ReminderService diff --git a/patterns/modern/dependency_injection/tests/test_invoice_reminders.py b/patterns/modern/dependency_injection/tests/test_invoice_reminders.py index 7a1b18d..1320748 100644 --- a/patterns/modern/dependency_injection/tests/test_invoice_reminders.py +++ b/patterns/modern/dependency_injection/tests/test_invoice_reminders.py @@ -6,13 +6,15 @@ import pytest -from patterns.modern.dependency_injection.examples.invoice_reminders import ( +from patterns.modern.dependency_injection.examples.invoice_reminders.__main__ import main +from patterns.modern.dependency_injection.examples.invoice_reminders.adapters import ( ConsoleMail, InMemoryInvoices, +) +from patterns.modern.dependency_injection.examples.invoice_reminders.app import ( build_service, sample_invoices, ) -from patterns.modern.dependency_injection.examples.invoice_reminders.__main__ import main from patterns.modern.dependency_injection.pattern import Invoice diff --git a/patterns/modern/registry/__init__.py b/patterns/modern/registry/__init__.py index 51eeae7..6e142df 100644 --- a/patterns/modern/registry/__init__.py +++ b/patterns/modern/registry/__init__.py @@ -1,8 +1,2 @@ -"""Registry — public API. - ->>> from patterns.modern.registry import Registry -""" - -from patterns.modern.registry.pattern import Registry, UnknownKeyError - -__all__ = ["Registry", "UnknownKeyError"] +from .pattern import Registry as Registry +from .pattern import UnknownKeyError as UnknownKeyError diff --git a/patterns/modern/registry/examples/__init__.py b/patterns/modern/registry/examples/__init__.py index bd1b838..e69de29 100644 --- a/patterns/modern/registry/examples/__init__.py +++ b/patterns/modern/registry/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Registry in practice.""" diff --git a/patterns/modern/registry/examples/export_plugins/__init__.py b/patterns/modern/registry/examples/export_plugins/__init__.py index fcbdedb..c20d74a 100644 --- a/patterns/modern/registry/examples/export_plugins/__init__.py +++ b/patterns/modern/registry/examples/export_plugins/__init__.py @@ -1,16 +1,2 @@ -"""Self-registering exporters over a shared ``Registry``. - -Run it: ``uv run python -m patterns.modern.registry.examples.export_plugins`` - -The import below is load-bearing: ``markdown`` registers itself at import -time, and a plugin nobody imports doesn't exist (the pattern's sharpest -caveat). This package's ``__init__`` is where that import is guaranteed. -""" - -from patterns.modern.registry.examples.export_plugins import markdown as markdown -from patterns.modern.registry.examples.export_plugins.exporters import ( - EXPORTERS, - export, -) - -__all__ = ["EXPORTERS", "export", "markdown"] +# Load-bearing: markdown registers itself at import time (the unit's caveat demo). +from . import markdown as markdown diff --git a/patterns/modern/registry/examples/export_plugins/__main__.py b/patterns/modern/registry/examples/export_plugins/__main__.py index e69d680..f7d7a77 100644 --- a/patterns/modern/registry/examples/export_plugins/__main__.py +++ b/patterns/modern/registry/examples/export_plugins/__main__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from patterns.modern.registry.examples.export_plugins import EXPORTERS, export +from patterns.modern.registry.examples.export_plugins.exporters import EXPORTERS, export from patterns.modern.registry.pattern import UnknownKeyError diff --git a/patterns/modern/registry/pattern/__init__.py b/patterns/modern/registry/pattern/__init__.py index da2e9ec..33c73e3 100644 --- a/patterns/modern/registry/pattern/__init__.py +++ b/patterns/modern/registry/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Registry pattern, importable as library code.""" - -from patterns.modern.registry.pattern.registry import Registry, UnknownKeyError - -__all__ = ["Registry", "UnknownKeyError"] +from .registry import Registry as Registry +from .registry import UnknownKeyError as UnknownKeyError diff --git a/patterns/modern/registry/tests/test_export_plugins.py b/patterns/modern/registry/tests/test_export_plugins.py index 64d009a..54f7274 100644 --- a/patterns/modern/registry/tests/test_export_plugins.py +++ b/patterns/modern/registry/tests/test_export_plugins.py @@ -6,8 +6,8 @@ import pytest -from patterns.modern.registry.examples.export_plugins import EXPORTERS, export from patterns.modern.registry.examples.export_plugins.__main__ import main +from patterns.modern.registry.examples.export_plugins.exporters import EXPORTERS, export from patterns.modern.registry.pattern import UnknownKeyError ROWS = [{"name": "ada", "role": "eng"}, {"name": "grace", "role": "ops"}] diff --git a/patterns/modern/repository/__init__.py b/patterns/modern/repository/__init__.py index 39528de..a60ab76 100644 --- a/patterns/modern/repository/__init__.py +++ b/patterns/modern/repository/__init__.py @@ -1,14 +1,5 @@ -"""Repository — public API. - ->>> from patterns.modern.repository import Invoices, InMemoryInvoices -""" - -from patterns.modern.repository.pattern import ( - InMemoryInvoices, - Invoice, - Invoices, - overdue, - total_owed, -) - -__all__ = ["InMemoryInvoices", "Invoice", "Invoices", "overdue", "total_owed"] +from .pattern import InMemoryInvoices as InMemoryInvoices +from .pattern import Invoice as Invoice +from .pattern import Invoices as Invoices +from .pattern import overdue as overdue +from .pattern import total_owed as total_owed diff --git a/patterns/modern/repository/examples/__init__.py b/patterns/modern/repository/examples/__init__.py index 8bacf97..e69de29 100644 --- a/patterns/modern/repository/examples/__init__.py +++ b/patterns/modern/repository/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Repository in practice.""" diff --git a/patterns/modern/repository/examples/invoice_ledger/__init__.py b/patterns/modern/repository/examples/invoice_ledger/__init__.py index d20e332..e69de29 100644 --- a/patterns/modern/repository/examples/invoice_ledger/__init__.py +++ b/patterns/modern/repository/examples/invoice_ledger/__init__.py @@ -1,8 +0,0 @@ -"""An invoice ledger over two interchangeable repositories. - -Run it: ``uv run python -m patterns.modern.repository.examples.invoice_ledger`` -""" - -from patterns.modern.repository.examples.invoice_ledger.sqlite_repo import SqliteInvoices - -__all__ = ["SqliteInvoices"] diff --git a/patterns/modern/repository/pattern/__init__.py b/patterns/modern/repository/pattern/__init__.py index 7606de8..195ae66 100644 --- a/patterns/modern/repository/pattern/__init__.py +++ b/patterns/modern/repository/pattern/__init__.py @@ -1,11 +1,5 @@ -"""The Repository pattern, importable as library code.""" - -from patterns.modern.repository.pattern.ledger import ( - InMemoryInvoices, - Invoice, - Invoices, - overdue, - total_owed, -) - -__all__ = ["InMemoryInvoices", "Invoice", "Invoices", "overdue", "total_owed"] +from .ledger import InMemoryInvoices as InMemoryInvoices +from .ledger import Invoice as Invoice +from .ledger import Invoices as Invoices +from .ledger import overdue as overdue +from .ledger import total_owed as total_owed diff --git a/patterns/modern/repository/tests/test_invoice_ledger.py b/patterns/modern/repository/tests/test_invoice_ledger.py index 2430ccc..e2b1e2f 100644 --- a/patterns/modern/repository/tests/test_invoice_ledger.py +++ b/patterns/modern/repository/tests/test_invoice_ledger.py @@ -14,8 +14,8 @@ import pytest -from patterns.modern.repository.examples.invoice_ledger import SqliteInvoices from patterns.modern.repository.examples.invoice_ledger.__main__ import main +from patterns.modern.repository.examples.invoice_ledger.sqlite_repo import SqliteInvoices from patterns.modern.repository.pattern import ( InMemoryInvoices, Invoice, diff --git a/patterns/principle/__init__.py b/patterns/principle/__init__.py index 14f93e4..e69de29 100644 --- a/patterns/principle/__init__.py +++ b/patterns/principle/__init__.py @@ -1 +0,0 @@ -"""Design principles.""" diff --git a/patterns/principle/composition_over_inheritance/__init__.py b/patterns/principle/composition_over_inheritance/__init__.py index ca5dfe6..5ca3f20 100644 --- a/patterns/principle/composition_over_inheritance/__init__.py +++ b/patterns/principle/composition_over_inheritance/__init__.py @@ -1,15 +1,6 @@ -"""Composition Over Inheritance — public API. - ->>> from patterns.principle.composition_over_inheritance import Pipeline, Logger -""" - -from patterns.principle.composition_over_inheritance.pattern import ( - Filter, - Logger, - Pipeline, - Sink, - Transform, - identity, -) - -__all__ = ["Filter", "Logger", "Pipeline", "Sink", "Transform", "identity"] +from .pattern import Filter as Filter +from .pattern import Logger as Logger +from .pattern import Pipeline as Pipeline +from .pattern import Sink as Sink +from .pattern import Transform as Transform +from .pattern import identity as identity diff --git a/patterns/principle/composition_over_inheritance/examples/__init__.py b/patterns/principle/composition_over_inheritance/examples/__init__.py index ca2cb3e..e69de29 100644 --- a/patterns/principle/composition_over_inheritance/examples/__init__.py +++ b/patterns/principle/composition_over_inheritance/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating Composition Over Inheritance in practice.""" diff --git a/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py b/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py index 46a58ee..e69de29 100644 --- a/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py +++ b/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py @@ -1,35 +0,0 @@ -"""An alert router built on Composition Over Inheritance. - -Run it: ``uv run python -m patterns.principle.composition_over_inheritance\ -.examples.notification_router`` -""" - -from patterns.principle.composition_over_inheritance.examples.notification_router.axes import ( - Dedup, - FakeWebhook, - MemorySink, - as_json, - console, - min_severity, - plain_text, -) -from patterns.principle.composition_over_inheritance.examples.notification_router.models import ( - Alert, -) -from patterns.principle.composition_over_inheritance.examples.notification_router.router import ( - Notifier, - Router, -) - -__all__ = [ - "Alert", - "Dedup", - "FakeWebhook", - "MemorySink", - "Notifier", - "Router", - "as_json", - "console", - "min_severity", - "plain_text", -] diff --git a/patterns/principle/composition_over_inheritance/pattern/__init__.py b/patterns/principle/composition_over_inheritance/pattern/__init__.py index 3b18b5f..ac4632b 100644 --- a/patterns/principle/composition_over_inheritance/pattern/__init__.py +++ b/patterns/principle/composition_over_inheritance/pattern/__init__.py @@ -1,12 +1,6 @@ -"""Composition Over Inheritance, importable as library code.""" - -from patterns.principle.composition_over_inheritance.pattern.compose import ( - Filter, - Logger, - Pipeline, - Sink, - Transform, - identity, -) - -__all__ = ["Filter", "Logger", "Pipeline", "Sink", "Transform", "identity"] +from .compose import Filter as Filter +from .compose import Logger as Logger +from .compose import Pipeline as Pipeline +from .compose import Sink as Sink +from .compose import Transform as Transform +from .compose import identity as identity diff --git a/patterns/principle/composition_over_inheritance/tests/test_notification_router.py b/patterns/principle/composition_over_inheritance/tests/test_notification_router.py index 455002a..de3189b 100644 --- a/patterns/principle/composition_over_inheritance/tests/test_notification_router.py +++ b/patterns/principle/composition_over_inheritance/tests/test_notification_router.py @@ -7,20 +7,24 @@ import pytest -from patterns.principle.composition_over_inheritance.examples.notification_router import ( - Alert, +from patterns.principle.composition_over_inheritance.examples.notification_router.__main__ import ( + main, +) +from patterns.principle.composition_over_inheritance.examples.notification_router.axes import ( Dedup, FakeWebhook, MemorySink, - Notifier, - Router, as_json, console, min_severity, plain_text, ) -from patterns.principle.composition_over_inheritance.examples.notification_router.__main__ import ( - main, +from patterns.principle.composition_over_inheritance.examples.notification_router.models import ( + Alert, +) +from patterns.principle.composition_over_inheritance.examples.notification_router.router import ( + Notifier, + Router, ) from patterns.principle.composition_over_inheritance.pattern import Filter diff --git a/patterns/python/__init__.py b/patterns/python/__init__.py index 00d09a4..e69de29 100644 --- a/patterns/python/__init__.py +++ b/patterns/python/__init__.py @@ -1 +0,0 @@ -"""Python-native patterns from python-patterns.guide.""" diff --git a/patterns/python/global_object/__init__.py b/patterns/python/global_object/__init__.py index d652803..16746fc 100644 --- a/patterns/python/global_object/__init__.py +++ b/patterns/python/global_object/__init__.py @@ -1,8 +1 @@ -"""Global Object — public API. - ->>> from patterns.python.global_object import Lazy -""" - -from patterns.python.global_object.pattern import Lazy - -__all__ = ["Lazy"] +from .pattern import Lazy as Lazy diff --git a/patterns/python/global_object/examples/__init__.py b/patterns/python/global_object/examples/__init__.py index 10598d3..e69de29 100644 --- a/patterns/python/global_object/examples/__init__.py +++ b/patterns/python/global_object/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Global Object pattern in practice.""" diff --git a/patterns/python/global_object/examples/settings_module/__init__.py b/patterns/python/global_object/examples/settings_module/__init__.py index 7e2989c..e69de29 100644 --- a/patterns/python/global_object/examples/settings_module/__init__.py +++ b/patterns/python/global_object/examples/settings_module/__init__.py @@ -1,24 +0,0 @@ -"""A small app's settings module done right, built on the Global Object pattern. - -Run it: ``uv run python -m patterns.python.global_object.examples.settings_module`` -""" - -from patterns.python.global_object.examples.settings_module.settings import ( - RETRY_LIMIT, - SLUG, - SUPPORTED_LOCALES, - ZONE_TABLE, -) -from patterns.python.global_object.examples.settings_module.shipping import ( - is_valid_slug, - shipping_zone, -) - -__all__ = [ - "RETRY_LIMIT", - "SLUG", - "SUPPORTED_LOCALES", - "ZONE_TABLE", - "is_valid_slug", - "shipping_zone", -] diff --git a/patterns/python/global_object/pattern/__init__.py b/patterns/python/global_object/pattern/__init__.py index ded7211..8fd5d1e 100644 --- a/patterns/python/global_object/pattern/__init__.py +++ b/patterns/python/global_object/pattern/__init__.py @@ -1,5 +1 @@ -"""The Global Object pattern, importable as library code.""" - -from patterns.python.global_object.pattern.lazy import Lazy - -__all__ = ["Lazy"] +from .lazy import Lazy as Lazy diff --git a/patterns/python/prebound_method/__init__.py b/patterns/python/prebound_method/__init__.py index d677cc8..1ec8f07 100644 --- a/patterns/python/prebound_method/__init__.py +++ b/patterns/python/prebound_method/__init__.py @@ -1,13 +1,4 @@ -"""Prebound Method — public API. - ->>> from patterns.python.prebound_method import increment, peek -""" - -from patterns.python.prebound_method.pattern import ( - Counter, - increment, - peek, - shares_instance, -) - -__all__ = ["Counter", "increment", "peek", "shares_instance"] +from .pattern import Counter as Counter +from .pattern import increment as increment +from .pattern import peek as peek +from .pattern import shares_instance as shares_instance diff --git a/patterns/python/prebound_method/examples/__init__.py b/patterns/python/prebound_method/examples/__init__.py index 01f4e23..e69de29 100644 --- a/patterns/python/prebound_method/examples/__init__.py +++ b/patterns/python/prebound_method/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Prebound Method pattern in practice.""" diff --git a/patterns/python/prebound_method/examples/metrics/__init__.py b/patterns/python/prebound_method/examples/metrics/__init__.py index affa698..e69de29 100644 --- a/patterns/python/prebound_method/examples/metrics/__init__.py +++ b/patterns/python/prebound_method/examples/metrics/__init__.py @@ -1,14 +0,0 @@ -"""Process-wide metrics built on the Prebound Method pattern. - -Run it: ``uv run python -m patterns.python.prebound_method.examples.metrics`` -""" - -from patterns.python.prebound_method.examples.metrics.api import ( - increment, - reset, - snapshot, - timing, -) -from patterns.python.prebound_method.examples.metrics.collector import MetricsCollector - -__all__ = ["MetricsCollector", "increment", "reset", "snapshot", "timing"] diff --git a/patterns/python/prebound_method/pattern/__init__.py b/patterns/python/prebound_method/pattern/__init__.py index 7b322a2..d6f901b 100644 --- a/patterns/python/prebound_method/pattern/__init__.py +++ b/patterns/python/prebound_method/pattern/__init__.py @@ -1,10 +1,4 @@ -"""The Prebound Method pattern, importable as library code.""" - -from patterns.python.prebound_method.pattern.prebound import ( - Counter, - increment, - peek, - shares_instance, -) - -__all__ = ["Counter", "increment", "peek", "shares_instance"] +from .prebound import Counter as Counter +from .prebound import increment as increment +from .prebound import peek as peek +from .prebound import shares_instance as shares_instance diff --git a/patterns/python/prebound_method/tests/test_metrics.py b/patterns/python/prebound_method/tests/test_metrics.py index 1ac92bd..9617d38 100644 --- a/patterns/python/prebound_method/tests/test_metrics.py +++ b/patterns/python/prebound_method/tests/test_metrics.py @@ -6,8 +6,9 @@ import pytest -from patterns.python.prebound_method.examples.metrics import MetricsCollector, api +from patterns.python.prebound_method.examples.metrics import api from patterns.python.prebound_method.examples.metrics.__main__ import main +from patterns.python.prebound_method.examples.metrics.collector import MetricsCollector from patterns.python.prebound_method.pattern import shares_instance diff --git a/patterns/python/sentinel_object/__init__.py b/patterns/python/sentinel_object/__init__.py index 9f4e79f..7ddc4ae 100644 --- a/patterns/python/sentinel_object/__init__.py +++ b/patterns/python/sentinel_object/__init__.py @@ -1,8 +1,2 @@ -"""Sentinel Object — public API. - ->>> from patterns.python.sentinel_object import MISSING, Sentinel -""" - -from patterns.python.sentinel_object.pattern import MISSING, Sentinel - -__all__ = ["MISSING", "Sentinel"] +from .pattern import MISSING as MISSING +from .pattern import Sentinel as Sentinel diff --git a/patterns/python/sentinel_object/examples/__init__.py b/patterns/python/sentinel_object/examples/__init__.py index 08830c5..e69de29 100644 --- a/patterns/python/sentinel_object/examples/__init__.py +++ b/patterns/python/sentinel_object/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Sentinel Object pattern in practice.""" diff --git a/patterns/python/sentinel_object/examples/layered_config/__init__.py b/patterns/python/sentinel_object/examples/layered_config/__init__.py index fab235b..e69de29 100644 --- a/patterns/python/sentinel_object/examples/layered_config/__init__.py +++ b/patterns/python/sentinel_object/examples/layered_config/__init__.py @@ -1,16 +0,0 @@ -"""Layered app configuration built on the Sentinel Object pattern. - -Run it: ``uv run python -m patterns.python.sentinel_object.examples.layered_config`` -""" - -from patterns.python.sentinel_object.examples.layered_config.config import ( - LayeredConfig, - Value, -) -from patterns.python.sentinel_object.examples.layered_config.notifier import ( - EmailNotifier, - NullNotifier, - notifier_for, -) - -__all__ = ["EmailNotifier", "LayeredConfig", "NullNotifier", "Value", "notifier_for"] diff --git a/patterns/python/sentinel_object/pattern/__init__.py b/patterns/python/sentinel_object/pattern/__init__.py index 8bc8420..8aa0d89 100644 --- a/patterns/python/sentinel_object/pattern/__init__.py +++ b/patterns/python/sentinel_object/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Sentinel Object pattern, importable as library code.""" - -from patterns.python.sentinel_object.pattern.sentinel import MISSING, Sentinel - -__all__ = ["MISSING", "Sentinel"] +from .sentinel import MISSING as MISSING +from .sentinel import Sentinel as Sentinel diff --git a/patterns/python/sentinel_object/tests/test_layered_config.py b/patterns/python/sentinel_object/tests/test_layered_config.py index d97b3d4..478cc92 100644 --- a/patterns/python/sentinel_object/tests/test_layered_config.py +++ b/patterns/python/sentinel_object/tests/test_layered_config.py @@ -4,13 +4,13 @@ import pytest -from patterns.python.sentinel_object.examples.layered_config import ( +from patterns.python.sentinel_object.examples.layered_config.__main__ import main +from patterns.python.sentinel_object.examples.layered_config.config import LayeredConfig +from patterns.python.sentinel_object.examples.layered_config.notifier import ( EmailNotifier, - LayeredConfig, NullNotifier, notifier_for, ) -from patterns.python.sentinel_object.examples.layered_config.__main__ import main from patterns.python.sentinel_object.pattern import Sentinel diff --git a/patterns/structural/__init__.py b/patterns/structural/__init__.py index 248d229..e69de29 100644 --- a/patterns/structural/__init__.py +++ b/patterns/structural/__init__.py @@ -1 +0,0 @@ -"""structural patterns.""" diff --git a/patterns/structural/adapter/__init__.py b/patterns/structural/adapter/__init__.py index d1af636..09a933a 100644 --- a/patterns/structural/adapter/__init__.py +++ b/patterns/structural/adapter/__init__.py @@ -1,8 +1 @@ -"""Adapter — public API. - ->>> from patterns.structural.adapter import DelegatingAdapter -""" - -from patterns.structural.adapter.pattern import DelegatingAdapter - -__all__ = ["DelegatingAdapter"] +from .pattern.adapter import DelegatingAdapter as DelegatingAdapter diff --git a/patterns/structural/adapter/examples/__init__.py b/patterns/structural/adapter/examples/__init__.py index 1f409cb..e69de29 100644 --- a/patterns/structural/adapter/examples/__init__.py +++ b/patterns/structural/adapter/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Adapter in practice.""" diff --git a/patterns/structural/adapter/examples/payment_gateways/__init__.py b/patterns/structural/adapter/examples/payment_gateways/__init__.py index 7a7c48c..e69de29 100644 --- a/patterns/structural/adapter/examples/payment_gateways/__init__.py +++ b/patterns/structural/adapter/examples/payment_gateways/__init__.py @@ -1,27 +0,0 @@ -"""Payment checkout over mismatched vendor SDKs, built on the Adapter. - -Run it: ``uv run python -m patterns.structural.adapter.examples.payment_gateways`` -""" - -from patterns.structural.adapter.examples.payment_gateways.adapters import ( - PaymentProcessor, - PaymentResult, - PayPalAdapter, - StripeAdapter, -) -from patterns.structural.adapter.examples.payment_gateways.checkout import Receipt, checkout -from patterns.structural.adapter.examples.payment_gateways.vendors import ( - PayPalLikeGateway, - StripeLikeClient, -) - -__all__ = [ - "PayPalAdapter", - "PayPalLikeGateway", - "PaymentProcessor", - "PaymentResult", - "Receipt", - "StripeAdapter", - "StripeLikeClient", - "checkout", -] diff --git a/patterns/structural/adapter/pattern/__init__.py b/patterns/structural/adapter/pattern/__init__.py index c791dce..ab5efa6 100644 --- a/patterns/structural/adapter/pattern/__init__.py +++ b/patterns/structural/adapter/pattern/__init__.py @@ -1,5 +1 @@ -"""The Adapter pattern, importable as library code.""" - -from patterns.structural.adapter.pattern.adapter import DelegatingAdapter - -__all__ = ["DelegatingAdapter"] +from .adapter import DelegatingAdapter as DelegatingAdapter diff --git a/patterns/structural/adapter/tests/test_payment_gateways.py b/patterns/structural/adapter/tests/test_payment_gateways.py index 1ba542e..5286ac9 100644 --- a/patterns/structural/adapter/tests/test_payment_gateways.py +++ b/patterns/structural/adapter/tests/test_payment_gateways.py @@ -10,15 +10,17 @@ import pytest -from patterns.structural.adapter.examples.payment_gateways import ( +from patterns.structural.adapter.examples.payment_gateways.__main__ import main +from patterns.structural.adapter.examples.payment_gateways.adapters import ( PaymentProcessor, PayPalAdapter, - PayPalLikeGateway, StripeAdapter, +) +from patterns.structural.adapter.examples.payment_gateways.checkout import checkout +from patterns.structural.adapter.examples.payment_gateways.vendors import ( + PayPalLikeGateway, StripeLikeClient, - checkout, ) -from patterns.structural.adapter.examples.payment_gateways.__main__ import main def stripe() -> PaymentProcessor: diff --git a/patterns/structural/bridge/__init__.py b/patterns/structural/bridge/__init__.py index f92f37e..3e44219 100644 --- a/patterns/structural/bridge/__init__.py +++ b/patterns/structural/bridge/__init__.py @@ -1,22 +1,6 @@ -"""Bridge — public API. - ->>> from patterns.structural.bridge import AlertNotifier, SlackTransport -""" - -from patterns.structural.bridge.pattern import ( - AlertNotifier, - DigestNotifier, - EmailTransport, - SlackTransport, - SmsTransport, - Transport, -) - -__all__ = [ - "AlertNotifier", - "DigestNotifier", - "EmailTransport", - "SlackTransport", - "SmsTransport", - "Transport", -] +from .pattern.bridge import AlertNotifier as AlertNotifier +from .pattern.bridge import DigestNotifier as DigestNotifier +from .pattern.bridge import EmailTransport as EmailTransport +from .pattern.bridge import SlackTransport as SlackTransport +from .pattern.bridge import SmsTransport as SmsTransport +from .pattern.bridge import Transport as Transport diff --git a/patterns/structural/bridge/examples/__init__.py b/patterns/structural/bridge/examples/__init__.py index e844b83..e69de29 100644 --- a/patterns/structural/bridge/examples/__init__.py +++ b/patterns/structural/bridge/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Bridge in practice.""" diff --git a/patterns/structural/bridge/examples/notification_center/__init__.py b/patterns/structural/bridge/examples/notification_center/__init__.py index 25d281a..e69de29 100644 --- a/patterns/structural/bridge/examples/notification_center/__init__.py +++ b/patterns/structural/bridge/examples/notification_center/__init__.py @@ -1,11 +0,0 @@ -"""Team notification routing built on the Bridge. - -Run it: ``uv run python -m patterns.structural.bridge.examples.notification_center`` -""" - -from patterns.structural.bridge.examples.notification_center.center import ( - NotificationCenter, - TeamChannel, -) - -__all__ = ["NotificationCenter", "TeamChannel"] diff --git a/patterns/structural/bridge/pattern/__init__.py b/patterns/structural/bridge/pattern/__init__.py index d06dd42..3f25a9c 100644 --- a/patterns/structural/bridge/pattern/__init__.py +++ b/patterns/structural/bridge/pattern/__init__.py @@ -1,19 +1,6 @@ -"""The Bridge pattern, importable as library code.""" - -from patterns.structural.bridge.pattern.bridge import ( - AlertNotifier, - DigestNotifier, - EmailTransport, - SlackTransport, - SmsTransport, - Transport, -) - -__all__ = [ - "AlertNotifier", - "DigestNotifier", - "EmailTransport", - "SlackTransport", - "SmsTransport", - "Transport", -] +from .bridge import AlertNotifier as AlertNotifier +from .bridge import DigestNotifier as DigestNotifier +from .bridge import EmailTransport as EmailTransport +from .bridge import SlackTransport as SlackTransport +from .bridge import SmsTransport as SmsTransport +from .bridge import Transport as Transport diff --git a/patterns/structural/bridge/tests/test_notification_center.py b/patterns/structural/bridge/tests/test_notification_center.py index e738154..24fb6b2 100644 --- a/patterns/structural/bridge/tests/test_notification_center.py +++ b/patterns/structural/bridge/tests/test_notification_center.py @@ -4,11 +4,11 @@ import pytest -from patterns.structural.bridge.examples.notification_center import ( +from patterns.structural.bridge.examples.notification_center.__main__ import main +from patterns.structural.bridge.examples.notification_center.center import ( NotificationCenter, TeamChannel, ) -from patterns.structural.bridge.examples.notification_center.__main__ import main from patterns.structural.bridge.pattern import EmailTransport, SlackTransport, SmsTransport diff --git a/patterns/structural/composite/__init__.py b/patterns/structural/composite/__init__.py index 4047ce9..0f9cbd2 100644 --- a/patterns/structural/composite/__init__.py +++ b/patterns/structural/composite/__init__.py @@ -1,8 +1,2 @@ -"""Composite — public API. - ->>> from patterns.structural.composite import Composite -""" - -from patterns.structural.composite.pattern import Composite, HasTotal - -__all__ = ["Composite", "HasTotal"] +from .pattern.tree import Composite as Composite +from .pattern.tree import HasTotal as HasTotal diff --git a/patterns/structural/composite/examples/__init__.py b/patterns/structural/composite/examples/__init__.py index abc9c1d..e69de29 100644 --- a/patterns/structural/composite/examples/__init__.py +++ b/patterns/structural/composite/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Composite in practice.""" diff --git a/patterns/structural/composite/examples/org_chart/__init__.py b/patterns/structural/composite/examples/org_chart/__init__.py index c462b5d..e69de29 100644 --- a/patterns/structural/composite/examples/org_chart/__init__.py +++ b/patterns/structural/composite/examples/org_chart/__init__.py @@ -1,12 +0,0 @@ -"""Org-chart rollups built on the Composite. - -Run it: ``uv run python -m patterns.structural.composite.examples.org_chart`` -""" - -from patterns.structural.composite.examples.org_chart.org import ( - Department, - Employee, - OrgMetrics, -) - -__all__ = ["Department", "Employee", "OrgMetrics"] diff --git a/patterns/structural/composite/pattern/__init__.py b/patterns/structural/composite/pattern/__init__.py index 8d9e6e4..1a842f8 100644 --- a/patterns/structural/composite/pattern/__init__.py +++ b/patterns/structural/composite/pattern/__init__.py @@ -1,5 +1,2 @@ -"""The Composite pattern, importable as library code.""" - -from patterns.structural.composite.pattern.tree import Composite, HasTotal - -__all__ = ["Composite", "HasTotal"] +from .tree import Composite as Composite +from .tree import HasTotal as HasTotal diff --git a/patterns/structural/composite/tests/test_org_chart.py b/patterns/structural/composite/tests/test_org_chart.py index 093f1a3..0237dbd 100644 --- a/patterns/structural/composite/tests/test_org_chart.py +++ b/patterns/structural/composite/tests/test_org_chart.py @@ -4,12 +4,8 @@ import pytest -from patterns.structural.composite.examples.org_chart import ( - Department, - Employee, - OrgMetrics, -) from patterns.structural.composite.examples.org_chart.__main__ import main +from patterns.structural.composite.examples.org_chart.org import Department, Employee, OrgMetrics def build_company() -> tuple[Department, Department]: diff --git a/patterns/structural/decorator/__init__.py b/patterns/structural/decorator/__init__.py index 19b1ae6..9a46136 100644 --- a/patterns/structural/decorator/__init__.py +++ b/patterns/structural/decorator/__init__.py @@ -1,14 +1,5 @@ -"""Decorator — public API. - ->>> from patterns.structural.decorator import retry -""" - -from patterns.structural.decorator.pattern import ( - RateLimitExceededError, - logged, - rate_limited, - retry, - timed, -) - -__all__ = ["RateLimitExceededError", "logged", "rate_limited", "retry", "timed"] +from .pattern.decorators import RateLimitExceededError as RateLimitExceededError +from .pattern.decorators import logged as logged +from .pattern.decorators import rate_limited as rate_limited +from .pattern.decorators import retry as retry +from .pattern.decorators import timed as timed diff --git a/patterns/structural/decorator/examples/__init__.py b/patterns/structural/decorator/examples/__init__.py index bb5582b..e69de29 100644 --- a/patterns/structural/decorator/examples/__init__.py +++ b/patterns/structural/decorator/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Decorator pattern in practice.""" diff --git a/patterns/structural/decorator/examples/resilient_client/__init__.py b/patterns/structural/decorator/examples/resilient_client/__init__.py index f3b12c3..e69de29 100644 --- a/patterns/structural/decorator/examples/resilient_client/__init__.py +++ b/patterns/structural/decorator/examples/resilient_client/__init__.py @@ -1,14 +0,0 @@ -"""A flaky API client hardened by stacking decorators. - -Run it: ``uv run python -m patterns.structural.decorator.examples.resilient_client`` -""" - -from patterns.structural.decorator.examples.resilient_client.client import ( - FlakyPaymentAPI, - TransientNetworkError, -) -from patterns.structural.decorator.examples.resilient_client.service import ( - build_charge, -) - -__all__ = ["FlakyPaymentAPI", "TransientNetworkError", "build_charge"] diff --git a/patterns/structural/decorator/pattern/__init__.py b/patterns/structural/decorator/pattern/__init__.py index 4348bba..cb23ca0 100644 --- a/patterns/structural/decorator/pattern/__init__.py +++ b/patterns/structural/decorator/pattern/__init__.py @@ -1,11 +1,5 @@ -"""The Decorator pattern, importable as library code.""" - -from patterns.structural.decorator.pattern.decorators import ( - RateLimitExceededError, - logged, - rate_limited, - retry, - timed, -) - -__all__ = ["RateLimitExceededError", "logged", "rate_limited", "retry", "timed"] +from .decorators import RateLimitExceededError as RateLimitExceededError +from .decorators import logged as logged +from .decorators import rate_limited as rate_limited +from .decorators import retry as retry +from .decorators import timed as timed diff --git a/patterns/structural/decorator/tests/test_resilient_client.py b/patterns/structural/decorator/tests/test_resilient_client.py index 47f62f5..5c7f564 100644 --- a/patterns/structural/decorator/tests/test_resilient_client.py +++ b/patterns/structural/decorator/tests/test_resilient_client.py @@ -4,10 +4,8 @@ import pytest -from patterns.structural.decorator.examples.resilient_client import ( - FlakyPaymentAPI, - build_charge, -) +from patterns.structural.decorator.examples.resilient_client.client import FlakyPaymentAPI +from patterns.structural.decorator.examples.resilient_client.service import build_charge from patterns.structural.decorator.pattern import RateLimitExceededError diff --git a/patterns/structural/facade/__init__.py b/patterns/structural/facade/__init__.py index a08e73d..31d81f4 100644 --- a/patterns/structural/facade/__init__.py +++ b/patterns/structural/facade/__init__.py @@ -1,22 +1,6 @@ -"""Facade — public API. - ->>> from patterns.structural.facade import place_order -""" - -from patterns.structural.facade.pattern import ( - Notifier, - OrderResult, - PaymentGateway, - Shipping, - Warehouse, - place_order, -) - -__all__ = [ - "Notifier", - "OrderResult", - "PaymentGateway", - "Shipping", - "Warehouse", - "place_order", -] +from .pattern.checkout import Notifier as Notifier +from .pattern.checkout import OrderResult as OrderResult +from .pattern.checkout import PaymentGateway as PaymentGateway +from .pattern.checkout import Shipping as Shipping +from .pattern.checkout import Warehouse as Warehouse +from .pattern.checkout import place_order as place_order diff --git a/patterns/structural/facade/examples/__init__.py b/patterns/structural/facade/examples/__init__.py index 83e55db..e69de29 100644 --- a/patterns/structural/facade/examples/__init__.py +++ b/patterns/structural/facade/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Facade pattern in practice.""" diff --git a/patterns/structural/facade/examples/order_checkout/__init__.py b/patterns/structural/facade/examples/order_checkout/__init__.py index 0aaab79..e69de29 100644 --- a/patterns/structural/facade/examples/order_checkout/__init__.py +++ b/patterns/structural/facade/examples/order_checkout/__init__.py @@ -1,11 +0,0 @@ -"""A storefront processing a day's orders through the checkout facade. - -Run it: ``uv run python -m patterns.structural.facade.examples.order_checkout`` -""" - -from patterns.structural.facade.examples.order_checkout.store import ( - Order, - Store, -) - -__all__ = ["Order", "Store"] diff --git a/patterns/structural/facade/pattern/__init__.py b/patterns/structural/facade/pattern/__init__.py index 4e2095d..b015114 100644 --- a/patterns/structural/facade/pattern/__init__.py +++ b/patterns/structural/facade/pattern/__init__.py @@ -1,19 +1,6 @@ -"""The Facade pattern, importable as library code.""" - -from patterns.structural.facade.pattern.checkout import ( - Notifier, - OrderResult, - PaymentGateway, - Shipping, - Warehouse, - place_order, -) - -__all__ = [ - "Notifier", - "OrderResult", - "PaymentGateway", - "Shipping", - "Warehouse", - "place_order", -] +from .checkout import Notifier as Notifier +from .checkout import OrderResult as OrderResult +from .checkout import PaymentGateway as PaymentGateway +from .checkout import Shipping as Shipping +from .checkout import Warehouse as Warehouse +from .checkout import place_order as place_order diff --git a/patterns/structural/facade/tests/test_order_checkout.py b/patterns/structural/facade/tests/test_order_checkout.py index 49cc014..b7469f9 100644 --- a/patterns/structural/facade/tests/test_order_checkout.py +++ b/patterns/structural/facade/tests/test_order_checkout.py @@ -2,7 +2,7 @@ from __future__ import annotations -from patterns.structural.facade.examples.order_checkout import Order, Store +from patterns.structural.facade.examples.order_checkout.store import Order, Store from patterns.structural.facade.pattern import PaymentGateway, Warehouse diff --git a/patterns/structural/flyweight/__init__.py b/patterns/structural/flyweight/__init__.py index 212925c..5fbed59 100644 --- a/patterns/structural/flyweight/__init__.py +++ b/patterns/structural/flyweight/__init__.py @@ -1,8 +1 @@ -"""Flyweight — public API. - ->>> from patterns.structural.flyweight import InternPool -""" - -from patterns.structural.flyweight.pattern import InternPool - -__all__ = ["InternPool"] +from .pattern.pool import InternPool as InternPool diff --git a/patterns/structural/flyweight/examples/__init__.py b/patterns/structural/flyweight/examples/__init__.py index 9dfaec4..e69de29 100644 --- a/patterns/structural/flyweight/examples/__init__.py +++ b/patterns/structural/flyweight/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Flyweight pattern in practice.""" diff --git a/patterns/structural/flyweight/examples/glyph_styles/__init__.py b/patterns/structural/flyweight/examples/glyph_styles/__init__.py index 0bdf7f3..e69de29 100644 --- a/patterns/structural/flyweight/examples/glyph_styles/__init__.py +++ b/patterns/structural/flyweight/examples/glyph_styles/__init__.py @@ -1,12 +0,0 @@ -"""A text buffer sharing character styles through an intern pool. - -Run it: ``uv run python -m patterns.structural.flyweight.examples.glyph_styles`` -""" - -from patterns.structural.flyweight.examples.glyph_styles.document import ( - Document, - Style, - StyleBook, -) - -__all__ = ["Document", "Style", "StyleBook"] diff --git a/patterns/structural/flyweight/pattern/__init__.py b/patterns/structural/flyweight/pattern/__init__.py index 5bb049f..8d0ce6b 100644 --- a/patterns/structural/flyweight/pattern/__init__.py +++ b/patterns/structural/flyweight/pattern/__init__.py @@ -1,5 +1 @@ -"""The Flyweight pattern, importable as library code.""" - -from patterns.structural.flyweight.pattern.pool import InternPool - -__all__ = ["InternPool"] +from .pool import InternPool as InternPool diff --git a/patterns/structural/flyweight/tests/test_glyph_styles.py b/patterns/structural/flyweight/tests/test_glyph_styles.py index 4bb2e06..d06201b 100644 --- a/patterns/structural/flyweight/tests/test_glyph_styles.py +++ b/patterns/structural/flyweight/tests/test_glyph_styles.py @@ -6,7 +6,7 @@ import pytest -from patterns.structural.flyweight.examples.glyph_styles import Document +from patterns.structural.flyweight.examples.glyph_styles.document import Document def test_many_glyphs_share_a_handful_of_styles() -> None: diff --git a/patterns/structural/proxy/__init__.py b/patterns/structural/proxy/__init__.py index a1476b3..d89cbd2 100644 --- a/patterns/structural/proxy/__init__.py +++ b/patterns/structural/proxy/__init__.py @@ -1,12 +1,3 @@ -"""Proxy — public API. - ->>> from patterns.structural.proxy import LazyProxy -""" - -from patterns.structural.proxy.pattern import ( - LazyProxy, - MeteringProxy, - ProtectionProxy, -) - -__all__ = ["LazyProxy", "MeteringProxy", "ProtectionProxy"] +from .pattern.proxies import LazyProxy as LazyProxy +from .pattern.proxies import MeteringProxy as MeteringProxy +from .pattern.proxies import ProtectionProxy as ProtectionProxy diff --git a/patterns/structural/proxy/examples/__init__.py b/patterns/structural/proxy/examples/__init__.py index aefb262..e69de29 100644 --- a/patterns/structural/proxy/examples/__init__.py +++ b/patterns/structural/proxy/examples/__init__.py @@ -1 +0,0 @@ -"""Mini-projects demonstrating the Proxy pattern in practice.""" diff --git a/patterns/structural/proxy/examples/db_gateway/__init__.py b/patterns/structural/proxy/examples/db_gateway/__init__.py index deefb61..e69de29 100644 --- a/patterns/structural/proxy/examples/db_gateway/__init__.py +++ b/patterns/structural/proxy/examples/db_gateway/__init__.py @@ -1,11 +0,0 @@ -"""An expensive warehouse connection behind stacked proxies. - -Run it: ``uv run python -m patterns.structural.proxy.examples.db_gateway`` -""" - -from patterns.structural.proxy.examples.db_gateway.gateway import ( - WarehouseConnection, - build_gateway, -) - -__all__ = ["WarehouseConnection", "build_gateway"] diff --git a/patterns/structural/proxy/pattern/__init__.py b/patterns/structural/proxy/pattern/__init__.py index 62c26aa..6493a2d 100644 --- a/patterns/structural/proxy/pattern/__init__.py +++ b/patterns/structural/proxy/pattern/__init__.py @@ -1,9 +1,3 @@ -"""The Proxy pattern, importable as library code.""" - -from patterns.structural.proxy.pattern.proxies import ( - LazyProxy, - MeteringProxy, - ProtectionProxy, -) - -__all__ = ["LazyProxy", "MeteringProxy", "ProtectionProxy"] +from .proxies import LazyProxy as LazyProxy +from .proxies import MeteringProxy as MeteringProxy +from .proxies import ProtectionProxy as ProtectionProxy diff --git a/patterns/structural/proxy/tests/test_db_gateway.py b/patterns/structural/proxy/tests/test_db_gateway.py index 22e7686..6fd5caf 100644 --- a/patterns/structural/proxy/tests/test_db_gateway.py +++ b/patterns/structural/proxy/tests/test_db_gateway.py @@ -4,10 +4,7 @@ import pytest -from patterns.structural.proxy.examples.db_gateway import ( - WarehouseConnection, - build_gateway, -) +from patterns.structural.proxy.examples.db_gateway.gateway import WarehouseConnection, build_gateway @pytest.fixture(autouse=True) diff --git a/src/design_patterns/__init__.py b/src/design_patterns/__init__.py index 38cee3d..e69de29 100644 --- a/src/design_patterns/__init__.py +++ b/src/design_patterns/__init__.py @@ -1,3 +0,0 @@ -"""Design patterns in Python: catalog loader and shared utilities.""" - -__version__ = "1.0.0" diff --git a/src/design_patterns/mcp/__init__.py b/src/design_patterns/mcp/__init__.py index 07b6c88..e69de29 100644 --- a/src/design_patterns/mcp/__init__.py +++ b/src/design_patterns/mcp/__init__.py @@ -1 +0,0 @@ -"""MCP server exposing the pattern catalog to agents.""" diff --git a/tests/conftest.py b/tests/conftest.py index 937173f..7d71ceb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,8 +15,11 @@ def write_module_unit(root: Path) -> Path: """Build ``/creational/thing`` as a complete, runnable module-shape unit.""" unit = root / "creational" / "thing" (unit / "pattern").mkdir(parents=True) - for pkg in (root, root / "creational", unit, unit / "pattern"): + for pkg in (root, root / "creational"): (pkg / "__init__.py").write_text("") + # The two API files model the house style: bare as-alias re-exports. + (unit / "__init__.py").write_text("from .pattern.thing import build as build\n") + (unit / "pattern" / "__init__.py").write_text("from .thing import build as build\n") (unit / "README.md").write_text( "---\n" "id: creational/thing\nname: Thing\nguide_url: null\n" diff --git a/tests/test_scaffold.py b/tests/test_scaffold.py index a5943f6..a89b5b2 100644 --- a/tests/test_scaffold.py +++ b/tests/test_scaffold.py @@ -1,7 +1,7 @@ -"""Smoke test: the package imports and reports a version.""" +"""Smoke test: the package is installed and reports a version.""" -import design_patterns +from importlib.metadata import version def test_version() -> None: - assert design_patterns.__version__ + assert version("python-design-patterns")