Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Python project organization, module architecture, and public API design. Use when setting up new projects, organizing modules, defining public interfaces with __all__, or planning directory layouts.
.claude/skills/wshobson-python-project-structure/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 62% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 11% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 25% | 0% |
Design well-organized Python projects with clear module boundaries, explicit public interfaces, and maintainable directory structures. Good organization makes code discoverable and changes predictable.
__all__Group related code that changes together. A module should have a single, clear purpose.
Define what's public with __all__. Everything not listed is an internal implementation detail.
Prefer shallow directory structures. Add depth only for genuine sub-domains.
Apply naming and organization patterns uniformly across the project.
myproject/
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── services/
│ ├── models/
│ └── api/
├── tests/
├── pyproject.toml
└── README.mdEach file should focus on a single concept or closely related set of functions. Consider splitting when a file:
python# Good: Focused files # user_service.py - User business logic # user_repository.py - User data access # user_models.py - User data structures # Avoid: Kitchen sink files # user.py - Contains service, repository, models, utilities...
__all__Define the public interface for every module. Unlisted members are internal implementation details.
python# mypackage/services/__init__.py from .user_service import UserService from .order_service import OrderService from .exceptions import ServiceError, ValidationError __all__ = [ "UserService", "OrderService", "ServiceError", "ValidationError", ] # Internal helpers remain private by omission # from .internal_helpers import _validate_input # Not exported
Prefer minimal nesting. Deep hierarchies make imports verbose and navigation difficult.
# Preferred: Flat structure
project/
├── api/
│ ├── routes.py
│ └── middleware.py
├── services/
│ ├── user_service.py
│ └── order_service.py
├── models/
│ ├── user.py
│ └── order.py
└── utils/
└── validation.py
# Avoid: Deep nesting
project/core/internal/services/impl/user/Add sub-packages only when there's a genuine sub-domain requiring isolation.
Choose one approach and apply it consistently throughout the project.
Option A: Colocated Tests
src/
├── user_service.py
├── test_user_service.py
├── order_service.py
└── test_order_service.pyBenefits: Tests live next to the code they verify. Easy to see coverage gaps.
Option B: Parallel Test Directory
src/
├── services/
│ ├── user_service.py
│ └── order_service.py
tests/
├── services/
│ ├── test_user_service.py
│ └── test_order_service.pyBenefits: Clean separation between production and test code. Standard for larger projects.
Use __init__.py to provide a clean public interface for package consumers.
python# mypackage/__init__.py """MyPackage - A library for doing useful things.""" from .core import MainClass, HelperClass from .exceptions import PackageError, ConfigError from .config import Settings __all__ = [ "MainClass", "HelperClass", "PackageError", "ConfigError", "Settings", ] __version__ = "1.0.0"
Consumers can then import directly from the package:
pythonfrom mypackage import MainClass, Settings
Organize code by architectural layer for clear separation of concerns.
myapp/
├── api/ # HTTP handlers, request/response
│ ├── routes/
│ └── middleware/
├── services/ # Business logic
├── repositories/ # Data access
├── models/ # Domain entities
├── schemas/ # API schemas (Pydantic)
└── config/ # ConfigurationEach layer should only depend on layers below it, never above.
For complex applications, organize by business domain rather than technical layer.
ecommerce/
├── users/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
├── orders/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
└── shared/
├── database.py
└── exceptions.pysnake_case for all file and module names: user_repository.pyuser_repository.py not usr_repo.pyUserService in user_service.pyUse absolute imports for clarity and reliability:
python# Preferred: Absolute imports from myproject.services import UserService from myproject.models import User # Avoid: Relative imports from ..services import UserService from . import models
Relative imports can break when modules are moved or reorganized.
__all__ explicitly - Make public interfaces clear| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-03 | pass→pass | 11,107 | 11,002 | -1% | 1 | 1 | 0% | 2,351 | 3,809 | +62% | 0 | 0 | — |
case-01 | pass→pass | 16,137 | 10,746 | -33% | 1 | 1 | 0% | 3,282 | 3,646 | +11% | 0 | 0 | — |
case-02 | pass→pass | 18,648 | 15,053 | -19% | 1 | 1 | 0% | 3,602 | 4,493 | +25% | 0 | 0 | — |
case-04 | pass→pass | 13,662 | 15,338 | +12% | 1 | 1 | 0% | 2,634 | 4,576 | +74% | 0 | 0 | — |
case-05 | pass→pass | 9,367 | 9,179 | -2% | 1 | 1 | 0% | 1,849 | 3,265 | +77% | 0 | 0 | — |
case-06 | fail→pass | 9,101 | 7,271 | -20% | 1 | 1 | 0% | 1,855 | 2,965 | +60% | 0 | 0 | — |
case-07 | pass→pass | 7,905 | 4,585 | -42% | 1 | 1 | 0% | 1,540 | 2,326 | +51% | 0 | 0 | — |
case-08 | pass→pass | 6,934 | 5,134 | -26% | 1 | 1 | 0% | 1,437 | 2,584 | +80% | 0 | 0 | — |
case-09 | pass→pass | 12,759 | 11,167 | -12% | 1 | 1 | 0% | 2,334 | 3,582 | +53% | 0 | 0 | — |
case-10 | fail→pass | 11,621 | 10,904 | -6% | 1 | 1 | 0% | 2,232 | 3,835 | +72% | 0 | 0 | — |
case-11 | pass→pass | 13,036 | 74,082 | +468% | 1 | 1 | 0% | 2,365 | 3,726 | +58% | 0 | 0 | — |
case-12 | pass→pass | 16,020 | 11,925 | -26% | 1 | 1 | 0% | 3,051 | 3,832 | +26% | 0 | 0 | — |
case-13 | pass→pass | 13,694 | 14,571 | +6% | 1 | 1 | 0% | 2,556 | 4,659 | +82% | 0 | 0 | — |
case-14 | pass→pass | 8,498 | 4,783 | -44% | 1 | 1 | 0% | 1,786 | 2,470 | +38% | 0 | 0 | — |
case-15 | pass→pass | 12,354 | 12,952 | +5% | 1 | 1 | 0% | 2,481 | 4,048 | +63% | 0 | 0 | — |
case-16 | pass→pass | 11,179 | 18,626 | +67% | 1 | 1 | 0% | 1,939 | 3,198 | +65% | 0 | 0 | — |
case-17 | pass→pass | 6,881 | 4,730 | -31% | 1 | 1 | 0% | 1,399 | 2,421 | +73% | 0 | 0 | — |
case-18 | pass→pass | 10,567 | 6,089 | -42% | 1 | 1 | 0% | 2,042 | 2,659 | +30% | 0 | 0 | — |
case-19 | pass→pass | 7,511 | 4,898 | -35% | 1 | 1 | 0% | 1,466 | 2,583 | +76% | 0 | 0 | — |
case-20 | pass→pass | 5,749 | 23,390 | +307% | 1 | 1 | 0% | 1,168 | 2,277 | +95% | 0 | 0 | — |
case-21 | pass→pass | 15,489 | 8,780 | -43% | 1 | 1 | 0% | 2,047 | 2,949 | +44% | 0 | 0 | — |
case-22 | pass→pass | 6,359 | 5,015 | -21% | 1 | 1 | 0% | 1,288 | 2,661 | +107% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.