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,239 @@
|
|
|
1
|
+
# Core: Advanced Python
|
|
2
|
+
|
|
3
|
+
**Purpose**: Iterators, generators, decorators, context managers, descriptors.
|
|
4
|
+
|
|
5
|
+
**When to use**: Implementing advanced patterns, libraries, or frameworks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Rules
|
|
10
|
+
|
|
11
|
+
### Iterators
|
|
12
|
+
```python
|
|
13
|
+
class Iterator:
|
|
14
|
+
def __iter__(self) -> Iterator:
|
|
15
|
+
return self
|
|
16
|
+
|
|
17
|
+
def __next__(self) -> Item:
|
|
18
|
+
if done:
|
|
19
|
+
raise StopIteration
|
|
20
|
+
return next_item
|
|
21
|
+
|
|
22
|
+
# Usage
|
|
23
|
+
for item in Iterator():
|
|
24
|
+
...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Implement `__iter__` (returns self) and `__next__`
|
|
28
|
+
- Raise `StopIteration` when exhausted
|
|
29
|
+
- Prefer generators for simple iterators
|
|
30
|
+
|
|
31
|
+
### Generators
|
|
32
|
+
```python
|
|
33
|
+
def generator() -> Generator[Item, None, None]:
|
|
34
|
+
for i in range(10):
|
|
35
|
+
yield i
|
|
36
|
+
yield from other_generator() # Delegate
|
|
37
|
+
|
|
38
|
+
# Generator expression
|
|
39
|
+
gen = (x * 2 for x in range(10))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- `yield` produces value, suspends function
|
|
43
|
+
- `yield from` delegates to sub-generator
|
|
44
|
+
- Lazy evaluation — computes on demand
|
|
45
|
+
- Can receive values via `send()` (rare)
|
|
46
|
+
|
|
47
|
+
### Decorators
|
|
48
|
+
```python
|
|
49
|
+
import functools
|
|
50
|
+
|
|
51
|
+
def decorator(func):
|
|
52
|
+
@functools.wraps(func)
|
|
53
|
+
def wrapper(*args, **kwargs):
|
|
54
|
+
pre()
|
|
55
|
+
try:
|
|
56
|
+
return func(*args, **kwargs)
|
|
57
|
+
finally:
|
|
58
|
+
post()
|
|
59
|
+
return wrapper
|
|
60
|
+
|
|
61
|
+
# With arguments
|
|
62
|
+
def decorator_with_args(arg):
|
|
63
|
+
def actual_decorator(func):
|
|
64
|
+
@functools.wraps(func)
|
|
65
|
+
def wrapper(*args, **kwargs):
|
|
66
|
+
return func(*args, **kwargs)
|
|
67
|
+
return wrapper
|
|
68
|
+
return actual_decorator
|
|
69
|
+
|
|
70
|
+
@decorator_with_args("value")
|
|
71
|
+
def func():
|
|
72
|
+
...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- **Always** use `@functools.wraps(func)` on wrapper
|
|
76
|
+
- Decorators execute at **definition time**
|
|
77
|
+
- Class decorators receive class, return class
|
|
78
|
+
|
|
79
|
+
### Context Managers
|
|
80
|
+
```python
|
|
81
|
+
# Class-based
|
|
82
|
+
class Resource:
|
|
83
|
+
def __enter__(self):
|
|
84
|
+
self.acquire()
|
|
85
|
+
return self
|
|
86
|
+
|
|
87
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
88
|
+
self.release()
|
|
89
|
+
return False # Don't suppress exceptions
|
|
90
|
+
|
|
91
|
+
# Generator-based (contextlib)
|
|
92
|
+
from contextlib import contextmanager
|
|
93
|
+
|
|
94
|
+
@contextmanager
|
|
95
|
+
def resource():
|
|
96
|
+
r = acquire()
|
|
97
|
+
try:
|
|
98
|
+
yield r
|
|
99
|
+
finally:
|
|
100
|
+
r.release()
|
|
101
|
+
|
|
102
|
+
# Usage
|
|
103
|
+
with resource() as r:
|
|
104
|
+
r.use()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- `__exit__` receives exception info; return `True` to suppress
|
|
108
|
+
- `@contextmanager` yields once; cleanup in `finally`
|
|
109
|
+
- Use for resource management (files, locks, connections, transactions)
|
|
110
|
+
|
|
111
|
+
### Descriptors
|
|
112
|
+
```python
|
|
113
|
+
class Descriptor:
|
|
114
|
+
def __get__(self, obj, objtype=None):
|
|
115
|
+
if obj is None:
|
|
116
|
+
return self
|
|
117
|
+
return obj._value
|
|
118
|
+
|
|
119
|
+
def __set__(self, obj, value):
|
|
120
|
+
obj._value = value
|
|
121
|
+
|
|
122
|
+
def __delete__(self, obj):
|
|
123
|
+
del obj._value
|
|
124
|
+
|
|
125
|
+
class MyClass:
|
|
126
|
+
attr = Descriptor()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- Protocol: `__get__`, `__set__`, `__delete__`
|
|
130
|
+
- Data descriptors (`__set__` or `__delete__`) override instance `__dict__`
|
|
131
|
+
- Non-data descriptors (only `__get__`) overridden by instance `__dict__`
|
|
132
|
+
- Used by: `property`, `classmethod`, `staticmethod`, `field`
|
|
133
|
+
|
|
134
|
+
### Metaclasses (Rare)
|
|
135
|
+
```python
|
|
136
|
+
class Meta(type):
|
|
137
|
+
def __new__(mcs, name, bases, namespace):
|
|
138
|
+
# Modify class creation
|
|
139
|
+
return super().__new__(mcs, name, bases, namespace)
|
|
140
|
+
|
|
141
|
+
class MyClass(metaclass=Meta):
|
|
142
|
+
...
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- Customize class creation
|
|
146
|
+
- Use sparingly; prefer `__init_subclass__` (Python 3.6+)
|
|
147
|
+
|
|
148
|
+
### `__init_subclass__`
|
|
149
|
+
```python
|
|
150
|
+
class Base:
|
|
151
|
+
subclasses = []
|
|
152
|
+
|
|
153
|
+
def __init_subclass__(cls, **kwargs):
|
|
154
|
+
super().__init_subclass__(**kwargs)
|
|
155
|
+
Base.subclasses.append(cls)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- Called when subclass is defined
|
|
159
|
+
- Simpler than metaclasses for registration
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Decision Rules
|
|
164
|
+
|
|
165
|
+
| Need | Tool |
|
|
166
|
+
|------|------|
|
|
167
|
+
| Simple iteration | Generator function |
|
|
168
|
+
| Complex iterator state | Iterator class |
|
|
169
|
+
| Resource cleanup | Context manager (`@contextmanager` or class) |
|
|
170
|
+
| Cross-cutting behavior | Decorator |
|
|
171
|
+
| Attribute access control | Descriptor / `property` |
|
|
172
|
+
| Class registration | `__init_subclass__` |
|
|
173
|
+
| Class creation control | Metaclass (last resort) |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Preferred Patterns
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
# Generator for lazy sequences
|
|
181
|
+
def read_lines(path: Path) -> Generator[str, None, None]:
|
|
182
|
+
with path.open() as f:
|
|
183
|
+
for line in f:
|
|
184
|
+
yield line.rstrip('\n')
|
|
185
|
+
|
|
186
|
+
# Context manager for temp resources
|
|
187
|
+
@contextmanager
|
|
188
|
+
def temp_dir():
|
|
189
|
+
path = Path(tempfile.mkdtemp())
|
|
190
|
+
try:
|
|
191
|
+
yield path
|
|
192
|
+
finally:
|
|
193
|
+
shutil.rmtree(path)
|
|
194
|
+
|
|
195
|
+
# Decorator with args preserving signature
|
|
196
|
+
def retry(times: int = 3, delay: float = 1.0):
|
|
197
|
+
def decorator(func):
|
|
198
|
+
@functools.wraps(func)
|
|
199
|
+
def wrapper(*args, **kwargs):
|
|
200
|
+
for attempt in range(times):
|
|
201
|
+
try:
|
|
202
|
+
return func(*args, **kwargs)
|
|
203
|
+
except Exception:
|
|
204
|
+
if attempt == times - 1:
|
|
205
|
+
raise
|
|
206
|
+
time.sleep(delay)
|
|
207
|
+
return wrapper
|
|
208
|
+
return decorator
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Avoid
|
|
214
|
+
|
|
215
|
+
- Generators that don't clean up resources (use `try/finally` or context manager)
|
|
216
|
+
- Decorators without `@functools.wraps`
|
|
217
|
+
- Complex metaclasses when `__init_subclass__` suffices
|
|
218
|
+
- Descriptors for simple attribute access (use `@property`)
|
|
219
|
+
- `yield` in `finally` block (confusing semantics)
|
|
220
|
+
- Mixing `yield` and `return` with values in same generator
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Validation Considerations
|
|
225
|
+
|
|
226
|
+
- `contextlib.closing` for objects with `close()`
|
|
227
|
+
- `contextlib.AsyncExitStack` for async context managers
|
|
228
|
+
- Type checkers understand generator types: `Generator[Yield, Send, Return]`
|
|
229
|
+
- `inspect.isgeneratorfunction()`, `inspect.isgenerator()`
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Related Skills
|
|
234
|
+
|
|
235
|
+
- `generation/async_concurrency.md` (async generators, context managers)
|
|
236
|
+
- `generation/error_handling.md` (context manager exception handling)
|
|
237
|
+
- `stdlib/functools.md` (wraps, lru_cache)
|
|
238
|
+
- `quality/functions.md`
|
|
239
|
+
- `anti_patterns/index.md`
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# Anti-Patterns: Index
|
|
2
|
+
|
|
3
|
+
**Purpose**: Prevent generation of known anti-patterns. This is the master reference.
|
|
4
|
+
|
|
5
|
+
**When to use**: Always active. Check before and during code generation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Category | Anti-Pattern | Prevention |
|
|
12
|
+
|----------|--------------|------------|
|
|
13
|
+
| **Exceptions** | Bare `except:` / `except Exception:` | Catch specific exceptions only |
|
|
14
|
+
| **Exceptions** | Swallowed exceptions | Log or re-raise, never silent |
|
|
15
|
+
| **Arguments** | Mutable default arguments | Use `None` sentinel pattern |
|
|
16
|
+
| **State** | Unnecessary global state | Use dependency injection |
|
|
17
|
+
| **Dependencies** | Unnecessary dependencies | Stdlib first, existing deps second |
|
|
18
|
+
| **Inheritance** | Excessive inheritance | Prefer composition |
|
|
19
|
+
| **Abstraction** | Premature abstraction | Wait for 3+ use cases (Rule of Three) |
|
|
20
|
+
| **Functions** | Giant functions (>50 lines) | Extract to smaller functions |
|
|
21
|
+
| **Classes** | God classes | Single responsibility, split |
|
|
22
|
+
| **Duplication** | Duplicated logic | Extract (true duplication only) |
|
|
23
|
+
| **Cleverness** | Unreadable one-liners | Prefer explicit, readable code |
|
|
24
|
+
| **Comprehensions** | Unnecessary/overly complex | Use loops for complex logic |
|
|
25
|
+
| **Async** | Premature async | Only for I/O-bound concurrency |
|
|
26
|
+
| **Optimization** | Premature optimization | Profile first, optimize bottlenecks |
|
|
27
|
+
| **Secrets** | Hardcoded secrets | Environment variables, secret managers |
|
|
28
|
+
| **Subprocess** | Unsafe subprocess usage | List form, no `shell=True`, allowlist |
|
|
29
|
+
| **Deserialization** | Unsafe deserialization | `json`, `yaml.safe_load`, never `pickle` |
|
|
30
|
+
| **SQL** | SQL injection | Parameterized queries only |
|
|
31
|
+
| **Files** | Insecure temp files | `tempfile`, validate paths |
|
|
32
|
+
| **Eval/Exec** | Unnecessary `eval`/`exec` | Never for untrusted input |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Detailed Patterns
|
|
37
|
+
|
|
38
|
+
### 1. Bare Except
|
|
39
|
+
```python
|
|
40
|
+
# ANTI-PATTERN
|
|
41
|
+
try:
|
|
42
|
+
risky()
|
|
43
|
+
except:
|
|
44
|
+
pass # Catches KeyboardInterrupt, SystemExit!
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
risky()
|
|
48
|
+
except Exception:
|
|
49
|
+
pass # Swallows all errors silently
|
|
50
|
+
|
|
51
|
+
# CORRECT
|
|
52
|
+
try:
|
|
53
|
+
risky()
|
|
54
|
+
except SpecificError:
|
|
55
|
+
handle()
|
|
56
|
+
except AnotherError:
|
|
57
|
+
handle()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Mutable Default Arguments
|
|
61
|
+
```python
|
|
62
|
+
# ANTI-PATTERN
|
|
63
|
+
def func(items=[]):
|
|
64
|
+
items.append(1)
|
|
65
|
+
return items
|
|
66
|
+
|
|
67
|
+
# CORRECT
|
|
68
|
+
def func(items=None):
|
|
69
|
+
if items is None:
|
|
70
|
+
items = []
|
|
71
|
+
items.append(1)
|
|
72
|
+
return items
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Global Mutable State
|
|
76
|
+
```python
|
|
77
|
+
# ANTI-PATTERN
|
|
78
|
+
cache = {}
|
|
79
|
+
|
|
80
|
+
def get_data(key):
|
|
81
|
+
if key not in cache:
|
|
82
|
+
cache[key] = fetch(key)
|
|
83
|
+
return cache[key]
|
|
84
|
+
|
|
85
|
+
# CORRECT
|
|
86
|
+
class DataService:
|
|
87
|
+
def __init__(self):
|
|
88
|
+
self._cache = {}
|
|
89
|
+
|
|
90
|
+
def get_data(self, key):
|
|
91
|
+
if key not in self._cache:
|
|
92
|
+
self._cache[key] = fetch(key)
|
|
93
|
+
return self._cache[key]
|
|
94
|
+
|
|
95
|
+
# Inject instance where needed
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 4. Swallowed Exceptions
|
|
99
|
+
```python
|
|
100
|
+
# ANTI-PATTERN
|
|
101
|
+
try:
|
|
102
|
+
save(user)
|
|
103
|
+
except:
|
|
104
|
+
pass # User not saved, no indication!
|
|
105
|
+
|
|
106
|
+
# CORRECT
|
|
107
|
+
try:
|
|
108
|
+
save(user)
|
|
109
|
+
except DatabaseError as e:
|
|
110
|
+
logger.error("Failed to save user", extra={"user_id": user.id, "error": str(e)})
|
|
111
|
+
raise SaveFailedError() from e
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 5. Unnecessary Dependencies
|
|
115
|
+
```python
|
|
116
|
+
# ANTI-PATTERN — adding `requests` for one HTTP call
|
|
117
|
+
# when `urllib` or `http.client` in stdlib works
|
|
118
|
+
|
|
119
|
+
# CORRECT — evaluate need
|
|
120
|
+
# If simple GET: urllib.request
|
|
121
|
+
# If complex: requests/httpx justified
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 6. Excessive Inheritance
|
|
125
|
+
```python
|
|
126
|
+
# ANTI-PATTERN
|
|
127
|
+
class Base:
|
|
128
|
+
def a(self): ...
|
|
129
|
+
def b(self): ...
|
|
130
|
+
|
|
131
|
+
class A(Base): ...
|
|
132
|
+
class B(A): ...
|
|
133
|
+
class C(B): ...
|
|
134
|
+
class D(C): ... # 4 levels!
|
|
135
|
+
|
|
136
|
+
# CORRECT — composition
|
|
137
|
+
class Service:
|
|
138
|
+
def __init__(self, a: A, b: B, c: C):
|
|
139
|
+
self.a = a
|
|
140
|
+
self.b = b
|
|
141
|
+
self.c = c
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 7. Premature Abstraction
|
|
145
|
+
```python
|
|
146
|
+
# ANTI-PATTERN — abstracting after 1 use
|
|
147
|
+
def process_user(user):
|
|
148
|
+
validate(user)
|
|
149
|
+
save(user)
|
|
150
|
+
notify(user)
|
|
151
|
+
|
|
152
|
+
def process_order(order):
|
|
153
|
+
validate(order)
|
|
154
|
+
save(order)
|
|
155
|
+
notify(order)
|
|
156
|
+
|
|
157
|
+
# Abstracted to:
|
|
158
|
+
def process(entity): # WRONG - different validation!
|
|
159
|
+
validate(entity)
|
|
160
|
+
save(entity)
|
|
161
|
+
notify(entity)
|
|
162
|
+
|
|
163
|
+
# CORRECT — wait for 3rd use case with SAME pattern
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 8. Giant Functions
|
|
167
|
+
```python
|
|
168
|
+
# ANTI-PATTERN
|
|
169
|
+
def process_everything(data):
|
|
170
|
+
# 200 lines of validation, calculation, persistence, notification
|
|
171
|
+
...
|
|
172
|
+
|
|
173
|
+
# CORRECT
|
|
174
|
+
def validate(data): ...
|
|
175
|
+
def calculate(data): ...
|
|
176
|
+
def persist(data): ...
|
|
177
|
+
def notify(data): ...
|
|
178
|
+
|
|
179
|
+
def process(data):
|
|
180
|
+
validate(data)
|
|
181
|
+
result = calculate(data)
|
|
182
|
+
persist(result)
|
|
183
|
+
notify(result)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 9. God Classes
|
|
187
|
+
```python
|
|
188
|
+
# ANTI-PATTERN
|
|
189
|
+
class UserManager:
|
|
190
|
+
def create(self): ...
|
|
191
|
+
def delete(self): ...
|
|
192
|
+
def update(self): ...
|
|
193
|
+
def get(self): ...
|
|
194
|
+
def list(self): ...
|
|
195
|
+
def send_email(self): ...
|
|
196
|
+
def generate_report(self): ...
|
|
197
|
+
def backup(self): ...
|
|
198
|
+
def migrate(self): ...
|
|
199
|
+
# 20+ methods, multiple responsibilities
|
|
200
|
+
|
|
201
|
+
# CORRECT
|
|
202
|
+
class UserRepository: ...
|
|
203
|
+
class UserService: ...
|
|
204
|
+
class EmailService: ...
|
|
205
|
+
class ReportGenerator: ...
|
|
206
|
+
class BackupService: ...
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 10. Clever One-Liners
|
|
210
|
+
```python
|
|
211
|
+
# ANTI-PATTERN
|
|
212
|
+
result = [x for y in data for x in y.split() if x.isalnum() and len(x) > 2]
|
|
213
|
+
|
|
214
|
+
# CORRECT
|
|
215
|
+
result = []
|
|
216
|
+
for item in data:
|
|
217
|
+
for word in item.split():
|
|
218
|
+
if word.isalnum() and len(word) > 2:
|
|
219
|
+
result.append(word)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 11. Premature Async
|
|
223
|
+
```python
|
|
224
|
+
# ANTI-PATTERN
|
|
225
|
+
async def process(data): # No I/O, just CPU
|
|
226
|
+
return compute(data)
|
|
227
|
+
|
|
228
|
+
# CORRECT — sync for CPU-bound
|
|
229
|
+
def process(data):
|
|
230
|
+
return compute(data)
|
|
231
|
+
|
|
232
|
+
# CORRECT — async for I/O-bound
|
|
233
|
+
async def fetch_data(url):
|
|
234
|
+
async with httpx.AsyncClient() as client:
|
|
235
|
+
return await client.get(url)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 12. Premature Optimization
|
|
239
|
+
```python
|
|
240
|
+
# ANTI-PATTERN
|
|
241
|
+
# Using complex caching for 10 items
|
|
242
|
+
# Using C extension for simple loop
|
|
243
|
+
# Pre-computing everything at startup
|
|
244
|
+
|
|
245
|
+
# CORRECT
|
|
246
|
+
# Profile first
|
|
247
|
+
# Optimize measured bottlenecks
|
|
248
|
+
# Keep simple until proven necessary
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 13. Hardcoded Secrets
|
|
252
|
+
```python
|
|
253
|
+
# ANTI-PATTERN
|
|
254
|
+
API_KEY = "sk_live_abc123"
|
|
255
|
+
DB_PASSWORD = "secret123"
|
|
256
|
+
|
|
257
|
+
# CORRECT
|
|
258
|
+
import os
|
|
259
|
+
API_KEY = os.getenv("API_KEY")
|
|
260
|
+
DB_PASSWORD = os.getenv("DB_PASSWORD")
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 14. Unsafe Subprocess
|
|
264
|
+
```python
|
|
265
|
+
# ANTI-PATTERN
|
|
266
|
+
subprocess.run(f"process {user_input}", shell=True)
|
|
267
|
+
|
|
268
|
+
# CORRECT
|
|
269
|
+
subprocess.run(["process", user_input], check=True)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 15. Unsafe Deserialization
|
|
273
|
+
```python
|
|
274
|
+
# ANTI-PATTERN
|
|
275
|
+
import pickle
|
|
276
|
+
data = pickle.loads(untrusted_bytes) # RCE!
|
|
277
|
+
|
|
278
|
+
import yaml
|
|
279
|
+
data = yaml.load(untrusted_string) # RCE!
|
|
280
|
+
|
|
281
|
+
# CORRECT
|
|
282
|
+
import json
|
|
283
|
+
data = json.loads(untrusted_string)
|
|
284
|
+
|
|
285
|
+
import yaml
|
|
286
|
+
data = yaml.safe_load(untrusted_string)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 16. SQL Injection
|
|
290
|
+
```python
|
|
291
|
+
# ANTI-PATTERN
|
|
292
|
+
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
|
|
293
|
+
|
|
294
|
+
# CORRECT
|
|
295
|
+
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 17. Insecure Temp Files
|
|
299
|
+
```python
|
|
300
|
+
# ANTI-PATTERN
|
|
301
|
+
with open("/tmp/myfile.txt", "w") as f: # Predictable, race condition
|
|
302
|
+
f.write(secret)
|
|
303
|
+
|
|
304
|
+
# CORRECT
|
|
305
|
+
import tempfile
|
|
306
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
|
307
|
+
f.write(secret)
|
|
308
|
+
# Or
|
|
309
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
310
|
+
path = Path(tmpdir) / "file.txt"
|
|
311
|
+
path.write_text(secret)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 18. Unnecessary Eval/Exec
|
|
315
|
+
```python
|
|
316
|
+
# ANTI-PATTERN
|
|
317
|
+
result = eval(user_input) # RCE!
|
|
318
|
+
exec(user_code) # RCE!
|
|
319
|
+
|
|
320
|
+
# CORRECT
|
|
321
|
+
# Never eval/exec untrusted input
|
|
322
|
+
# Use proper parsing (json, ast.literal_eval for safe subset)
|
|
323
|
+
import ast
|
|
324
|
+
safe = ast.literal_eval(user_input) # Only literals
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Validation Checklist (Before Committing Code)
|
|
330
|
+
|
|
331
|
+
- [ ] No bare `except:` or `except Exception:`
|
|
332
|
+
- [ ] No mutable default arguments
|
|
333
|
+
- [ ] No global mutable state
|
|
334
|
+
- [ ] No swallowed exceptions
|
|
335
|
+
- [ ] No unnecessary dependencies added
|
|
336
|
+
- [ ] No inheritance >2 levels
|
|
337
|
+
- [ ] No abstraction without 3+ use cases
|
|
338
|
+
- [ ] No functions >50 lines
|
|
339
|
+
- [ ] No classes with >10 public methods
|
|
340
|
+
- [ ] No duplicated logic (true duplication)
|
|
341
|
+
- [ ] No clever unreadable one-liners
|
|
342
|
+
- [ ] No unnecessary comprehensions
|
|
343
|
+
- [ ] No async without I/O
|
|
344
|
+
- [ ] No optimization without profiling
|
|
345
|
+
- [ ] No hardcoded secrets
|
|
346
|
+
- [ ] No `shell=True` with user input
|
|
347
|
+
- [ ] No `pickle`/`yaml.load` on untrusted data
|
|
348
|
+
- [ ] No string interpolation in SQL
|
|
349
|
+
- [ ] No predictable temp file names
|
|
350
|
+
- [ ] No `eval`/`exec` on untrusted input
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Enforcement
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
# Ruff rules that catch many
|
|
358
|
+
ruff check .
|
|
359
|
+
# B001: bare except
|
|
360
|
+
# B006: mutable default argument
|
|
361
|
+
# B007: loop variable in closure
|
|
362
|
+
# B008: function call in default arg
|
|
363
|
+
# B009: unused loop variable
|
|
364
|
+
# B010: redundant exception caught
|
|
365
|
+
# B011: assert in non-test
|
|
366
|
+
# B012: mutable class attribute
|
|
367
|
+
# B014: unnecessary list comp
|
|
368
|
+
# B015: unnecessary set comp
|
|
369
|
+
# B016: unnecessary dict comp
|
|
370
|
+
# B017: unnecessary generator
|
|
371
|
+
# B018: unnecessary ternary
|
|
372
|
+
# B019: unnecessary lambda
|
|
373
|
+
# S101: assert in test (OK in tests)
|
|
374
|
+
# S102: exec
|
|
375
|
+
# S103: eval
|
|
376
|
+
# S104: hardcoded password
|
|
377
|
+
# S105: hardcoded password in string
|
|
378
|
+
# S106: hardcoded password in config
|
|
379
|
+
# S107: hardcoded password in command
|
|
380
|
+
# S108: hardcoded tmp directory
|
|
381
|
+
# S109: hardcoded password in function call
|
|
382
|
+
# S601: shell=True
|
|
383
|
+
# S602: shell=True with variable
|
|
384
|
+
# S603: shell=True with input
|
|
385
|
+
# S604: shell=True with user input
|
|
386
|
+
# S605: shell=True with command
|
|
387
|
+
# S606: shell=True with user input
|
|
388
|
+
# S607: shell=True with variable
|
|
389
|
+
# S608: SQL injection
|
|
390
|
+
# S609: SQL injection
|
|
391
|
+
# S610: shell=True with variable
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Related Skills
|
|
397
|
+
|
|
398
|
+
All skills reference anti-patterns. Key connections:
|
|
399
|
+
- `generation/error_handling.md` (exceptions)
|
|
400
|
+
- `core/functions.md` (mutable defaults)
|
|
401
|
+
- `quality/abstractions.md` (premature abstraction)
|
|
402
|
+
- `quality/functions.md` (giant functions)
|
|
403
|
+
- `quality/duplication.md` (duplication)
|
|
404
|
+
- `generation/async_concurrency.md` (premature async)
|
|
405
|
+
- `security/*` (secrets, injection, deserialization)
|
|
406
|
+
- `debugging/common_bugs.md` (common bug patterns)
|