agentic-team-templates 0.12.1 → 0.13.1
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.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/index.js +9 -5
- package/src/index.test.js +2 -1
- package/templates/python-expert/.cursorrules/async-python.md +214 -0
- package/templates/python-expert/.cursorrules/overview.md +174 -0
- package/templates/python-expert/.cursorrules/patterns-and-idioms.md +251 -0
- package/templates/python-expert/.cursorrules/performance.md +208 -0
- package/templates/python-expert/.cursorrules/testing.md +238 -0
- package/templates/python-expert/.cursorrules/tooling.md +240 -0
- package/templates/python-expert/.cursorrules/type-system.md +203 -0
- package/templates/python-expert/.cursorrules/web-and-apis.md +231 -0
- package/templates/python-expert/CLAUDE.md +264 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Python Expert Development Guide
|
|
2
|
+
|
|
3
|
+
Principal-level guidelines for Python engineering. Idiomatic Python, production systems, and deep interpreter knowledge.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This guide applies to:
|
|
10
|
+
- Web services and APIs (Django, FastAPI, Flask)
|
|
11
|
+
- CLI tools and automation
|
|
12
|
+
- Data processing and ETL pipelines
|
|
13
|
+
- Libraries and PyPI packages
|
|
14
|
+
- Async services and event-driven architectures
|
|
15
|
+
|
|
16
|
+
### Core Philosophy
|
|
17
|
+
|
|
18
|
+
Python's power is in its clarity. The best Python code reads like well-written prose.
|
|
19
|
+
|
|
20
|
+
- **Readability counts.** The Zen of Python is the engineering standard.
|
|
21
|
+
- **Explicit is better than implicit.** Type hints, clear names, no magic.
|
|
22
|
+
- **Errors should never pass silently.** Bare `except:` is a bug.
|
|
23
|
+
- **The standard library is rich — use it.** `collections`, `itertools`, `pathlib`, `dataclasses`, `contextlib`.
|
|
24
|
+
- **If you don't know, say so.** Admitting uncertainty is professional.
|
|
25
|
+
|
|
26
|
+
### Project Structure
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
project/
|
|
30
|
+
├── src/mypackage/
|
|
31
|
+
│ ├── __init__.py
|
|
32
|
+
│ ├── py.typed
|
|
33
|
+
│ ├── models/
|
|
34
|
+
│ ├── services/
|
|
35
|
+
│ ├── repositories/
|
|
36
|
+
│ └── api/
|
|
37
|
+
├── tests/
|
|
38
|
+
│ ├── conftest.py
|
|
39
|
+
│ ├── unit/
|
|
40
|
+
│ └── integration/
|
|
41
|
+
├── pyproject.toml
|
|
42
|
+
└── Makefile
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Type System
|
|
48
|
+
|
|
49
|
+
### Modern Typed Python
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
def fetch_users(
|
|
53
|
+
db: Database, *, limit: int = 100, active_only: bool = True
|
|
54
|
+
) -> list[User]: ...
|
|
55
|
+
|
|
56
|
+
# Union types (3.10+)
|
|
57
|
+
def find_user(email: str) -> User | None: ...
|
|
58
|
+
|
|
59
|
+
# Protocol for structural subtyping
|
|
60
|
+
class Renderable(Protocol):
|
|
61
|
+
def render(self) -> str: ...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Rules
|
|
65
|
+
|
|
66
|
+
- `mypy --strict` is the baseline
|
|
67
|
+
- All function signatures fully typed
|
|
68
|
+
- `dataclasses` or Pydantic over raw dicts
|
|
69
|
+
- No `Any` as a crutch — type properly or explain why not
|
|
70
|
+
- No `# type: ignore` without inline explanation
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Patterns and Idioms
|
|
75
|
+
|
|
76
|
+
### Data Model
|
|
77
|
+
|
|
78
|
+
Implement `__repr__`, `__eq__`, `__hash__` via `@dataclass`. Use `frozen=True` and `slots=True` for immutable value objects.
|
|
79
|
+
|
|
80
|
+
### Generators
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
def read_large_file(path: Path) -> Iterator[str]:
|
|
84
|
+
with open(path) as f:
|
|
85
|
+
for line in f:
|
|
86
|
+
yield line.strip()
|
|
87
|
+
|
|
88
|
+
# Generator expressions over list comprehensions when iterating once
|
|
89
|
+
total = sum(order.total for order in orders)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Context Managers
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
@contextmanager
|
|
96
|
+
def timed_operation(name: str) -> Iterator[None]:
|
|
97
|
+
start = time.monotonic()
|
|
98
|
+
try:
|
|
99
|
+
yield
|
|
100
|
+
finally:
|
|
101
|
+
logger.info(f"{name} took {time.monotonic() - start:.3f}s")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Decorators
|
|
105
|
+
|
|
106
|
+
Use `functools.wraps` and `ParamSpec` for properly typed decorators that preserve signatures.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Async Python
|
|
111
|
+
|
|
112
|
+
### TaskGroup (3.11+)
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
async with asyncio.TaskGroup() as tg:
|
|
116
|
+
user_task = tg.create_task(fetch_users())
|
|
117
|
+
post_task = tg.create_task(fetch_posts())
|
|
118
|
+
# All complete or all cancelled on failure
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Bounded Concurrency
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
semaphore = asyncio.Semaphore(10)
|
|
125
|
+
async def bounded_fetch(url: str) -> Response:
|
|
126
|
+
async with semaphore:
|
|
127
|
+
return await fetch(url)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Rules
|
|
131
|
+
|
|
132
|
+
- Never use blocking calls (`requests`, `time.sleep`) in async code
|
|
133
|
+
- Use `run_in_executor` for CPU-bound work
|
|
134
|
+
- Every spawned task needs error handling
|
|
135
|
+
- Use `asyncio.timeout()` (3.11+) for deadlines
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Testing
|
|
140
|
+
|
|
141
|
+
### pytest Patterns
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
@pytest.mark.parametrize("input_str, expected", [
|
|
145
|
+
("hello world", "hello-world"),
|
|
146
|
+
("UPPER", "upper"),
|
|
147
|
+
("", ""),
|
|
148
|
+
])
|
|
149
|
+
def test_slugify(input_str: str, expected: str) -> None:
|
|
150
|
+
assert slugify(input_str) == expected
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Dependency Injection Over Mocking
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
def test_create_user_sends_notification() -> None:
|
|
157
|
+
notifier = Mock(spec=Notifier)
|
|
158
|
+
service = UserService(FakeUserRepo(), notifier)
|
|
159
|
+
service.create(input_data)
|
|
160
|
+
notifier.send_welcome.assert_called_once()
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Rules
|
|
164
|
+
|
|
165
|
+
- Arrange-Act-Assert structure
|
|
166
|
+
- Descriptive test names
|
|
167
|
+
- Test error cases, not just happy paths
|
|
168
|
+
- Prefer DI over `@patch`
|
|
169
|
+
- No `time.sleep()` in tests
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Performance
|
|
174
|
+
|
|
175
|
+
### Profile First
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
py-spy record -o profile.svg -- python myapp.py
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Key Patterns
|
|
182
|
+
|
|
183
|
+
- `"".join()` over `+=` for string concatenation
|
|
184
|
+
- Generator expressions to avoid intermediate lists
|
|
185
|
+
- `set` for O(1) membership testing
|
|
186
|
+
- `deque` for O(1) append/pop from both ends
|
|
187
|
+
- `slots=True` on dataclasses for memory efficiency
|
|
188
|
+
- `ThreadPoolExecutor` for I/O parallelism
|
|
189
|
+
- `ProcessPoolExecutor` for CPU parallelism
|
|
190
|
+
- `lru_cache` / `cache` for expensive pure functions
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Web and APIs
|
|
195
|
+
|
|
196
|
+
### FastAPI
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
CurrentUser = Annotated[User, Depends(get_current_user)]
|
|
200
|
+
DB = Annotated[Database, Depends(get_db)]
|
|
201
|
+
|
|
202
|
+
@app.get("/users/me")
|
|
203
|
+
async def get_me(user: CurrentUser) -> UserResponse:
|
|
204
|
+
return UserResponse.model_validate(user)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Pydantic for Validation
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
class CreateUserRequest(BaseModel):
|
|
211
|
+
model_config = ConfigDict(strict=True)
|
|
212
|
+
name: str = Field(min_length=1, max_length=200)
|
|
213
|
+
email: EmailStr
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Configuration
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
class Settings(BaseSettings):
|
|
220
|
+
model_config = ConfigDict(env_file=".env")
|
|
221
|
+
database_url: str
|
|
222
|
+
debug: bool = False
|
|
223
|
+
settings = Settings() # Validate at import time
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Tooling
|
|
229
|
+
|
|
230
|
+
### Essential Stack
|
|
231
|
+
|
|
232
|
+
| Tool | Purpose |
|
|
233
|
+
|------|---------|
|
|
234
|
+
| uv | Package management |
|
|
235
|
+
| ruff | Linting + formatting |
|
|
236
|
+
| mypy | Type checking |
|
|
237
|
+
| pytest | Testing |
|
|
238
|
+
| pre-commit | Git hooks |
|
|
239
|
+
|
|
240
|
+
### CI Essentials
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
ruff format --check .
|
|
244
|
+
ruff check .
|
|
245
|
+
mypy .
|
|
246
|
+
pytest --cov
|
|
247
|
+
pip-audit .
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Definition of Done
|
|
253
|
+
|
|
254
|
+
A Python feature is complete when:
|
|
255
|
+
|
|
256
|
+
- [ ] `mypy --strict` passes
|
|
257
|
+
- [ ] `ruff check` and `ruff format --check` pass
|
|
258
|
+
- [ ] `pytest` passes with no failures
|
|
259
|
+
- [ ] Error cases are tested
|
|
260
|
+
- [ ] Docstrings on all public functions and classes
|
|
261
|
+
- [ ] No bare `except:` without re-raise
|
|
262
|
+
- [ ] No mutable default arguments
|
|
263
|
+
- [ ] No `# type: ignore` without explanation
|
|
264
|
+
- [ ] Code reviewed and approved
|