modern-python-guidance 0.3.4__tar.gz → 0.3.6__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.4 → modern_python_guidance-0.3.6}/.github/workflows/ci.yml +5 -2
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/CHANGELOG.md +30 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/CONTRIBUTING.md +15 -3
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/PKG-INFO +12 -11
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/README.md +10 -10
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/score_v5.py +6 -3
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/pyproject.toml +18 -2
- modern_python_guidance-0.3.6/rules/modern-python.md +70 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/__init__.py +1 -1
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/cli.py +30 -10
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/frontmatter.py +1 -3
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/mcp_server.py +8 -5
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/search.py +25 -17
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/setup_cmd.py +106 -2
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/uninstall_cmd.py +49 -2
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/version_detect.py +2 -6
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_cli_integration.py +27 -5
- modern_python_guidance-0.3.6/tests/test_guide_structure.py +180 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_mcp_server.py +157 -70
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_retrieve.py +10 -2
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_search.py +6 -23
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_setup.py +205 -43
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_skill_sync.py +2 -6
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_uninstall.py +117 -35
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_version_detect.py +6 -18
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/.github/workflows/check-python-release.yml +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/.github/workflows/publish.yml +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/.gitignore +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/LICENSE +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/LICENSE-MIT +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/SECURITY.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/edge-cases/opus48_multiline.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/edge-cases/valid_alt_patterns.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/pyproject.toml +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/app.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/config.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/crawler.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/models.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/scanner.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-modern/src/utils.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/pyproject.toml +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/setup.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/app.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/config.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/crawler.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/models.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/scanner.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-a-outdated/src/utils.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-b-modern/myapp/models.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-b-modern/myapp/views.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-b-outdated/myapp/models.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-b-outdated/myapp/views.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-c-modern/tests/test_calculator.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/fixtures/variant-c-outdated/tests/test_calculator.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/mcp-config.json +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v2.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v3-mcp.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v3.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v4-a.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v4-b.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt-v4-c.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompt.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-a-detailed.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-a-normal.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-a-terse.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-b-detailed.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-b-normal.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-b-terse.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-c-detailed.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-c-normal.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/prompts/v5-c-terse.txt +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/run-mcp.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/run-v4.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/run-v5.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/run.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/score-v2.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/score-v3.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/score-v4.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/score.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/bench/test-scorer.sh +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/docs/benchmark-evaluation.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/docs/benchmark-procedure.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/docs/benchmark-v5.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/docs/design.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/SKILL.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/async/async-timeout-context.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/async/exception-groups.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/async/taskgroup-over-gather.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/data-structures/dataclass-modern.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/data-structures/dict-merge-operator.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/data-structures/match-case-patterns.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/django/django-async-views.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/django/django-check-constraints.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/django/django-json-field.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/fastapi/fastapi-annotated-depends.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/fastapi/fastapi-lifespan.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/fastapi/fastapi-typed-state.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/httpx/httpx-async-client-reuse.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/httpx/httpx-streaming.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-config.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-model-api.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-serialization.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pydantic/pydantic-v2-validators.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pytest/pytest-parametrize.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pytest/pytest-raises-match.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/pytest/pytest-tmp-path.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-2-style.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-async-session.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/sqlalchemy/sqlalchemy-mapped-column.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/stdlib/datetime-utc.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/stdlib/pathlib-over-os-path.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/stdlib/removeprefix-removesuffix.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/stdlib/template-strings.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/stdlib/tomllib-builtin.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/toolchain/no-pickle.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/toolchain/pyproject-toml-over-setup.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/toolchain/ruff-over-flake8.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/toolchain/safe-subprocess.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/toolchain/uv-over-pip.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/deferred-annotations.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/override-decorator.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/paramspec-decorators.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/type-parameter-syntax.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/typeis-vs-typeguard.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/union-syntax.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/skills/modern-python-guidance/guides/typing/use-builtin-generics.md +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/__main__.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/compat.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/guide_index.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/retrieve.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_frontmatter.py +0 -0
- {modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/tests/test_scorer_v5.py +0 -0
|
@@ -30,8 +30,11 @@ jobs:
|
|
|
30
30
|
- name: Install dependencies
|
|
31
31
|
run: uv pip install --system -e ".[dev]"
|
|
32
32
|
|
|
33
|
-
- name:
|
|
34
|
-
run:
|
|
33
|
+
- name: Check formatting
|
|
34
|
+
run: ruff format --check src/ tests/
|
|
35
35
|
|
|
36
36
|
- name: Run linter
|
|
37
37
|
run: ruff check src/ tests/
|
|
38
|
+
|
|
39
|
+
- name: Run tests
|
|
40
|
+
run: pytest --tb=short -q --cov --cov-report=term-missing
|
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.3.6] — 2026-05-31
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Rule-based delivery via symlink: `mpg setup` creates `.claude/rules/modern-python.md` that auto-injects modern Python guidance whenever Python-related files are touched, replacing reliance on probabilistic skill matching (closes #79)
|
|
10
|
+
- `setup_rules()` / `uninstall_rules()` mirroring skills symlink pattern
|
|
11
|
+
- `source.is_symlink()` security check to refuse symlink-to-symlink chains
|
|
12
|
+
- CI sync test enforcing SKILL.md body == rule body consistency
|
|
13
|
+
- 21 new tests (V-037 to V-060) for setup, uninstall, CI sync, and security
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- `--skills-only` now includes Rules (both are project-local artifacts)
|
|
18
|
+
- README updated to document 4 delivery methods (was 3)
|
|
19
|
+
- `--project-dir` help text updated to mention Skills/Rules symlinks
|
|
20
|
+
|
|
21
|
+
## [0.3.5] — 2026-05-30
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- CI format gate: `ruff format --check src/ tests/` runs before linter, catching formatting regressions at PR time (closes #19)
|
|
26
|
+
- Coverage reporting: `pytest-cov` with branch coverage and `fail_under = 59%` ratchet threshold (closes #15)
|
|
27
|
+
- Guide structure validation: 248 parametrized tests validating all 41 guides — frontmatter fields, section order, code fences, H1 title, no duplicate IDs (closes #16)
|
|
28
|
+
- CONTRIBUTING.md: documented CI checks, format fix command, and guide count update step
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Auto-formatted 12 existing source/test files with `ruff format` (whitespace only, no logic changes)
|
|
33
|
+
- CI step order: checkout → setup → install → **format check** → linter → tests (with `--cov`)
|
|
34
|
+
|
|
5
35
|
## [0.3.4] — 2026-05-30
|
|
6
36
|
|
|
7
37
|
### Fixed
|
|
@@ -37,13 +37,25 @@ See [docs/design.md](docs/design.md) for the full design document.
|
|
|
37
37
|
| `frequency` | string | `high` (LLMs do this often), `medium`, `low` |
|
|
38
38
|
|
|
39
39
|
3. Write BAD/GOOD/Why/Version Notes sections
|
|
40
|
-
4.
|
|
40
|
+
4. Update `EXPECTED_GUIDE_COUNT` in `tests/test_guide_structure.py`
|
|
41
|
+
5. Run `pytest` — the guide structure tests validate frontmatter, section order, and code fences automatically
|
|
41
42
|
|
|
42
43
|
## Running tests
|
|
43
44
|
|
|
44
45
|
```bash
|
|
45
46
|
uv venv && source .venv/bin/activate
|
|
46
47
|
uv pip install -e ".[dev]"
|
|
47
|
-
pytest
|
|
48
|
-
ruff check src/ tests/
|
|
48
|
+
pytest # 510+ tests including guide structure validation
|
|
49
|
+
ruff check src/ tests/ # lint
|
|
50
|
+
ruff format --check src/ tests/ # format check (CI enforced)
|
|
49
51
|
```
|
|
52
|
+
|
|
53
|
+
To auto-fix formatting: `ruff format src/ tests/`
|
|
54
|
+
|
|
55
|
+
## CI checks
|
|
56
|
+
|
|
57
|
+
All PRs run these checks on Python 3.11, 3.12, and 3.13:
|
|
58
|
+
|
|
59
|
+
1. `ruff format --check` — formatting
|
|
60
|
+
2. `ruff check` — linting
|
|
61
|
+
3. `pytest --cov` — tests with branch coverage (`fail_under = 59%`)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modern-python-guidance
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
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
|
|
@@ -25,6 +25,7 @@ Classifier: Typing :: Typed
|
|
|
25
25
|
Requires-Python: >=3.11
|
|
26
26
|
Requires-Dist: packaging>=23.0
|
|
27
27
|
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
28
29
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
30
|
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
@@ -43,7 +44,7 @@ Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 41 versio
|
|
|
43
44
|
- **Measurable impact**: AI writes modern Python 98% of the time with mpg, vs 79% without — even with vague prompts (Opus 4.8, [V5 benchmark details](docs/benchmark-v5.md))
|
|
44
45
|
- **41 guides** across stdlib, Pydantic, FastAPI, Django, SQLAlchemy, pytest, and toolchain
|
|
45
46
|
- **Version-aware**: auto-detects your project's Python version and filters guides accordingly
|
|
46
|
-
- **
|
|
47
|
+
- **4 delivery methods**: MCP server, CLI, Agent Skills, and Rules (auto-injects on `.py` file touch)
|
|
47
48
|
- **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
|
|
48
49
|
|
|
49
50
|
> **Note:** The tool itself requires Python 3.11+ to run. Guides cover patterns from Python 3.9 onward, and `--python-version` filters guides for your target environment.
|
|
@@ -57,7 +58,7 @@ pip install modern-python-guidance
|
|
|
57
58
|
mpg setup
|
|
58
59
|
```
|
|
59
60
|
|
|
60
|
-
This registers the MCP server
|
|
61
|
+
This registers the MCP server, links Agent Skills, and creates a Rules file (`.claude/rules/modern-python.md`) in one command. The Rules file auto-injects modern Python guidance whenever you touch Python-related files. Start a new Claude Code session afterwards — newly registered MCP servers, skills, and rules take effect on the next launch.
|
|
61
62
|
|
|
62
63
|
### CLI
|
|
63
64
|
|
|
@@ -89,7 +90,7 @@ claude mcp add mpg -- mpg mcp
|
|
|
89
90
|
}
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
**Agent Skills
|
|
93
|
+
**Agent Skills + Rules only (Claude Code):**
|
|
93
94
|
```bash
|
|
94
95
|
mpg setup --skills-only
|
|
95
96
|
```
|
|
@@ -98,25 +99,25 @@ mpg setup --skills-only
|
|
|
98
99
|
| Flag | Purpose |
|
|
99
100
|
|------|---------|
|
|
100
101
|
| `--mcp-only` | MCP registration only |
|
|
101
|
-
| `--skills-only` |
|
|
102
|
+
| `--skills-only` | Project-local artifacts only (Skills + Rules) |
|
|
102
103
|
| `--scope {user,local}` | MCP scope (default: user) |
|
|
103
|
-
| `--project-dir PATH` | Target project for Skills
|
|
104
|
+
| `--project-dir PATH` | Target project for Skills/Rules symlinks |
|
|
104
105
|
| `--dry-run` | Show what would be done |
|
|
105
106
|
|
|
106
|
-
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills):
|
|
107
|
+
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills + Rules):
|
|
107
108
|
```bash
|
|
108
|
-
mpg uninstall # remove
|
|
109
|
+
mpg uninstall # remove all
|
|
109
110
|
mpg uninstall --dry-run # preview what would be removed
|
|
110
111
|
```
|
|
111
112
|
|
|
112
113
|
| Flag | Purpose |
|
|
113
114
|
|------|---------|
|
|
114
115
|
| `--mcp-only` | MCP deregistration only |
|
|
115
|
-
| `--skills-only` |
|
|
116
|
-
| `--project-dir PATH` | Target project for
|
|
116
|
+
| `--skills-only` | Project-local artifacts only (Skills + Rules) |
|
|
117
|
+
| `--project-dir PATH` | Target project for Skills/Rules symlinks |
|
|
117
118
|
| `--dry-run` | Show what would be done |
|
|
118
119
|
|
|
119
|
-
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the
|
|
120
|
+
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the symlinks mpg created (never their targets or other files), and is idempotent — running it on an already-clean state is a harmless no-op.
|
|
120
121
|
|
|
121
122
|
</details>
|
|
122
123
|
|
|
@@ -12,7 +12,7 @@ Stop your AI from writing `typing.List`, `@validator`, and `setup.py`. 41 versio
|
|
|
12
12
|
- **Measurable impact**: AI writes modern Python 98% of the time with mpg, vs 79% without — even with vague prompts (Opus 4.8, [V5 benchmark details](docs/benchmark-v5.md))
|
|
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
|
+
- **4 delivery methods**: MCP server, CLI, Agent Skills, and Rules (auto-injects on `.py` file touch)
|
|
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
|
|
17
17
|
|
|
18
18
|
> **Note:** The tool itself requires Python 3.11+ to run. Guides cover patterns from Python 3.9 onward, and `--python-version` filters guides for your target environment.
|
|
@@ -26,7 +26,7 @@ pip install modern-python-guidance
|
|
|
26
26
|
mpg setup
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
This registers the MCP server
|
|
29
|
+
This registers the MCP server, links Agent Skills, and creates a Rules file (`.claude/rules/modern-python.md`) in one command. The Rules file auto-injects modern Python guidance whenever you touch Python-related files. Start a new Claude Code session afterwards — newly registered MCP servers, skills, and rules take effect on the next launch.
|
|
30
30
|
|
|
31
31
|
### CLI
|
|
32
32
|
|
|
@@ -58,7 +58,7 @@ claude mcp add mpg -- mpg mcp
|
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
**Agent Skills
|
|
61
|
+
**Agent Skills + Rules only (Claude Code):**
|
|
62
62
|
```bash
|
|
63
63
|
mpg setup --skills-only
|
|
64
64
|
```
|
|
@@ -67,25 +67,25 @@ mpg setup --skills-only
|
|
|
67
67
|
| Flag | Purpose |
|
|
68
68
|
|------|---------|
|
|
69
69
|
| `--mcp-only` | MCP registration only |
|
|
70
|
-
| `--skills-only` |
|
|
70
|
+
| `--skills-only` | Project-local artifacts only (Skills + Rules) |
|
|
71
71
|
| `--scope {user,local}` | MCP scope (default: user) |
|
|
72
|
-
| `--project-dir PATH` | Target project for Skills
|
|
72
|
+
| `--project-dir PATH` | Target project for Skills/Rules symlinks |
|
|
73
73
|
| `--dry-run` | Show what would be done |
|
|
74
74
|
|
|
75
|
-
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills):
|
|
75
|
+
**Uninstall** — reverse `mpg setup` (deregister the MCP server and unlink Agent Skills + Rules):
|
|
76
76
|
```bash
|
|
77
|
-
mpg uninstall # remove
|
|
77
|
+
mpg uninstall # remove all
|
|
78
78
|
mpg uninstall --dry-run # preview what would be removed
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
| Flag | Purpose |
|
|
82
82
|
|------|---------|
|
|
83
83
|
| `--mcp-only` | MCP deregistration only |
|
|
84
|
-
| `--skills-only` |
|
|
85
|
-
| `--project-dir PATH` | Target project for
|
|
84
|
+
| `--skills-only` | Project-local artifacts only (Skills + Rules) |
|
|
85
|
+
| `--project-dir PATH` | Target project for Skills/Rules symlinks |
|
|
86
86
|
| `--dry-run` | Show what would be done |
|
|
87
87
|
|
|
88
|
-
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the
|
|
88
|
+
`mpg uninstall` clears the MCP registration from every scope `setup` can write to (user and local), removes only the symlinks mpg created (never their targets or other files), and is idempotent — running it on an already-clean state is a harmless no-op.
|
|
89
89
|
|
|
90
90
|
</details>
|
|
91
91
|
|
|
@@ -1476,14 +1476,17 @@ def main() -> None:
|
|
|
1476
1476
|
"c": "C (pytest)",
|
|
1477
1477
|
}
|
|
1478
1478
|
v_label = variant_labels.get(args.variant, args.variant)
|
|
1479
|
-
|
|
1480
|
-
|
|
1479
|
+
|
|
1480
|
+
if args.output_format == "human":
|
|
1481
|
+
print(f"=== V5 Scoring: Variant {v_label}, Run {args.run_id} ===")
|
|
1482
|
+
print()
|
|
1481
1483
|
|
|
1482
1484
|
output = {}
|
|
1483
1485
|
for session_name in ("control", "treatment"):
|
|
1484
1486
|
session_dir = results_dir / session_name
|
|
1485
1487
|
if not session_dir.is_dir():
|
|
1486
|
-
|
|
1488
|
+
if args.output_format == "human":
|
|
1489
|
+
print(f" [{session_name}] Directory not found, skipping.")
|
|
1487
1490
|
continue
|
|
1488
1491
|
data = score_session(session_dir, args.variant)
|
|
1489
1492
|
output[session_name] = data
|
|
@@ -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.6"
|
|
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"
|
|
@@ -34,6 +34,7 @@ dependencies = [
|
|
|
34
34
|
[project.optional-dependencies]
|
|
35
35
|
dev = [
|
|
36
36
|
"pytest>=7.0",
|
|
37
|
+
"pytest-cov>=4.0",
|
|
37
38
|
"ruff>=0.4.0",
|
|
38
39
|
]
|
|
39
40
|
|
|
@@ -48,11 +49,12 @@ Issues = "https://github.com/yottayoshida/modern-python-guidance/issues"
|
|
|
48
49
|
|
|
49
50
|
[tool.hatch.build.targets.wheel]
|
|
50
51
|
packages = ["src/modern_python_guidance"]
|
|
51
|
-
only-include = ["src/modern_python_guidance", "skills"]
|
|
52
|
+
only-include = ["src/modern_python_guidance", "skills", "rules"]
|
|
52
53
|
|
|
53
54
|
[tool.hatch.build.targets.wheel.sources]
|
|
54
55
|
"src" = ""
|
|
55
56
|
"skills" = "modern_python_guidance/skills"
|
|
57
|
+
"rules" = "modern_python_guidance/rules"
|
|
56
58
|
|
|
57
59
|
[tool.ruff]
|
|
58
60
|
target-version = "py311"
|
|
@@ -66,3 +68,17 @@ select = ["E", "F", "W", "I", "UP", "FURB", "B", "SIM", "RUF"]
|
|
|
66
68
|
|
|
67
69
|
[tool.pytest.ini_options]
|
|
68
70
|
testpaths = ["tests"]
|
|
71
|
+
|
|
72
|
+
[tool.coverage.run]
|
|
73
|
+
source = ["modern_python_guidance"]
|
|
74
|
+
branch = true
|
|
75
|
+
|
|
76
|
+
[tool.coverage.report]
|
|
77
|
+
show_missing = true
|
|
78
|
+
skip_empty = true
|
|
79
|
+
fail_under = 59
|
|
80
|
+
exclude_lines = [
|
|
81
|
+
"pragma: no cover",
|
|
82
|
+
"if __name__ == .__main__.",
|
|
83
|
+
"if TYPE_CHECKING:",
|
|
84
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths: ["**/*.py", "*.py", "**/pyproject.toml", "**/requirements*.txt", "**/setup.py", "**/setup.cfg", "**/.python-version", "**/Pipfile"]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Modern Python Guidance
|
|
6
|
+
|
|
7
|
+
Pre-generation design patterns that Ruff cannot auto-fix. Apply these transformations when writing or reviewing Python code.
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- Writing new Python code (use modern patterns from the start)
|
|
12
|
+
- Reviewing Python code (flag outdated patterns)
|
|
13
|
+
- Migrating from Pydantic V1 to V2
|
|
14
|
+
- Upgrading Python version (check which new features are available)
|
|
15
|
+
- Replacing legacy tooling (setup.py, flake8, pip)
|
|
16
|
+
|
|
17
|
+
## Embedded patterns (high-frequency, Ruff-uncovered)
|
|
18
|
+
|
|
19
|
+
### Pydantic V2 (>=3.9)
|
|
20
|
+
|
|
21
|
+
- `@validator("f")` → `@field_validator("f")`
|
|
22
|
+
- `@root_validator` → `@model_validator(mode="after")`
|
|
23
|
+
- `class Config:` → `model_config = ConfigDict(...)`
|
|
24
|
+
- `orm_mode` → `from_attributes`, `allow_population_by_field_name` → `populate_by_name`
|
|
25
|
+
- `.parse_obj(d)` → `.model_validate(d)`, `.parse_raw(j)` → `.model_validate_json(j)`
|
|
26
|
+
- `.dict()` → `.model_dump()`, `.json()` → `.model_dump_json()`
|
|
27
|
+
- `.schema()` → `.model_json_schema()`, `.copy()` → `.model_copy()`
|
|
28
|
+
|
|
29
|
+
### FastAPI (>=3.9)
|
|
30
|
+
|
|
31
|
+
- `@app.on_event("startup")`/`"shutdown"` → `@asynccontextmanager` lifespan + `FastAPI(lifespan=lifespan)`; yield dict becomes `request.state`
|
|
32
|
+
- `db: Session = Depends(get_db)` → `DbDep = Annotated[Session, Depends(get_db)]`; reusable type alias per PEP 593
|
|
33
|
+
|
|
34
|
+
### httpx
|
|
35
|
+
|
|
36
|
+
- Per-request `async with httpx.AsyncClient()` → shared `AsyncClient` with `base_url`
|
|
37
|
+
- Caveat: shared client must be closed via `async with` or lifespan management
|
|
38
|
+
|
|
39
|
+
### asyncio (>=3.11)
|
|
40
|
+
|
|
41
|
+
- `await asyncio.gather(a(), b())` → `async with asyncio.TaskGroup() as tg:` + `tg.create_task()`; access results via `task.result()`
|
|
42
|
+
- Caveat: 3.11+ only. `TaskGroup` cancels siblings on error and raises `ExceptionGroup`; `gather` preserves return order and supports `return_exceptions=True`
|
|
43
|
+
|
|
44
|
+
### SQLAlchemy 2.0 (>=3.9)
|
|
45
|
+
|
|
46
|
+
- `session.query(User).filter()` → `session.execute(select(User).where())`; use `session.scalars()` for ORM results
|
|
47
|
+
- `Column(Integer)` → `Mapped[int] = mapped_column()`; type inferred from annotation, nullability from `Optional`/`| None`
|
|
48
|
+
- Sync `Session` with `asyncio.to_thread` → `AsyncSession` + `create_async_engine` + `async_sessionmaker`
|
|
49
|
+
|
|
50
|
+
### Toolchain
|
|
51
|
+
|
|
52
|
+
- `setup.py` / `setup.cfg` → `pyproject.toml` with `[build-system]` + `[project]` (PEP 621)
|
|
53
|
+
- `subprocess.run(f"cmd {arg}", shell=True)` → `subprocess.run(["cmd", arg], check=True)`
|
|
54
|
+
- Caveat: `shell=True` is valid when pipes/globs are needed; use `shlex.quote()` for user input
|
|
55
|
+
|
|
56
|
+
## All 41 guides by category
|
|
57
|
+
|
|
58
|
+
- **typing** (7): `use-builtin-generics`, `union-syntax`, `type-parameter-syntax`, `override-decorator`, `typeis-vs-typeguard`, `paramspec-decorators`, `deferred-annotations`
|
|
59
|
+
- **async** (3): `taskgroup-over-gather`, `exception-groups`, `async-timeout-context`
|
|
60
|
+
- **stdlib** (5): `datetime-utc`, `pathlib-over-os-path`, `tomllib-builtin`, `removeprefix-removesuffix`, `template-strings`
|
|
61
|
+
- **data-structures** (3): `dict-merge-operator`, `match-case-patterns`, `dataclass-modern`
|
|
62
|
+
- **pydantic** (4): `pydantic-v2-validators`, `pydantic-v2-config`, `pydantic-v2-model-api`, `pydantic-v2-serialization`
|
|
63
|
+
- **fastapi** (3): `fastapi-lifespan`, `fastapi-annotated-depends`, `fastapi-typed-state`
|
|
64
|
+
- **httpx** (2): `httpx-async-client-reuse`, `httpx-streaming`
|
|
65
|
+
- **django** (3): `django-json-field`, `django-async-views`, `django-check-constraints`
|
|
66
|
+
- **sqlalchemy** (3): `sqlalchemy-2-style`, `sqlalchemy-mapped-column`, `sqlalchemy-async-session`
|
|
67
|
+
- **pytest** (3): `pytest-parametrize`, `pytest-tmp-path`, `pytest-raises-match`
|
|
68
|
+
- **toolchain** (5): `pyproject-toml-over-setup`, `uv-over-pip`, `ruff-over-flake8`, `no-pickle`, `safe-subprocess`
|
|
69
|
+
|
|
70
|
+
For full code examples, use `mpg retrieve <guide-id>` or MCP tool `retrieve_guides`.
|
{modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/cli.py
RENAMED
|
@@ -36,7 +36,9 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
36
36
|
p_search.add_argument("--category", help="Filter by category")
|
|
37
37
|
p_search.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
38
38
|
p_search.add_argument(
|
|
39
|
-
"--format",
|
|
39
|
+
"--format",
|
|
40
|
+
choices=["json", "human"],
|
|
41
|
+
default=None,
|
|
40
42
|
help="Output format (default: json when piped, human when TTY)",
|
|
41
43
|
)
|
|
42
44
|
|
|
@@ -45,7 +47,9 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
45
47
|
p_retrieve.add_argument("ids", help="Comma-separated guide IDs")
|
|
46
48
|
p_retrieve.add_argument("--python-version", help="Target Python version")
|
|
47
49
|
p_retrieve.add_argument(
|
|
48
|
-
"--format",
|
|
50
|
+
"--format",
|
|
51
|
+
choices=["json", "human"],
|
|
52
|
+
default=None,
|
|
49
53
|
help="Output format (default: json when piped, human when TTY)",
|
|
50
54
|
)
|
|
51
55
|
|
|
@@ -54,7 +58,9 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
54
58
|
p_list.add_argument("--category", help="Filter by category")
|
|
55
59
|
p_list.add_argument("--python-version", help="Filter by Python version")
|
|
56
60
|
p_list.add_argument(
|
|
57
|
-
"--format",
|
|
61
|
+
"--format",
|
|
62
|
+
choices=["json", "human"],
|
|
63
|
+
default=None,
|
|
58
64
|
help="Output format (default: json when piped, human when TTY)",
|
|
59
65
|
)
|
|
60
66
|
|
|
@@ -67,27 +73,41 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
67
73
|
|
|
68
74
|
# setup
|
|
69
75
|
p_setup = subparsers.add_parser(
|
|
70
|
-
"setup",
|
|
76
|
+
"setup",
|
|
77
|
+
help="Register MCP server and link Agent Skills + Rules",
|
|
71
78
|
)
|
|
72
79
|
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
80
|
p_setup.add_argument(
|
|
75
|
-
"--
|
|
81
|
+
"--skills-only", action="store_true", help="Project-local artifacts only (Skills + Rules)"
|
|
82
|
+
)
|
|
83
|
+
p_setup.add_argument(
|
|
84
|
+
"--scope",
|
|
85
|
+
choices=["user", "local"],
|
|
86
|
+
default="user",
|
|
76
87
|
help="MCP scope (default: user)",
|
|
77
88
|
)
|
|
78
89
|
p_setup.add_argument(
|
|
79
|
-
"--project-dir",
|
|
90
|
+
"--project-dir",
|
|
91
|
+
type=Path,
|
|
92
|
+
help="Project directory for Skills/Rules symlinks",
|
|
80
93
|
)
|
|
81
94
|
p_setup.add_argument("--dry-run", action="store_true", help="Show what would be done")
|
|
82
95
|
|
|
83
96
|
# uninstall
|
|
84
97
|
p_uninstall = subparsers.add_parser(
|
|
85
|
-
"uninstall",
|
|
98
|
+
"uninstall",
|
|
99
|
+
help="Reverse 'setup': deregister MCP server and unlink Agent Skills + Rules",
|
|
86
100
|
)
|
|
87
101
|
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
102
|
p_uninstall.add_argument(
|
|
90
|
-
"--
|
|
103
|
+
"--skills-only",
|
|
104
|
+
action="store_true",
|
|
105
|
+
help="Project-local artifacts only (Skills + Rules)",
|
|
106
|
+
)
|
|
107
|
+
p_uninstall.add_argument(
|
|
108
|
+
"--project-dir",
|
|
109
|
+
type=Path,
|
|
110
|
+
help="Project directory for Skills/Rules symlinks",
|
|
91
111
|
)
|
|
92
112
|
p_uninstall.add_argument("--dry-run", action="store_true", help="Show what would be done")
|
|
93
113
|
|
|
@@ -75,9 +75,7 @@ def _parse_raw(lines: list[str]) -> dict[str, Any]:
|
|
|
75
75
|
if current_key is None:
|
|
76
76
|
raise FrontmatterError("list item without preceding key", line=i)
|
|
77
77
|
if not isinstance(data[current_key], list):
|
|
78
|
-
raise FrontmatterError(
|
|
79
|
-
f"list item for non-list key '{current_key}'", line=i
|
|
80
|
-
)
|
|
78
|
+
raise FrontmatterError(f"list item for non-list key '{current_key}'", line=i)
|
|
81
79
|
data[current_key].append(_parse_scalar(list_match.group(1).strip()))
|
|
82
80
|
continue
|
|
83
81
|
|
|
@@ -340,11 +340,14 @@ def _handle_request(msg: dict) -> dict | None:
|
|
|
340
340
|
return None
|
|
341
341
|
|
|
342
342
|
if method == "initialize":
|
|
343
|
-
result = _result_response(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
343
|
+
result = _result_response(
|
|
344
|
+
req_id,
|
|
345
|
+
{
|
|
346
|
+
"protocolVersion": PROTOCOL_VERSION,
|
|
347
|
+
"capabilities": {"tools": {}},
|
|
348
|
+
"serverInfo": {"name": "modern-python-guidance", "version": __version__},
|
|
349
|
+
},
|
|
350
|
+
)
|
|
348
351
|
return None if is_notification else result
|
|
349
352
|
|
|
350
353
|
if method == "tools/list":
|
{modern_python_guidance-0.3.4 → modern_python_guidance-0.3.6}/src/modern_python_guidance/search.py
RENAMED
|
@@ -60,19 +60,25 @@ def search(
|
|
|
60
60
|
|
|
61
61
|
if score > 0:
|
|
62
62
|
score += FREQ_BOOST.get(meta.frequency, 0.0)
|
|
63
|
-
results.append(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
results.append(
|
|
64
|
+
SearchResult(
|
|
65
|
+
guide_id=guide_id,
|
|
66
|
+
score=score,
|
|
67
|
+
meta=meta,
|
|
68
|
+
token_estimate=token_estimate(guide.body),
|
|
69
|
+
snippet=guide.snippet,
|
|
70
|
+
)
|
|
71
|
+
)
|
|
70
72
|
|
|
71
73
|
results.sort(key=lambda r: (-r.score, r.guide_id))
|
|
72
74
|
|
|
73
75
|
if not results:
|
|
74
76
|
return _fuzzy_fallback(
|
|
75
|
-
index,
|
|
77
|
+
index,
|
|
78
|
+
query,
|
|
79
|
+
python_version=python_version,
|
|
80
|
+
category=category,
|
|
81
|
+
limit=limit,
|
|
76
82
|
)
|
|
77
83
|
|
|
78
84
|
return results[:limit]
|
|
@@ -139,14 +145,16 @@ def _fuzzy_fallback(
|
|
|
139
145
|
continue
|
|
140
146
|
seen.add(guide_id)
|
|
141
147
|
guide = candidates[guide_id]
|
|
142
|
-
results.append(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
results.append(
|
|
149
|
+
SearchResult(
|
|
150
|
+
guide_id=guide_id,
|
|
151
|
+
score=round(ratio, 3),
|
|
152
|
+
meta=guide.meta,
|
|
153
|
+
token_estimate=token_estimate(guide.body),
|
|
154
|
+
fuzzy=True,
|
|
155
|
+
snippet=guide.snippet,
|
|
156
|
+
)
|
|
157
|
+
)
|
|
150
158
|
|
|
151
159
|
results.sort(key=lambda r: (-r.score, r.guide_id))
|
|
152
|
-
return results[:min(limit, FUZZY_MAX)]
|
|
160
|
+
return results[: min(limit, FUZZY_MAX)]
|