python · diff
git:20260719.e3c793f to git:20260722.f0eb407
22 added, 93 removed. Audit A to A.
---
name: python
- description: Engineer, review, debug, type, secure, package, or test Python code and projects, including .py files, pyproject.toml, dependency files, async code, and Python tooling.
+ description: Engineer Python language, interpreter, typing, async, packaging, imports, subprocess, and serialization behavior. Use for Python-owned semantics; not non-Python work merely because pyproject.toml or a Python tool exists.
---
# Python
- Use this skill to make Python changes that are grounded in the project, easy to review, secure by default, and validated at the right depth.
-
- ## Operating Rules
-
- - Inspect project files before giving advice or editing code. Use `pyproject.toml`, lock files, `requirements*.txt`, `setup.cfg`, `tox.ini`, `noxfile.py`, CI, README, tests, and nearby code as the source of truth.
- - For unstable or version-specific claims, verify against project metadata and official documentation before relying on memory. Prefer `docs.python.org`, `packaging.python.org`, pytest docs, and the official docs for the framework or library in use.
- - Use the project's package manager, formatter, linter, type checker, and test runner. Do not replace tooling because another tool is currently fashionable.
-
- ## First Pass
-
- 1. Identify the supported Python version from `requires-python`, classifiers, runtime images, CI matrices, tox/nox envs, or lock files.
- 2. Identify the packaging and dependency workflow: `uv`, Poetry, PDM, Hatch, setuptools, pip-tools, plain pip, conda, or project-specific scripts.
- 3. Locate the relevant package, entry points, tests, fixtures, configuration, and call sites with targeted search.
- 4. Determine the cheapest useful validation command before editing.
- 5. For non-trivial or cross-cutting changes, keep a short internal plan and update it as facts change; report plans only when the user asks or a safe decision blocks progress.
-
- ## Design And Architecture
-
- - Keep domain logic separate from I/O, framework adapters, persistence, CLI parsing, environment lookup, time, randomness, and network calls.
- - Preserve existing layering. Typical boundaries are API/CLI, service or use-case logic, domain models, persistence, and infrastructure clients.
- - Put dependencies at the edges. Use small protocols or adapter interfaces when code needs substitutable external services.
- - Prefer clear functions and cohesive classes over clever abstractions. Add an abstraction only when it removes real duplication or isolates a volatile dependency.
- - Avoid import-time side effects. Importing a module should not open sockets, read secrets, mutate global state, run migrations, or start worker loops.
- - Parse configuration once near the application edge. Keep secrets out of source, logs, test snapshots, and default reprs.
- - Use `pathlib`, context managers, explicit encodings, timezone-aware datetimes, and `Decimal` for money or exact decimal quantities.
- - Use structured logging for services and libraries. Reserve `print` for small scripts and CLIs where it is the user interface.
-
- ## Typing Rules
-
- - Type public APIs, dataclasses/models, fixtures with non-obvious shape, callbacks, async boundaries, and complex internal helpers.
- - Match syntax to the project's minimum Python version. Use newer syntax such as `list[str]`, `X | Y`, `Self`, the `type Alias = ...` statement, or type parameters only when supported. Retain `TypeAlias` for older-version compatibility; it has been deprecated since Python 3.12 without a planned removal.
- - For Python 3.14+ projects, verify current `typing`, `annotationlib`, t-string, and concurrency behavior against official docs before relying on new syntax or reflection semantics. Use PEPs for rationale/status and current language/library documentation for implemented behavior.
- - Prefer precise interfaces: `Sequence` over `list` for read-only inputs, `Mapping` over `dict` for read-only mappings, `Iterable` for streams, `Protocol` for structural dependencies, and `TypedDict` or dataclasses for structured dictionaries.
- - Avoid widening to `Any`. If `Any`, `cast`, or `# type: ignore` is necessary, keep it local and explain why when the reason is not obvious.
- - Treat type hints as design and tooling input, not runtime validation. Validate untrusted data explicitly at the boundary.
- - Use `typing_extensions` only when the project already depends on it or the compatibility benefit justifies the dependency.
-
- ## Testing Rules
-
- - Add or update tests for changed behavior unless the change is mechanical and existing tests cover it.
- - Follow the existing test framework. Use pytest conventions when pytest is present; use `unittest` where the project already uses it.
- - Test behavior, boundaries, and regressions. Include success cases, representative failure cases, and edge cases tied to the bug or feature.
- - Keep tests deterministic and isolated. Use fixtures such as `tmp_path`, `monkeypatch`, and log capture instead of real home directories, clocks, network calls, or global environment mutation.
- - Mock only process boundaries: network, subprocesses, time, randomness, file systems outside temp dirs, and expensive external services. Do not mock the unit under test into tautology.
- - Prefer small focused tests first, then broader integration tests for high-risk paths.
- - If a bug is fixed, make the test fail before the fix when practical.
-
- ## Tooling And Dependencies
-
- - Centralize project metadata and tool configuration in `pyproject.toml` when the project already uses it. Do not migrate scattered config opportunistically.
- - Respect lock files. When changing dependencies, update the lock file with the project's tool and include the lock change.
- - Separate runtime dependencies from development/test dependencies using the project's existing convention. Use dependency groups, `pylock.toml`, or other PyPA packaging features only when the tooling in the project supports them.
- - Do not add dependencies for small standard-library-solvable problems. If adding one, justify maintenance, security, license, transitive dependency, and deployment impact.
- - Do not install packages globally. Use the existing virtual environment, tool runner, or project command.
- - Do not use `sudo pip` or `--break-system-packages` unless the user explicitly asks after the system-package risk is clear.
- - For PyPI publishing, prefer Trusted Publishers/OIDC and attestations over long-lived API tokens when the project and CI provider support them.
- - Run formatter/linter/type checker commands that the project already defines. Common tools include Ruff, Black, isort, mypy, Pyright, pytest, coverage, tox, and nox.
- - Avoid changing generated files, vendored files, lock files, or snapshots unless the task requires it and the generation path is known.
-
- ## Security Rules
-
- - Validate paths before reading or writing user-controlled locations. Resolve paths and prevent traversal outside the intended root.
- - When extracting tar archives on Python 3.12+, pass `filter="data"` explicitly for stable intent across versions; still extract into an isolated directory and bound count, total bytes, per-file bytes, depth, links, and resource use because the filter is not a denial-of-service defense. For other formats or older runtimes, validate every member equivalently.
- - Use parameterized database queries and framework-safe query builders. Do not concatenate SQL or shell commands with untrusted input.
- - Prefer `subprocess.run([...], shell=False, check=True, timeout=...)` with a verified executable and argument list. On Windows, `.bat`/`.cmd` files can still be launched through the system shell; never pass untrusted values to batch wrappers, and use a real executable or platform-safe API instead.
- - Avoid `eval`, `exec`, unsafe YAML loaders, dynamic imports from untrusted strings, and `pickle` or marshal data from untrusted sources.
- - For network clients, set timeouts, validate TLS by default, and guard URL fetchers against SSRF where user-supplied URLs are possible.
- - Retry only transient failures, only when the operation is idempotent or protected by an idempotency key, with bounded attempts, backoff plus jitter, and `Retry-After` support when available.
- - Use secure randomness from `secrets` for tokens. Do not use `random` for security-sensitive values.
- - Check dependency-audit or vulnerability tools if the project has them, especially after dependency changes.
+ ## Establish the Python contract
- ## Async And Concurrency
+ - Inspect the touched modules, `pyproject.toml`, lock and requirements files, `setup.cfg`, tox/nox configuration, runtime images, CI matrix, and project scripts. Resolve the interpreter actually used by the project command or environment and its exact version; distinguish it from the declared minimum in `requires-python` and classifiers.
+ - Identify the packaging workflow—such as uv, Poetry, PDM, Hatch, setuptools, pip-tools, pip, or conda—from repository evidence. Use its existing environments, dependency groups, lock behavior, entry points, and commands; do not substitute another tool.
+ - Determine package roots, import style, namespace packages, editable-install assumptions, generated metadata, type-checker mode, and sync/async entry points before editing.
- - Use async for I/O concurrency, not CPU speedups. Use processes, native/vectorized libraries, or worker pools for CPU-bound work.
- - Do not block the event loop with synchronous file, network, database, sleep, or CPU-heavy calls. Move blocking work to a thread or process executor when necessary.
- - Bound concurrency with semaphores, queues, pools, or worker limits. Avoid unbounded task creation.
- - Use explicit timeouts and cancellation-aware cleanup around external calls.
- - Prefer structured concurrency such as `asyncio.TaskGroup` and `asyncio.timeout` when the project's supported Python version allows it. Otherwise use existing project patterns with clear error and cancellation handling.
- - Treat free-threaded Python and subinterpreter-based concurrency as version- and extension-sensitive. Verify dependency support before assuming code is safe without the GIL or across interpreters.
- - Do not swallow `asyncio.CancelledError` unless cleanup requires it; re-raise after cleanup.
- - Library code should not call `asyncio.run()` internally or assume ownership of the event loop.
- - Keep thread-shared state minimal. Protect shared mutation with locks or queues and document invariants.
+ Read [version, packaging, and security boundaries](references/version-packaging-security.md) before changing the minimum version, annotations, free-threaded behavior, packaging metadata or locks, archives, subprocesses, or serialization. Use [authoritative Python sources](references/sources.md) for exact interpreter and packaging behavior.
- ## Data And API Boundaries
+ ## Preserve language, typing, and package semantics
- - Validate and normalize untrusted data at the boundary, then pass typed internal objects through the core.
- - Make errors actionable. Raise specific exceptions in libraries; translate them to user-facing messages at CLI/API boundaries.
- - For APIs and services, handle idempotency, retries, pagination, rate limits, and partial failures deliberately.
- - Keep serialization formats stable. Avoid changing JSON field names, nullability, date formats, or enum values without tests and migration notes.
- - Read [version, packaging, and security boundaries](references/version-packaging-security.md) before changing minimum Python, typing/annotations, free-threaded or interpreter behavior, packaging metadata/locks, publishing, archive handling, subprocesses, or serialization.
+ - Match syntax to the supported minimum: built-in generics, union syntax, `Self`, type-parameter syntax, exception groups, `TaskGroup`, and newer annotation behavior are version-sensitive.
+ - Type public APIs and non-obvious boundaries. Prefer precise read-only protocols such as `Sequence` and `Mapping`, structural `Protocol` where substitution is real, and `TypedDict` or dataclasses for stable records. Keep `Any`, casts, and ignores local.
+ - Treat annotations as tooling input, not runtime validation. Reflection and deferred annotations vary by Python version; verify before relying on evaluated annotation objects.
+ - Avoid import-time network calls, file mutation, secret reads, migrations, and worker startup. Keep library code from taking ownership of the event loop with `asyncio.run()`.
+ - Preserve packaging contracts: import names, entry points, extras or dependency groups, wheel contents, data files, editable installs, and minimum-Python metadata. Update locks only through the project's package manager when dependency input actually changes.
+ - Raise specific exceptions in libraries and translate them at CLI, worker, or service boundaries. Chain useful causes and clean up context-managed resources without hiding the original failure.
- ## Validation Before Final Response
+ ## Bound concurrency and unsafe boundaries
- - Run the cheapest useful validation first: targeted tests, import checks, lint, format check, type check, or a narrow integration command.
- - Escalate to broader tests when the change touches shared infrastructure, public APIs, concurrency, persistence, security-sensitive behavior, packaging, or dependency resolution.
+ - Use async for I/O concurrency, not CPU acceleration. Keep blocking filesystem, database, network, sleep, and CPU-heavy calls off the event loop; use existing thread or process executors when required.
+ - Bound task creation, queues, pools, and worker counts. Use structured concurrency and timeout APIs only when supported by the minimum version. Preserve cancellation and re-raise `asyncio.CancelledError` after cleanup.
+ - Treat free-threaded builds and subinterpreters as separate compatibility targets. Verify extension and dependency support before assuming shared state is safe without the GIL or portable across interpreters.
+ - Prefer `subprocess.run` with a verified executable, argument list, `shell=False`, `check=True`, and a timeout. On Windows, batch wrappers still introduce shell parsing; never pass untrusted values through them.
+ - Do not load untrusted pickle, marshal, unsafe YAML, dynamic imports, or executable strings. Resolve user-controlled paths beneath an allowed root. For archives, validate members and bound count, total bytes, depth, links, and extraction location even when a safe filter is available.
+ - Use explicit encodings, timezone-aware datetimes, `Decimal` for exact decimal quantities, and stable serialization rules at persistent or public boundaries.
- ## References
+ ## Use project feedback
- - Read [version, packaging, and security boundaries](references/version-packaging-security.md) for interpreter compatibility, annotations and typing, free-threaded/subinterpreter assumptions, PyPA specifications, archives, subprocesses, and unsafe serialization.
- - Read [authoritative Python sources](references/sources.md) for current supported versions and exact standard-library/packaging behavior. Pin the project's interpreter and tool versions before applying rolling documentation.
+ Run the smallest configured formatter or lint check, type checker, and focused test or import check that covers the touched package. Run tox/nox environments, build wheels/sdists, or test installed artifacts when changing supported Python versions, imports, entry points, package metadata, generated declarations, or dependency resolution. Exercise cancellation, subprocess failure, archive rejection, or serialization errors when those semantics changed.