codeforge-dev 1.5.8 → 1.8.0
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/.devcontainer/.env +4 -5
- package/.devcontainer/.env.example +29 -0
- package/.devcontainer/.gitignore +8 -0
- package/.devcontainer/.secrets.example +12 -0
- package/.devcontainer/CHANGELOG.md +186 -0
- package/.devcontainer/CLAUDE.md +108 -21
- package/.devcontainer/README.md +173 -57
- package/.devcontainer/config/defaults/keybindings.json +5 -0
- package/.devcontainer/config/{main-system-prompt.md → defaults/main-system-prompt.md} +135 -2
- package/.devcontainer/config/{settings.json → defaults/settings.json} +25 -6
- package/.devcontainer/config/file-manifest.json +20 -0
- package/.devcontainer/devcontainer.json +38 -2
- package/.devcontainer/docs/configuration-reference.md +90 -0
- package/.devcontainer/docs/keybindings.md +100 -0
- package/.devcontainer/docs/optional-features.md +129 -0
- package/.devcontainer/docs/plugins.md +154 -0
- package/.devcontainer/docs/troubleshooting.md +128 -0
- package/.devcontainer/features/README.md +21 -7
- package/.devcontainer/features/agent-browser/install.sh +6 -0
- package/.devcontainer/features/ast-grep/install.sh +6 -0
- package/.devcontainer/features/biome/README.md +27 -0
- package/.devcontainer/features/biome/install.sh +6 -0
- package/.devcontainer/features/ccburn/README.md +60 -0
- package/.devcontainer/features/ccburn/devcontainer-feature.json +38 -0
- package/.devcontainer/features/ccburn/install.sh +180 -0
- package/.devcontainer/features/ccstatusline/README.md +22 -21
- package/.devcontainer/features/ccstatusline/devcontainer-feature.json +6 -1
- package/.devcontainer/features/ccstatusline/install.sh +55 -16
- package/.devcontainer/features/ccusage/install.sh +6 -0
- package/.devcontainer/features/claude-monitor/install.sh +6 -0
- package/.devcontainer/features/dprint/README.md +30 -0
- package/.devcontainer/features/dprint/devcontainer-feature.json +18 -0
- package/.devcontainer/features/dprint/install.sh +131 -0
- package/.devcontainer/features/hadolint/README.md +35 -0
- package/.devcontainer/features/hadolint/devcontainer-feature.json +13 -0
- package/.devcontainer/features/hadolint/install.sh +86 -0
- package/.devcontainer/features/lsp-servers/devcontainer-feature.json +5 -0
- package/.devcontainer/features/lsp-servers/install.sh +7 -0
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +6 -1
- package/.devcontainer/features/mcp-qdrant/install.sh +13 -6
- package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +6 -1
- package/.devcontainer/features/mcp-reasoner/install.sh +8 -1
- package/.devcontainer/features/notify-hook/devcontainer-feature.json +5 -0
- package/.devcontainer/features/notify-hook/install.sh +7 -0
- package/.devcontainer/features/ruff/README.md +26 -0
- package/.devcontainer/features/ruff/devcontainer-feature.json +21 -0
- package/.devcontainer/features/ruff/install.sh +74 -0
- package/.devcontainer/features/shellcheck/README.md +38 -0
- package/.devcontainer/features/shellcheck/devcontainer-feature.json +13 -0
- package/.devcontainer/features/shellcheck/install.sh +24 -0
- package/.devcontainer/features/shfmt/README.md +37 -0
- package/.devcontainer/features/shfmt/devcontainer-feature.json +13 -0
- package/.devcontainer/features/shfmt/install.sh +85 -0
- package/.devcontainer/features/splitrail/devcontainer-feature.json +5 -0
- package/.devcontainer/features/splitrail/install.sh +7 -0
- package/.devcontainer/features/tmux/install.sh +8 -0
- package/.devcontainer/features/tree-sitter/install.sh +6 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +3 -10
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/__pycache__/format-on-stop.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +133 -13
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +4 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/__pycache__/lint-file.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +477 -78
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/AGENT-REDIRECTION.md +226 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/REVIEW-RUBRIC.md +440 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/architect.md +207 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/bash-exec.md +173 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/claude-guide.md +146 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/debug-logs.md +2 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/dependency-analyst.md +250 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +246 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/explorer.md +237 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/generalist.md +134 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/git-archaeologist.md +242 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/migrator.md +201 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/perf-profiler.md +265 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/refactorer.md +213 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/researcher.md +195 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/security-auditor.md +289 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +297 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/statusline-config.md +188 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/test-writer.md +248 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +51 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/advisory-test-runner.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/collect-edited-files.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/commit-reminder.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/git-state-injector.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/guard-readonly-bash.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/redirect-builtin-agents.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/skill-suggester.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/syntax-validator.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/ticket-linker.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/todo-harvester.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/verify-no-regression.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/verify-tests-pass.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/advisory-test-runner.py +174 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/collect-edited-files.py +8 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/commit-reminder.py +90 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/git-state-injector.py +114 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/guard-readonly-bash.py +611 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/redirect-builtin-agents.py +83 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py +146 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/syntax-validator.py +9 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/ticket-linker.py +137 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/todo-harvester.py +130 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/verify-no-regression.py +221 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/verify-tests-pass.py +176 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/SKILL.md +224 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/error-handling.md +166 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/rest-conventions.md +215 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/SKILL.md +211 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/references/language-patterns.md +327 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/claude-agent-sdk/SKILL.md +599 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/claude-agent-sdk/references/sdk-typescript-reference.md +954 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/SKILL.md +134 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/ecosystem-commands.md +264 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/license-compliance.md +80 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/SKILL.md +153 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/api-doc-templates.md +221 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/docstring-formats.md +296 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/git-forensics/SKILL.md +276 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/git-forensics/references/advanced-commands.md +332 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/git-forensics/references/investigation-playbooks.md +319 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/SKILL.md +150 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/javascript-migrations.md +179 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/python-migrations.md +141 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/performance-profiling/SKILL.md +341 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/performance-profiling/references/interpreting-results.md +235 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/performance-profiling/references/tool-commands.md +395 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/refactoring-patterns/SKILL.md +344 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/refactoring-patterns/references/safe-transformations.md +247 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/refactoring-patterns/references/smell-catalog.md +332 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/security-checklist/SKILL.md +277 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/security-checklist/references/owasp-patterns.md +269 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/security-checklist/references/secrets-patterns.md +253 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/SKILL.md +320 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/references/criteria-patterns.md +245 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/references/ears-templates.md +239 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/__pycache__/block-dangerous.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/__pycache__/guard-protected.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +40 -39
- package/.devcontainer/scripts/check-setup.sh +72 -0
- package/.devcontainer/scripts/setup-aliases.sh +51 -6
- package/.devcontainer/scripts/setup-auth.sh +74 -0
- package/.devcontainer/scripts/setup-config.sh +112 -20
- package/.devcontainer/scripts/setup-plugins.sh +38 -46
- package/.devcontainer/scripts/setup-projects.sh +175 -0
- package/.devcontainer/scripts/setup-symlink-claude.sh +36 -0
- package/.devcontainer/scripts/setup-update-claude.sh +19 -8
- package/.devcontainer/scripts/setup.sh +49 -14
- package/README.md +23 -190
- package/package.json +1 -1
- package/setup.js +245 -71
- package/.devcontainer/features/claude-code/README.md +0 -498
- package/.devcontainer/features/claude-code/config/settings.json +0 -36
- package/.devcontainer/features/claude-code/config/system-prompt.md +0 -118
- package/.devcontainer/features/claude-code/config/world-building-sp.md +0 -1432
- package/.devcontainer/features/claude-code/devcontainer-feature.json +0 -42
- package/.devcontainer/features/claude-code/install.sh +0 -466
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +0 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +0 -17
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +0 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +0 -14
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +0 -989
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +0 -33
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +0 -71
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +0 -68
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +0 -120
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +0 -133
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +0 -253
- package/.devcontainer/scripts/setup-irie-claude.sh +0 -32
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Python Migration Patterns
|
|
2
|
+
|
|
3
|
+
## Python Version Upgrades (3.8 → 3.12)
|
|
4
|
+
|
|
5
|
+
### Typing Modernization
|
|
6
|
+
|
|
7
|
+
| Old Pattern (3.8) | New Pattern (3.10+) | Search Pattern |
|
|
8
|
+
|-------------------|---------------------|----------------|
|
|
9
|
+
| `Optional[X]` | `X \| None` | `from typing import Optional` |
|
|
10
|
+
| `Union[X, Y]` | `X \| Y` | `from typing import Union` |
|
|
11
|
+
| `List[str]` | `list[str]` | `from typing import List` |
|
|
12
|
+
| `Dict[str, int]` | `dict[str, int]` | `from typing import Dict` |
|
|
13
|
+
| `Tuple[int, ...]` | `tuple[int, ...]` | `from typing import Tuple` |
|
|
14
|
+
| `Set[str]` | `set[str]` | `from typing import Set` |
|
|
15
|
+
| `FrozenSet[str]` | `frozenset[str]` | `from typing import FrozenSet` |
|
|
16
|
+
| `Type[X]` | `type[X]` | `from typing import Type` |
|
|
17
|
+
|
|
18
|
+
**Migration step**: Replace all `typing` imports of built-in generics with lowercase equivalents. Remove unused `typing` imports after replacement.
|
|
19
|
+
|
|
20
|
+
### Deprecated / Removed Modules
|
|
21
|
+
|
|
22
|
+
| Module | Removed In | Replacement |
|
|
23
|
+
|--------|-----------|-------------|
|
|
24
|
+
| `distutils` | 3.12 | `setuptools`, `shutil` |
|
|
25
|
+
| `imp` | 3.12 | `importlib` |
|
|
26
|
+
| `lib2to3` | 3.13 | `libcst` or manual |
|
|
27
|
+
| `aifc` | 3.13 | Third-party audio libraries |
|
|
28
|
+
| `cgi` | 3.13 | `urllib.parse`, `email.message` |
|
|
29
|
+
| `cgitb` | 3.13 | `traceback` |
|
|
30
|
+
|
|
31
|
+
### collections.abc Migration
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
# Old (deprecated in 3.9, removed warning in 3.10+)
|
|
35
|
+
from collections import MutableMapping, Sequence, Iterable
|
|
36
|
+
|
|
37
|
+
# New
|
|
38
|
+
from collections.abc import MutableMapping, Sequence, Iterable
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Search for: `from collections import` and check if any imported names are ABCs.
|
|
42
|
+
|
|
43
|
+
### asyncio Changes
|
|
44
|
+
|
|
45
|
+
| Old Pattern | New Pattern (3.10+) | Version |
|
|
46
|
+
|------------|---------------------|---------|
|
|
47
|
+
| `asyncio.get_event_loop()` | `asyncio.get_running_loop()` (in async context) | 3.10 |
|
|
48
|
+
| `@asyncio.coroutine` / `yield from` | `async def` / `await` | 3.8 (removed 3.11) |
|
|
49
|
+
| `loop.create_task()` | `asyncio.create_task()` | 3.7 |
|
|
50
|
+
| `asyncio.wait(tasks)` | `asyncio.wait(tasks)` (must pass set) | 3.11 |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Pydantic v1 → v2
|
|
55
|
+
|
|
56
|
+
### Complete API Mapping
|
|
57
|
+
|
|
58
|
+
| Pydantic v1 | Pydantic v2 | Notes |
|
|
59
|
+
|-------------|-------------|-------|
|
|
60
|
+
| `@validator('field')` | `@field_validator('field')` | Import from `pydantic` |
|
|
61
|
+
| `@validator('field', pre=True)` | `@field_validator('field', mode='before')` | `mode='before'` replaces `pre=True` |
|
|
62
|
+
| `@validator('field', always=True)` | `@field_validator('field')` + `@model_validator` | `always` removed; use model validator for defaults |
|
|
63
|
+
| `@root_validator` | `@model_validator` | Import from `pydantic` |
|
|
64
|
+
| `@root_validator(pre=True)` | `@model_validator(mode='before')` | Mode parameter |
|
|
65
|
+
| `.dict()` | `.model_dump()` | Method renamed |
|
|
66
|
+
| `.json()` | `.model_dump_json()` | Method renamed |
|
|
67
|
+
| `.parse_obj(data)` | `.model_validate(data)` | Class method renamed |
|
|
68
|
+
| `.parse_raw(json_str)` | `.model_validate_json(json_str)` | Class method renamed |
|
|
69
|
+
| `.schema()` | `.model_json_schema()` | Class method renamed |
|
|
70
|
+
| `.construct()` | `.model_construct()` | Class method renamed |
|
|
71
|
+
| `.copy()` | `.model_copy()` | Method renamed |
|
|
72
|
+
| `class Config:` | `model_config = ConfigDict(...)` | Inline config dict |
|
|
73
|
+
| `Config.schema_extra` | `model_config = ConfigDict(json_schema_extra=...)` | Renamed field |
|
|
74
|
+
| `Config.orm_mode = True` | `model_config = ConfigDict(from_attributes=True)` | Renamed field |
|
|
75
|
+
| `Config.allow_population_by_field_name` | `model_config = ConfigDict(populate_by_name=True)` | Renamed field |
|
|
76
|
+
| `Field(regex=...)` | `Field(pattern=...)` | Parameter renamed |
|
|
77
|
+
|
|
78
|
+
### Migration Steps
|
|
79
|
+
|
|
80
|
+
1. Update `pydantic` version in manifest: `pydantic>=2.0`
|
|
81
|
+
2. Convert `class Config:` blocks to `model_config = ConfigDict(...)` — add `from pydantic import ConfigDict`
|
|
82
|
+
3. Convert `@validator` to `@field_validator` — update signatures (first arg is now `cls`, values accessed differently)
|
|
83
|
+
4. Convert `@root_validator` to `@model_validator` — update mode parameter
|
|
84
|
+
5. Replace `.dict()` → `.model_dump()`, `.json()` → `.model_dump_json()`
|
|
85
|
+
6. Replace `.parse_obj()` → `.model_validate()`, `.parse_raw()` → `.model_validate_json()`
|
|
86
|
+
7. Run `pytest` after each step
|
|
87
|
+
|
|
88
|
+
### Validator Signature Change
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# v1
|
|
92
|
+
@validator('name')
|
|
93
|
+
def validate_name(cls, v, values):
|
|
94
|
+
return v.strip()
|
|
95
|
+
|
|
96
|
+
# v2
|
|
97
|
+
@field_validator('name')
|
|
98
|
+
@classmethod
|
|
99
|
+
def validate_name(cls, v: str, info: ValidationInfo) -> str:
|
|
100
|
+
return v.strip()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Note: In v2, `info.data` replaces `values` for accessing other fields.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Django Version Upgrades
|
|
108
|
+
|
|
109
|
+
### Common Breaking Changes by Version
|
|
110
|
+
|
|
111
|
+
| Version | Key Changes |
|
|
112
|
+
|---------|------------|
|
|
113
|
+
| 3.2 → 4.0 | `default_app_config` removed, `USE_L10N` default changed to True |
|
|
114
|
+
| 4.0 → 4.1 | Async view support expanded, `assertFormError` signature changed |
|
|
115
|
+
| 4.1 → 4.2 | `CSRF_TRUSTED_ORIGINS` requires scheme, psycopg3 support |
|
|
116
|
+
| 4.2 → 5.0 | `DEFAULT_AUTO_FIELD` required, `logout()` changed to POST-only |
|
|
117
|
+
| 5.0 → 5.1 | `LoginRequiredMiddleware` added, `HttpResponse.content` stricter |
|
|
118
|
+
|
|
119
|
+
### Migration Steps
|
|
120
|
+
|
|
121
|
+
1. Run `python -m django check --deploy` to identify deprecation warnings.
|
|
122
|
+
2. Read the release notes for each version between current and target.
|
|
123
|
+
3. Upgrade one minor version at a time (4.0→4.1→4.2, not 4.0→4.2).
|
|
124
|
+
4. Run `python manage.py migrate` and `python manage.py test` after each version bump.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## SQLAlchemy 1.x → 2.x
|
|
129
|
+
|
|
130
|
+
### Key Changes
|
|
131
|
+
|
|
132
|
+
| SQLAlchemy 1.x | SQLAlchemy 2.x | Notes |
|
|
133
|
+
|----------------|----------------|-------|
|
|
134
|
+
| `session.query(Model)` | `select(Model)` + `session.execute()` | New select() style |
|
|
135
|
+
| `query.filter()` | `select().where()` | Method renamed |
|
|
136
|
+
| `query.all()` | `session.execute(stmt).scalars().all()` | Execution separated from query building |
|
|
137
|
+
| `Column(Integer)` | `mapped_column(Integer)` | New declarative style |
|
|
138
|
+
| `relationship()` | `relationship()` | Mostly compatible |
|
|
139
|
+
| `engine.execute()` | Removed | Use `with engine.connect() as conn: conn.execute()` |
|
|
140
|
+
|
|
141
|
+
Run with `SQLALCHEMY_WARN_20=1` environment variable to get deprecation warnings for 1.x patterns before migrating.
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance-profiling
|
|
3
|
+
description: >-
|
|
4
|
+
This skill should be used when the user asks to "profile this code",
|
|
5
|
+
"find the bottleneck", "optimize performance", "measure execution time",
|
|
6
|
+
"check memory usage", "create a flamegraph", "benchmark this function",
|
|
7
|
+
"find memory leaks", "reduce latency", "run a performance test",
|
|
8
|
+
or discusses profiling tools, flamegraphs, benchmarking methodology,
|
|
9
|
+
cProfile, py-spy, scalene, Chrome DevTools performance,
|
|
10
|
+
memory profiling, or hot path analysis.
|
|
11
|
+
version: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Performance Profiling
|
|
15
|
+
|
|
16
|
+
## Mental Model
|
|
17
|
+
|
|
18
|
+
Performance work follows one rule: **measure first, optimize second**. Bottlenecks are almost never where you think they are. Developers consistently misjudge performance by 10-100x -- the "obviously slow" nested loop is often fast, while the "simple" database query is the real bottleneck.
|
|
19
|
+
|
|
20
|
+
The profiling workflow is:
|
|
21
|
+
1. **Establish a baseline** -- measure current performance with a reproducible benchmark
|
|
22
|
+
2. **Profile** -- identify where time and memory are actually spent
|
|
23
|
+
3. **Hypothesize** -- form a specific theory about the bottleneck
|
|
24
|
+
4. **Optimize** -- make one targeted change
|
|
25
|
+
5. **Measure again** -- verify the optimization actually helped
|
|
26
|
+
6. **Compare** -- did the change improve the baseline? By how much?
|
|
27
|
+
|
|
28
|
+
Without this discipline, you'll waste time optimizing code that doesn't matter, introduce complexity without measurable benefit, and have no proof that your changes helped.
|
|
29
|
+
|
|
30
|
+
**Amdahl's Law** sets the ceiling: if a function consumes 5% of total runtime, making it infinitely fast saves only 5%. Focus on the biggest bars in the profile first.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Python Profiling
|
|
35
|
+
|
|
36
|
+
### cProfile (built-in, deterministic)
|
|
37
|
+
|
|
38
|
+
cProfile instruments every function call. It shows call count, cumulative time, and per-call time:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Profile a script
|
|
42
|
+
python -m cProfile -s cumtime myapp.py
|
|
43
|
+
|
|
44
|
+
# Profile and save to a file for analysis
|
|
45
|
+
python -m cProfile -o profile.prof myapp.py
|
|
46
|
+
|
|
47
|
+
# Analyze the saved profile
|
|
48
|
+
python -c "
|
|
49
|
+
import pstats
|
|
50
|
+
p = pstats.Stats('profile.prof')
|
|
51
|
+
p.sort_stats('cumulative')
|
|
52
|
+
p.print_stats(20) # top 20 functions
|
|
53
|
+
"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Tradeoff:** cProfile adds ~30% overhead and measures wall-clock time. It's deterministic (traces every call) so it catches everything but distorts timing for very fast functions.
|
|
57
|
+
|
|
58
|
+
### py-spy (sampling, no overhead)
|
|
59
|
+
|
|
60
|
+
py-spy samples the call stack without modifying the target process. It can attach to running processes:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Record a flamegraph (SVG)
|
|
64
|
+
py-spy record -o flamegraph.svg -- python myapp.py
|
|
65
|
+
|
|
66
|
+
# Attach to a running process
|
|
67
|
+
py-spy record -o flamegraph.svg --pid 12345
|
|
68
|
+
|
|
69
|
+
# Top-like live view
|
|
70
|
+
py-spy top --pid 12345
|
|
71
|
+
|
|
72
|
+
# Profile for a specific duration
|
|
73
|
+
py-spy record --duration 30 -o flamegraph.svg --pid 12345
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Tradeoff:** Sampling misses very short functions but has near-zero overhead. Ideal for production profiling.
|
|
77
|
+
|
|
78
|
+
### scalene (CPU + memory + GPU)
|
|
79
|
+
|
|
80
|
+
Scalene profiles CPU time, memory allocation, and memory usage simultaneously. It distinguishes Python time from native (C) time:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Profile a script
|
|
84
|
+
scalene myapp.py
|
|
85
|
+
|
|
86
|
+
# Profile with specific options
|
|
87
|
+
scalene --cpu --memory --reduced-profile myapp.py
|
|
88
|
+
|
|
89
|
+
# Profile a specific function (in code)
|
|
90
|
+
# from scalene import scalene_profiler
|
|
91
|
+
# scalene_profiler.start()
|
|
92
|
+
# ... code to profile ...
|
|
93
|
+
# scalene_profiler.stop()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### memory_profiler (line-by-line memory)
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from memory_profiler import profile
|
|
100
|
+
import pandas as pd
|
|
101
|
+
|
|
102
|
+
@profile
|
|
103
|
+
def process_data() -> pd.DataFrame:
|
|
104
|
+
data = pd.read_csv("large.csv") # Line 5: +500 MiB
|
|
105
|
+
filtered = data[data["active"]] # Line 6: +200 MiB
|
|
106
|
+
result = filtered.groupby("region").sum() # Line 7: +50 MiB
|
|
107
|
+
del data, filtered # Line 8: -700 MiB
|
|
108
|
+
return result
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
python -m memory_profiler myapp.py
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### line_profiler (line-by-line CPU)
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
# Decorate functions to profile
|
|
119
|
+
@profile
|
|
120
|
+
def expensive_function():
|
|
121
|
+
result = [] # 0.0%
|
|
122
|
+
for item in large_list: # 2.1%
|
|
123
|
+
parsed = parse(item) # 45.3% <-- hot line
|
|
124
|
+
if validate(parsed): # 12.7%
|
|
125
|
+
result.append(parsed) # 0.4%
|
|
126
|
+
return result
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
kernprof -l -v myapp.py
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> **Deep dive:** See `references/tool-commands.md` for the full command reference per language and tool.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## JavaScript / Node.js Profiling
|
|
138
|
+
|
|
139
|
+
### V8 Profiler (`--prof`)
|
|
140
|
+
|
|
141
|
+
Node's built-in V8 profiler generates a log that can be processed into a human-readable report:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Generate a V8 profile log
|
|
145
|
+
node --prof app.js
|
|
146
|
+
|
|
147
|
+
# Process the log into readable output
|
|
148
|
+
node --prof-process isolate-*.log > processed.txt
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### clinic.js
|
|
152
|
+
|
|
153
|
+
A suite of profiling tools for Node.js:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Install
|
|
157
|
+
npm install -g clinic
|
|
158
|
+
|
|
159
|
+
# Doctor: overall health check (event loop, GC, I/O)
|
|
160
|
+
clinic doctor -- node app.js
|
|
161
|
+
|
|
162
|
+
# Flame: flamegraph
|
|
163
|
+
clinic flame -- node app.js
|
|
164
|
+
|
|
165
|
+
# Bubbleprof: async flow visualization
|
|
166
|
+
clinic bubbleprof -- node app.js
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Chrome DevTools
|
|
170
|
+
|
|
171
|
+
For both browser and Node.js profiling:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Start Node with inspector
|
|
175
|
+
node --inspect app.js
|
|
176
|
+
|
|
177
|
+
# Or break on first line
|
|
178
|
+
node --inspect-brk app.js
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Then open `chrome://inspect` in Chrome:
|
|
182
|
+
- **Performance tab:** Record a profile, see flamechart, call tree, and bottom-up views
|
|
183
|
+
- **Memory tab:** Take heap snapshots, record allocation timelines, detect leaks
|
|
184
|
+
|
|
185
|
+
### Lighthouse (Web Performance)
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# CLI audit
|
|
189
|
+
npx lighthouse https://example.com --output json --output html
|
|
190
|
+
|
|
191
|
+
# Key metrics: FCP, LCP, TTI, TBT, CLS
|
|
192
|
+
# Target: Performance score > 90
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## System Profiling
|
|
198
|
+
|
|
199
|
+
When the bottleneck isn't in your code but in the system:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Wall-clock time, user CPU, system CPU
|
|
203
|
+
time python myapp.py
|
|
204
|
+
|
|
205
|
+
# Process-level resource usage (live)
|
|
206
|
+
htop # interactive process viewer
|
|
207
|
+
htop -p 12345 # monitor specific PID
|
|
208
|
+
|
|
209
|
+
# I/O statistics
|
|
210
|
+
iostat -x 1 # disk I/O per device, every 1 second
|
|
211
|
+
|
|
212
|
+
# CPU performance counters (Linux)
|
|
213
|
+
perf stat python myapp.py
|
|
214
|
+
# Counts: cycles, instructions, cache misses, branch misses
|
|
215
|
+
|
|
216
|
+
# System call tracing
|
|
217
|
+
strace -c python myapp.py # summary of syscall time
|
|
218
|
+
strace -e trace=network app # only network syscalls
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Interpreting `time` output:**
|
|
222
|
+
- **real** > **user** + **sys** → I/O bound (waiting for disk, network, or sleep)
|
|
223
|
+
- **user** >> **sys** → CPU bound in userspace (computation)
|
|
224
|
+
- **sys** >> **user** → CPU bound in kernel (many syscalls, context switches)
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Benchmarking Methodology
|
|
229
|
+
|
|
230
|
+
Benchmarks must be reproducible, statistically sound, and isolated from noise.
|
|
231
|
+
|
|
232
|
+
### CLI Benchmarking with hyperfine
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Basic benchmark with warmup
|
|
236
|
+
hyperfine --warmup 3 'python myapp.py'
|
|
237
|
+
|
|
238
|
+
# Compare two implementations
|
|
239
|
+
hyperfine --warmup 3 'python v1.py' 'python v2.py'
|
|
240
|
+
|
|
241
|
+
# With parameter sweeps
|
|
242
|
+
hyperfine --warmup 3 -P size 100,1000,10000 'python bench.py --size {size}'
|
|
243
|
+
|
|
244
|
+
# Export results
|
|
245
|
+
hyperfine --warmup 3 --export-json results.json 'python myapp.py'
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
hyperfine automatically detects outliers, calculates mean/median/stddev, and warns about statistical issues.
|
|
249
|
+
|
|
250
|
+
### Python Benchmarking with pytest-benchmark
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
# benchmark fixture is injected by pytest-benchmark — no import needed
|
|
254
|
+
def test_sort_performance(benchmark) -> None:
|
|
255
|
+
data = list(range(10000, 0, -1))
|
|
256
|
+
result = benchmark(sorted, data)
|
|
257
|
+
assert result == list(range(1, 10001))
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def test_json_parse_performance(benchmark) -> None:
|
|
261
|
+
"""Benchmark with setup to exclude data preparation from timing."""
|
|
262
|
+
import json
|
|
263
|
+
payload = json.dumps({"users": [{"id": i, "name": f"user_{i}"} for i in range(1000)]})
|
|
264
|
+
result = benchmark(json.loads, payload)
|
|
265
|
+
assert len(result["users"]) == 1000
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pytest --benchmark-only --benchmark-sort=mean
|
|
270
|
+
pytest --benchmark-compare # compare against saved baseline
|
|
271
|
+
pytest --benchmark-save=baseline # save current results
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Benchmarking Rules
|
|
275
|
+
|
|
276
|
+
1. **Warmup runs** -- JIT compilers, caches, and OS page faults all affect the first run. Always include warmup.
|
|
277
|
+
2. **Multiple iterations** -- A single measurement is noise. Run at least 10 iterations and report mean, median, and stddev.
|
|
278
|
+
3. **Isolate variables** -- Change one thing at a time. Benchmark before and after each optimization.
|
|
279
|
+
4. **Control the environment** -- Close other applications, disable turbo boost for CPU benchmarks, use consistent hardware.
|
|
280
|
+
5. **Statistical significance** -- If the difference is less than 2x the standard deviation, it's probably noise.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Interpreting Results
|
|
285
|
+
|
|
286
|
+
### Reading Flamegraphs
|
|
287
|
+
|
|
288
|
+
Flamegraphs show the call stack over time. The x-axis is **not** time -- it's alphabetically sorted stack frames. Width represents the proportion of total samples.
|
|
289
|
+
|
|
290
|
+
- **Wide bars at the top** = functions that consume a lot of CPU directly
|
|
291
|
+
- **Wide bars at the bottom** = functions that call expensive children
|
|
292
|
+
- **Plateaus** (flat tops) = functions where time is spent in the function itself, not its children
|
|
293
|
+
- **Look for:** the widest bars at the top of the graph -- these are your hot paths
|
|
294
|
+
|
|
295
|
+
### Identifying Hot Paths
|
|
296
|
+
|
|
297
|
+
A hot path is the sequence of function calls that consumes the most cumulative time:
|
|
298
|
+
|
|
299
|
+
1. Sort by cumulative time (`cumtime` in cProfile)
|
|
300
|
+
2. Find the top-level function with the highest cumulative time
|
|
301
|
+
3. Follow its callees -- which child function consumes the most?
|
|
302
|
+
4. Repeat until you reach a leaf function
|
|
303
|
+
|
|
304
|
+
The hot path tells you where optimization effort will have the most impact.
|
|
305
|
+
|
|
306
|
+
### Memory Leak Patterns
|
|
307
|
+
|
|
308
|
+
Signs of a memory leak:
|
|
309
|
+
- Memory usage grows linearly with time/requests
|
|
310
|
+
- `gc.collect()` doesn't reclaim memory
|
|
311
|
+
- Heap snapshots show growing object counts for a specific type
|
|
312
|
+
|
|
313
|
+
Common causes:
|
|
314
|
+
- **Unbounded caches** -- dictionaries that grow forever. Fix: use `functools.lru_cache(maxsize=N)` or TTL-based caching.
|
|
315
|
+
- **Event listener accumulation** -- listeners added but never removed. Fix: use weak references or explicit cleanup.
|
|
316
|
+
- **Circular references with `__del__`** -- Python's GC can't collect cycles that have finalizers. Fix: use `weakref` to break the cycle.
|
|
317
|
+
- **Global state accumulation** -- appending to module-level lists. Fix: scope the collection to the request/session lifecycle.
|
|
318
|
+
|
|
319
|
+
> **Deep dive:** See `references/interpreting-results.md` for annotated examples of profiler output and how to read them.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Ambiguity Policy
|
|
324
|
+
|
|
325
|
+
These defaults apply when the user does not specify a preference. State the assumption when making a choice:
|
|
326
|
+
|
|
327
|
+
- **Profiler choice:** Default to py-spy for Python (low overhead, flamegraph output), clinic.js for Node.js, and Chrome DevTools for browser. Use cProfile when the user needs exact call counts.
|
|
328
|
+
- **Benchmark iterations:** Default to at least 10 iterations with 3 warmup runs. Increase for sub-millisecond operations.
|
|
329
|
+
- **Metric focus:** Default to wall-clock time. Switch to CPU time when I/O is deliberately excluded. Switch to memory when the user mentions "memory", "leak", or "OOM".
|
|
330
|
+
- **Optimization scope:** Optimize only the identified hot path. Do not refactor surrounding code for "consistency" unless it's part of the hot path.
|
|
331
|
+
- **Baseline requirement:** Always establish a baseline measurement before optimizing. Refuse to optimize without one -- "it feels slow" is not a baseline.
|
|
332
|
+
- **Reporting:** Report absolute numbers (ms, MB) alongside relative improvements (%). A 50% improvement from 2ms to 1ms matters less than a 10% improvement from 10s to 9s.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Reference Files
|
|
337
|
+
|
|
338
|
+
| File | Contents |
|
|
339
|
+
|------|----------|
|
|
340
|
+
| `references/tool-commands.md` | Full command reference for Python, JavaScript, and system profiling tools with all flags and options |
|
|
341
|
+
| `references/interpreting-results.md` | How to read profiler output: annotated cProfile tables, flamegraph walkthroughs, memory timeline interpretation, and benchmark result analysis |
|