Python Strict Development
Use this skill when Python code should meet the user's strict local quality bar rather than a minimal lint setup. Start from the current repository and adapt paths, package names, Python version, and CI commands before editing.
Source Priority
- Read
pyproject.toml, package.json, .vscode/settings.json, pylock.toml or pylock.*.toml, requirements files, tool-specific lockfiles, CI workflows, and existing tests before changing tools.
- Prefer existing repo conventions when they are already strict and working.
- Use strict-tooling.md when adding or repairing Ruff, mypy, Pyright, pytest, VS Code, or npm-script configuration.
- Use project-shapes.md when the repository is not a simple
scripts + tests project.
- Use strict-fix-patterns.md when strict diagnostics are valid but the right code fix is not obvious.
- Use
scripts/audit_python_strict.py for a read-only strict profile audit before or after manual config edits. Read the auditor contract when consuming its check IDs or JSON: it statically parses configuration and npm-script composition without executing project commands.
- Do not weaken strict diagnostics, broad Ruff rule selection, or typecheck gates just to get a quick pass. Fix code first; use only narrow, justified ignores after proving the tool finding is intentionally tolerated.
Workflow
- Inventory Python entrypoints, import roots, test roots, minimum supported Python version, target platforms, dependency manager, direct script execution requirements, and first-party module names.
- Confirm the resolved environment can run the expected tools:
ruff==0.15.20, mypy==2.1.0, pyright==1.1.411, pytest==9.1.1, and python -m compileall when those versions are declared by the repository.
- Set up or sync the repo-local environment with the existing dependency manager and authoritative resolution file. Use strict-tooling.md for requirements,
pylock.toml, and tool-specific lock workflows; do not add a parallel dependency source merely to bootstrap the strict tools. Put the environment's scripts directory first on PATH before running npm-backed Python scripts.
- Configure or repair the project around one strict gate:
ruff check plus ruff format --check
mypy with strict = true and extra error codes
pyright in strict mode with explicit diagnostics
pytest strict config, strict markers, strict config, and warning errors
python -m compileall over source and tests
- Add npm package scripts only when the repository already uses npm as the task runner or the user asks for cross-language scripts; prefer
check:python, format:python, lint:python, typecheck:python, test:python, and compile:python.
- Keep ignores local and documented. The complete audited Ruff profile permits only the narrow global ignore/unfixable set and
tests/**/*.py = ["S101"] described in the reference; an omitted exception is stricter. Do not add root-wide exclusions, catch-all per-file patterns, mypy catch-all regexes/overrides, Pyright ignores/environments, or downgraded report... settings.
- Do not mass-disable rules, add broad
ignore lists, or downgrade warnings because a diagnostic batch fails. Fix the repeated pattern, add typed adapters, split helpers, or narrow the one intentional exception. Treat additive suppressions as weakening even when every documented strict flag is still present.
- Keep editor settings in
.vscode/settings.json aligned with repo config: Ruff uses filesystem config first, Pyright/Pylance runs workspace diagnostics, and tests use pytest.
- Run
python <skill>/scripts/audit_python_strict.py <repo> when auditing strict-tooling drift, then inspect every failure's expected/actual field context before editing. Use --json for stable machine-readable check IDs and preserve those IDs in downstream automation. The auditor statically models only && composition, exact npm aliases/helpers, and the documented dependency profiles; it never executes configured commands or reflects dependency targets/source contents in diagnostics.
- Run the narrow failing command after each fix, then run the aggregate gate.
Python Code Standards
- Use explicit types at public and internal boundaries; avoid
Any unless the boundary is genuinely dynamic.
- Prefer typed adapters for untyped third-party responses instead of spreading casts through business logic.
- Use
typing.override where supported and let Pyright catch missing override markers.
- Use
pathlib, subprocess.run(..., check=True) with fixed argument arrays, and structured exceptions.
- Keep CLI output and API/client logic separated enough that tests can assert behavior without scraping terminal output.
- Treat
# type: ignore[...], # noqa: ..., and Ruff per-file ignores as review surfaces that require a reason.
- Treat generated coverage and checker output as validation artifacts. The default profile writes mypy reports under
coverage/mypy, uses .cache/.ruff_cache, .cache/.mypy_cache, .cache/.pytest_cache, and lets pytest emit strict JUnit-compatible metadata when configured.
- Treat dependency bootstrap as part of the quality gate: one exact requirements/lock target, exact pins for every invoked strict tool, all-entry sha256 hashes when
--require-hashes is selected, structurally valid hashed lock artifacts, and an activated or directly invoked .venv interpreter.
Validation Commands
Prefer repo-local scripts when present. Otherwise, run the equivalent direct commands:
ruff check scripts tests
ruff format --check scripts tests
mypy scripts tests
pyright scripts tests
pytest
python -m compileall -q -x "[\\/]\\." scripts tests
For npm-backed Python repositories, prefer:
npm run check:python
npm run lint:python
npm run typecheck:python
npm run test:python
npm run compile:python
Output
Finish with the strict configuration surfaces changed, the commands run, any remaining justified ignores, and any tool or interpreter prerequisite that blocked validation.
1---2name: python-strict-development3description: Maintains strict Python projects with Ruff, mypy, Pyright, pytest, editor, and package-script gates. Use when creating, auditing, or repairing strict lint, format, typecheck, test, compile, or VS Code tooling practices.4---56# Python Strict Development78Use this skill when Python code should meet the user's strict local quality bar rather than a minimal lint setup. Start from the current repository and adapt paths, package names, Python version, and CI commands before editing.910## Source Priority11121. Read `pyproject.toml`, `package.json`, `.vscode/settings.json`, `pylock.toml` or `pylock.*.toml`, requirements files, tool-specific lockfiles, CI workflows, and existing tests before changing tools.132. Prefer existing repo conventions when they are already strict and working.143. Use [strict-tooling.md](references/strict-tooling.md) when adding or repairing Ruff, mypy, Pyright, pytest, VS Code, or npm-script configuration.154. Use [project-shapes.md](references/project-shapes.md) when the repository is not a simple `scripts` + `tests` project.165. Use [strict-fix-patterns.md](references/strict-fix-patterns.md) when strict diagnostics are valid but the right code fix is not obvious.176. Use `scripts/audit_python_strict.py` for a read-only strict profile audit before or after manual config edits. Read the [auditor contract](references/strict-tooling.md#auditor-contract) when consuming its check IDs or JSON: it statically parses configuration and npm-script composition without executing project commands.187. Do not weaken strict diagnostics, broad Ruff rule selection, or typecheck gates just to get a quick pass. Fix code first; use only narrow, justified ignores after proving the tool finding is intentionally tolerated.1920## Workflow21221. Inventory Python entrypoints, import roots, test roots, minimum supported Python version, target platforms, dependency manager, direct script execution requirements, and first-party module names.232. Confirm the resolved environment can run the expected tools: `ruff==0.15.20`, `mypy==2.1.0`, `pyright==1.1.411`, `pytest==9.1.1`, and `python -m compileall` when those versions are declared by the repository.243. Set up or sync the repo-local environment with the existing dependency manager and authoritative resolution file. Use [strict-tooling.md](references/strict-tooling.md) for requirements, `pylock.toml`, and tool-specific lock workflows; do not add a parallel dependency source merely to bootstrap the strict tools. Put the environment's scripts directory first on `PATH` before running npm-backed Python scripts.254. Configure or repair the project around one strict gate:26 - `ruff check` plus `ruff format --check`27 - `mypy` with `strict = true` and extra error codes28 - `pyright` in strict mode with explicit diagnostics29 - `pytest` strict config, strict markers, strict config, and warning errors30 - `python -m compileall` over source and tests315. Add npm package scripts only when the repository already uses npm as the task runner or the user asks for cross-language scripts; prefer `check:python`, `format:python`, `lint:python`, `typecheck:python`, `test:python`, and `compile:python`.326. Keep ignores local and documented. The complete audited Ruff profile permits only the narrow global ignore/unfixable set and `tests/**/*.py = ["S101"]` described in the reference; an omitted exception is stricter. Do not add root-wide exclusions, catch-all per-file patterns, mypy catch-all regexes/overrides, Pyright ignores/environments, or downgraded `report...` settings.337. Do not mass-disable rules, add broad `ignore` lists, or downgrade warnings because a diagnostic batch fails. Fix the repeated pattern, add typed adapters, split helpers, or narrow the one intentional exception. Treat additive suppressions as weakening even when every documented strict flag is still present.348. Keep editor settings in `.vscode/settings.json` aligned with repo config: Ruff uses filesystem config first, Pyright/Pylance runs workspace diagnostics, and tests use pytest.359. Run `python <skill>/scripts/audit_python_strict.py <repo>` when auditing strict-tooling drift, then inspect every failure's expected/actual field context before editing. Use `--json` for stable machine-readable check IDs and preserve those IDs in downstream automation. The auditor statically models only `&&` composition, exact npm aliases/helpers, and the documented dependency profiles; it never executes configured commands or reflects dependency targets/source contents in diagnostics.3610. Run the narrow failing command after each fix, then run the aggregate gate.3738## Python Code Standards3940- Use explicit types at public and internal boundaries; avoid `Any` unless the boundary is genuinely dynamic.41- Prefer typed adapters for untyped third-party responses instead of spreading casts through business logic.42- Use `typing.override` where supported and let Pyright catch missing override markers.43- Use `pathlib`, `subprocess.run(..., check=True)` with fixed argument arrays, and structured exceptions.44- Keep CLI output and API/client logic separated enough that tests can assert behavior without scraping terminal output.45- Treat `# type: ignore[...]`, `# noqa: ...`, and Ruff per-file ignores as review surfaces that require a reason.46- Treat generated coverage and checker output as validation artifacts. The default profile writes mypy reports under `coverage/mypy`, uses `.cache/.ruff_cache`, `.cache/.mypy_cache`, `.cache/.pytest_cache`, and lets pytest emit strict JUnit-compatible metadata when configured.47- Treat dependency bootstrap as part of the quality gate: one exact requirements/lock target, exact pins for every invoked strict tool, all-entry sha256 hashes when `--require-hashes` is selected, structurally valid hashed lock artifacts, and an activated or directly invoked `.venv` interpreter.4849## Validation Commands5051Prefer repo-local scripts when present. Otherwise, run the equivalent direct commands:5253```powershell54ruff check scripts tests55ruff format --check scripts tests56mypy scripts tests57pyright scripts tests58pytest59python -m compileall -q -x "[\\/]\\." scripts tests60```6162For npm-backed Python repositories, prefer:6364```powershell65npm run check:python66npm run lint:python67npm run typecheck:python68npm run test:python69npm run compile:python70```7172## Output7374Finish with the strict configuration surfaces changed, the commands run, any remaining justified ignores, and any tool or interpreter prerequisite that blocked validation.