Install
$ agentstack add skill-owenlamont-agent-skills-python-code-style ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Python Code Style
Standards for writing Python source in this project.
Style guide and docstrings
- Follow the
Google Python Style Guide for all code, including its Google-style docstrings.
Type hints
- Type everything with the strongest type that still matches how the value is used —
specific to its semantics/interface, which for an iterated-only parameter is Iterable[X] rather than list[X].
- Use modern type-hint syntax: lowercase built-in generics (
list,dict,tuple),
X | None over Optional[X], and collections.abc types (Iterable, Sequence, Mapping).
- Model categorical values as a
StrEnum(or anotherEnum), not a barestr, so the
permitted values are explicit and type-checked.
- When a dict's keys and value types are known ahead of time, use a
TypedDictor a
dataclass rather than a plain dict, or a Pydantic model when you also need runtime validation.
- Type-hint module-level constants with
Final, name themALL_CAPS
(MAX_RETRIES: Final = 3), and prefix module-local (non-exported) ones with an underscore (_MAX_RETRIES); function- and class-local values need neither Final nor ALL_CAPS. Give magic numbers a named constant rather than inlining them.
- Don't use
typing.cast(); fix the underlying type error instead of suppressing it. - Keep
Anyto a minimum by giving values a specific type wherever one fits. For a
genuinely untypable value, prefer Any over object (which forces isinstance/casts before use and conveys no intent).
type: ignoreshould almost never be used — only for third-party packages with no
typing or with dynamic typing.
- Prefer explicit typed signatures and attribute access over runtime introspection
(getattr/hasattr/__dict__) and *args/**kwargs passthrough; both defeat static type checking, autocomplete, and grep-based refactoring.
- Dispatch on a finite set of values with an explicit mapping or
match/caserather
than an if/elif chain.
Functions and data modelling
- Make invalid states unrepresentable: model data so bad combinations can't be
constructed — an Enum instead of several booleans, a sub-model instead of loosely related flat fields, one canonical representation of "empty" — and minimise optional/None-able fields. Prefer it to runtime validation that patches bad input.
- Don't mutate objects passed in as arguments; copy and return a new value (recreate
Pydantic models). In-place mutation is a surprising side effect that hampers reasoning and testing.
- Make every parameter keyword-only with a leading bare
*when any of these holds:
three or more parameters, two or more of the same type, or any boolean parameter (prevents argument-order and boolean-trap bugs).
- Group related values that travel together into a named dataclass/model rather than a
positional tuple, and defer extracting a shared helper until the duplication is real.
Comments and docstrings
- Keep comments to an absolute minimum. Achieve readability through meaningful class,
function, and variable names instead — and prefer extracting a well-named intermediate variable over a comment that explains a complex expression.
- Suffix variables and function arguments with their unit of measure where one applies
(e.g. timeout_ms, payload_size_bytes, duration_seconds), so the name carries the unit.
- Name for meaning rather than implementation, write boolean predicates positively to
avoid double negation, don't use generic module names like utils.py, and keep acronyms fully upper-case (HTTPClient, not HttpClient).
- Don't write module- or class-level docstrings. Keep function docstrings only, and
short; put a CLI's usage narrative in its command/argument help (e.g. Typer), not a module docstring.
- Public functions should have docstrings. Parameters only need to be documented when
the name and type hint don't convey their full semantics.
- Always document non-obvious side effects, the exceptions a function raises, and
whether numeric range bounds are inclusive or exclusive, even when the parameters themselves are self-evident.
- Private functions (single-underscore prefix, per PEP 8) used within a module don't need
docstrings, unless their names and type hints aren't sufficient to convey their semantics.
- Comments should only be used to explain:
- unavoidable code smells arising from third-party package use,
- the reason for temporary dependency version pinning (e.g. linking an unresolved
GitHub issue), or
- opaque code, non-obvious trade-offs, or workarounds.
- Link every suppression (
noqa,type: ignore, a coveragepragma) to a tracking
issue or a one-line justification.
Imports
- Keep all imports at the top of the module unless an import must be local to avoid a
circular import.
- Use absolute imports only — no relative imports.
- Don't import private (underscore-prefixed) names across modules; if another module
needs it, make it public and place it in the module its domain belongs to.
- Keep
__init__.pyfiles empty: no re-exports; import each symbol from the module that
defines it. (Exception: deliberately curated public-API packages populate __init__.py to simplify import paths.)
- Don't add
from __future__ import annotations; the project's Python version defers
annotation evaluation already.
Language idioms
- Use the most modern Python idioms and syntax allowed by the project's minimum
supported Python version.
- Prefer immutable containers (
tuple,frozenset) for fixed or read-only data,
including module-level constants; use mutable containers only when the data changes, and default_factory for any mutable dataclass/Pydantic default.
- Use
pathlib.Path(notos/os.path) for filesystem work and as path-argument
types, and reach for stdlib helpers (Counter, itertools, str.removeprefix, //) over hand-rolled equivalents.
- Build collections with comprehensions or generator expressions rather than
loop-and-append. Pass a generator (not a materialised list) to one-shot consumers like str.join, sum, or pd.concat.
- Use
contextlib.suppress(...)instead of an emptytry/except: pass; use float
literals in float arithmetic and never compare floats with == (use math.isclose or an explicit tolerance).
- Use a plain string literal, not an f-string, when there's nothing to interpolate.
- Keep non-trivial SQL in
.sqlfiles loaded at runtime, not embedded in Python string
literals, so SQL tooling can lint and format it.
- Compare versions with
packaging.version.Version, not string or tuple comparison
(which sorts e.g. 0.10 before 0.9).
Testing
Test authoring and layout conventions live in the python-pytest skill.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: owenlamont
- Source: owenlamont/agent_skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.