Python code review checklist
Python code review often misses code that hides failures. This Python PR checklist covers the mistakes Revix checks for in pull requests. Look for a broad except that swallows errors, a log message formatted before it is needed, and Any used where a precise type fits. Each rule shows the code to flag, the fix and its source.
- Avoid bare except or broad except Exception that swallows errors
- Pre-formatting log messages defeats deferred formatting
- Avoid Any where a precise or object type fits
- Return Self instead of the base class name
- Avoid tempfile.mktemp (race-prone)
- Do not pass untrusted input to getoutput or getstatusoutput
- Do not store passwords in recoverable form
- Passing non-literal strings to LiteralString parameters
- Serializing NaN or Infinity produces invalid JSON
- strict=False admits control characters
- Unpickling untrusted data
11 rules to check in every Python pull request
Revix reviews Python pull requests against 386 rules. This page shows a short list we picked from them. Each rule has a bad example, a good example and a source. We check each rule against its source and update the list every month. Rules marked as flagged by Revix have come up in real reviews.
Avoid bare except or broad except Exception that swallows errors
Broad handlers mask programming errors such as NameError or TypeError and make failures surface far from their cause.
Avoid
try:
value = int(raw)
except:
value = 0Prefer
try:
value = int(raw)
except ValueError:
value = 0Flagged by Revix in real reviews · Anti-pattern · All current versions · Source: 8.5. Exception Chaining
Pre-formatting log messages defeats deferred formatting
Eager formatting wastes CPU in hot paths where debug logging is disabled in production.
Avoid
logger.debug(f'user {user!r} loaded')Prefer
logger.debug('user %r loaded', user)Flagged by Revix in real reviews · Performance · All current versions · Source: Logging HOWTO
Avoid Any where a precise or object type fits
Annotating with Any silently removes the protection the type checker provides at the call sites that receive the value.
Avoid
def load(x: Any) -> str: return xPrefer
def load(x: object) -> str: return str(x)Flagged by Revix in real reviews · Anti-pattern · All current versions · Source: typing — Support for type hints
Return Self instead of the base class name
Using the class name loses the subclass type for chained calls and alternative constructors.
Avoid
def set_name(self, n: str) -> 'Foo': self.n = n; return selfPrefer
def set_name(self, n: str) -> Self: self.n = n; return selfFlagged by Revix in real reviews · Best practice · All current versions · Source: typing — Support for type hints
Avoid tempfile.mktemp (race-prone)
The gap between naming and creating a file allows a symlink or pre-creation attack on the path.
Avoid
import tempfile
path = tempfile.mktemp()
open(path, 'w').write(data)Prefer
import tempfile
f = tempfile.NamedTemporaryFile(delete=False)
f.write(data)
f.close()Security · All current versions · Source: tempfile — SpooledTemporaryFile
Do not pass untrusted input to getoutput or getstatusoutput
These helpers give up the argument-list safety of subprocess and are unsafe with dynamic input.
Avoid
subprocess.getoutput('ls ' + path)Prefer
subprocess.check_output(['ls', path], text=True)Security · All current versions · Source: subprocess - Timeout Behavior
Do not store passwords in recoverable form
Recoverable password storage turns any database leak into an immediate account compromise.
Avoid
user.password = request.form['password']
user.save()Prefer
import hashlib, os
salt = os.urandom(16)
user.password_hash = hashlib.pbkdf2_hmac('sha256', pw.encode(), salt, 600000)Security · All current versions · Source: secrets — Generate secure random numbers for managing secrets
Passing non-literal strings to LiteralString parameters
Sensitive APIs typed with LiteralString rely on that guarantee to prevent injection.
Avoid
run_query(f'SELECT * FROM t WHERE n = {name}')Prefer
cursor.execute('SELECT * FROM t WHERE n = ?', (name,))Security · All current versions · Source: typing — Support for type hints
Serializing NaN or Infinity produces invalid JSON
The default silently produces output that is not valid JSON, so the error appears far from the source, often in a downstream consumer.
Avoid
payload = json.dumps({'avg': float('nan')})Prefer
payload = json.dumps({'avg': avg}, allow_nan=False)Security · All current versions · Source: json — JSON encoder and decoder
strict=False admits control characters
Relaxed parsing of untrusted input weakens the validity guarantee the decoder otherwise gives.
Avoid
json.JSONDecoder(strict=False).decode(body)Prefer
json.JSONDecoder().decode(body)Security · All current versions · Source: json — JSON encoder and decoder
Unpickling untrusted data
Unpickling attacker-controlled bytes gives the attacker code execution in your process.
Avoid
obj = pickle.loads(request.body)Prefer
obj = json.loads(request.body) # or verify an hmac signature before pickle.loadsSecurity · All current versions · Source: pickle - Python object serialization
How Revix applies these rules in pull requests
Revix matches these rules against the code each pull request changes. When a comment rests on one, it names the rule, so the author can read the reasoning and the source instead of taking the bot's word for it.

revixappdevBot
issue: Broad handlers mask programming errors such as NameError or TypeError and make failures surface far from their cause.
📚 Rule (Python): Avoid bare except or broad except Exception that swallows errors
Keep reading
- How to Write a Great PR Review CommentMost PR comments waste the author's time because they never say what they actually want. Here is the four-part format that fixes that.
- Repo-Aware AI Code Review vs. Diff-Based ReviewRepo-aware vs diff-based AI code review: diff review reads only the patch. Repo-aware review catches broken conventions, duplicate abstractions, and drift.
Revix also learns your team's own rules from the code you already merged. Start a free trial and see them on your next pull request.