python-skills 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. python_skills/__init__.py +10 -0
  2. python_skills/__main__.py +6 -0
  3. python_skills/adapters/__init__.py +48 -0
  4. python_skills/adapters/agent_skills.py +415 -0
  5. python_skills/adapters/aider_adapter.py +226 -0
  6. python_skills/adapters/base.py +153 -0
  7. python_skills/adapters/claude.py +474 -0
  8. python_skills/adapters/cline.py +332 -0
  9. python_skills/adapters/codex.py +24 -0
  10. python_skills/adapters/continue_adapter.py +198 -0
  11. python_skills/adapters/cursor.py +327 -0
  12. python_skills/adapters/gemini.py +26 -0
  13. python_skills/adapters/goose.py +26 -0
  14. python_skills/adapters/junie.py +25 -0
  15. python_skills/adapters/kiro.py +382 -0
  16. python_skills/adapters/opencode.py +27 -0
  17. python_skills/adapters/roo.py +25 -0
  18. python_skills/adapters/universal.py +203 -0
  19. python_skills/adapters/vscode.py +27 -0
  20. python_skills/adapters/windsurf.py +26 -0
  21. python_skills/adapters/zed.py +27 -0
  22. python_skills/cli.py +326 -0
  23. python_skills/config.py +160 -0
  24. python_skills/detector.py +152 -0
  25. python_skills/installer.py +163 -0
  26. python_skills/markers.py +115 -0
  27. python_skills/skills/__init__.py +14 -0
  28. python_skills/skills/loader.py +171 -0
  29. python_skills/skills/metadata.py +152 -0
  30. python_skills/skills/registry.py +101 -0
  31. python_skills/state.py +204 -0
  32. python_skills-1.0.0.dist-info/METADATA +99 -0
  33. python_skills-1.0.0.dist-info/RECORD +105 -0
  34. python_skills-1.0.0.dist-info/WHEEL +4 -0
  35. python_skills-1.0.0.dist-info/entry_points.txt +2 -0
  36. python_skills-1.0.0.dist-info/licenses/LICENSE +21 -0
  37. skills/advanced_python.md +239 -0
  38. skills/anti_patterns/index.md +406 -0
  39. skills/comprehensions.md +167 -0
  40. skills/control_flow.md +175 -0
  41. skills/data_structures.md +243 -0
  42. skills/debugging/common_bugs.md +222 -0
  43. skills/debugging/inspection_techniques.md +249 -0
  44. skills/debugging/root_cause.md +203 -0
  45. skills/engineering/application_logging.md +195 -0
  46. skills/engineering/cli_apps.md +207 -0
  47. skills/engineering/configuration.md +218 -0
  48. skills/engineering/database.md +240 -0
  49. skills/engineering/dependency_management.md +205 -0
  50. skills/engineering/http_clients.md +267 -0
  51. skills/engineering/modules_packages.md +211 -0
  52. skills/engineering/packaging.md +197 -0
  53. skills/engineering/project_structure.md +155 -0
  54. skills/engineering/pyproject_toml.md +302 -0
  55. skills/engineering/virtual_environments.md +206 -0
  56. skills/functions.md +244 -0
  57. skills/generation/async_concurrency.md +291 -0
  58. skills/generation/error_handling.md +276 -0
  59. skills/generation/protocols_generics.md +243 -0
  60. skills/generation/type_hints.md +290 -0
  61. skills/generation/validation_pipeline.md +274 -0
  62. skills/generation/workflow.md +190 -0
  63. skills/oop.md +228 -0
  64. skills/quality/abstractions.md +154 -0
  65. skills/quality/comments.md +177 -0
  66. skills/quality/documentation.md +176 -0
  67. skills/quality/duplication.md +137 -0
  68. skills/quality/maintainability.md +142 -0
  69. skills/quality/naming.md +171 -0
  70. skills/quality/quality_functions.md +245 -0
  71. skills/quality/readability.md +239 -0
  72. skills/quality/type_annotations.md +192 -0
  73. skills/refactoring/behavior_preservation.md +157 -0
  74. skills/refactoring/incremental.md +187 -0
  75. skills/refactoring/interface_stability.md +199 -0
  76. skills/refactoring/safe_refactoring.md +206 -0
  77. skills/security/auth_boundaries.md +200 -0
  78. skills/security/command_injection.md +207 -0
  79. skills/security/dependency_risks.md +282 -0
  80. skills/security/file_handling.md +156 -0
  81. skills/security/input_validation.md +190 -0
  82. skills/security/path_traversal.md +172 -0
  83. skills/security/secrets.md +171 -0
  84. skills/security/sql_injection.md +188 -0
  85. skills/security/unsafe_deserialization.md +164 -0
  86. skills/stdlib/argparse.md +178 -0
  87. skills/stdlib/collections.md +212 -0
  88. skills/stdlib/datetime.md +187 -0
  89. skills/stdlib/functools.md +238 -0
  90. skills/stdlib/itertools.md +183 -0
  91. skills/stdlib/json.md +162 -0
  92. skills/stdlib/logging.md +185 -0
  93. skills/stdlib/os_sys.md +184 -0
  94. skills/stdlib/pathlib.md +218 -0
  95. skills/stdlib/re.md +171 -0
  96. skills/stdlib/statistics.md +112 -0
  97. skills/stdlib/subprocess.md +211 -0
  98. skills/testing/async_tests.md +249 -0
  99. skills/testing/coverage.md +168 -0
  100. skills/testing/edge_cases.md +197 -0
  101. skills/testing/fixtures_mocks.md +203 -0
  102. skills/testing/organization.md +205 -0
  103. skills/testing/parameterized.md +174 -0
  104. skills/testing/regression_tests.md +165 -0
  105. skills/variables_types.md +107 -0
@@ -0,0 +1,177 @@
1
+ # Quality: Comments
2
+
3
+ **Purpose**: When and how to comment code effectively.
4
+
5
+ **When to use**: All code generation and review.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Comment Philosophy
12
+ - **Code explains WHAT** — Comments explain WHY
13
+ - **Good code > Good comments** — Refactor to make code self-explanatory
14
+ - **Outdated comments are worse than no comments** — They mislead
15
+
16
+ ### When to Comment
17
+
18
+ ```python
19
+ # GOOD — Why: business rule, not obvious
20
+ def calculate_tax(amount: Decimal, region: str) -> Decimal:
21
+ # Region X has special 0% rate for orders > $1000 per local law
22
+ if region == "X" and amount > 1000:
23
+ return Decimal("0")
24
+ return amount * TAX_RATES[region]
25
+
26
+ # GOOD — Why: workaround for external limitation
27
+ def fetch_data(url: str) -> Data:
28
+ # API returns 500 on HEAD requests, use GET with Range header
29
+ response = http.get(url, headers={"Range": "bytes=0-"})
30
+ ...
31
+
32
+ # GOOD — Why: non-obvious algorithm choice
33
+ def sort_items(items: list[Item]) -> list[Item]:
34
+ # Timsort stable sort preserves insertion order for equal keys
35
+ # Required for consistent pagination
36
+ return sorted(items, key=lambda x: (x.priority, x.created_at))
37
+
38
+ # BAD — Restates code
39
+ def get_user(user_id: int) -> User:
40
+ # Get user by ID
41
+ return db.query(User).filter_by(id=user_id).first()
42
+
43
+ # BAD — Obvious
44
+ x = x + 1 # Increment x
45
+ ```
46
+
47
+ ### Docstrings (Not Comments)
48
+ ```python
49
+ # Module docstring
50
+ """User management service.
51
+
52
+ Provides CRUD operations for users and authentication.
53
+ """
54
+
55
+ # Class docstring
56
+ class UserService:
57
+ """Manages user lifecycle and authentication.
58
+
59
+ Handles user creation, validation, and session management.
60
+ Uses UserRepository for persistence.
61
+ """
62
+
63
+ def create_user(self, data: UserData) -> User:
64
+ """Create a new user.
65
+
66
+ Args:
67
+ data: Validated user data.
68
+
69
+ Returns:
70
+ Created user with assigned ID.
71
+
72
+ Raises:
73
+ ValidationError: If data is invalid.
74
+ ConflictError: If email already exists.
75
+ """
76
+ ...
77
+ ```
78
+
79
+ ### Inline Comments (Rare)
80
+ ```python
81
+ # Only for non-obvious logic
82
+ result = complex_calculation() # type: ignore[assignment] # mypy false positive
83
+
84
+ # Or algorithm explanation
85
+ # Use Fisher-Yates shuffle for uniform distribution
86
+ for i in range(len(items) - 1, 0, -1):
87
+ j = random.randint(0, i)
88
+ items[i], items[j] = items[j], items[i]
89
+ ```
90
+
91
+ ### TODO/FIXME Comments
92
+ ```python
93
+ # Format: # TODO(author): description
94
+ # TODO(john): Add retry logic when API supports it
95
+
96
+ # FIXME: Known bug
97
+ # FIXME: Race condition on concurrent updates
98
+ ```
99
+
100
+ ### Commented Code
101
+ ```python
102
+ # NEVER commit commented-out code
103
+ # def old_function():
104
+ # ...
105
+ # Use version control history instead
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Decision Rules
111
+
112
+ | Situation | Comment? |
113
+ |-----------|----------|
114
+ | Non-obvious business logic | Yes (WHY) |
115
+ | Workaround for external issue | Yes (WHY) |
116
+ | Algorithm choice rationale | Yes (WHY) |
117
+ | Complex regex | Yes (pattern explanation) |
118
+ | Obvious code | No |
119
+ | Restating code | No |
120
+ | TODO without issue reference | No (use issue tracker) |
121
+
122
+ ---
123
+
124
+ ## Preferred Patterns
125
+
126
+ ```python
127
+ # Docstring for public API
128
+ def process_payment(payment: Payment) -> PaymentResult:
129
+ """Process a payment through the configured gateway.
130
+
131
+ Handles validation, authorization, and capture.
132
+ Retries on transient gateway errors (up to 3 attempts).
133
+
134
+ Args:
135
+ payment: Validated payment with amount and method.
136
+
137
+ Returns:
138
+ PaymentResult with transaction ID and status.
139
+
140
+ Raises:
141
+ PaymentError: If gateway rejects payment.
142
+ GatewayUnavailable: If gateway is unreachable.
143
+ """
144
+ ...
145
+
146
+ # Inline only for genuinely tricky code
147
+ def hash_password(password: str) -> str:
148
+ # Argon2id with memory=64MB, iterations=3, parallelism=4
149
+ # Parameters per OWASP 2023 recommendations
150
+ return argon2.hash(password)
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Avoid
156
+
157
+ - Commented-out code blocks
158
+ - Redundant comments (`i = i + 1 # increment`)
159
+ - Comments that can be replaced by better naming
160
+ - Comments explaining standard library usage
161
+ - Outdated comments (delete when code changes)
162
+
163
+ ---
164
+
165
+ ## Validation Considerations
166
+
167
+ - `ruff` checks for TODO/FIXME format
168
+ - Docstring coverage (`pydocstyle`, `interrogate`)
169
+ - No commented code in diffs
170
+
171
+ ---
172
+
173
+ ## Related Skills
174
+
175
+ - `quality/documentation.md`
176
+ - `quality/readability.md`
177
+ - `quality/naming.md`
@@ -0,0 +1,176 @@
1
+ # Quality: Documentation
2
+
3
+ **Purpose**: Document public APIs and non-obvious behavior appropriately.
4
+
5
+ **When to use**: Public modules, classes, functions, complex systems.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Documentation Levels
12
+
13
+ | Level | Audience | Format |
14
+ |-------|----------|--------|
15
+ | **Docstrings** | Developers using API | In-code, accessible via `help()` |
16
+ | **README** | Users, contributors | Markdown in repo root |
17
+ | **Architecture docs** | Maintainers | Project-specific (e.g., `project-docs/architecture.md`) |
18
+ | **API reference** | External consumers | Generated (Sphinx, pdoc) |
19
+ | **Changelog** | Users | `CHANGELOG.md` |
20
+
21
+ ### Docstring Format (Google/NumPy/Sphinx)
22
+ ```python
23
+ def fetch_users(
24
+ client: APIClient,
25
+ filters: UserFilters | None = None,
26
+ limit: int = 100,
27
+ ) -> list[User]:
28
+ """Fetch users matching filters.
29
+
30
+ Args:
31
+ client: Authenticated API client.
32
+ filters: Optional filters (name, status, role).
33
+ limit: Maximum results (default 100, max 1000).
34
+
35
+ Returns:
36
+ List of users matching criteria.
37
+
38
+ Raises:
39
+ APIError: If request fails.
40
+ ValidationError: If limit exceeds maximum.
41
+
42
+ Example:
43
+ >>> client = APIClient(token="abc")
44
+ >>> users = fetch_users(client, UserFilters(active=True), limit=50)
45
+ """
46
+ ...
47
+ ```
48
+
49
+ ### Module Docstring
50
+ ```python
51
+ """Payment processing module.
52
+
53
+ Provides payment authorization, capture, and refund operations.
54
+ Supports multiple gateways via the PaymentGateway protocol.
55
+
56
+ Typical usage:
57
+ gateway = StripeGateway(api_key="sk_...")
58
+ processor = PaymentProcessor(gateway)
59
+ result = processor.charge(amount=1000, currency="USD")
60
+ """
61
+ ```
62
+
63
+ ### Class Docstring
64
+ ```python
65
+ class PaymentProcessor:
66
+ """Orchestrates payment operations across gateways.
67
+
68
+ Handles retry logic, idempotency, and gateway failover.
69
+ Not thread-safe; use one instance per request.
70
+
71
+ Attributes:
72
+ gateway: Primary payment gateway.
73
+ fallback: Optional fallback gateway.
74
+ """
75
+
76
+ def __init__(self, gateway: PaymentGateway, fallback: PaymentGateway | None = None):
77
+ self.gateway = gateway
78
+ self.fallback = fallback
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Decision Rules
84
+
85
+ | Element | Docstring Required? |
86
+ |---------|---------------------|
87
+ | Public module | Yes |
88
+ | Public class | Yes |
89
+ | Public function/method | Yes |
90
+ | Private (`_` prefix) | Optional |
91
+ | Override (same behavior) | No (inherit) |
92
+ | Property | Yes (describe what it returns) |
93
+
94
+ ### README Structure
95
+ ```markdown
96
+ # Package Name
97
+
98
+ One-line description.
99
+
100
+ ## Installation
101
+ ```bash
102
+ pip install package-name
103
+ ```
104
+
105
+ ## Quick Start
106
+ ```python
107
+ from package import main
108
+ main()
109
+ ```
110
+
111
+ ## Configuration
112
+ Environment variables...
113
+
114
+ ## API Reference
115
+ Link to generated docs.
116
+
117
+ ## Contributing
118
+ ...
119
+
120
+ ## License
121
+ ...
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Preferred Patterns
127
+
128
+ ```python
129
+ # Type hints + docstring = complete API docs
130
+ def process(
131
+ data: InputData,
132
+ config: ProcessingConfig = ProcessingConfig(),
133
+ ) -> OutputData:
134
+ """Process input data according to configuration.
135
+
136
+ Args:
137
+ data: Input to process. Must be validated.
138
+ config: Processing options. Defaults used if omitted.
139
+
140
+ Returns:
141
+ Processed output data.
142
+
143
+ Raises:
144
+ ValidationError: If input data is invalid.
145
+ ProcessingError: If processing fails.
146
+ """
147
+ ...
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Avoid
153
+
154
+ - Missing docstrings on public API
155
+ - Docstrings that just repeat signature
156
+ - Outdated docstrings (update with code)
157
+ - Documenting private implementation details
158
+ - Redundant type information in docstring (use type hints)
159
+
160
+ ---
161
+
162
+ ## Validation Considerations
163
+
164
+ - `pydocstyle` / `ruff` docstring checks
165
+ - `interrogate` for coverage
166
+ - `pdoc` / `sphinx` build succeeds
167
+ - Examples in docstrings runnable (doctest)
168
+
169
+ ---
170
+
171
+ ## Related Skills
172
+
173
+ - `quality/comments.md`
174
+ - `generation/type_hints.md`
175
+ - `engineering/packaging.md`
176
+ - `quality/readability.md`
@@ -0,0 +1,137 @@
1
+ # Quality: Duplication
2
+
3
+ **Purpose**: Remove meaningful duplication without creating unnecessary abstractions.
4
+
5
+ **When to use**: Refactoring, code review, applying DRY principle correctly.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Types of Duplication
12
+
13
+ | Type | Example | Action |
14
+ |------|---------|--------|
15
+ | **True duplication** | Same logic, same reason to change | Extract |
16
+ | **Accidental duplication** | Same code, different reasons to change | Keep separate |
17
+ | **Structural duplication** | Similar structure, different domain | Keep separate |
18
+
19
+ ### True Duplication (Extract)
20
+ ```python
21
+ # Before — same validation logic
22
+ def create_user(data):
23
+ if not data.email or "@" not in data.email:
24
+ raise ValueError("Invalid email")
25
+ if not data.name or len(data.name) < 2:
26
+ raise ValueError("Invalid name")
27
+ return save_user(data)
28
+
29
+ def update_user(user_id, data):
30
+ if not data.email or "@" not in data.email:
31
+ raise ValueError("Invalid email")
32
+ if not data.name or len(data.name) < 2:
33
+ raise ValueError("Invalid name")
34
+ return update_user(user_id, data)
35
+
36
+ # After — extract
37
+ def validate_user_data(data):
38
+ if not data.email or "@" not in data.email:
39
+ raise ValueError("Invalid email")
40
+ if not data.name or len(data.name) < 2:
41
+ raise ValueError("Invalid name")
42
+
43
+ def create_user(data):
44
+ validate_user_data(data)
45
+ return save_user(data)
46
+
47
+ def update_user(user_id, data):
48
+ validate_user_data(data)
49
+ return update_user(user_id, data)
50
+ ```
51
+
52
+ ### Accidental Duplication (Don't Extract)
53
+ ```python
54
+ # User validation
55
+ def validate_user(user):
56
+ if not user.email or "@" not in user.email:
57
+ raise ValueError("Invalid email")
58
+ if user.age < 13:
59
+ raise ValueError("Too young")
60
+
61
+ # Product validation — LOOKS similar but DIFFERENT rules
62
+ def validate_product(product):
63
+ if not product.sku:
64
+ raise ValueError("SKU required")
65
+ if product.price <= 0:
66
+ raise ValueError("Price must be positive")
67
+
68
+ # DON'T extract "validate_required_fields" — different domains, different change reasons
69
+ ```
70
+
71
+ ### Rule of Three
72
+ - First time: Write code
73
+ - Second time: Note similarity, but don't extract yet
74
+ - Third time: Extract common abstraction
75
+
76
+ ---
77
+
78
+ ## Decision Rules
79
+
80
+ | Duplication Type | Action |
81
+ |------------------|--------|
82
+ | Same logic, same domain, same change reason | Extract |
83
+ | Similar structure, different domain | Keep separate |
84
+ | Similar structure, different change reasons | Keep separate |
85
+ | Boilerplate (imports, decorators) | Accept or use code gen |
86
+ | Test setup | Fixtures/helpers OK |
87
+
88
+ ---
89
+
90
+ ## Preferred Patterns
91
+
92
+ ```python
93
+ # Extract to function with clear name
94
+ def validate_email(email: str) -> None:
95
+ if not email or "@" not in email:
96
+ raise ValidationError("email", "Invalid email format")
97
+
98
+ # Extract to protocol for behavioral duplication
99
+ class Validator(Protocol):
100
+ def validate(self, data: Any) -> None: ...
101
+
102
+ # Use decorators for cross-cutting duplication
103
+ def validate_request(schema: type):
104
+ def decorator(func):
105
+ @wraps(func)
106
+ def wrapper(request):
107
+ data = schema.model_validate(request.json)
108
+ return func(data)
109
+ return wrapper
110
+ return decorator
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Avoid
116
+
117
+ - Extracting "utility" functions used once
118
+ - Creating base classes for accidental duplication
119
+ - Parameterizing extracted function to handle differences (creates complexity)
120
+ - DRY obsession — "Duplication is far cheaper than the wrong abstraction" (Sandi Metz)
121
+
122
+ ---
123
+
124
+ ## Validation Considerations
125
+
126
+ - `flake8-duplicates` / `pylint` duplicate-code detection
127
+ - Manual review: "If I change X, do I need to change Y?"
128
+ - Test each extracted unit independently
129
+
130
+ ---
131
+
132
+ ## Related Skills
133
+
134
+ - `quality/abstractions.md`
135
+ - `quality/functions.md`
136
+ - `quality/maintainability.md`
137
+ - `refactoring/safe_refactoring.md`
@@ -0,0 +1,142 @@
1
+ # Quality: Maintainability
2
+
3
+ **Purpose**: Avoid unnecessary coupling and complexity for long-term maintenance.
4
+
5
+ **When to use**: Architecture decisions, refactoring, code review.
6
+ ---
7
+ ---
8
+ name: quality_maintainability
9
+ purpose: Avoid unnecessary coupling and complexity for long-term maintenance
10
+ category: quality
11
+ triggers:
12
+ - coupling
13
+ - cohesion
14
+ - complexity
15
+ - architecture
16
+ - god class
17
+ - circular dependency
18
+ dependencies:
19
+ - quality/abstractions.md
20
+ - quality/duplication.md
21
+ - quality/functions.md
22
+ - generation/protocols_generics.md
23
+ - engineering/modules_packages.md
24
+ priority: primary
25
+ estimated_tokens: 1400
26
+ ---
27
+
28
+ ## Core Rules
29
+
30
+ ### Coupling
31
+ - **Low coupling**: Modules interact through well-defined interfaces
32
+ - **High cohesion**: Related functionality grouped together
33
+
34
+ ```python
35
+ # GOOD — low coupling via protocol
36
+ class PaymentProcessor(Protocol):
37
+ def charge(self, amount: int, token: str) -> ChargeResult: ...
38
+
39
+ def process_order(order: Order, processor: PaymentProcessor) -> Result:
40
+ ...
41
+
42
+ # BAD — high coupling to concrete implementation
43
+ def process_order(order: Order, processor: StripeProcessor) -> Result:
44
+ ...
45
+ ```
46
+
47
+ ### Dependency Direction
48
+ ```
49
+ Domain (business logic) <-- DOES NOT DEPEND ON --> Infrastructure (DB, HTTP, UI)
50
+ ^ ^
51
+ +-- Depends on abstractions --+
52
+ ```
53
+
54
+ - Domain defines interfaces (Protocols)
55
+ - Infrastructure implements them
56
+ - Application wires them together
57
+
58
+ ### Complexity Metrics
59
+ | Metric | Threshold | Action |
60
+ |--------|-----------|--------|
61
+ | Cyclomatic complexity | >10 | Refactor |
62
+ | Function length | >50 lines | Split |
63
+ | Class length | >300 lines | Split |
64
+ | Parameters | >7 | Use config object |
65
+ | Nesting depth | >3 | Extract/guard clauses |
66
+
67
+ ### Single Responsibility
68
+ - Each module/class/function has one reason to change
69
+ - If you can't name it simply, it does too much
70
+
71
+ ### Change Amplification
72
+ - A change in one place should not require changes in many others
73
+ - If adding a field requires changes in 5+ files, design is too coupled
74
+ - Use dependency inversion to contain changes
75
+
76
+ ---
77
+
78
+ ## Decision Rules
79
+
80
+ | Situation | Approach |
81
+ |-----------|----------|
82
+ | New feature | Add to existing cohesive module or create new |
83
+ | Shared code | Extract to utility only if used 3+ times |
84
+ | Cross-cutting concern | Decorator / middleware / context manager |
85
+ | Configuration | Central config object, not global constants |
86
+
87
+ ---
88
+
89
+ ## Preferred Patterns
90
+
91
+ ```python
92
+ # Config object instead of many parameters
93
+ @dataclass
94
+ class ProcessingConfig:
95
+ timeout: float = 30.0
96
+ retries: int = 3
97
+ validate: bool = True
98
+ callback: Callable[[str], None] | None = None
99
+
100
+ def process(data: Data, config: ProcessingConfig) -> Result:
101
+ ...
102
+
103
+ # Protocol for dependency inversion
104
+ class Cache(Protocol):
105
+ async def get(self, key: str) -> bytes | None: ...
106
+ async def set(self, key: str, value: bytes, ttl: int) -> None: ...
107
+
108
+ class Service:
109
+ def __init__(self, cache: Cache):
110
+ self.cache = cache # Depends on abstraction
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Avoid
116
+
117
+ - God classes (knows everything, does everything)
118
+ - Circular dependencies between modules
119
+ - Global mutable state
120
+ - Hardcoded infrastructure in domain logic
121
+ - Premature abstraction (wait for 3rd use case)
122
+ - Copy-paste modification (refactor instead)
123
+
124
+ ---
125
+
126
+ ## Validation Considerations
127
+
128
+ - `radon cc` for cyclomatic complexity
129
+ - `xenon` for complexity thresholds
130
+ - Import graph analysis (no cycles)
131
+ - Architecture tests (import-linter, pydeps)
132
+ - `ruff` B007 (loop variable in closure)
133
+
134
+ ---
135
+
136
+ ## Related Skills
137
+
138
+ - `quality/abstractions.md`
139
+ - `quality/duplication.md`
140
+ - `quality/functions.md`
141
+ - `generation/protocols_generics.md`
142
+ - `engineering/modules_packages.md`