SKILL.md
Python Code Standards
Standards for Python code (>= 3.11).
Runtime
- All Python code should be run with
uv
PEP Compliance
- PEP 604: Use union types as
X | Y(notUnion[X, Y]) - PEP 673: Use
Selftype for self-referential types
Required Elements
- Type hints on ALL function parameters
- Return types on ALL functions
- Docstrings in Google Style Guide format for:
- Modules - Classes - Functions/methods
Docstring Format (Google Style)
def function_with_docstring(
param1: str,
param2: int,
) -> bool:
"""Short description of function.
Longer description if needed.
Args:
param1: Description of param1.
param2: Description of param2.
Returns:
Description of return value.
Raises:
ValueError: When something is wrong.
"""
Design Patterns
- Use
dataclassesfor structured records with fixed fields and named attributes - Use
collections.defaultdictfor dynamic key-value aggregation with automatic
defaults
- Choose based on the use case: typed record-like object (
dataclass) vs map with
default values (defaultdict)
- Each dataclass should be in a separate file
- String Enums should use
StrEnumwithauto() - Use
auto()with all Enums where it makes sense
Idioms
Prefer Python-native constructs over verbose cross-language patterns.
any()/all()over flag-and-break loops:
```python # Don't found = False for p in paths: if p.exists(): found = True break
# Do found = any(p.exists() for p in paths) ```
dict.get()over key-in checks:
```python # Don't if name in registry: return registry[name] return None
# Do return registry.get(name) ```
pathliboveros.path— never mix the two in one codebase:
```python # Don't root = os.path.dirname(os.path.dirname(os.path.dirname(path)))
# Do root = Path(path).parents[2] ```
- Truthiness over length checks:
```python # Don't if len(items) == 0: ...
# Do if not items: ... ```
- Comprehensions over loop-append for simple transforms:
```python # Don't names = [] for user in users: names.append(user.name)
# Do names = [user.name for user in users] ```
- Direct boolean returns:
```python # Don't if count > limit: return True return False
# Do return count > limit ```
contextlib.suppress(SomeError)over atry/except SomeError: passblock- Reach for
itertools/functools(chain,pairwise,cache,reduce) when
they replace hand-rolled loop logic
Formatting Rules
- More than 1 arg/param requires a trailing comma:
```python # Good def foo(bar: str, baz: int,) -> None:
# Bad def foo(bar: str, baz: int) -> None: ```
- Be explicit with function calls when more than 1 arg:
```python # Good foo(bar=bar, baz=baz)
# Bad foo(bar, baz) ```
- Single arg can be positional:
``python # OK foo(bar) ``
Linting
Follow the lint skill for linting and formatting workflow.
Ignoring Issues
Follow the lint skill ignore policy (Rules section): fix the root cause first; if suppression is genuinely required, use the narrowest possible ignore (specific rule code, single line) with an inline justification; blanket or file-level ignores require a documented exception.
Python-specific: Bandit requires an inline # nosec or # nosec BXXX - reason on the same line as the flagged statement (preceding-line # nosec is silently ignored by Bandit). See the lint skill for other tool ignore configurations (e.g. mypy may use a preceding-line comment plus inline # type: ignore):
# Don't - blanket, unjustified ignore
subprocess.run(["validate.sh"]) # nosec
# Do - narrowest code, inline justification
subprocess.run(["validate.sh"]) # nosec B603 - fixed argv list; no shell
Additional Python-specific note: docstrings are required even for tests — no exceptions.
Testing (Pytest)
- NEVER use unittest style or test classes
- Use pytest-style test functions only
- Leverage
conftest.pyfor shared fixtures - Use fixtures for reusable setup/teardown
- Use
@pytest.mark.parametrizeto reduce duplication - ALWAYS use
assertpyfor assertions — never bareassertstatements.
Keep pytest.raises for exception contexts (assertpy does not replace it)
# Don't
assert result.count == 3
assert "drift" in output
# Do
from assertpy import assert_that
assert_that(result.count).is_equal_to(3)
assert_that(output).contains("drift")
# WRONG
class TestFoo(unittest.TestCase):
def test_bar(self):
...
# CORRECT
def test_foo_bar() -> None:
"""Verify foo handles bar correctly."""
...
Wiring vs. Behavior
A test that asserts field == "literal" where "literal" is also defined in source code is duplication, and produces silent drift the moment either side changes.
- Wiring tests (does X read from canonical Y) — source from the constant. Better
still, ask whether the test is just restating the constant's value; if so, delete it. The codegen / source-of-truth machinery is what guarantees that wiring, not a per-consumer assertion.
- Behavior tests (does X meet a fixed external contract — protocol versions, public
API shapes, business rules) — hardcode the literal. The literal is the contract.
- Fixture data and parser inputs are not wiring — keep those literal. They represent
the world being modeled, not internal state.
Parametrize IDs should describe the case under test (attr=minversion), never encode mutable data values (minversionis0.43.0) — IDs that change with every dependency bump are a smell.
Parametrize ID Hygiene
# WRONG — id encodes the data, churns on every bump
ids=["min_version_is_0.43.0"]
# CORRECT — id names the case
ids=["attr=min_version"]