From 67f232daf3a7b6070a41457f9a4f679498fb86d3 Mon Sep 17 00:00:00 2001 From: SuperElectron Date: Thu, 27 Aug 2026 14:23:43 -0700 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20delete=20all=20104=20empty=20?= =?UTF-8?q?=5F=5Finit=5F=5F.py=20=E2=80=94=20namespace=20packages=20(PEP?= =?UTF-8?q?=20420)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only load-bearing __init__.py remain (64 unit API files + registry's plugin-registration demo). pytest --import-mode=importlib for same-basename tests; mypy explicit_package_bases + mypy_path; ruff known-first-party declared (no __init__ to infer from); loader now REJECTS empty __init__.py and no longer demands example packages be regular packages; fixtures emit the new shape. Co-Authored-By: Claude Fable 5 --- patterns/__init__.py | 0 patterns/behavioral/__init__.py | 0 .../examples/__init__.py | 0 .../examples/ticket_escalation/__init__.py | 0 .../chain_of_responsibility/tests/__init__.py | 0 .../behavioral/command/examples/__init__.py | 0 .../command/examples/editor_undo/__init__.py | 0 patterns/behavioral/command/tests/__init__.py | 0 .../interpreter/examples/__init__.py | 0 .../examples/flag_rules/__init__.py | 0 .../behavioral/interpreter/tests/__init__.py | 0 .../behavioral/iterator/examples/__init__.py | 0 .../examples/paginated_client/__init__.py | 0 .../behavioral/iterator/tests/__init__.py | 0 .../behavioral/mediator/examples/__init__.py | 0 .../examples/checkout_form/__init__.py | 0 .../behavioral/mediator/tests/__init__.py | 0 .../behavioral/memento/examples/__init__.py | 0 .../examples/config_checkpoints/__init__.py | 0 patterns/behavioral/memento/tests/__init__.py | 0 .../behavioral/observer/examples/__init__.py | 0 .../examples/order_events/__init__.py | 0 .../behavioral/observer/tests/__init__.py | 0 .../behavioral/state/examples/__init__.py | 0 .../examples/order_lifecycle/__init__.py | 0 patterns/behavioral/state/tests/__init__.py | 0 .../behavioral/strategy/examples/__init__.py | 0 .../strategy/examples/promotions/__init__.py | 0 .../behavioral/strategy/tests/__init__.py | 0 .../template_method/examples/__init__.py | 0 .../examples/report_pipeline/__init__.py | 0 .../template_method/tests/__init__.py | 0 .../behavioral/visitor/examples/__init__.py | 0 .../examples/doc_exporters/__init__.py | 0 patterns/behavioral/visitor/tests/__init__.py | 0 patterns/creational/__init__.py | 0 .../abstract_factory/examples/__init__.py | 0 .../examples/report_renderer/__init__.py | 0 .../abstract_factory/tests/__init__.py | 0 .../creational/builder/examples/__init__.py | 0 .../examples/sql_select_builder/__init__.py | 0 patterns/creational/builder/tests/__init__.py | 0 .../factory_method/examples/__init__.py | 0 .../examples/feed_client/__init__.py | 0 .../factory_method/tests/__init__.py | 0 .../creational/prototype/examples/__init__.py | 0 .../examples/report_job_templates/__init__.py | 0 .../creational/prototype/tests/__init__.py | 0 .../creational/singleton/examples/__init__.py | 0 .../singleton/examples/app_config/__init__.py | 0 .../creational/singleton/tests/__init__.py | 0 patterns/modern/__init__.py | 0 .../examples/__init__.py | 0 .../examples/feed_fetcher/__init__.py | 0 .../async_producer_consumer/tests/__init__.py | 0 .../context_manager/examples/__init__.py | 0 .../examples/atomic_deploy/__init__.py | 0 .../modern/context_manager/tests/__init__.py | 0 .../dependency_injection/examples/__init__.py | 0 .../examples/invoice_reminders/__init__.py | 0 .../dependency_injection/tests/__init__.py | 0 patterns/modern/registry/examples/__init__.py | 0 patterns/modern/registry/tests/__init__.py | 0 .../modern/repository/examples/__init__.py | 0 .../examples/invoice_ledger/__init__.py | 0 patterns/modern/repository/tests/__init__.py | 0 patterns/principle/__init__.py | 0 .../examples/__init__.py | 0 .../examples/notification_router/__init__.py | 0 .../tests/__init__.py | 0 patterns/python/__init__.py | 0 .../python/global_object/examples/__init__.py | 0 .../examples/settings_module/__init__.py | 0 .../python/global_object/tests/__init__.py | 0 .../prebound_method/examples/__init__.py | 0 .../examples/metrics/__init__.py | 0 .../python/prebound_method/tests/__init__.py | 0 .../sentinel_object/examples/__init__.py | 0 .../examples/layered_config/__init__.py | 0 .../python/sentinel_object/tests/__init__.py | 0 patterns/structural/__init__.py | 0 .../structural/adapter/examples/__init__.py | 0 .../examples/payment_gateways/__init__.py | 0 patterns/structural/adapter/tests/__init__.py | 0 .../structural/bridge/examples/__init__.py | 0 .../examples/notification_center/__init__.py | 0 patterns/structural/bridge/tests/__init__.py | 0 .../structural/composite/examples/__init__.py | 0 .../composite/examples/org_chart/__init__.py | 0 .../structural/composite/tests/__init__.py | 0 .../structural/decorator/examples/__init__.py | 0 .../examples/resilient_client/__init__.py | 0 .../structural/decorator/tests/__init__.py | 0 .../structural/facade/examples/__init__.py | 0 .../examples/order_checkout/__init__.py | 0 patterns/structural/facade/tests/__init__.py | 0 .../structural/flyweight/examples/__init__.py | 0 .../examples/glyph_styles/__init__.py | 0 .../structural/flyweight/tests/__init__.py | 0 .../structural/proxy/examples/__init__.py | 0 .../proxy/examples/db_gateway/__init__.py | 0 patterns/structural/proxy/tests/__init__.py | 0 pyproject.toml | 10 ++++++- src/design_patterns/__init__.py | 0 src/design_patterns/catalog.py | 17 ++++++++---- src/design_patterns/mcp/__init__.py | 0 tests/conftest.py | 7 ++--- tests/test_catalog.py | 27 ++++++++++++------- 108 files changed, 40 insertions(+), 21 deletions(-) delete mode 100644 patterns/__init__.py delete mode 100644 patterns/behavioral/__init__.py delete mode 100644 patterns/behavioral/chain_of_responsibility/examples/__init__.py delete mode 100644 patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py delete mode 100644 patterns/behavioral/chain_of_responsibility/tests/__init__.py delete mode 100644 patterns/behavioral/command/examples/__init__.py delete mode 100644 patterns/behavioral/command/examples/editor_undo/__init__.py delete mode 100644 patterns/behavioral/command/tests/__init__.py delete mode 100644 patterns/behavioral/interpreter/examples/__init__.py delete mode 100644 patterns/behavioral/interpreter/examples/flag_rules/__init__.py delete mode 100644 patterns/behavioral/interpreter/tests/__init__.py delete mode 100644 patterns/behavioral/iterator/examples/__init__.py delete mode 100644 patterns/behavioral/iterator/examples/paginated_client/__init__.py delete mode 100644 patterns/behavioral/iterator/tests/__init__.py delete mode 100644 patterns/behavioral/mediator/examples/__init__.py delete mode 100644 patterns/behavioral/mediator/examples/checkout_form/__init__.py delete mode 100644 patterns/behavioral/mediator/tests/__init__.py delete mode 100644 patterns/behavioral/memento/examples/__init__.py delete mode 100644 patterns/behavioral/memento/examples/config_checkpoints/__init__.py delete mode 100644 patterns/behavioral/memento/tests/__init__.py delete mode 100644 patterns/behavioral/observer/examples/__init__.py delete mode 100644 patterns/behavioral/observer/examples/order_events/__init__.py delete mode 100644 patterns/behavioral/observer/tests/__init__.py delete mode 100644 patterns/behavioral/state/examples/__init__.py delete mode 100644 patterns/behavioral/state/examples/order_lifecycle/__init__.py delete mode 100644 patterns/behavioral/state/tests/__init__.py delete mode 100644 patterns/behavioral/strategy/examples/__init__.py delete mode 100644 patterns/behavioral/strategy/examples/promotions/__init__.py delete mode 100644 patterns/behavioral/strategy/tests/__init__.py delete mode 100644 patterns/behavioral/template_method/examples/__init__.py delete mode 100644 patterns/behavioral/template_method/examples/report_pipeline/__init__.py delete mode 100644 patterns/behavioral/template_method/tests/__init__.py delete mode 100644 patterns/behavioral/visitor/examples/__init__.py delete mode 100644 patterns/behavioral/visitor/examples/doc_exporters/__init__.py delete mode 100644 patterns/behavioral/visitor/tests/__init__.py delete mode 100644 patterns/creational/__init__.py delete mode 100644 patterns/creational/abstract_factory/examples/__init__.py delete mode 100644 patterns/creational/abstract_factory/examples/report_renderer/__init__.py delete mode 100644 patterns/creational/abstract_factory/tests/__init__.py delete mode 100644 patterns/creational/builder/examples/__init__.py delete mode 100644 patterns/creational/builder/examples/sql_select_builder/__init__.py delete mode 100644 patterns/creational/builder/tests/__init__.py delete mode 100644 patterns/creational/factory_method/examples/__init__.py delete mode 100644 patterns/creational/factory_method/examples/feed_client/__init__.py delete mode 100644 patterns/creational/factory_method/tests/__init__.py delete mode 100644 patterns/creational/prototype/examples/__init__.py delete mode 100644 patterns/creational/prototype/examples/report_job_templates/__init__.py delete mode 100644 patterns/creational/prototype/tests/__init__.py delete mode 100644 patterns/creational/singleton/examples/__init__.py delete mode 100644 patterns/creational/singleton/examples/app_config/__init__.py delete mode 100644 patterns/creational/singleton/tests/__init__.py delete mode 100644 patterns/modern/__init__.py delete mode 100644 patterns/modern/async_producer_consumer/examples/__init__.py delete mode 100644 patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py delete mode 100644 patterns/modern/async_producer_consumer/tests/__init__.py delete mode 100644 patterns/modern/context_manager/examples/__init__.py delete mode 100644 patterns/modern/context_manager/examples/atomic_deploy/__init__.py delete mode 100644 patterns/modern/context_manager/tests/__init__.py delete mode 100644 patterns/modern/dependency_injection/examples/__init__.py delete mode 100644 patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py delete mode 100644 patterns/modern/dependency_injection/tests/__init__.py delete mode 100644 patterns/modern/registry/examples/__init__.py delete mode 100644 patterns/modern/registry/tests/__init__.py delete mode 100644 patterns/modern/repository/examples/__init__.py delete mode 100644 patterns/modern/repository/examples/invoice_ledger/__init__.py delete mode 100644 patterns/modern/repository/tests/__init__.py delete mode 100644 patterns/principle/__init__.py delete mode 100644 patterns/principle/composition_over_inheritance/examples/__init__.py delete mode 100644 patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py delete mode 100644 patterns/principle/composition_over_inheritance/tests/__init__.py delete mode 100644 patterns/python/__init__.py delete mode 100644 patterns/python/global_object/examples/__init__.py delete mode 100644 patterns/python/global_object/examples/settings_module/__init__.py delete mode 100644 patterns/python/global_object/tests/__init__.py delete mode 100644 patterns/python/prebound_method/examples/__init__.py delete mode 100644 patterns/python/prebound_method/examples/metrics/__init__.py delete mode 100644 patterns/python/prebound_method/tests/__init__.py delete mode 100644 patterns/python/sentinel_object/examples/__init__.py delete mode 100644 patterns/python/sentinel_object/examples/layered_config/__init__.py delete mode 100644 patterns/python/sentinel_object/tests/__init__.py delete mode 100644 patterns/structural/__init__.py delete mode 100644 patterns/structural/adapter/examples/__init__.py delete mode 100644 patterns/structural/adapter/examples/payment_gateways/__init__.py delete mode 100644 patterns/structural/adapter/tests/__init__.py delete mode 100644 patterns/structural/bridge/examples/__init__.py delete mode 100644 patterns/structural/bridge/examples/notification_center/__init__.py delete mode 100644 patterns/structural/bridge/tests/__init__.py delete mode 100644 patterns/structural/composite/examples/__init__.py delete mode 100644 patterns/structural/composite/examples/org_chart/__init__.py delete mode 100644 patterns/structural/composite/tests/__init__.py delete mode 100644 patterns/structural/decorator/examples/__init__.py delete mode 100644 patterns/structural/decorator/examples/resilient_client/__init__.py delete mode 100644 patterns/structural/decorator/tests/__init__.py delete mode 100644 patterns/structural/facade/examples/__init__.py delete mode 100644 patterns/structural/facade/examples/order_checkout/__init__.py delete mode 100644 patterns/structural/facade/tests/__init__.py delete mode 100644 patterns/structural/flyweight/examples/__init__.py delete mode 100644 patterns/structural/flyweight/examples/glyph_styles/__init__.py delete mode 100644 patterns/structural/flyweight/tests/__init__.py delete mode 100644 patterns/structural/proxy/examples/__init__.py delete mode 100644 patterns/structural/proxy/examples/db_gateway/__init__.py delete mode 100644 patterns/structural/proxy/tests/__init__.py delete mode 100644 src/design_patterns/__init__.py delete mode 100644 src/design_patterns/mcp/__init__.py diff --git a/patterns/__init__.py b/patterns/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/__init__.py b/patterns/behavioral/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/chain_of_responsibility/examples/__init__.py b/patterns/behavioral/chain_of_responsibility/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py b/patterns/behavioral/chain_of_responsibility/examples/ticket_escalation/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/chain_of_responsibility/tests/__init__.py b/patterns/behavioral/chain_of_responsibility/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/command/examples/__init__.py b/patterns/behavioral/command/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/command/examples/editor_undo/__init__.py b/patterns/behavioral/command/examples/editor_undo/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/command/tests/__init__.py b/patterns/behavioral/command/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/interpreter/examples/__init__.py b/patterns/behavioral/interpreter/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/interpreter/examples/flag_rules/__init__.py b/patterns/behavioral/interpreter/examples/flag_rules/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/interpreter/tests/__init__.py b/patterns/behavioral/interpreter/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/iterator/examples/__init__.py b/patterns/behavioral/iterator/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/iterator/examples/paginated_client/__init__.py b/patterns/behavioral/iterator/examples/paginated_client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/iterator/tests/__init__.py b/patterns/behavioral/iterator/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/mediator/examples/__init__.py b/patterns/behavioral/mediator/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/mediator/examples/checkout_form/__init__.py b/patterns/behavioral/mediator/examples/checkout_form/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/mediator/tests/__init__.py b/patterns/behavioral/mediator/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/memento/examples/__init__.py b/patterns/behavioral/memento/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/memento/examples/config_checkpoints/__init__.py b/patterns/behavioral/memento/examples/config_checkpoints/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/memento/tests/__init__.py b/patterns/behavioral/memento/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/observer/examples/__init__.py b/patterns/behavioral/observer/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/observer/examples/order_events/__init__.py b/patterns/behavioral/observer/examples/order_events/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/observer/tests/__init__.py b/patterns/behavioral/observer/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/state/examples/__init__.py b/patterns/behavioral/state/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/state/examples/order_lifecycle/__init__.py b/patterns/behavioral/state/examples/order_lifecycle/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/state/tests/__init__.py b/patterns/behavioral/state/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/strategy/examples/__init__.py b/patterns/behavioral/strategy/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/strategy/examples/promotions/__init__.py b/patterns/behavioral/strategy/examples/promotions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/strategy/tests/__init__.py b/patterns/behavioral/strategy/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/template_method/examples/__init__.py b/patterns/behavioral/template_method/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/template_method/examples/report_pipeline/__init__.py b/patterns/behavioral/template_method/examples/report_pipeline/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/template_method/tests/__init__.py b/patterns/behavioral/template_method/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/visitor/examples/__init__.py b/patterns/behavioral/visitor/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/visitor/examples/doc_exporters/__init__.py b/patterns/behavioral/visitor/examples/doc_exporters/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/behavioral/visitor/tests/__init__.py b/patterns/behavioral/visitor/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/__init__.py b/patterns/creational/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/abstract_factory/examples/__init__.py b/patterns/creational/abstract_factory/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/abstract_factory/examples/report_renderer/__init__.py b/patterns/creational/abstract_factory/examples/report_renderer/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/abstract_factory/tests/__init__.py b/patterns/creational/abstract_factory/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/builder/examples/__init__.py b/patterns/creational/builder/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/builder/examples/sql_select_builder/__init__.py b/patterns/creational/builder/examples/sql_select_builder/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/builder/tests/__init__.py b/patterns/creational/builder/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/factory_method/examples/__init__.py b/patterns/creational/factory_method/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/factory_method/examples/feed_client/__init__.py b/patterns/creational/factory_method/examples/feed_client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/factory_method/tests/__init__.py b/patterns/creational/factory_method/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/prototype/examples/__init__.py b/patterns/creational/prototype/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/prototype/examples/report_job_templates/__init__.py b/patterns/creational/prototype/examples/report_job_templates/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/prototype/tests/__init__.py b/patterns/creational/prototype/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/singleton/examples/__init__.py b/patterns/creational/singleton/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/singleton/examples/app_config/__init__.py b/patterns/creational/singleton/examples/app_config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/creational/singleton/tests/__init__.py b/patterns/creational/singleton/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/__init__.py b/patterns/modern/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/async_producer_consumer/examples/__init__.py b/patterns/modern/async_producer_consumer/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py b/patterns/modern/async_producer_consumer/examples/feed_fetcher/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/async_producer_consumer/tests/__init__.py b/patterns/modern/async_producer_consumer/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/context_manager/examples/__init__.py b/patterns/modern/context_manager/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/context_manager/examples/atomic_deploy/__init__.py b/patterns/modern/context_manager/examples/atomic_deploy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/context_manager/tests/__init__.py b/patterns/modern/context_manager/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/dependency_injection/examples/__init__.py b/patterns/modern/dependency_injection/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py b/patterns/modern/dependency_injection/examples/invoice_reminders/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/dependency_injection/tests/__init__.py b/patterns/modern/dependency_injection/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/registry/examples/__init__.py b/patterns/modern/registry/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/registry/tests/__init__.py b/patterns/modern/registry/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/repository/examples/__init__.py b/patterns/modern/repository/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/repository/examples/invoice_ledger/__init__.py b/patterns/modern/repository/examples/invoice_ledger/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/modern/repository/tests/__init__.py b/patterns/modern/repository/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/principle/__init__.py b/patterns/principle/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/principle/composition_over_inheritance/examples/__init__.py b/patterns/principle/composition_over_inheritance/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py b/patterns/principle/composition_over_inheritance/examples/notification_router/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/principle/composition_over_inheritance/tests/__init__.py b/patterns/principle/composition_over_inheritance/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/__init__.py b/patterns/python/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/global_object/examples/__init__.py b/patterns/python/global_object/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/global_object/examples/settings_module/__init__.py b/patterns/python/global_object/examples/settings_module/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/global_object/tests/__init__.py b/patterns/python/global_object/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/prebound_method/examples/__init__.py b/patterns/python/prebound_method/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/prebound_method/examples/metrics/__init__.py b/patterns/python/prebound_method/examples/metrics/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/prebound_method/tests/__init__.py b/patterns/python/prebound_method/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/sentinel_object/examples/__init__.py b/patterns/python/sentinel_object/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/sentinel_object/examples/layered_config/__init__.py b/patterns/python/sentinel_object/examples/layered_config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/python/sentinel_object/tests/__init__.py b/patterns/python/sentinel_object/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/__init__.py b/patterns/structural/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/adapter/examples/__init__.py b/patterns/structural/adapter/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/adapter/examples/payment_gateways/__init__.py b/patterns/structural/adapter/examples/payment_gateways/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/adapter/tests/__init__.py b/patterns/structural/adapter/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/bridge/examples/__init__.py b/patterns/structural/bridge/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/bridge/examples/notification_center/__init__.py b/patterns/structural/bridge/examples/notification_center/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/bridge/tests/__init__.py b/patterns/structural/bridge/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/composite/examples/__init__.py b/patterns/structural/composite/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/composite/examples/org_chart/__init__.py b/patterns/structural/composite/examples/org_chart/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/composite/tests/__init__.py b/patterns/structural/composite/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/decorator/examples/__init__.py b/patterns/structural/decorator/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/decorator/examples/resilient_client/__init__.py b/patterns/structural/decorator/examples/resilient_client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/decorator/tests/__init__.py b/patterns/structural/decorator/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/facade/examples/__init__.py b/patterns/structural/facade/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/facade/examples/order_checkout/__init__.py b/patterns/structural/facade/examples/order_checkout/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/facade/tests/__init__.py b/patterns/structural/facade/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/flyweight/examples/__init__.py b/patterns/structural/flyweight/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/flyweight/examples/glyph_styles/__init__.py b/patterns/structural/flyweight/examples/glyph_styles/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/flyweight/tests/__init__.py b/patterns/structural/flyweight/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/proxy/examples/__init__.py b/patterns/structural/proxy/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/proxy/examples/db_gateway/__init__.py b/patterns/structural/proxy/examples/db_gateway/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/patterns/structural/proxy/tests/__init__.py b/patterns/structural/proxy/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pyproject.toml b/pyproject.toml index 6646e48..8277bd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,16 +55,24 @@ src = ["src", "patterns", "tests"] [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"] +[tool.ruff.lint.isort] +# Namespace packages (PEP 420): no __init__.py to detect these by, so declare them. +known-first-party = ["patterns", "design_patterns"] + [tool.mypy] strict = true python_version = "3.11" files = ["src", "patterns"] +# Namespace packages (PEP 420): no empty __init__.py — resolve modules by +# their full dotted path from the package bases below. +explicit_package_bases = true +mypy_path = ["src", "."] [tool.pytest.ini_options] testpaths = ["tests", "patterns"] pythonpath = ["."] asyncio_mode = "auto" -addopts = "-q --cov=src --cov=patterns --cov-report=term-missing" +addopts = "-q --import-mode=importlib --cov=src --cov=patterns --cov-report=term-missing" timeout = 30 # a shutdown regression must fail CI, not hang it [tool.coverage.report] diff --git a/src/design_patterns/__init__.py b/src/design_patterns/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/design_patterns/catalog.py b/src/design_patterns/catalog.py index eb69c12..985b821 100644 --- a/src/design_patterns/catalog.py +++ b/src/design_patterns/catalog.py @@ -164,16 +164,23 @@ def _validate_shape(pattern: Pattern, readme: Path) -> None: raise CatalogError( f"{readme}: module unit ships no runnable examples//__main__.py" ) - if not (unit / "examples" / "__init__.py").is_file(): - raise CatalogError(f"{readme}: examples/ is not a package (no __init__.py)") - for name, path in examples.items(): - if not (path / "__init__.py").is_file(): - raise CatalogError(f"{readme}: example {name!r} is not a package (no __init__.py)") + for stray in _empty_inits(unit): + raise CatalogError( + f"{readme}: delete empty __init__.py ({stray.relative_to(unit)}) — " + "namespace packages (PEP 420) carry the structure" + ) tests_dir = unit / "tests" if not any(tests_dir.glob("test_*.py")): raise CatalogError(f"{readme}: module unit has no tests/test_*.py") +def _empty_inits(unit: Path) -> list[Path]: + """Empty ``__init__.py`` anywhere in the unit — banned; only load-bearing ones exist.""" + return sorted( + f for f in unit.rglob("__init__.py") if f.stat().st_size == 0 or not f.read_text().strip() + ) + + @dataclass(frozen=True) class Catalog: """All validated pattern units, ordered by id.""" diff --git a/src/design_patterns/mcp/__init__.py b/src/design_patterns/mcp/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/conftest.py b/tests/conftest.py index 7d71ceb..5c04ec4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,9 +15,8 @@ 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"): - (pkg / "__init__.py").write_text("") - # The two API files model the house style: bare as-alias re-exports. + # No empty __init__.py anywhere — namespace packages (PEP 420) carry the + # structure. 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( @@ -34,8 +33,6 @@ def write_module_unit(root: Path) -> Path: (docs / f"{name}.md").write_text(f"# {name} of Thing\n") project = unit / "examples" / "demo" project.mkdir(parents=True) - (unit / "examples" / "__init__.py").write_text("") - (project / "__init__.py").write_text("") (project / "__main__.py").write_text( "from patterns.creational.thing.pattern.thing import build\n\nprint(build())\n" ) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index c5684b5..5662fb0 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -130,8 +130,9 @@ def _write_module_unit(root: Path, group: str, slug: str, frontmatter: str) -> P unit = root / group / slug (unit / "pattern").mkdir(parents=True) (unit / "README.md").write_text(f"---\n{frontmatter}\n---\n\n# x\n") - (unit / "__init__.py").write_text("") - (unit / "pattern" / "__init__.py").write_text("") + # Only load-bearing __init__.py exist (house rule): the two API files. + (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 / "pattern" / "thing.py").write_text("def build() -> str:\n return 'thing'\n") docs = unit / "docs" docs.mkdir() @@ -139,8 +140,6 @@ def _write_module_unit(root: Path, group: str, slug: str, frontmatter: str) -> P (docs / f"{name}.md").write_text(f"# {name}\n") project = unit / "examples" / "demo" project.mkdir(parents=True) - (unit / "examples" / "__init__.py").write_text("") - (project / "__init__.py").write_text("") (project / "__main__.py").write_text("print('demo ran')\n") tests = unit / "tests" tests.mkdir() @@ -168,10 +167,10 @@ def test_no_example_fails(self, tmp_path: Path) -> None: with pytest.raises(CatalogError, match="no runnable examples"): load_catalog(tmp_path) - def test_example_not_a_package_fails(self, tmp_path: Path) -> None: + def test_empty_init_in_example_fails(self, tmp_path: Path) -> None: unit = _write_module_unit(tmp_path, "creational", "thing", GOOD) - (unit / "examples" / "demo" / "__init__.py").unlink() - with pytest.raises(CatalogError, match="not a package"): + (unit / "examples" / "demo" / "__init__.py").write_text("") + with pytest.raises(CatalogError, match=r"delete empty __init__\.py"): load_catalog(tmp_path) def test_empty_tests_fails(self, tmp_path: Path) -> None: @@ -200,12 +199,20 @@ def test_partial_unit_fails_loudly(self, tmp_path: Path) -> None: with pytest.raises(CatalogError, match="module unit missing docs"): load_catalog(tmp_path) - def test_examples_dir_needs_init(self, tmp_path: Path) -> None: + def test_empty_init_in_examples_dir_fails(self, tmp_path: Path) -> None: unit = _write_module_unit(tmp_path, "creational", "thing", GOOD) - (unit / "examples" / "__init__.py").unlink() - with pytest.raises(CatalogError, match=r"examples/ is not a package"): + (unit / "examples" / "__init__.py").write_text("") + with pytest.raises(CatalogError, match=r"delete empty __init__\.py"): load_catalog(tmp_path) + def test_loadbearing_example_init_is_allowed(self, tmp_path: Path) -> None: + # A NON-empty example __init__.py (e.g. plugin self-registration) is fine. + unit = _write_module_unit(tmp_path, "creational", "thing", GOOD) + (unit / "examples" / "demo" / "__init__.py").write_text( + "# load-bearing: demo of import-time registration\n" + ) + assert load_catalog(tmp_path).get("creational/thing").examples() + def test_index_json_carries_docs_and_examples(self, tmp_path: Path) -> None: _write_module_unit(tmp_path, "creational", "thing", GOOD) entries = json.loads(load_catalog(tmp_path).to_json()) From ba3effd9074d695f188186402e1e4e1abae277ac Mon Sep 17 00:00:00 2001 From: SuperElectron Date: Thu, 27 Aug 2026 14:24:28 -0700 Subject: [PATCH 2/2] docs: house rule and scaffold for the no-empty-__init__ shape CLAUDE.md template tree + house rule updated (delete, don't create; PEP 420); AGENTS.md regenerated as mirror; /new-pattern scaffolds without empty inits. Co-Authored-By: Claude Fable 5 --- .claude/commands/new-pattern.md | 6 +++--- AGENTS.md | 10 +++++++--- CLAUDE.md | 10 +++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.claude/commands/new-pattern.md b/.claude/commands/new-pattern.md index d903a1c..2edae05 100644 --- a/.claude/commands/new-pattern.md +++ b/.claude/commands/new-pattern.md @@ -17,9 +17,9 @@ Scaffold a new pattern module for $ARGUMENTS. - `docs/fundamentals.md`, `docs/implementation.md`, `docs/examples.md` — each a heading plus a `TODO` line naming what belongs there (classic-form contrast in fundamentals; never use the word "naive"). - - `examples/__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`. + - `examples/demo/__main__.py` with a typed `main() -> None` + script guard + that imports from `...pattern`. Create NO other `__init__.py` — empty ones + are banned (PEP 420 namespace packages); the loader rejects them. - `tests/test_.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/AGENTS.md b/AGENTS.md index 88b55a2..45d9d38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,11 +30,13 @@ patterns/// │ ├── implementation.md# introducing it into a real system: smell, steps, idioms, pitfalls │ └── examples.md # cited EXTERNAL usages: stdlib, OSS, articles ├── examples/ # runnable mini-projects that import pattern/ -│ ├── __init__.py │ └── / # realistic domain, no Foo/Bar; __main__.py + modules └── tests/ # isolated: test_.py + test_.py ``` +No other `__init__.py` exist — namespace packages (PEP 420) carry the rest; +the loader rejects empty ones. + - Everything import-safe (no side effects at import); mini-projects run via `uv run python -m patterns...examples.`. - Tests assert behavior, never just "it runs"; load-bearing claims get the @@ -49,8 +51,10 @@ 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__`. +- No empty `__init__.py` — delete them (PEP 420 namespace packages). One exists + only when load-bearing: the unit's public-API re-exports + (`from .pattern.x import Y as Y` — the as-alias form) or an import-time + effect the unit teaches. Never `__all__`. ## Frontmatter schema (the MCP server indexes this — keep it valid) diff --git a/CLAUDE.md b/CLAUDE.md index 6af2aed..42097cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,11 +30,13 @@ patterns/// │ ├── implementation.md# introducing it into a real system: smell, steps, idioms, pitfalls │ └── examples.md # cited EXTERNAL usages: stdlib, OSS, articles ├── examples/ # runnable mini-projects that import pattern/ -│ ├── __init__.py │ └── / # realistic domain, no Foo/Bar; __main__.py + modules └── tests/ # isolated: test_.py + test_.py ``` +No other `__init__.py` exist — namespace packages (PEP 420) carry the rest; +the loader rejects empty ones. + - Everything import-safe (no side effects at import); mini-projects run via `uv run python -m patterns...examples.`. - Tests assert behavior, never just "it runs"; load-bearing claims get the @@ -49,8 +51,10 @@ 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__`. +- No empty `__init__.py` — delete them (PEP 420 namespace packages). One exists + only when load-bearing: the unit's public-API re-exports + (`from .pattern.x import Y as Y` — the as-alias form) or an import-time + effect the unit teaches. Never `__all__`. ## Frontmatter schema (the MCP server indexes this — keep it valid)