modern-python-guidance 0.3.0__tar.gz → 0.3.2__tar.gz
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.
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/CHANGELOG.md +53 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/CONTRIBUTING.md +1 -1
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/PKG-INFO +46 -25
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/README.md +45 -24
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/docs/design.md +1 -1
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/pyproject.toml +1 -1
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/SKILL.md +3 -3
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/fastapi/fastapi-lifespan.md +1 -1
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/fastapi/fastapi-typed-state.md +5 -0
- modern_python_guidance-0.3.2/skills/modern-python-guidance/guides/stdlib/template-strings.md +70 -0
- modern_python_guidance-0.3.2/skills/modern-python-guidance/guides/typing/deferred-annotations.md +63 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/__init__.py +1 -1
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/cli.py +55 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/mcp_server.py +4 -4
- modern_python_guidance-0.3.2/src/modern_python_guidance/setup_cmd.py +189 -0
- modern_python_guidance-0.3.2/src/modern_python_guidance/uninstall_cmd.py +171 -0
- modern_python_guidance-0.3.2/tests/test_setup.py +425 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_skill_sync.py +6 -6
- modern_python_guidance-0.3.2/tests/test_uninstall.py +371 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/.github/workflows/ci.yml +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/.github/workflows/publish.yml +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/.gitignore +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/LICENSE +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/LICENSE-MIT +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/SECURITY.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/pyproject.toml +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/app.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/config.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/crawler.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/models.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/scanner.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-modern/src/utils.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/pyproject.toml +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/setup.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/app.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/config.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/crawler.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/models.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/scanner.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-a-outdated/src/utils.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-b-modern/myapp/models.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-b-modern/myapp/views.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-b-outdated/myapp/models.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-b-outdated/myapp/views.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-c-modern/tests/test_calculator.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/fixtures/variant-c-outdated/tests/test_calculator.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/mcp-config.json +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v2.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v3-mcp.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v3.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v4-a.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v4-b.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt-v4-c.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/prompt.txt +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/run-mcp.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/run-v4.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/run.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/score-v2.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/score-v3.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/score-v4.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/score.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/bench/test-scorer.sh +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/docs/benchmark-evaluation.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/docs/benchmark-procedure.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/async/async-timeout-context.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/async/exception-groups.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/async/taskgroup-over-gather.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/data-structures/dataclass-modern.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/data-structures/dict-merge-operator.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/data-structures/match-case-patterns.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/django/django-async-views.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/django/django-check-constraints.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/django/django-json-field.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/fastapi/fastapi-annotated-depends.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/httpx/httpx-async-client-reuse.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/httpx/httpx-streaming.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-config.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-model-api.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-serialization.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-validators.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pytest/pytest-parametrize.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pytest/pytest-raises-match.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/pytest/pytest-tmp-path.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-2-style.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-async-session.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-mapped-column.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/stdlib/datetime-utc.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/stdlib/pathlib-over-os-path.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/stdlib/removeprefix-removesuffix.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/stdlib/tomllib-builtin.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/toolchain/no-pickle.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/toolchain/pyproject-toml-over-setup.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/toolchain/ruff-over-flake8.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/toolchain/safe-subprocess.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/toolchain/uv-over-pip.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/override-decorator.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/paramspec-decorators.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/type-parameter-syntax.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/typeis-vs-typeguard.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/union-syntax.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/guides/typing/use-builtin-generics.md +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/__main__.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/compat.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/frontmatter.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/guide_index.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/retrieve.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/search.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/version_detect.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_cli_integration.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_frontmatter.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_mcp_server.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_retrieve.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_search.py +0 -0
- {modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/tests/test_version_detect.py +0 -0
|
@@ -2,8 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.3.2] — 2026-05-29
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `deferred-annotations` guide (PEP 649): drop unnecessary `from __future__ import annotations` on Python 3.14+ projects where annotations are lazily evaluated by default (closes #28)
|
|
10
|
+
- `template-strings` guide (PEP 750): use t-strings with processing functions for safe SQL/HTML parameterization instead of f-string interpolation (closes #28)
|
|
11
|
+
- Guide count: 39 → 41. Layer 1 coverage: 16 → 18
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `setup_mcp` now catches `OSError` from `subprocess.run`, matching `uninstall_mcp` behavior — an unexecutable `claude` binary produces a clean error message instead of a traceback (closes #65)
|
|
16
|
+
- MCP `retrieve_guides` schema `maxItems` and runtime guard updated from 39 to 41 to allow retrieval of all guides
|
|
17
|
+
|
|
18
|
+
## [0.3.1] — 2026-05-29
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `mpg uninstall` command: reverses `mpg setup` by deregistering the MCP server and removing the Agent Skills symlink in one command (closes #63)
|
|
23
|
+
- CLI flags: `--mcp-only`, `--skills-only`, `--project-dir`, `--dry-run` (no `--scope`; uninstall clears every scope `setup` can write to)
|
|
24
|
+
- Per-scope MCP deregistration (`claude mcp remove -s local` and `-s user`): a live probe showed `claude mcp remove` without a scope removes nothing when the server is registered in multiple scopes, so uninstall enumerates scopes explicitly to avoid leaving residue
|
|
25
|
+
- Symlink-only removal safety: only the symlink mpg created is removed (never its target), a non-symlink entity at the link path is refused, dangling symlinks are removed, and the parent `.claude/skills/` directory is preserved
|
|
26
|
+
- 26 new tests (V-015 through V-031)
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Extracted shared `_skills_link_path` helper in `setup_cmd` so `setup` and `uninstall` resolve the Skills symlink location identically (no drift)
|
|
31
|
+
|
|
5
32
|
## [0.3.0] — 2026-05-28
|
|
6
33
|
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `mpg setup` command: one-command MCP server registration + Agent Skills symlink creation. Replaces 3-4 manual steps with `pip install modern-python-guidance && mpg setup` (closes #60)
|
|
37
|
+
- CLI flags: `--mcp-only`, `--skills-only`, `--scope {user,local}`, `--project-dir`, `--dry-run`
|
|
38
|
+
- Project root auto-detection (`.claude/` → `.git/` → `pyproject.toml` upward search) for correct Skills symlink placement from subdirectories
|
|
39
|
+
- Idempotent operation: re-running `mpg setup` skips already-correct state, replaces stale/broken symlinks, errors on non-symlink blockers
|
|
40
|
+
- Partial success handling: MCP and Skills run independently; one failure does not block the other
|
|
41
|
+
- 33 new tests for setup command (V-001 through V-014 verification points)
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- README Quick Start: reduced from 3 code blocks to 2 lines (`pip install` + `mpg setup`). Manual setup moved to collapsible `<details>` section
|
|
46
|
+
|
|
47
|
+
## [0.2.3] — 2026-05-28
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- `fastapi-typed-state` guide: added missing Version Notes section (closes #13)
|
|
52
|
+
- `fastapi-typed-state` and `fastapi-lifespan` guides: corrected minimum version from FastAPI >= 0.93.0 to >= 0.94.0 (lifespan state dict requires Starlette >= 0.26.0, which FastAPI 0.93.0 excludes)
|
|
53
|
+
|
|
54
|
+
## [0.2.2] — 2026-05-28
|
|
55
|
+
|
|
7
56
|
### Changed
|
|
8
57
|
|
|
9
58
|
- Search response (MCP + CLI) now includes `tags`, `python`, `frequency`, and `snippet` fields for richer agent decision-making without requiring a follow-up retrieve call
|
|
@@ -81,7 +130,11 @@ Initial release.
|
|
|
81
130
|
- Strict YAML-subset frontmatter parser (no PyYAML dependency)
|
|
82
131
|
- GitHub Actions CI (pytest + ruff on Python 3.11, 3.12, 3.13)
|
|
83
132
|
|
|
133
|
+
[0.3.2]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.3.2
|
|
134
|
+
[0.3.1]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.3.1
|
|
84
135
|
[0.3.0]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.3.0
|
|
136
|
+
[0.2.3]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.2.3
|
|
137
|
+
[0.2.2]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.2.2
|
|
85
138
|
[0.2.1]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.2.1
|
|
86
139
|
[0.2.0]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.2.0
|
|
87
140
|
[0.1.2]: https://github.com/yottayoshida/modern-python-guidance/releases/tag/v0.1.2
|
|
@@ -15,7 +15,7 @@ src/modern_python_guidance/
|
|
|
15
15
|
|
|
16
16
|
skills/modern-python-guidance/
|
|
17
17
|
├── SKILL.md # Agent Skills plugin entry point
|
|
18
|
-
└── guides/ #
|
|
18
|
+
└── guides/ # 41 guide files by category
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
See [docs/design.md](docs/design.md) for the full design document.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modern-python-guidance
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Version-aware BAD/GOOD pattern guides that help AI coding agents generate modern Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/yottayoshida/modern-python-guidance
|
|
6
6
|
Project-URL: Repository, https://github.com/yottayoshida/modern-python-guidance
|
|
@@ -36,12 +36,12 @@ Description-Content-Type: text/markdown
|
|
|
36
36
|
[](https://pypi.org/project/modern-python-guidance/)
|
|
37
37
|
[](LICENSE)
|
|
38
38
|
|
|
39
|
-
Stop your AI from writing `typing.List`, `@validator`, and `setup.py`.
|
|
39
|
+
Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 41 version-aware BAD/GOOD pattern guides that teach AI coding agents to write modern Python — delivered via MCP, CLI, or Agent Skills.
|
|
40
40
|
|
|
41
41
|
## Highlights
|
|
42
42
|
|
|
43
43
|
- **Measurable impact**: +14.7pp overall improvement in A/B benchmark via Agent Skills (38 scored items, [details](docs/benchmark-evaluation.md)). Largest variant (FastAPI, 32 items): Control 60.4% → Treatment 82.3%
|
|
44
|
-
- **
|
|
44
|
+
- **41 guides** across stdlib, Pydantic, FastAPI, Django, SQLAlchemy, pytest, and toolchain
|
|
45
45
|
- **Version-aware**: auto-detects your project's Python version and filters guides accordingly
|
|
46
46
|
- **3 delivery methods**: MCP server, CLI, Agent Skills plugin
|
|
47
47
|
- **Not Ruff**: Ruff auto-fixes syntax (`List` → `list`). mpg guides design decisions that Ruff can't touch — `TaskGroup` over `gather`, Pydantic V2 migration, SQLAlchemy 2.0 style
|
|
@@ -50,15 +50,29 @@ Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 39 versio
|
|
|
50
50
|
|
|
51
51
|
## Quick start
|
|
52
52
|
|
|
53
|
-
###
|
|
53
|
+
### Claude Code (recommended)
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
```bash
|
|
56
|
+
pip install modern-python-guidance
|
|
57
|
+
mpg setup
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This registers the MCP server and links Agent Skills in one command. Start a new Claude Code session afterwards — newly registered MCP servers and skills take effect on the next launch.
|
|
61
|
+
|
|
62
|
+
### CLI
|
|
56
63
|
|
|
57
64
|
```bash
|
|
58
65
|
pip install modern-python-guidance
|
|
66
|
+
mpg search "pydantic validator"
|
|
67
|
+
mpg retrieve pydantic-v2-validators
|
|
59
68
|
```
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
`mpg` is the short alias for `modern-python-guidance`. Both work.
|
|
71
|
+
|
|
72
|
+
<details>
|
|
73
|
+
<summary>Manual setup / other agents</summary>
|
|
74
|
+
|
|
75
|
+
**MCP registration (Claude Code):**
|
|
62
76
|
```bash
|
|
63
77
|
claude mcp add mpg -- mpg mcp
|
|
64
78
|
```
|
|
@@ -75,29 +89,36 @@ claude mcp add mpg -- mpg mcp
|
|
|
75
89
|
}
|
|
76
90
|
```
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
### CLI
|
|
81
|
-
|
|
92
|
+
**Agent Skills symlink (Claude Code):**
|
|
82
93
|
```bash
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# Search for a pattern
|
|
86
|
-
mpg search "pydantic validator"
|
|
87
|
-
|
|
88
|
-
# Get the full guide
|
|
89
|
-
mpg retrieve pydantic-v2-validators
|
|
94
|
+
mpg setup --skills-only
|
|
90
95
|
```
|
|
91
96
|
|
|
92
|
-
|
|
97
|
+
**`mpg setup` flags:**
|
|
98
|
+
| Flag | Purpose |
|
|
99
|
+
|------|---------|
|
|
100
|
+
| `--mcp-only` | MCP registration only |
|
|
101
|
+
| `--skills-only` | Agent Skills symlink only |
|
|
102
|
+
| `--scope {user,local}` | MCP scope (default: user) |
|
|
103
|
+
| `--project-dir PATH` | Target project for Skills symlink |
|
|
104
|
+
| `--dry-run` | Show what would be done |
|
|
93
105
|
|
|
106
|
+
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills):
|
|
94
107
|
```bash
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
ln -s "$SKILL_DIR" your-project/.claude/skills/modern-python-guidance
|
|
108
|
+
mpg uninstall # remove both
|
|
109
|
+
mpg uninstall --dry-run # preview what would be removed
|
|
98
110
|
```
|
|
99
111
|
|
|
100
|
-
|
|
112
|
+
| Flag | Purpose |
|
|
113
|
+
|------|---------|
|
|
114
|
+
| `--mcp-only` | MCP deregistration only |
|
|
115
|
+
| `--skills-only` | Agent Skills unlink only |
|
|
116
|
+
| `--project-dir PATH` | Target project for the Skills symlink |
|
|
117
|
+
| `--dry-run` | Show what would be done |
|
|
118
|
+
|
|
119
|
+
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the symlink mpg created (never its target or other skills), and is idempotent — running it on an already-clean state is a harmless no-op.
|
|
120
|
+
|
|
121
|
+
</details>
|
|
101
122
|
|
|
102
123
|
## CLI usage
|
|
103
124
|
|
|
@@ -123,15 +144,15 @@ mpg search "typing" --format json | jq '.[0].id'
|
|
|
123
144
|
|
|
124
145
|
## Guide coverage
|
|
125
146
|
|
|
126
|
-
|
|
147
|
+
41 guides across 3 layers:
|
|
127
148
|
|
|
128
149
|
| Layer | Categories | Count | Examples |
|
|
129
150
|
|-------|-----------|-------|---------|
|
|
130
|
-
| **1 — stdlib** | typing, async, stdlib, data-structures |
|
|
151
|
+
| **1 — stdlib** | typing, async, stdlib, data-structures | 18 | `list` over `List`, `match`/`case`, `TaskGroup`, deferred annotations, t-strings |
|
|
131
152
|
| **2 — frameworks** | pydantic, fastapi, httpx, django, sqlalchemy, pytest | 18 | Pydantic V2 migration, SQLAlchemy 2.0 style, `Annotated[Depends]` |
|
|
132
153
|
| **3 — toolchain** | toolchain | 5 | `uv` over `pip`, `ruff` over flake8, `pickle` avoidance |
|
|
133
154
|
|
|
134
|
-
Run `mpg list` to see all
|
|
155
|
+
Run `mpg list` to see all 41 guides, or [browse them on GitHub](skills/modern-python-guidance/guides/).
|
|
135
156
|
|
|
136
157
|
## Version-aware filtering
|
|
137
158
|
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
[](https://pypi.org/project/modern-python-guidance/)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
Stop your AI from writing `typing.List`, `@validator`, and `setup.py`.
|
|
8
|
+
Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 41 version-aware BAD/GOOD pattern guides that teach AI coding agents to write modern Python — delivered via MCP, CLI, or Agent Skills.
|
|
9
9
|
|
|
10
10
|
## Highlights
|
|
11
11
|
|
|
12
12
|
- **Measurable impact**: +14.7pp overall improvement in A/B benchmark via Agent Skills (38 scored items, [details](docs/benchmark-evaluation.md)). Largest variant (FastAPI, 32 items): Control 60.4% → Treatment 82.3%
|
|
13
|
-
- **
|
|
13
|
+
- **41 guides** across stdlib, Pydantic, FastAPI, Django, SQLAlchemy, pytest, and toolchain
|
|
14
14
|
- **Version-aware**: auto-detects your project's Python version and filters guides accordingly
|
|
15
15
|
- **3 delivery methods**: MCP server, CLI, Agent Skills plugin
|
|
16
16
|
- **Not Ruff**: Ruff auto-fixes syntax (`List` → `list`). mpg guides design decisions that Ruff can't touch — `TaskGroup` over `gather`, Pydantic V2 migration, SQLAlchemy 2.0 style
|
|
@@ -19,15 +19,29 @@ Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 39 versio
|
|
|
19
19
|
|
|
20
20
|
## Quick start
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Claude Code (recommended)
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
```bash
|
|
25
|
+
pip install modern-python-guidance
|
|
26
|
+
mpg setup
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This registers the MCP server and links Agent Skills in one command. Start a new Claude Code session afterwards — newly registered MCP servers and skills take effect on the next launch.
|
|
30
|
+
|
|
31
|
+
### CLI
|
|
25
32
|
|
|
26
33
|
```bash
|
|
27
34
|
pip install modern-python-guidance
|
|
35
|
+
mpg search "pydantic validator"
|
|
36
|
+
mpg retrieve pydantic-v2-validators
|
|
28
37
|
```
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
`mpg` is the short alias for `modern-python-guidance`. Both work.
|
|
40
|
+
|
|
41
|
+
<details>
|
|
42
|
+
<summary>Manual setup / other agents</summary>
|
|
43
|
+
|
|
44
|
+
**MCP registration (Claude Code):**
|
|
31
45
|
```bash
|
|
32
46
|
claude mcp add mpg -- mpg mcp
|
|
33
47
|
```
|
|
@@ -44,29 +58,36 @@ claude mcp add mpg -- mpg mcp
|
|
|
44
58
|
}
|
|
45
59
|
```
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
### CLI
|
|
50
|
-
|
|
61
|
+
**Agent Skills symlink (Claude Code):**
|
|
51
62
|
```bash
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Search for a pattern
|
|
55
|
-
mpg search "pydantic validator"
|
|
56
|
-
|
|
57
|
-
# Get the full guide
|
|
58
|
-
mpg retrieve pydantic-v2-validators
|
|
63
|
+
mpg setup --skills-only
|
|
59
64
|
```
|
|
60
65
|
|
|
61
|
-
|
|
66
|
+
**`mpg setup` flags:**
|
|
67
|
+
| Flag | Purpose |
|
|
68
|
+
|------|---------|
|
|
69
|
+
| `--mcp-only` | MCP registration only |
|
|
70
|
+
| `--skills-only` | Agent Skills symlink only |
|
|
71
|
+
| `--scope {user,local}` | MCP scope (default: user) |
|
|
72
|
+
| `--project-dir PATH` | Target project for Skills symlink |
|
|
73
|
+
| `--dry-run` | Show what would be done |
|
|
62
74
|
|
|
75
|
+
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills):
|
|
63
76
|
```bash
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
ln -s "$SKILL_DIR" your-project/.claude/skills/modern-python-guidance
|
|
77
|
+
mpg uninstall # remove both
|
|
78
|
+
mpg uninstall --dry-run # preview what would be removed
|
|
67
79
|
```
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
| Flag | Purpose |
|
|
82
|
+
|------|---------|
|
|
83
|
+
| `--mcp-only` | MCP deregistration only |
|
|
84
|
+
| `--skills-only` | Agent Skills unlink only |
|
|
85
|
+
| `--project-dir PATH` | Target project for the Skills symlink |
|
|
86
|
+
| `--dry-run` | Show what would be done |
|
|
87
|
+
|
|
88
|
+
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the symlink mpg created (never its target or other skills), and is idempotent — running it on an already-clean state is a harmless no-op.
|
|
89
|
+
|
|
90
|
+
</details>
|
|
70
91
|
|
|
71
92
|
## CLI usage
|
|
72
93
|
|
|
@@ -92,15 +113,15 @@ mpg search "typing" --format json | jq '.[0].id'
|
|
|
92
113
|
|
|
93
114
|
## Guide coverage
|
|
94
115
|
|
|
95
|
-
|
|
116
|
+
41 guides across 3 layers:
|
|
96
117
|
|
|
97
118
|
| Layer | Categories | Count | Examples |
|
|
98
119
|
|-------|-----------|-------|---------|
|
|
99
|
-
| **1 — stdlib** | typing, async, stdlib, data-structures |
|
|
120
|
+
| **1 — stdlib** | typing, async, stdlib, data-structures | 18 | `list` over `List`, `match`/`case`, `TaskGroup`, deferred annotations, t-strings |
|
|
100
121
|
| **2 — frameworks** | pydantic, fastapi, httpx, django, sqlalchemy, pytest | 18 | Pydantic V2 migration, SQLAlchemy 2.0 style, `Annotated[Depends]` |
|
|
101
122
|
| **3 — toolchain** | toolchain | 5 | `uv` over `pip`, `ruff` over flake8, `pickle` avoidance |
|
|
102
123
|
|
|
103
|
-
Run `mpg list` to see all
|
|
124
|
+
Run `mpg list` to see all 41 guides, or [browse them on GitHub](skills/modern-python-guidance/guides/).
|
|
104
125
|
|
|
105
126
|
## Version-aware filtering
|
|
106
127
|
|
|
@@ -52,7 +52,7 @@ LLMs frequently generate outdated Python patterns: `typing.List` instead of `lis
|
|
|
52
52
|
│ typing/ async/ stdlib/ data-structures/ │
|
|
53
53
|
│ pydantic/ fastapi/ httpx/ toolchain/ │
|
|
54
54
|
│ django/ sqlalchemy/ pytest/ │
|
|
55
|
-
│ (
|
|
55
|
+
│ (41 guide files) │
|
|
56
56
|
└─────────────────────────────────────────────────────────┘
|
|
57
57
|
```
|
|
58
58
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "modern-python-guidance"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "Version-aware BAD/GOOD pattern guides that help AI coding agents generate modern Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0 OR MIT"
|
{modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/skills/modern-python-guidance/SKILL.md
RENAMED
|
@@ -55,11 +55,11 @@ Pre-generation design patterns that Ruff cannot auto-fix. Apply these transforma
|
|
|
55
55
|
- `subprocess.run(f"cmd {arg}", shell=True)` → `subprocess.run(["cmd", arg], check=True)`
|
|
56
56
|
- Caveat: `shell=True` is valid when pipes/globs are needed; use `shlex.quote()` for user input
|
|
57
57
|
|
|
58
|
-
## All
|
|
58
|
+
## All 41 guides by category
|
|
59
59
|
|
|
60
|
-
- **typing** (
|
|
60
|
+
- **typing** (7): `use-builtin-generics`, `union-syntax`, `type-parameter-syntax`, `override-decorator`, `typeis-vs-typeguard`, `paramspec-decorators`, `deferred-annotations`
|
|
61
61
|
- **async** (3): `taskgroup-over-gather`, `exception-groups`, `async-timeout-context`
|
|
62
|
-
- **stdlib** (
|
|
62
|
+
- **stdlib** (5): `datetime-utc`, `pathlib-over-os-path`, `tomllib-builtin`, `removeprefix-removesuffix`, `template-strings`
|
|
63
63
|
- **data-structures** (3): `dict-merge-operator`, `match-case-patterns`, `dataclass-modern`
|
|
64
64
|
- **pydantic** (4): `pydantic-v2-validators`, `pydantic-v2-config`, `pydantic-v2-model-api`, `pydantic-v2-serialization`
|
|
65
65
|
- **fastapi** (3): `fastapi-lifespan`, `fastapi-annotated-depends`, `fastapi-typed-state`
|
|
@@ -68,7 +68,7 @@ async def root(request: Request):
|
|
|
68
68
|
|
|
69
69
|
## Version Notes
|
|
70
70
|
|
|
71
|
-
- Works on Python 3.9+ with FastAPI >= 0.
|
|
71
|
+
- Works on Python 3.9+ with FastAPI >= 0.94.0 (lifespan state dict requires Starlette >= 0.26.0)
|
|
72
72
|
- `AsyncIterator` moved from `typing` to `collections.abc` in 3.9
|
|
73
73
|
|
|
74
74
|
## References
|
|
@@ -70,6 +70,11 @@ async def root(request: Request):
|
|
|
70
70
|
- `dataclass` or `TypedDict` documents the expected shape
|
|
71
71
|
- Resource cleanup is guaranteed by the context manager
|
|
72
72
|
|
|
73
|
+
## Version Notes
|
|
74
|
+
|
|
75
|
+
- Lifespan state dict requires FastAPI >= 0.94.0 (Starlette >= 0.26.0)
|
|
76
|
+
- `@dataclass(slots=True)` requires Python 3.10+; use plain `@dataclass` on 3.9
|
|
77
|
+
|
|
73
78
|
## References
|
|
74
79
|
|
|
75
80
|
- [FastAPI Lifespan State](https://fastapi.tiangolo.com/advanced/events/#lifespan-state)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: template-strings
|
|
3
|
+
title: Use Template Strings (t-strings) for Structured String Processing
|
|
4
|
+
category: stdlib
|
|
5
|
+
layer: 1
|
|
6
|
+
tags:
|
|
7
|
+
- strings
|
|
8
|
+
- templates
|
|
9
|
+
- security
|
|
10
|
+
- sql
|
|
11
|
+
aliases:
|
|
12
|
+
- t-string
|
|
13
|
+
- 't"'
|
|
14
|
+
- Template
|
|
15
|
+
- string.templatelib
|
|
16
|
+
python: ">=3.14"
|
|
17
|
+
frequency: medium
|
|
18
|
+
pep: 750
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Use Template Strings for Structured String Processing
|
|
22
|
+
|
|
23
|
+
Python 3.14 introduces t-strings (PEP 750): a `t"..."` prefix that produces a `Template` object instead of a `str`. Pass the `Template` to a processing function that separates literal text from interpolated values, enabling safe parameterization for SQL, HTML, shell commands, and other injection-sensitive contexts.
|
|
24
|
+
|
|
25
|
+
## BAD
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
def query_user(db, user_id: str) -> dict:
|
|
29
|
+
sql = f"SELECT * FROM users WHERE id = '{user_id}'"
|
|
30
|
+
return db.execute(sql).fetchone()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## GOOD
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from string.templatelib import Interpolation
|
|
37
|
+
|
|
38
|
+
def sql(template) -> tuple[str, list]:
|
|
39
|
+
parts, params = [], []
|
|
40
|
+
for item in template:
|
|
41
|
+
if isinstance(item, Interpolation):
|
|
42
|
+
parts.append("?")
|
|
43
|
+
params.append(item.value)
|
|
44
|
+
else:
|
|
45
|
+
parts.append(item)
|
|
46
|
+
return "".join(parts), params
|
|
47
|
+
|
|
48
|
+
def query_user(db, user_id: str) -> dict:
|
|
49
|
+
query, params = sql(t"SELECT * FROM users WHERE id = {user_id}")
|
|
50
|
+
return db.execute(query, params).fetchone()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Why
|
|
54
|
+
|
|
55
|
+
- f-strings produce a final `str` with interpolated values already baked in, making it impossible to distinguish user input from literal SQL after the fact
|
|
56
|
+
- t-strings produce a `Template` that preserves the structure: literal segments as strings, interpolated values as `Interpolation` objects with `value`, `expression`, `conversion`, and `format_spec` attributes
|
|
57
|
+
- A processing function can then route each interpolated value through proper escaping or parameterization, preventing injection by construction
|
|
58
|
+
- t-strings do NOT make strings safe by themselves -- safety comes entirely from the processing function that receives the `Template`
|
|
59
|
+
|
|
60
|
+
## Version Notes
|
|
61
|
+
|
|
62
|
+
- 3.14+: `t"..."` syntax and `string.templatelib` module (`Template`, `Interpolation`)
|
|
63
|
+
- Pre-3.14: Use parameterized queries directly (`db.execute("SELECT ... WHERE id = ?", [user_id])`) or template engines with auto-escaping
|
|
64
|
+
- For simple string formatting where injection is not a concern, f-strings remain the appropriate choice
|
|
65
|
+
- `Template` objects do not render to `str` automatically -- a processing function is always required
|
|
66
|
+
|
|
67
|
+
## References
|
|
68
|
+
|
|
69
|
+
- [PEP 750 -- Template Strings](https://peps.python.org/pep-0750/)
|
|
70
|
+
- [string.templatelib documentation](https://docs.python.org/3/library/string.templatelib.html)
|
modern_python_guidance-0.3.2/skills/modern-python-guidance/guides/typing/deferred-annotations.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: deferred-annotations
|
|
3
|
+
title: 'Drop "from __future__ import annotations" on Python 3.14+'
|
|
4
|
+
category: typing
|
|
5
|
+
layer: 1
|
|
6
|
+
tags:
|
|
7
|
+
- type-hints
|
|
8
|
+
- annotations
|
|
9
|
+
- forward-reference
|
|
10
|
+
aliases:
|
|
11
|
+
- "from __future__ import annotations"
|
|
12
|
+
- "__future__.annotations"
|
|
13
|
+
- ForwardRef
|
|
14
|
+
python: ">=3.14"
|
|
15
|
+
frequency: high
|
|
16
|
+
pep: 649
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Drop `from __future__ import annotations` on Python 3.14+
|
|
20
|
+
|
|
21
|
+
On Python 3.14+, annotations are lazily evaluated by default (PEP 649). The `from __future__ import annotations` import is no longer needed for forward references in 3.14-only projects.
|
|
22
|
+
|
|
23
|
+
## BAD
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
class Tree:
|
|
29
|
+
left: Tree | None = None
|
|
30
|
+
right: Tree | None = None
|
|
31
|
+
|
|
32
|
+
def children(self) -> list[Tree]:
|
|
33
|
+
return [c for c in (self.left, self.right) if c]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## GOOD
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
class Tree:
|
|
40
|
+
left: Tree | None = None
|
|
41
|
+
right: Tree | None = None
|
|
42
|
+
|
|
43
|
+
def children(self) -> list[Tree]:
|
|
44
|
+
return [c for c in (self.left, self.right) if c]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Why
|
|
48
|
+
|
|
49
|
+
- Python 3.14 evaluates annotations lazily by default, so forward references like `Tree` inside the `Tree` class body just work
|
|
50
|
+
- The future import forces all-string semantics (PEP 563), which is different from 3.14's lazy evaluation and can interact poorly with runtime annotation consumers
|
|
51
|
+
- Removing the unnecessary import keeps the module cleaner and avoids the subtle behavioral difference between stringified and lazily-evaluated annotations
|
|
52
|
+
|
|
53
|
+
## Version Notes
|
|
54
|
+
|
|
55
|
+
- 3.14+: Annotations are lazily evaluated by default. Remove `from __future__ import annotations` in 3.14-only projects
|
|
56
|
+
- Pre-3.14: The future import remains the correct way to enable string annotations for forward references
|
|
57
|
+
- `from __future__ import annotations` is deprecated but NOT removed in 3.14. It still works but forces all-string semantics. Removal is not expected before Python 3.13 EOL (~2029)
|
|
58
|
+
- Libraries that read annotations at runtime (`typing.get_type_hints()`, Pydantic, FastAPI, attrs) may need updates for 3.14's lazy evaluation. Verify library compatibility before removing the import in projects that depend on runtime annotation inspection
|
|
59
|
+
|
|
60
|
+
## References
|
|
61
|
+
|
|
62
|
+
- [PEP 649 -- Deferred Evaluation of Annotations Using Descriptors](https://peps.python.org/pep-0649/)
|
|
63
|
+
- [PEP 749 -- Implementing PEP 649](https://peps.python.org/pep-0749/)
|
{modern_python_guidance-0.3.0 → modern_python_guidance-0.3.2}/src/modern_python_guidance/cli.py
RENAMED
|
@@ -65,6 +65,32 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
65
65
|
# mcp
|
|
66
66
|
subparsers.add_parser("mcp", help="Start MCP server (JSON-RPC over stdio)")
|
|
67
67
|
|
|
68
|
+
# setup
|
|
69
|
+
p_setup = subparsers.add_parser(
|
|
70
|
+
"setup", help="Register MCP server and link Agent Skills",
|
|
71
|
+
)
|
|
72
|
+
p_setup.add_argument("--mcp-only", action="store_true", help="MCP registration only")
|
|
73
|
+
p_setup.add_argument("--skills-only", action="store_true", help="Skills symlink only")
|
|
74
|
+
p_setup.add_argument(
|
|
75
|
+
"--scope", choices=["user", "local"], default="user",
|
|
76
|
+
help="MCP scope (default: user)",
|
|
77
|
+
)
|
|
78
|
+
p_setup.add_argument(
|
|
79
|
+
"--project-dir", type=Path, help="Project directory for Skills symlink",
|
|
80
|
+
)
|
|
81
|
+
p_setup.add_argument("--dry-run", action="store_true", help="Show what would be done")
|
|
82
|
+
|
|
83
|
+
# uninstall
|
|
84
|
+
p_uninstall = subparsers.add_parser(
|
|
85
|
+
"uninstall", help="Reverse 'setup': deregister MCP server and unlink Agent Skills",
|
|
86
|
+
)
|
|
87
|
+
p_uninstall.add_argument("--mcp-only", action="store_true", help="MCP deregistration only")
|
|
88
|
+
p_uninstall.add_argument("--skills-only", action="store_true", help="Skills unlink only")
|
|
89
|
+
p_uninstall.add_argument(
|
|
90
|
+
"--project-dir", type=Path, help="Project directory for Skills symlink",
|
|
91
|
+
)
|
|
92
|
+
p_uninstall.add_argument("--dry-run", action="store_true", help="Show what would be done")
|
|
93
|
+
|
|
68
94
|
args = parser.parse_args(argv)
|
|
69
95
|
|
|
70
96
|
if args.command is None:
|
|
@@ -86,6 +112,10 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
86
112
|
_cmd_detect_version(args)
|
|
87
113
|
elif args.command == "mcp":
|
|
88
114
|
_cmd_mcp()
|
|
115
|
+
elif args.command == "setup":
|
|
116
|
+
_cmd_setup(args)
|
|
117
|
+
elif args.command == "uninstall":
|
|
118
|
+
_cmd_uninstall(args)
|
|
89
119
|
except BrokenPipeError:
|
|
90
120
|
sys.exit(0)
|
|
91
121
|
|
|
@@ -215,3 +245,28 @@ def _cmd_mcp() -> None:
|
|
|
215
245
|
from modern_python_guidance.mcp_server import serve
|
|
216
246
|
|
|
217
247
|
serve()
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _cmd_setup(args: argparse.Namespace) -> None:
|
|
251
|
+
from modern_python_guidance.setup_cmd import run_setup
|
|
252
|
+
|
|
253
|
+
code = run_setup(
|
|
254
|
+
scope=args.scope,
|
|
255
|
+
mcp_only=args.mcp_only,
|
|
256
|
+
skills_only=args.skills_only,
|
|
257
|
+
project_dir=args.project_dir,
|
|
258
|
+
dry_run=args.dry_run,
|
|
259
|
+
)
|
|
260
|
+
sys.exit(code)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _cmd_uninstall(args: argparse.Namespace) -> None:
|
|
264
|
+
from modern_python_guidance.uninstall_cmd import run_uninstall
|
|
265
|
+
|
|
266
|
+
code = run_uninstall(
|
|
267
|
+
mcp_only=args.mcp_only,
|
|
268
|
+
skills_only=args.skills_only,
|
|
269
|
+
project_dir=args.project_dir,
|
|
270
|
+
dry_run=args.dry_run,
|
|
271
|
+
)
|
|
272
|
+
sys.exit(code)
|
|
@@ -121,8 +121,8 @@ TOOLS = [
|
|
|
121
121
|
"guide_ids": {
|
|
122
122
|
"type": "array",
|
|
123
123
|
"items": {"type": "string"},
|
|
124
|
-
"description": "Guide IDs to retrieve (max
|
|
125
|
-
"maxItems":
|
|
124
|
+
"description": "Guide IDs to retrieve (max 41)",
|
|
125
|
+
"maxItems": 41,
|
|
126
126
|
},
|
|
127
127
|
"python_version": {
|
|
128
128
|
"type": "string",
|
|
@@ -269,8 +269,8 @@ def _tool_retrieve(arguments: dict) -> dict:
|
|
|
269
269
|
guide_ids = arguments.get("guide_ids", [])
|
|
270
270
|
if not guide_ids:
|
|
271
271
|
return _tool_result("guide_ids is required and must not be empty", is_error=True)
|
|
272
|
-
if len(guide_ids) >
|
|
273
|
-
return _tool_result("guide_ids exceeds maximum of
|
|
272
|
+
if len(guide_ids) > 41:
|
|
273
|
+
return _tool_result("guide_ids exceeds maximum of 41", is_error=True)
|
|
274
274
|
|
|
275
275
|
pv = arguments.get("python_version")
|
|
276
276
|
err = _validate_python_version(pv)
|