Skip to content
OpenAgentsbeta
text
1# Python Style Rules
2
3Ordered by how much damage breaking them does.
4
5## Failures must be visible
6
71. **Never write a bare `except:` or `except Exception:` that continues.** It catches
8 the typo in the line above it too. Catch the specific exception you expect.
92. **Never swallow an exception silently.** If ignoring it is right, log it or comment
10 why in one line.
113. **Do not return `None` to signal an error** in a function that also returns `None`
12 legitimately. Raise, or return an explicit result type.
134. **Chain exceptions.** `raise X from err`. Dropping the cause discards the traceback
14 that explains the failure.
155. **Validate at the boundary.** Data from a network, a file, or a subprocess is
16 untrusted. Check it once on the way in, not defensively at every use.
17
18## The obvious traps
19
206. **No mutable default arguments.** `def f(x=[])` shares one list across every call.
21 Use `None` and build inside.
227. **Do not mutate a collection you are iterating.** Build a new one.
238. **Close what you open.** Use `with`, always, including for subprocesses and locks.
249. **Compare with `is` only for `None`, `True`, `False`.** Not for strings or numbers.
2510. **Beware truthiness on containers and numbers.** `if not count` is true for zero.
26 Say `if count is None` when that is what you mean.
27
28## Types and data
29
3011. **Type hints must be honest.** If it can return `None`, the hint says `| None`.
31 A wrong hint is worse than none, because tools trust it.
3212. **Prefer a dataclass or NamedTuple to a dict** for anything with a fixed shape.
33 A dict of known keys is a class that has not admitted it yet.
3413. **Do not use a tuple with more than three elements as a return value.** Name the
35 fields.
36
37## Dependencies
38
3914. **Do not add a dependency for something the standard library does.** `pathlib`,
40 `json`, `itertools`, `dataclasses`, `subprocess` cover an enormous amount.
4115. **Do not add a dependency for one function.** Copy the twenty lines, with credit.
4216. **Pin what you add**, and say in the commit why it is needed.
43
44## Structure
45
4617. **Functions do one thing and are named after it.** A name with `and` in it is two
47 functions.
4818. **No side effects at import time.** No network calls, no file writes, no
49 environment mutation in module scope. Import must be free.
5019. **Match the file you are editing.** Its conventions win over your preferences.
51
52## Comments
53
5420. **Comment the why.** The constraint, the workaround, the reason for the odd choice.
5521. **Docstring the contract**, not the implementation: what it takes, what it returns,
56 what it raises.
5722. **Delete commented-out code.**
58
59## What good looks like
60
61```python
62# The vendor API returns 200 with an empty body on rate limit, so a status
63# check is not enough to tell success from throttling here.
64try:
65 payload = json.loads(response.text)
66except json.JSONDecodeError as err:
67 raise UpstreamError(f"non-JSON body from {url}") from err
68```
69
70Specific exception, cause preserved, and a comment explaining something the reader
71could not have guessed from the code.
72

Keyboard shortcuts

Focus search
/
Go to Explore
ge
Go to Home
gh
Go to Tags
gt
Go to Collections
gc
Show this help
?
Close suggestions or this dialog
Esc