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.
- python_skills/__init__.py +10 -0
- python_skills/__main__.py +6 -0
- python_skills/adapters/__init__.py +48 -0
- python_skills/adapters/agent_skills.py +415 -0
- python_skills/adapters/aider_adapter.py +226 -0
- python_skills/adapters/base.py +153 -0
- python_skills/adapters/claude.py +474 -0
- python_skills/adapters/cline.py +332 -0
- python_skills/adapters/codex.py +24 -0
- python_skills/adapters/continue_adapter.py +198 -0
- python_skills/adapters/cursor.py +327 -0
- python_skills/adapters/gemini.py +26 -0
- python_skills/adapters/goose.py +26 -0
- python_skills/adapters/junie.py +25 -0
- python_skills/adapters/kiro.py +382 -0
- python_skills/adapters/opencode.py +27 -0
- python_skills/adapters/roo.py +25 -0
- python_skills/adapters/universal.py +203 -0
- python_skills/adapters/vscode.py +27 -0
- python_skills/adapters/windsurf.py +26 -0
- python_skills/adapters/zed.py +27 -0
- python_skills/cli.py +326 -0
- python_skills/config.py +160 -0
- python_skills/detector.py +152 -0
- python_skills/installer.py +163 -0
- python_skills/markers.py +115 -0
- python_skills/skills/__init__.py +14 -0
- python_skills/skills/loader.py +171 -0
- python_skills/skills/metadata.py +152 -0
- python_skills/skills/registry.py +101 -0
- python_skills/state.py +204 -0
- python_skills-1.0.0.dist-info/METADATA +99 -0
- python_skills-1.0.0.dist-info/RECORD +105 -0
- python_skills-1.0.0.dist-info/WHEEL +4 -0
- python_skills-1.0.0.dist-info/entry_points.txt +2 -0
- python_skills-1.0.0.dist-info/licenses/LICENSE +21 -0
- skills/advanced_python.md +239 -0
- skills/anti_patterns/index.md +406 -0
- skills/comprehensions.md +167 -0
- skills/control_flow.md +175 -0
- skills/data_structures.md +243 -0
- skills/debugging/common_bugs.md +222 -0
- skills/debugging/inspection_techniques.md +249 -0
- skills/debugging/root_cause.md +203 -0
- skills/engineering/application_logging.md +195 -0
- skills/engineering/cli_apps.md +207 -0
- skills/engineering/configuration.md +218 -0
- skills/engineering/database.md +240 -0
- skills/engineering/dependency_management.md +205 -0
- skills/engineering/http_clients.md +267 -0
- skills/engineering/modules_packages.md +211 -0
- skills/engineering/packaging.md +197 -0
- skills/engineering/project_structure.md +155 -0
- skills/engineering/pyproject_toml.md +302 -0
- skills/engineering/virtual_environments.md +206 -0
- skills/functions.md +244 -0
- skills/generation/async_concurrency.md +291 -0
- skills/generation/error_handling.md +276 -0
- skills/generation/protocols_generics.md +243 -0
- skills/generation/type_hints.md +290 -0
- skills/generation/validation_pipeline.md +274 -0
- skills/generation/workflow.md +190 -0
- skills/oop.md +228 -0
- skills/quality/abstractions.md +154 -0
- skills/quality/comments.md +177 -0
- skills/quality/documentation.md +176 -0
- skills/quality/duplication.md +137 -0
- skills/quality/maintainability.md +142 -0
- skills/quality/naming.md +171 -0
- skills/quality/quality_functions.md +245 -0
- skills/quality/readability.md +239 -0
- skills/quality/type_annotations.md +192 -0
- skills/refactoring/behavior_preservation.md +157 -0
- skills/refactoring/incremental.md +187 -0
- skills/refactoring/interface_stability.md +199 -0
- skills/refactoring/safe_refactoring.md +206 -0
- skills/security/auth_boundaries.md +200 -0
- skills/security/command_injection.md +207 -0
- skills/security/dependency_risks.md +282 -0
- skills/security/file_handling.md +156 -0
- skills/security/input_validation.md +190 -0
- skills/security/path_traversal.md +172 -0
- skills/security/secrets.md +171 -0
- skills/security/sql_injection.md +188 -0
- skills/security/unsafe_deserialization.md +164 -0
- skills/stdlib/argparse.md +178 -0
- skills/stdlib/collections.md +212 -0
- skills/stdlib/datetime.md +187 -0
- skills/stdlib/functools.md +238 -0
- skills/stdlib/itertools.md +183 -0
- skills/stdlib/json.md +162 -0
- skills/stdlib/logging.md +185 -0
- skills/stdlib/os_sys.md +184 -0
- skills/stdlib/pathlib.md +218 -0
- skills/stdlib/re.md +171 -0
- skills/stdlib/statistics.md +112 -0
- skills/stdlib/subprocess.md +211 -0
- skills/testing/async_tests.md +249 -0
- skills/testing/coverage.md +168 -0
- skills/testing/edge_cases.md +197 -0
- skills/testing/fixtures_mocks.md +203 -0
- skills/testing/organization.md +205 -0
- skills/testing/parameterized.md +174 -0
- skills/testing/regression_tests.md +165 -0
- skills/variables_types.md +107 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Generation: Workflow
|
|
2
|
+
|
|
3
|
+
**Purpose**: Explicit code generation workflow for AI agents.
|
|
4
|
+
|
|
5
|
+
**When to use**: Every code generation or modification task.
|
|
6
|
+
---
|
|
7
|
+
---
|
|
8
|
+
name: generation_workflow
|
|
9
|
+
purpose: Explicit code generation workflow for AI agents
|
|
10
|
+
category: generation
|
|
11
|
+
triggers:
|
|
12
|
+
- workflow
|
|
13
|
+
- implementation
|
|
14
|
+
- code generation
|
|
15
|
+
- modification
|
|
16
|
+
- validation
|
|
17
|
+
- review
|
|
18
|
+
dependencies:
|
|
19
|
+
- core/* (all core language skills)
|
|
20
|
+
- generation/type_hints.md
|
|
21
|
+
- generation/error_handling.md
|
|
22
|
+
- generation/validation_pipeline.md
|
|
23
|
+
- engineering/pyproject_toml.md
|
|
24
|
+
- testing/organization.md
|
|
25
|
+
- security/*
|
|
26
|
+
priority: primary
|
|
27
|
+
estimated_tokens: 2000
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Workflow Steps
|
|
31
|
+
|
|
32
|
+
### 1. UNDERSTAND
|
|
33
|
+
- What is the user asking for?
|
|
34
|
+
- What problem does this solve?
|
|
35
|
+
- What are the constraints (performance, compatibility, security)?
|
|
36
|
+
- What is the expected output (function, class, module, fix)?
|
|
37
|
+
|
|
38
|
+
### 2. INSPECT (Existing Codebase)
|
|
39
|
+
Before touching code, gather:
|
|
40
|
+
- Python version (`pyproject.toml`, CI, Dockerfile, docs)
|
|
41
|
+
- Project structure and package layout
|
|
42
|
+
- `pyproject.toml` (dependencies, tooling, config)
|
|
43
|
+
- Existing dependencies and versions
|
|
44
|
+
- Existing abstractions, utilities, patterns
|
|
45
|
+
- Existing test structure and conventions
|
|
46
|
+
- Related modules and their interfaces
|
|
47
|
+
- Configuration management approach
|
|
48
|
+
- Error-handling conventions
|
|
49
|
+
- Logging setup
|
|
50
|
+
|
|
51
|
+
**Do not generate code before inspecting.**
|
|
52
|
+
|
|
53
|
+
### 3. PLAN
|
|
54
|
+
- What files need to change?
|
|
55
|
+
- What new code is needed?
|
|
56
|
+
- Which existing utilities can be reused?
|
|
57
|
+
- What tests need updating?
|
|
58
|
+
- What are the integration points?
|
|
59
|
+
- What could break?
|
|
60
|
+
|
|
61
|
+
### 4. SELECT RELEVANT SKILLS
|
|
62
|
+
Load skills based on task type (see SKILL.md loading strategy):
|
|
63
|
+
- Task-specific skills (HTTP, CLI, DB, etc.)
|
|
64
|
+
- Always: `generation/error_handling`, `generation/type_hints`, `quality/naming`
|
|
65
|
+
- Security: `security/input_validation`, `security/secrets`
|
|
66
|
+
- Testing: `testing/organization`, `testing/fixtures_mocks`
|
|
67
|
+
|
|
68
|
+
### 5. IMPLEMENT
|
|
69
|
+
- Write code following project conventions
|
|
70
|
+
- Use existing patterns and utilities
|
|
71
|
+
- Add type hints appropriate to project config
|
|
72
|
+
- Keep functions small and focused
|
|
73
|
+
- Handle errors explicitly
|
|
74
|
+
- No premature optimization
|
|
75
|
+
|
|
76
|
+
### 6. REVIEW
|
|
77
|
+
- Does it solve the stated problem?
|
|
78
|
+
- Does it preserve existing behavior?
|
|
79
|
+
- Are types correct?
|
|
80
|
+
- Are errors handled?
|
|
81
|
+
- Is it secure?
|
|
82
|
+
- Is it readable?
|
|
83
|
+
- Are names meaningful?
|
|
84
|
+
|
|
85
|
+
### 7. VALIDATE
|
|
86
|
+
Run project's validation pipeline (detect first):
|
|
87
|
+
```bash
|
|
88
|
+
# Syntax
|
|
89
|
+
python -m py_compile file.py
|
|
90
|
+
|
|
91
|
+
# Type checking (if configured)
|
|
92
|
+
mypy file.py
|
|
93
|
+
# or
|
|
94
|
+
pyright file.py
|
|
95
|
+
|
|
96
|
+
# Linting (if configured)
|
|
97
|
+
ruff check file.py
|
|
98
|
+
# or
|
|
99
|
+
flake8 file.py
|
|
100
|
+
|
|
101
|
+
# Formatting (if configured)
|
|
102
|
+
ruff format file.py
|
|
103
|
+
# or
|
|
104
|
+
black file.py
|
|
105
|
+
|
|
106
|
+
# Tests
|
|
107
|
+
pytest path/to/tests -v
|
|
108
|
+
# or project's test command
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 8. FIX
|
|
112
|
+
- Address all validation failures
|
|
113
|
+
- Re-run validation until clean
|
|
114
|
+
- Do not skip steps
|
|
115
|
+
|
|
116
|
+
### 9. FINALIZE
|
|
117
|
+
- Confirm all tests pass
|
|
118
|
+
- Confirm no regressions
|
|
119
|
+
- Document any behavior changes
|
|
120
|
+
- Update related documentation if needed
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Validation Pipeline (Project-Dependent)
|
|
125
|
+
|
|
126
|
+
Detect project tooling first:
|
|
127
|
+
```bash
|
|
128
|
+
# Check for config files
|
|
129
|
+
ls pyproject.toml setup.cfg tox.ini ruff.toml .pre-commit-config.yaml
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| Tool | Command | Purpose |
|
|
133
|
+
|------|---------|---------|
|
|
134
|
+
| mypy | `mypy .` | Static type checking |
|
|
135
|
+
| pyright | `pyright` | Fast type checking |
|
|
136
|
+
| ruff | `ruff check .` | Linting (fast) |
|
|
137
|
+
| black | `black --check .` | Formatting check |
|
|
138
|
+
| pytest | `pytest` | Testing |
|
|
139
|
+
| bandit | `bandit -r .` | Security linting |
|
|
140
|
+
|
|
141
|
+
**Never claim** "tested", "verified", "linted", "type-safe" without running the tools.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Existing Code Modification Rules
|
|
146
|
+
|
|
147
|
+
When modifying existing code:
|
|
148
|
+
|
|
149
|
+
1. **Understand first** — read related files, understand the flow
|
|
150
|
+
2. **Minimal change** — smallest coherent change
|
|
151
|
+
3. **Preserve behavior** — existing tests must pass
|
|
152
|
+
4. **Follow conventions** — match existing style, patterns
|
|
153
|
+
5. **Reuse** — use existing utilities, don't duplicate
|
|
154
|
+
6. **Test** — run related tests before and after
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Integration Over Perfection
|
|
159
|
+
|
|
160
|
+
**The agent should understand that integration with the existing codebase is more important than producing an isolated "perfect" implementation.**
|
|
161
|
+
|
|
162
|
+
- Match the project's architecture
|
|
163
|
+
- Use the project's utilities
|
|
164
|
+
- Follow the project's error handling
|
|
165
|
+
- Respect the project's type hint level
|
|
166
|
+
- Keep the project's test patterns
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Decision Checklist (Before Generating)
|
|
171
|
+
|
|
172
|
+
- [ ] Inspected project structure and conventions
|
|
173
|
+
- [ ] Identified relevant existing code
|
|
174
|
+
- [ ] Selected appropriate skills
|
|
175
|
+
- [ ] Planned minimal coherent change
|
|
176
|
+
- [ ] Know how to validate (test command, lint, type check)
|
|
177
|
+
- [ ] Considered security implications
|
|
178
|
+
- [ ] Considered Python version compatibility
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Related Skills
|
|
183
|
+
|
|
184
|
+
- `core/*` (all core language skills)
|
|
185
|
+
- `generation/type_hints.md`
|
|
186
|
+
- `generation/error_handling.md`
|
|
187
|
+
- `generation/validation_pipeline.md`
|
|
188
|
+
- `engineering/pyproject_toml.md`
|
|
189
|
+
- `testing/organization.md`
|
|
190
|
+
- `security/*`
|
skills/oop.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Core: Object-Oriented Programming
|
|
2
|
+
|
|
3
|
+
**Purpose**: Python OOP patterns, inheritance, composition, and protocols.
|
|
4
|
+
|
|
5
|
+
**When to use**: Designing classes, inheritance hierarchies, or interfaces.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Rules
|
|
10
|
+
|
|
11
|
+
### Class Definition
|
|
12
|
+
```python
|
|
13
|
+
class ClassName(BaseClass, AnotherBase):
|
|
14
|
+
"""Class docstring."""
|
|
15
|
+
|
|
16
|
+
class_attr: ClassVar[int] = 0 # Class variable (type hint)
|
|
17
|
+
|
|
18
|
+
def __init__(self, param: type) -> None:
|
|
19
|
+
self.instance_attr: type = param
|
|
20
|
+
|
|
21
|
+
def method(self) -> return_type:
|
|
22
|
+
return self.instance_attr
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def class_method(cls, arg: type) -> return_type:
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def static_method(arg: type) -> return_type:
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def computed(self) -> type:
|
|
34
|
+
return derive(self.instance_attr)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Inheritance
|
|
38
|
+
```python
|
|
39
|
+
class Base:
|
|
40
|
+
def method(self) -> int:
|
|
41
|
+
return 1
|
|
42
|
+
|
|
43
|
+
class Derived(Base):
|
|
44
|
+
def method(self) -> int:
|
|
45
|
+
return super().method() + 1 # Cooperative inheritance
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- Use `super()` for cooperative multiple inheritance
|
|
49
|
+
- Method Resolution Order (MRO): C3 linearization (`Class.__mro__`)
|
|
50
|
+
- Prefer composition over inheritance for code reuse
|
|
51
|
+
|
|
52
|
+
### Abstract Base Classes (ABC)
|
|
53
|
+
```python
|
|
54
|
+
from abc import ABC, abstractmethod
|
|
55
|
+
|
|
56
|
+
class Interface(ABC):
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def required(self) -> int:
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def value(self) -> str:
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
def concrete(self) -> str:
|
|
67
|
+
return f"value: {self.value}"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Protocols (Structural Subtyping, Python 3.8+)
|
|
71
|
+
```python
|
|
72
|
+
from typing import Protocol
|
|
73
|
+
|
|
74
|
+
class Drawable(Protocol):
|
|
75
|
+
def draw(self) -> None: ...
|
|
76
|
+
|
|
77
|
+
class Circle:
|
|
78
|
+
def draw(self) -> None: # Implicitly implements Drawable
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
def render(d: Drawable) -> None:
|
|
82
|
+
d.draw() # Accepts any object with draw()
|
|
83
|
+
```
|
|
84
|
+
- No explicit inheritance required
|
|
85
|
+
- Preferred over ABC for duck-typing interfaces
|
|
86
|
+
- `@runtime_checkable` for `isinstance` checks
|
|
87
|
+
|
|
88
|
+
### Dataclasses (Python 3.7+)
|
|
89
|
+
```python
|
|
90
|
+
from dataclasses import dataclass, field
|
|
91
|
+
from typing import Optional
|
|
92
|
+
|
|
93
|
+
@dataclass(order=True, frozen=False)
|
|
94
|
+
class Point:
|
|
95
|
+
x: float
|
|
96
|
+
y: float
|
|
97
|
+
label: str = "" # Default
|
|
98
|
+
metadata: dict = field(default_factory=dict) # Mutable default
|
|
99
|
+
_private: float = field(init=False, repr=False) # Computed
|
|
100
|
+
|
|
101
|
+
def __post_init__(self):
|
|
102
|
+
self._private = self.x * self.y
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Magic Methods (Key Ones)
|
|
106
|
+
| Method | Purpose |
|
|
107
|
+
|--------|---------|
|
|
108
|
+
| `__init__` | Initialization |
|
|
109
|
+
| `__new__` | Instance creation (rare) |
|
|
110
|
+
| `__repr__` | Unambiguous representation (for debugging) |
|
|
111
|
+
| `__str__` | Readable representation (for users) |
|
|
112
|
+
| `__eq__`, `__hash__` | Equality and hashing (together!) |
|
|
113
|
+
| `__lt__`, `__le__`, `__gt__`, `__ge__` | Ordering |
|
|
114
|
+
| `__bool__` | Truth value |
|
|
115
|
+
| `__len__` | Length |
|
|
116
|
+
| `__getitem__`, `__setitem__`, `__delitem__` | Subscripting |
|
|
117
|
+
| `__iter__` | Iteration |
|
|
118
|
+
| `__contains__` | `in` operator |
|
|
119
|
+
| `__enter__`, `__exit__` | Context manager |
|
|
120
|
+
| `__call__` | Callable instances |
|
|
121
|
+
| `__getattr__`, `__getattribute__` | Attribute access |
|
|
122
|
+
| `__slots__` | Memory optimization, restrict attributes |
|
|
123
|
+
|
|
124
|
+
### Slots
|
|
125
|
+
```python
|
|
126
|
+
class Slotted:
|
|
127
|
+
__slots__ = ('x', 'y') # No __dict__, fixed attributes
|
|
128
|
+
|
|
129
|
+
def __init__(self, x: float, y: float):
|
|
130
|
+
self.x = x
|
|
131
|
+
self.y = y
|
|
132
|
+
```
|
|
133
|
+
- Reduces memory, prevents arbitrary attributes
|
|
134
|
+
- Incompatible with multiple inheritance (unless all parents use slots)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Composition over Inheritance
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
# Composition: has-a relationship
|
|
142
|
+
class Engine:
|
|
143
|
+
def start(self) -> None: ...
|
|
144
|
+
|
|
145
|
+
class Car:
|
|
146
|
+
def __init__(self, engine: Engine):
|
|
147
|
+
self.engine = engine # Delegation
|
|
148
|
+
|
|
149
|
+
def start(self) -> None:
|
|
150
|
+
self.engine.start()
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- More flexible, testable, maintainable
|
|
154
|
+
- Avoid deep inheritance hierarchies (>2 levels)
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Decision Rules
|
|
159
|
+
|
|
160
|
+
| Situation | Pattern |
|
|
161
|
+
|-----------|---------|
|
|
162
|
+
| Fixed schema, data container | `@dataclass` |
|
|
163
|
+
| Interface definition | `Protocol` (or `ABC` for runtime checks) |
|
|
164
|
+
| Shared behavior, single hierarchy | Inheritance |
|
|
165
|
+
| Reuse without hierarchy | Composition / Mixins |
|
|
166
|
+
| Value object (immutable) | `@dataclass(frozen=True)` |
|
|
167
|
+
| Need ordering | `@dataclass(order=True)` or `__lt__` |
|
|
168
|
+
| Need hashing in sets/dicts | `__eq__` + `__hash__` (or `frozen=True`) |
|
|
169
|
+
| Memory-critical many instances | `__slots__` |
|
|
170
|
+
| Dynamic attributes | Regular class (no slots) |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Preferred Patterns
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
# Immutable data carrier
|
|
178
|
+
@dataclass(frozen=True, slots=True)
|
|
179
|
+
class Config:
|
|
180
|
+
host: str
|
|
181
|
+
port: int
|
|
182
|
+
timeout: float = 5.0
|
|
183
|
+
|
|
184
|
+
# Protocol for dependency inversion
|
|
185
|
+
class Repository(Protocol):
|
|
186
|
+
def get(self, id: str) -> User: ...
|
|
187
|
+
def save(self, user: User) -> None: ...
|
|
188
|
+
|
|
189
|
+
# Mixin for reusable behavior
|
|
190
|
+
class TimestampMixin:
|
|
191
|
+
created_at: datetime
|
|
192
|
+
updated_at: datetime
|
|
193
|
+
|
|
194
|
+
def touch(self) -> None:
|
|
195
|
+
self.updated_at = datetime.now()
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Avoid
|
|
201
|
+
|
|
202
|
+
- Deep inheritance chains (>2 levels)
|
|
203
|
+
- Multiple inheritance without clear design (diamond problem)
|
|
204
|
+
- Mutable class attributes shared across instances
|
|
205
|
+
- `__del__` (unreliable, use context managers)
|
|
206
|
+
- Overriding `__init__` without calling `super().__init__()`
|
|
207
|
+
- Using `type()` for type checks (use `isinstance`)
|
|
208
|
+
- Properties with side effects
|
|
209
|
+
- Getter/setter methods (use `@property`)
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Validation Considerations
|
|
214
|
+
|
|
215
|
+
- `mypy` verifies protocol conformance
|
|
216
|
+
- `@dataclass` generates `__init__`, `__repr__`, `__eq__`
|
|
217
|
+
- `slots=True` (Python 3.10+) enables slots on dataclasses
|
|
218
|
+
- `frozen=True` makes instances hashable (if all fields hashable)
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Related Skills
|
|
223
|
+
|
|
224
|
+
- `generation/protocols_generics.md`
|
|
225
|
+
- `generation/type_hints.md`
|
|
226
|
+
- `core/advanced_python.md` (descriptors, metaclasses)
|
|
227
|
+
- `quality/abstractions.md`
|
|
228
|
+
- `anti_patterns/index.md` (excessive inheritance)
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Quality: Abstractions
|
|
2
|
+
|
|
3
|
+
**Purpose**: When and how to create abstractions.
|
|
4
|
+
|
|
5
|
+
**When to use**: Refactoring, designing new modules, avoiding duplication.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Rules
|
|
10
|
+
|
|
11
|
+
### Abstraction Principles
|
|
12
|
+
|
|
13
|
+
1. **Wait for 3** — Don't abstract until 3+ concrete use cases
|
|
14
|
+
2. **Prefer composition** — Over inheritance
|
|
15
|
+
3. **Depend on abstractions** — Protocols/Interfaces, not concretions
|
|
16
|
+
4. **Leaky abstractions** — Avoid (abstraction reveals implementation details)
|
|
17
|
+
5. **Wrong abstraction** — Worse than duplication (prefer duplication over wrong abstraction)
|
|
18
|
+
|
|
19
|
+
### When to Abstract
|
|
20
|
+
```python
|
|
21
|
+
# GOOD — 3+ similar patterns
|
|
22
|
+
def process_user(user):
|
|
23
|
+
validate(user)
|
|
24
|
+
save(user)
|
|
25
|
+
notify(user)
|
|
26
|
+
|
|
27
|
+
def process_order(order):
|
|
28
|
+
validate(order)
|
|
29
|
+
save(order)
|
|
30
|
+
notify(order)
|
|
31
|
+
|
|
32
|
+
def process_payment(payment):
|
|
33
|
+
validate(payment)
|
|
34
|
+
save(payment)
|
|
35
|
+
notify(payment)
|
|
36
|
+
|
|
37
|
+
# Abstract to:
|
|
38
|
+
def process_entity(entity: Entity):
|
|
39
|
+
validate(entity)
|
|
40
|
+
save(entity)
|
|
41
|
+
notify(entity)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### When NOT to Abstract
|
|
45
|
+
```python
|
|
46
|
+
# BAD — premature, different semantics
|
|
47
|
+
def process_user(user):
|
|
48
|
+
validate_email(user.email)
|
|
49
|
+
save_user(user)
|
|
50
|
+
send_welcome_email(user)
|
|
51
|
+
|
|
52
|
+
def process_file(file):
|
|
53
|
+
validate_checksum(file.checksum)
|
|
54
|
+
save_file(file)
|
|
55
|
+
index_file(file)
|
|
56
|
+
|
|
57
|
+
# These are DIFFERENT operations, not same pattern
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Interface Design
|
|
61
|
+
```python
|
|
62
|
+
# GOOD — Protocol (structural, flexible)
|
|
63
|
+
class Repository(Protocol[T]):
|
|
64
|
+
def get(self, id: str) -> T | None: ...
|
|
65
|
+
def save(self, entity: T) -> T: ...
|
|
66
|
+
|
|
67
|
+
# GOOD — ABC (when runtime check needed)
|
|
68
|
+
class Cache(ABC):
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def get(self, key: str) -> bytes | None: ...
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def set(self, key: str, value: bytes, ttl: int) -> None: ...
|
|
73
|
+
|
|
74
|
+
# BAD — Concrete base class forcing inheritance
|
|
75
|
+
class BaseRepository:
|
|
76
|
+
def get(self, id: str) -> User:
|
|
77
|
+
return self.db.query(User).filter_by(id=id).first()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Abstraction Levels
|
|
81
|
+
```
|
|
82
|
+
High-level policy (business rules)
|
|
83
|
+
↓
|
|
84
|
+
Application services (orchestration)
|
|
85
|
+
↓
|
|
86
|
+
Domain services (business logic)
|
|
87
|
+
↓
|
|
88
|
+
Infrastructure (DB, HTTP, FS)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Each layer depends only on layer below
|
|
92
|
+
- Domain has NO dependencies on infrastructure
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Decision Rules
|
|
97
|
+
|
|
98
|
+
| Situation | Action |
|
|
99
|
+
|-----------|--------|
|
|
100
|
+
| 3+ similar implementations | Abstract |
|
|
101
|
+
| 1-2 implementations | Keep concrete |
|
|
102
|
+
| Different semantics | Don't abstract |
|
|
103
|
+
| Need runtime swap | Protocol/ABC |
|
|
104
|
+
| Compile-time only | Protocol |
|
|
105
|
+
| Cross-cutting (logging, timing) | Decorator/middleware |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Preferred Patterns
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
# Strategy pattern via Protocol
|
|
113
|
+
class Exporter(Protocol):
|
|
114
|
+
def export(self, data: Data) -> bytes: ...
|
|
115
|
+
|
|
116
|
+
class JSONExporter:
|
|
117
|
+
def export(self, data: Data) -> bytes:
|
|
118
|
+
return json.dumps(data).encode()
|
|
119
|
+
|
|
120
|
+
class CSVExporter:
|
|
121
|
+
def export(self, data: Data) -> bytes:
|
|
122
|
+
return csv_encode(data)
|
|
123
|
+
|
|
124
|
+
def export_data(data: Data, exporter: Exporter) -> bytes:
|
|
125
|
+
return exporter.export(data)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Avoid
|
|
131
|
+
|
|
132
|
+
- Abstract base classes with concrete methods (use composition)
|
|
133
|
+
- Deep inheritance hierarchies (>2 levels)
|
|
134
|
+
- "Manager", "Handler", "Utils", "Helper" classes
|
|
135
|
+
- Abstracting control flow (use functions)
|
|
136
|
+
- Frameworks (inverting control) vs libraries (you call them)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Validation Considerations
|
|
141
|
+
|
|
142
|
+
- Can implementations be swapped without changing consumers?
|
|
143
|
+
- Are protocols minimal (only what's needed)?
|
|
144
|
+
- Does abstraction leak implementation details?
|
|
145
|
+
- Is there a test for each implementation?
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Related Skills
|
|
150
|
+
|
|
151
|
+
- `quality/maintainability.md`
|
|
152
|
+
- `quality/duplication.md`
|
|
153
|
+
- `generation/protocols_generics.md`
|
|
154
|
+
- `core/oop.md`
|