---
name: python-helper
description: Current Python development guidance for versions, uv and pip, packaging, typing, asyncio, pytest, Ruff, security, and runtime boundaries. Use when writing or reviewing Python, pyproject.toml, Python CI, tests, dependency workflows, or Python upgrades.
---

# Python Helper

Follow the project's declared Python version and dependency workflow. Validate runtime data, make async ownership explicit, and distinguish read-only checks, local mutations, and external publication.

## Current baseline

Verified 2026-08-03:

| Line | Status |
| --- | --- |
| Python 3.14.6 | Current stable; 3.14 and 3.13 are bugfix branches |
| Python 3.12, 3.11, 3.10 | Security-only branches |
| Python 3.15.0b4 | Prerelease; RC1 was scheduled for 2026-08-04 and final for 2026-10-01 |

Python 3.14.7 was scheduled for the day after this verification. Check live status before repeating a patch number:

```bash
python --version
uv --version
```

The project's `requires-python` is the syntax and standard-library ceiling. Do not use a current interpreter to justify APIs outside that declared range.

Read [references/releases.md](references/releases.md) for the 48-page research ledger and 3.14/3.15 features. Read [references/tooling-and-packaging.md](references/tooling-and-packaging.md) for uv, pip, publishing, Ruff, and type-checkers. Read [references/testing-and-concurrency.md](references/testing-and-concurrency.md) for pytest, asyncio, TaskGroup, interpreters, and free threading. Read [references/types-and-security.md](references/types-and-security.md) for typed boundaries, deferred annotations, subprocesses, archives, and secrets.

## Command authority

Read-only or check-oriented commands:

```bash
python --version
uv --version
uv python list
uv tree --locked
uv run --locked ruff check .
uv run --locked ruff format --check .
uv run --locked pytest --collect-only
uv run --locked mypy .
uv run --locked pyright
```

For a uv-managed project, run project-installed tools through `uv run --locked` so checks use the versions selected by `uv.lock` and fail on lock drift. For another dependency workflow, use its verified project environment rather than whichever global tool happens to be on `PATH`.

Local mutations include `uv add`, `uv sync`, `uv python install`, `uv python pin`, `ruff check --fix`, and `ruff format`. Ruff unsafe fixes can change runtime behavior or remove comments; require an explicit diff review and focused tests.

`uv publish` mutates an external registry. Require explicit artifacts, registry, credentials, and publication authorization.

## uv projects

Use uv's project interface for a uv-managed application or package:

```bash
uv sync --locked
uv run --locked pytest
uv add httpx
uv add --dev pytest ruff
```

- Commit `uv.lock`; it is a universal exact-resolution lockfile.
- `--locked` checks that project metadata and lock agree.
- `--frozen` uses the lock without checking whether project metadata changed; it is not the stricter CI option.
- Development tools belong in `[dependency-groups].dev`.
- `[project.optional-dependencies]` defines consumer-installable extras.
- `uv pip` is the lower-level environment interface, not the default project/lock workflow.
- `uv --version` reports the uv binary. `uv version` reads or can update the project version.

## pip boundaries

Use `python -m pip` inside a verified virtual environment when a project uses pip. `pip freeze` is an environment snapshot, not a portable lock or secure supply-chain workflow. `pip lock` remains experimental and its `pylock.toml` is specific to the current Python/platform.

Secure requirements installs need complete hashes and may disallow source distributions:

```bash
python -m pip install --require-hashes --only-binary :all: -r requirements.txt
```

## Type and validate boundaries

Avoid bare `dict` and `list[dict]`; they introduce imprecise values. Use dataclasses, `TypedDict`, Pydantic models, or precise mappings according to whether runtime validation is needed.

```python
from pydantic import BaseModel, TypeAdapter


class User(BaseModel):
    id: int
    email: str


Users = TypeAdapter(list[User])
users = Users.validate_python(response.json())
```

Check HTTP status before parsing. A type annotation does not validate JSON, environment variables, database results, cache values, or deserialized files.

`Any` disables static checking and is not an escape hatch for repository code.
Use precise protocols, generics, or `object` plus boundary validation instead.
Use `Never` for exhaustiveness.

`TypeIs` narrows both branches and requires the narrowed type to be a subtype. `TypeGuard` remains necessary for some invariant-container or otherwise non-subtype narrowing. Neither is universally preferred.

## Async and concurrency

Use `TaskGroup` when sibling cancellation and grouped failures are the intended semantics. `asyncio.gather()` does not cancel sibling awaitables merely because one fails. `return_exceptions=True` turns exceptions into results and must not silently normalize failure.

Reuse clients so connection pooling works:

```python
import asyncio

import httpx


async def fetch_all(urls: list[str]) -> list[str]:
    async with httpx.AsyncClient() as client:
        async with asyncio.TaskGroup() as group:
            tasks = [group.create_task(fetch_text(client, url)) for url in urls]
    return [task.result() for task in tasks]


async def fetch_text(client: httpx.AsyncClient, url: str) -> str:
    response = await client.get(url)
    response.raise_for_status()
    return response.text
```

Own the event loop at the application boundary. Do not monkey-patch it with archived `nest_asyncio`; use top-level `await` in notebooks or refactor nested `asyncio.run()` calls.

Subinterpreters have separate execution contexts and GILs but are not security boundaries. Free-threaded Python is supported in 3.14, yet extensions can re-enable the GIL and shared state still requires synchronization.

## Tests

Current pytest documentation is 9.1.1. Avoid embedding volatile minimum-version pins unless compatibility requires them.

- Use exact state, value, status, body, and side-effect assertions.
- Do not skip “not implemented” behavior or xfail known bugs to make the suite green.
- Use controlled servers or HTTP fakes instead of `example.com`.
- Prefer `--import-mode=importlib` for new projects and a src layout where appropriate.
- Use pytest-asyncio `auto` only when asyncio is the suite's sole async framework; use strict mode for plugin coexistence.
- `-n auto` is pytest-xdist, and coverage flags are pytest-cov, not core pytest.

## Ruff and type-checkers

Let Ruff infer `target-version` from `requires-python` or set the true minimum. Formatting is best-effort against line length; E501 can still report a formatted line. Use safe fixes by default and note that Ruff is pre-1.0, so minor releases can contain breaking changes.

Choose mypy or Pyright from the repository's existing configuration, plugin needs, editor integration, and intended strictness. Do not suppress missing imports globally or claim one checker is categorically the “CI” or “fast” choice.

## Security

- Use `secrets`, not `random`, for tokens and credential material.
- Pass subprocess argument sequences; avoid `shell=True` with untrusted input.
- Never unpickle untrusted data.
- Keep tarfile's safer `data` filter and inspect untrusted archives even on Python 3.14.
- Audit with `uv run --locked --with pip-audit pip-audit`, not the nonexistent
  `pip audit` / `uv pip audit` commands. Use `uv run --locked --with`, not `uvx`: `uvx
  pip-audit` runs pip-audit in its own isolated tool environment and audits
  pip-audit's dependencies, not the project's; `uv run --locked --with pip-audit`
  layers pip-audit onto the project's synced environment so it inspects the
  project's actual installed packages. `uv audit` remains a preview-only
  subcommand (behind `--preview`) and is absent entirely in older uv releases,
  so don't rely on it as a stable, version-independent option.
- Fail on missing required environment configuration; do not silently switch databases.
- Prefer trusted publishing and pinned container artifacts over static tokens and `latest` tags.
- Open text files with an explicit encoding while Python 3.14 remains platform-sensitive by default.

## Review checklist

- Verify Python, uv, and the project's `requires-python` range.
- Separate read-only checks, local mutations, and external publication.
- Commit and enforce the lock with `--locked` in CI.
- Validate external data before returning domain types.
- Keep async failure and cancellation semantics explicit.
- Reuse network clients and check response status.
- Use exact tests without skips, weak assertions, or real public-network dependencies.
- Keep Ruff fixes safe unless an unsafe fix is explicitly reviewed.
- Avoid archived monkey patches and unqualified performance claims.
- Check security-sensitive serialization, subprocess, archive, secret, and publishing boundaries.
