Skip to content
Skills Library
Programming · Building & coding

python-conventions

/python-conventions

Use when a ticket adds or changes Python code and it must follow the repo's Python conventions — PEP 8, full type hints (PEP 484) checked by mypy/pyright, dataclasses, pythonic idioms, explicit error handling, asyncio and thread safety, ruff-clean, and pytest with coverage via the repo's env manager (uv/poetry). Invoke for "add this in Python", "fix the type/lint errors", "add the FastAPI/Django endpoint", or as the language pack for any Python change or Python review.

Repository
gaffer ↗
Licence
Apache-2.0
Last repository change
29.09.2026

Assessment and security

90/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content25 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 29.09.2026, without references to retired models or APIs.

Licence

Apache-2.0, otwarta: można używać i zmieniać, z zachowaniem licencji i informacji o zmianach.

What it does and when to use it

Use when a ticket adds or changes Python code and it must follow the repo's Python conventions — PEP 8, full type hints (PEP 484) checked by mypy/pyright, dataclasses, pythonic idioms, explicit error handling, asyncio and thread safety, ruff-clean, and pytest with coverage via the repo's env manager (uv/poetry). Invoke for "add this in Python", "fix the type/lint errors", "add the FastAPI/Django endpoint", or as the language pack for any Python change or Python review.

Triggers from the description

s env manager (uv/poetry). Invoke forfix the type/lint errorsadd the FastAPI/Django endpoint
Original author description

Use when a ticket adds or changes Python code and it must follow the repo's Python conventions — PEP 8, full type hints (PEP 484) checked by mypy/pyright, dataclasses, pythonic idioms, explicit error handling, asyncio and thread safety, ruff-clean, and pytest with coverage via the repo's env manager (uv/poetry). Invoke for "add this in Python", "fix the type/lint errors", "add the FastAPI/Django endpoint", or as the language pack for any Python change or Python review.

How it works

  1. Procedure
  2. Commands
  3. Idioms that matter
  4. Concurrency and resource safety
  5. Review checklist — flag as defects
  6. Capture lore
Original SKILL.md headings · 119 lines, 1,139 words
SKILL.md preview
---
name: python-conventions
description: Use when a ticket adds or changes Python code and it must follow the repo's Python conventions — PEP 8, full type hints (PEP 484) checked by mypy/pyright, dataclasses, pythonic idioms, explicit error handling, asyncio and thread safety, ruff-clean, and pytest with coverage via the repo's env manager (uv/poetry). Invoke for "add this in Python", "fix the type/lint errors", "add the FastAPI/Django endpoint", or as the language pack for any Python change or Python review.
stack: [python]
area: language
---

# Write idiomatic, typed Python

Python stays maintainable when every signature is typed, errors are narrow, resources
live in `with` blocks and shared state is guarded. For the builder and the reviewer of a Python diff; the repo's config and existing code win over it.

## Procedure

1. **Discover the repo's conventions first.** Call `search_lore` for Python conventions.
   Read `pyproject.toml` (`requires-python`, `[tool.ruff]`, `[tool.mypy]`/`[tool.pyright]`,
   `[tool.pytest.ini_options]`), the lockfile that names the env manager (`uv.lock` → uv,
   `poetry.lock` → Poetry, `requirements*.txt` → pip/venv), `tox.ini`/`noxfile.py`,
   `.pre-commit-config.yaml` and the CI workflow. Open the nearest sibling module and its
   test; copy its imports, data modelling (dataclass/Pydantic/attrs), logging and fixtures.
   Never install into the system interpreter; never edit tool config to make your change pass.
2. **Pin the exact commands** from CI, `Makefile`, tox/nox or pre-commit (the `run-tests`
   and `run-lint` skills). Use the defaults below only when the repo defines none.
3. **Write the change with the idioms below**, then walk the concurrency section for
   every task, thread, file, connection and shared object you touched.
4. **Test each acceptance criterion's own behaviour.** One pytest test (or `parametrize`
   case) per AC that fails without your change, plus its error path. If the AC involves
   shared state or persistence, add a test that runs N concurrent callers
   (`ThreadPoolExecutor` or `asyncio.gather`) and asserts the invariant.
5. **Verify, then stop.** Done when: lint and format check are clean, the type checker
   reports no new errors, the test suite (with the repo's coverage gate) is green, and
   every AC has a test. Record the output with the `record-evidence` skill; the runner
   submits the work.

## Commands

- Env: use the existing environment — `uv run --no-sync …` (plain `uv run` syncs, i.e.
  installs), `poetry run …`, or `.venv/bin/…`. Never install: the hook blocks
  `pip install`, and `uv sync`/`poetry install`/`uv add` are forbidden too though the hook
  does not catch them. A missing tool goes in the evidence.
- Lint and format: `ruff check .` and `ruff format --check .` (or `black --check .` and
  `isort --check` where the repo still uses them).
- Types: `mypy .` (or the configured paths/`--strict`) or `pyright`, per the repo.
- Tests: `pytest -q`; one test: `pytest path/test_x.py::test_name`; coverage:
  `pytest --cov=<pkg> --cov-report=term-missing`.
- Security when relevant: `pip-audit` (if installed; it reads the environment, never
  fixes it); `bandit -r <pkg>` if configured.

## Idioms that matter

- **Types everywhere** (PEP 484): annotate every signature and public attribute; precise
  types (`Sequence`, `Mapping`, `Protocol`, `TypedDict`, `Literal`, `Self`) over `Any`;
  fix the cause rather than adding `# type: ignore` (if unavoidable, use a code:
  `# type: ignore[arg-type]` plus a reason).
- **Model data** with `@dataclass(frozen=True, slots=True)` or the repo's Pydantic models
  at boundaries, not dicts of string keys. Validate external input (request bodies, env,
  files) once, at the boundary.
- **Errors**: catch the narrowest exception; no bare `except:` (it catches
  `KeyboardInterrupt`/`SystemExit`); `raise DomainError(...) from err` to keep the cause;
  log with `logger.exception` only where you handle it.
- **Pythonic**: `pathlib`, `zip(strict=True)`, `is None`; module-level
  `logger = logging.getLogger(__name__)`.
- **Time**: timezone-aware datetimes (`datetime.now(timezone.utc)`); `datetime.utcnow()`
  is deprecated (3.12) and returns a naive value.

## Concurrency and resource safety

- **Resources in `with`** (files, locks, sockets, DB sessions, `tempfile`); `open()` gets
  an explicit `encoding="utf-8"` for text.
- **The GIL is not a lock.** `counter += 1`, check-then-set on a dict, and read-modify-write
  of a file are races between threads, and free-threaded CPython 3.13+/3.14 removes even
  incidental protection. Guard shared state with `threading.Lock`, hold it across the
  whole read-modify-write, and prefer `queue.Queue` for handoff.
- **Files other requests read**: never overwrite in place or through a fixed temp name.
  Write with `tempfile.NamedTemporaryFile(dir=target.parent, delete=False)` (unique, same
  filesystem), `flush` + `os.fsync`, then `os.replace(tmp, target)`. Cross-process
  exclusion needs an OS lock (`fcntl.flock`) or the database; a time-only lease lets a
  paused holder write after another took over, so the write must verify a fencing token
  or version.
- **asyncio**: never call blocking code (`time.sleep`, `requests`, sync DB drivers, heavy
  CPU) inside `async def`; use the async client or `await asyncio.to_thread(...)`. Keep a
  reference to every `asyncio.create_task(...)` (the loop holds only weak references) or
  use `asyncio.TaskGroup` (3.11+); bound fan-out with `asyncio.Semaphore`; put deadlines on waits
  with `asyncio.timeout(...)`. Do not swallow `asyncio.CancelledError`: clean up and re-raise.
- **Shared async state** still races across `await`: a read, an `await`, then a write can
  interleave with another task. Use `asyncio.Lock` or do it in one transaction.
- **Mutable defaults** (`def f(x=[])`) and late-binding lambdas in loops share state across
  calls; use `None` and bind loop values explicitly.
- **Untrusted data** never reaches `eval`, `pickle.loads`, `yaml.load` (use
  `yaml.safe_load`), `subprocess(..., shell=True)` or an f-string SQL query.

## Review checklist — flag as defects

Walk this against the diff. An item is grounds for CHANGES only when, in changed code, it
causes a concrete failure (wrong result, crash, lost or corrupted data, security hole) or
leaves an AC's own behaviour untested: cite the line and that failure. Otherwise it is an
`(optional)` note. Formatting the tools would fix, and preferences the repo
does not enforce, are not findings. Do not patch the code under review.

- [ ] A bare `except:`, or `except Exception` that passes, logs-and-continues where the
      caller needed the failure, or loses the cause (no `from err`).
- [ ] A signature is untyped or uses unexplained `Any`; a new `# type: ignore` or ruff
      `noqa` without a code and reason; tool config loosened.
- [ ] A mutable default argument, or a closure capturing a loop variable by reference.
- [ ] Shared state mutated from threads or tasks without a lock, or a read-modify-write
      that spans an `await` or releases the lock midway.
- [ ] A blocking call inside `async def`; a created task not referenced or awaited;
      `CancelledError` swallowed; an unbounded `gather` over user-sized input.
- [ ] A file, connection or lock acquired outside `with` and not released on the error path.
- [ ] A shared file written in place or via a fixed temp name; a lock with a time-only lease
      and no fencing check.
- [ ] External input used without validation; untrusted data reaches `eval`, `pickle`,
      `yaml.load`, `shell=True` or string-built SQL.
- [ ] Naive datetimes compared with aware ones, or `utcnow()` in new code.
- [ ] An AC has no test, the test mocks away the code the AC is about, or a concurrency AC
      has no concurrent test.

## Capture lore

This skill is one of the places durable, reusable knowledge naturally surfaces:
**A Python convention this repo enforces beyond the obvious — a version constraint, a typing/validation pattern, an env-manager quirk, or a lint/type-checker rule.** That kind of fact is *lore*. Capture it via the **lore-capture
protocol in your brief** (`CLAUDE.factory.md`, step 11 "Memory contribution"):
call the Memory MCP `suggest_lore` once at the close of your work — reusable
conventions, gotchas, decisions, and boundaries only, never per-ticket trivia.

Versions

RepositoryScoreLicence
This page · tmj-90/gaffer90Apache-2.0
wyattowalsh/agents100MIT
aratkruglik/claude-sdlc95MIT

Database snapshot: 13.11.2026 · package version 5e975efcc097 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100python
    Use when writing, reviewing, or modernizing Python 3.11+ code. Produces fully type-annotated modules, async I/O, dataclasses and protocols, pytest suites, and a lint/type gate built on ruff and mypy --strict. Trigger on "add type hints to this", "mypy is complaining", "convert…
  • 100rc-python
    Idiomatic typed Python 3.12+ — asyncio, dataclasses, pytest, ruff, uv. Use when writing or reviewing Python. Do not use for JS/TS or Go.
  • 100python
    Python language (3.10-3.14). Covers typing, async, and modern patterns. Use when writing Python applications. USE WHEN: user mentions "python", "type hints", "dataclasses", "async/await", asks about "asyncio", "context managers", "match statement", "walrus operator", "PEP 695",…
  • 100python-standards
    Python coding standards for modern (3.11+) projects - strict typing, ruff/mypy config, uv packaging, pytest testing, async patterns, error handling, security, docstrings, Docker, and FastAPI/Pydantic/SQLAlchemy/Django/Flask conventions. Use this skill whenever the user writes,…
  • 90python-expert
    Use when building Python 3.11+ applications requiring type safety, async programming, or production-grade patterns. Invoke for type hints, pytest, async/await, dataclasses, mypy configuration.
  • 100python
    Guides Python development with modern idioms, tooling, and project structure. ALWAYS trigger on "python project", "pyproject.toml", "ruff", "mypy", "pytest", "poetry", "python setup", "type hints", "pydantic", "dataclass", "async python", "asyncio", "python anti-pattern",…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.