Python Standards Skill
Inspects Python backend for violations of Python language standards and best practices — expectations for production-quality code.
Covers: Style (PEP 8), Naming, Type Annotations, Idiomatic Python, Project Structure, Error Handling, Logging, Testing, Security.
Each finding specifies: standards area, file path, severity, evidence, remediation.
Standards Areas
1 — PEP 8: Style and Formatting
"Code is read much more often than it is written."
Look for:
- Wrong indentation (not 4 spaces — tabs, 2-space)
- Lines exceeding configured limit (flag if no config and regularly >120 chars)
- Import ordering wrong (not: stdlib, third-party, local with blank lines between)
- Wildcard imports (
from module import *)
- Unused imports
- Whitespace issues (missing around operators, before colons, inconsistent blank lines)
- No formatter configured (
black, ruff format, autopep8 in config/pre-commit)
Severity:
- Wildcard imports in production: High
- No formatter, widespread inconsistent style: Medium
- Unused imports across multiple files: Medium
- Inconsistent indentation (mixed tabs/spaces): Medium
- Minor whitespace issues: Low
- Lines slightly over limit: Low
Evidence: File path, line #, PEP 8 rule violated, formatter configured?, snippet
2 — Naming Conventions
"There are only two hard things: cache invalidation and naming things."
Look for:
- Classes not
PascalCase (class user_service, class userService)
- Functions/methods not
snake_case (def getUserById, def GetUser)
- Variables/attributes not
snake_case (userName, orderTotal)
- Constants not
UPPER_SNAKE_CASE (module-level max_retries = 3)
- Modules not lowercase
snake_case (UserService.py, orderProcessing.py)
- Misuse of
_private, __dunder__
- Booleans without predicates (
active vs. is_active)
- Cryptic abbreviations in domain logic (
usr, mgr, proc, cfg)
- Single-letter names outside comprehensions/formulas
Severity:
- Classes using
snake_case/camelCase project-wide: High
camelCase functions/variables widely used: High
- Module files in
PascalCase/camelCase: Medium
- Single-letter variable outside comprehension: Low
- One-off naming inconsistency: Low
Evidence: File path, line #, offending name, expected convention, pattern across codebase?
3 — Type Annotations
"Type hints improve clarity, enable IDE support, and catch bugs before runtime."
Look for:
- Missing return type annotations (especially public methods/API functions)
- Missing parameter type annotations (public/exported functions)
- Excessive
Any usage (>10% of annotated functions)
- Old-style hints (
typing.Optional[X] vs. X | None on Python 3.10+, typing.List vs. list)
- Missing
-> None on void functions
# type: ignore comments everywhere (types wrong, being silenced)
- No type checker configured (
mypy, pyright, pytype, basedpyright in dev deps/CI)
- Strings instead of Enums/Literals for type safety
Severity:
- No type annotations anywhere: High
- Public API functions missing annotations: High
- Excessive
Any (>10%): Medium
- No type checker in dev deps/CI: Medium
- Old-style
typing.Optional/List on Python 3.10+: Low
- Missing
-> None: Low
- Few
# type: ignore comments (<5): Low
Evidence: File path, function signature, missing annotations, project Python version, type checker configured?
4 — Idiomatic Python (Pythonic Code)
"There should be one obvious way to do it." — Zen of Python
Look for:
- Manual index iteration (
for i in range(len(items)) vs. for item in items or enumerate)
- Manual dict key-checking (
if key in d: value = d[key] vs. d.get(key))
- Not using comprehensions (building list with loop +
.append())
- Not using context managers (manual
open()/close(), acquire()/release())
- String concatenation in loops (
+= vs. "".join() or f-strings)
- Mutable default arguments (
def func(items=[]))
- Using
== with None/True/False (should use is None, is True, is False)
- Bare
except: (catches KeyboardInterrupt, SystemExit)
- Not using
pathlib (string manipulation for paths)
- Reimplementing stdlib (
itertools, collections, functools, dataclasses)
- Using
type() instead of isinstance()
- Using dicts/tuples instead of dataclasses/Pydantic
- Global mutable state without thread safety
Severity:
- Mutable default arguments used across codebase: High
- Bare
except:: High
- Global mutable state without thread safety: High
- Manual file/resource management without context managers: Medium
- Widespread
for i in range(len(...)): Medium
- Not using
pathlib: Low
- Not using comprehensions where cleaner: Low
Evidence: File path, line #, non-idiomatic pattern, idiomatic alternative
5 — Project Structure and Packaging
"A well-structured project is easier to navigate, test, and deploy."
Look for:
- No
pyproject.toml (relying only on setup.py/setup.cfg without PEP 517/518/621)
- No clear source layout (all files in repo root vs.
src/ or package directory)
- Missing
__init__.py in packages (non-namespace packages)
- Circular imports (modules import each other →
ImportError or import-inside-function workarounds)
- No
.gitignore for Python (__pycache__, *.pyc, .mypy_cache, .pytest_cache, dist/, *.egg-info)
- Secrets/credentials in source (
.env files, API keys, passwords committed)
- No dependency pinning (
requests vs. requests>=2.28,<3 or no lock file)
requirements.txt only (no pyproject.toml [project.dependencies] for installable lib/app)
- Monolithic modules (single files >500-1000 lines with unrelated classes/functions)
Severity:
- Secrets/API keys/passwords committed: Critical
- Circular imports causing runtime errors: High
- No clear package structure (all files in root): High
- No
pyproject.toml and no setup.py/setup.cfg: Medium
- No
.gitignore for Python: Medium
- Unpinned dependencies, no lock file: Medium
- Monolithic 1000+ line modules: Medium
- Missing
__init__.py: Low
Evidence: Folder structure, missing/misconfigured files, circular import chain, secrets found (redacted values)
6 — Error Handling
"Errors should never pass silently." — Zen of Python
Look for:
- Bare
except: (catches SystemExit, KeyboardInterrupt, GeneratorExit)
- Broad
except Exception: without discrimination (only acceptable at top-level with logging)
- Silent swallowing (
except Exception: pass)
- String exceptions or bare
raise outside except
- Missing exception context (
raise NewException() vs. raise NewException() from original)
- Returning error codes (
None, -1, {"error": ...}) instead of raising
- Overly granular try/except (wrapping every line instead of letting propagation)
- No custom exception hierarchy (all
Exception, ValueError, RuntimeError)
- Missing finally/cleanup (resources not using try/finally or context managers)
- Catching and re-raising without adding context (
except Exception as e: raise e)
Severity:
except: pass or except Exception: pass hiding errors in critical paths: Critical
- Bare
except: in production: High
- Missing exception chain across codebase: Medium
- No custom exception classes: Medium
- Returning error codes in internal APIs: Medium
- Broad
except Exception: with proper logging: Low
- Missing
from in single isolated raise: Low
Evidence: File path, line #, try/except block, exception types caught, handler action, impact
7 — Logging
"Print statements are not a logging strategy."
Look for:
print() for operational output (not CLI tools/scripts)
- No logging configuration (imported but never configured)
- Logging secrets/PII (passwords, tokens, API keys, credit cards, emails)
- Wrong log levels (
logger.info() for errors, logger.error() for info messages)
- No structured logging (plain strings vs. key-value pairs in production services — recommendation not hard rule)
- String formatting in log calls (
logger.info(f"Got {value}") vs. logger.info("Got %s", value))
- Missing exception info (
logger.error(f"Failed: {e}") vs. logger.exception("Failed") or exc_info=True)
- No log correlation (no request ID/correlation ID in multi-user services)
Severity:
- Logging secrets/tokens/PII: Critical
print() throughout production as primary output: High
- No logging configuration in service/application: High
- Missing
exc_info/logger.exception() across codebase: Medium
- Wrong log levels systematically: Medium
- f-string in log calls (performance): Low
- No structured logging in smaller project: Low
Evidence: File path, line #, print()/logger.*() call, info logged (flag if sensitive), logging configured?
8 — Testing Conventions
"Code without tests is broken by design."
Look for:
- No tests at all (no
tests/ dir, no pytest/unittest in deps)
- No test runner configured (not in dev deps or
pyproject.toml [tool.pytest])
- Tests with no assertions (pass regardless of correctness)
- Tests depend on external services without mocking (require live DB/API/network)
- No test isolation (shared mutable state, fail in different order)
- No fixtures/factories (every test manually constructs complex data)
- Test files not following naming (
test_*.py or *_test.py — may not be discovered)
- No coverage configuration (no
pytest-cov, coverage.py)
- Tests mixed with source code (in source package vs. separate
tests/ dir)
Severity:
- No tests in production project: Critical
- Tests assert nothing (false coverage): High
- Tests require live external services, no mock/fake: High
- No test runner in dependencies: High
- Tests share mutable state, break in parallel: Medium
- No coverage configuration: Medium
- Test files not following naming: Medium
- Tests mixed with source: Low
- Missing fixtures for complex setup: Low
Evidence: tests/ dir exists?, test runner/coverage in deps, files with no assertions, tests making external calls
9 — Security Hygiene
"Security is a process, not a product."
Look for:
- Hardcoded secrets (API keys, passwords, tokens, connection strings)
eval()/exec() with user input (arbitrary code execution)
pickle with untrusted data (pickle.loads() on external data)
subprocess with shell=True and user input (command injection)
- SQL injection (string formatting in queries vs. parameterized)
yaml.load() without Loader=SafeLoader
- Debug mode in production config (
DEBUG = True, app.run(debug=True))
- Overly permissive CORS (
allow_origins=["*"] in production)
- No dependency vulnerability scanning (
safety, pip-audit, snyk, dependabot)
- Insecure random (
random vs. secrets for tokens/passwords/session IDs)
assert for validation (stripped with -O flag)
Severity:
- Hardcoded secrets: Critical
eval()/exec() with user input: Critical
pickle.loads() on external/untrusted data: Critical
- SQL injection via string formatting: Critical
subprocess with shell=True + user input: Critical
yaml.load() without safe loader: High
- Debug mode in production config: High
assert for input validation/security: High
random instead of secrets for security values: High
- Overly permissive CORS in production: Medium
- No dependency vulnerability scanning: Medium
- Insecure default settings overridden in production: Low
Evidence: File path, line #, vulnerable code (redact secret values), attack vector, suggested fix
Audit Instructions
- Determine Python version and tooling — check
pyproject.toml, setup.cfg, .python-version, etc. for target version. Check for linters (ruff, flake8), formatters (black), type checkers (mypy, pyright), test runners (pytest).
- Traverse source tree —
.py files in source directories. Skip venvs (venv/, .venv/), auto-generated, migrations, vendored code.
- For each area (1-9), review files using "Look for" patterns.
- Collect findings with: standards area, file path, line #, title, snippet, severity, remediation.
- Report only observable violations — backed by code patterns.
- Respect project's configured standards — defer to project's explicit config (line length, etc.) over default PEP 8.
- Classify conservatively — when in doubt, choose lower severity.
Source: EndToEndLabCR/e-commerce-api-python — distributed by TomeVault.
1---2name: python-standards-33description: Audits Python code for language standards — PEP 8 style, type hints (PEP 484/604), naming, idiomatic patterns, project structure, dependencies, error handling, logging, testing, security. Use when this capability is needed.4---56# Python Standards Skill78Inspects Python backend for violations of **Python language standards and best practices** — expectations for production-quality code.910Covers: Style (PEP 8), Naming, Type Annotations, Idiomatic Python, Project Structure, Error Handling, Logging, Testing, Security.1112Each finding specifies: standards area, file path, severity, evidence, remediation.1314---1516## Standards Areas1718---1920### 1 — PEP 8: Style and Formatting2122> *"Code is read much more often than it is written."*2324**Look for:**25- Wrong indentation (not 4 spaces — tabs, 2-space)26- Lines exceeding configured limit (flag if no config and regularly >120 chars)27- Import ordering wrong (not: stdlib, third-party, local with blank lines between)28- Wildcard imports (`from module import *`)29- Unused imports30- Whitespace issues (missing around operators, before colons, inconsistent blank lines)31- No formatter configured (`black`, `ruff format`, `autopep8` in config/pre-commit)3233**Severity:**34- Wildcard imports in production: **High**35- No formatter, widespread inconsistent style: **Medium**36- Unused imports across multiple files: **Medium**37- Inconsistent indentation (mixed tabs/spaces): **Medium**38- Minor whitespace issues: **Low**39- Lines slightly over limit: **Low**4041**Evidence:** File path, line #, PEP 8 rule violated, formatter configured?, snippet4243---4445### 2 — Naming Conventions4647> *"There are only two hard things: cache invalidation and naming things."*4849**Look for:**50- Classes not `PascalCase` (`class user_service`, `class userService`)51- Functions/methods not `snake_case` (`def getUserById`, `def GetUser`)52- Variables/attributes not `snake_case` (`userName`, `orderTotal`)53- Constants not `UPPER_SNAKE_CASE` (module-level `max_retries = 3`)54- Modules not lowercase `snake_case` (`UserService.py`, `orderProcessing.py`)55- Misuse of `_private`, `__dunder__`56- Booleans without predicates (`active` vs. `is_active`)57- Cryptic abbreviations in domain logic (`usr`, `mgr`, `proc`, `cfg`)58- Single-letter names outside comprehensions/formulas5960**Severity:**61- Classes using `snake_case`/`camelCase` project-wide: **High**62- `camelCase` functions/variables widely used: **High**63- Module files in `PascalCase`/`camelCase`: **Medium**64- Single-letter variable outside comprehension: **Low**65- One-off naming inconsistency: **Low**6667**Evidence:** File path, line #, offending name, expected convention, pattern across codebase?6869---7071### 3 — Type Annotations7273> *"Type hints improve clarity, enable IDE support, and catch bugs before runtime."*7475**Look for:**76- Missing return type annotations (especially public methods/API functions)77- Missing parameter type annotations (public/exported functions)78- Excessive `Any` usage (>10% of annotated functions)79- Old-style hints (`typing.Optional[X]` vs. `X | None` on Python 3.10+, `typing.List` vs. `list`)80- Missing `-> None` on void functions81- `# type: ignore` comments everywhere (types wrong, being silenced)82- No type checker configured (`mypy`, `pyright`, `pytype`, `basedpyright` in dev deps/CI)83- Strings instead of Enums/Literals for type safety8485**Severity:**86- No type annotations anywhere: **High**87- Public API functions missing annotations: **High**88- Excessive `Any` (>10%): **Medium**89- No type checker in dev deps/CI: **Medium**90- Old-style `typing.Optional`/`List` on Python 3.10+: **Low**91- Missing `-> None`: **Low**92- Few `# type: ignore` comments (<5): **Low**9394**Evidence:** File path, function signature, missing annotations, project Python version, type checker configured?9596---9798### 4 — Idiomatic Python (Pythonic Code)99100> *"There should be one obvious way to do it."* — Zen of Python101102**Look for:**103- Manual index iteration (`for i in range(len(items))` vs. `for item in items` or `enumerate`)104- Manual dict key-checking (`if key in d: value = d[key]` vs. `d.get(key)`)105- Not using comprehensions (building list with loop + `.append()`)106- Not using context managers (manual `open()`/`close()`, `acquire()`/`release()`)107- String concatenation in loops (`+=` vs. `"".join()` or f-strings)108- Mutable default arguments (`def func(items=[])`)109- Using `==` with `None`/`True`/`False` (should use `is None`, `is True`, `is False`)110- Bare `except:` (catches `KeyboardInterrupt`, `SystemExit`)111- Not using `pathlib` (string manipulation for paths)112- Reimplementing stdlib (`itertools`, `collections`, `functools`, `dataclasses`)113- Using `type()` instead of `isinstance()`114- Using dicts/tuples instead of dataclasses/Pydantic115- Global mutable state without thread safety116117**Severity:**118- Mutable default arguments used across codebase: **High**119- Bare `except:`: **High**120- Global mutable state without thread safety: **High**121- Manual file/resource management without context managers: **Medium**122- Widespread `for i in range(len(...))`: **Medium**123- Not using `pathlib`: **Low**124- Not using comprehensions where cleaner: **Low**125126**Evidence:** File path, line #, non-idiomatic pattern, idiomatic alternative127128---129130### 5 — Project Structure and Packaging131132> *"A well-structured project is easier to navigate, test, and deploy."*133134**Look for:**135- No `pyproject.toml` (relying only on `setup.py`/`setup.cfg` without PEP 517/518/621)136- No clear source layout (all files in repo root vs. `src/` or package directory)137- Missing `__init__.py` in packages (non-namespace packages)138- Circular imports (modules import each other → `ImportError` or import-inside-function workarounds)139- No `.gitignore` for Python (`__pycache__`, `*.pyc`, `.mypy_cache`, `.pytest_cache`, `dist/`, `*.egg-info`)140- Secrets/credentials in source (`.env` files, API keys, passwords committed)141- No dependency pinning (`requests` vs. `requests>=2.28,<3` or no lock file)142- `requirements.txt` only (no `pyproject.toml [project.dependencies]` for installable lib/app)143- Monolithic modules (single files >500-1000 lines with unrelated classes/functions)144145**Severity:**146- Secrets/API keys/passwords committed: **Critical**147- Circular imports causing runtime errors: **High**148- No clear package structure (all files in root): **High**149- No `pyproject.toml` and no `setup.py`/`setup.cfg`: **Medium**150- No `.gitignore` for Python: **Medium**151- Unpinned dependencies, no lock file: **Medium**152- Monolithic 1000+ line modules: **Medium**153- Missing `__init__.py`: **Low**154155**Evidence:** Folder structure, missing/misconfigured files, circular import chain, secrets found (redacted values)156157---158159### 6 — Error Handling160161> *"Errors should never pass silently."* — Zen of Python162163**Look for:**164- Bare `except:` (catches `SystemExit`, `KeyboardInterrupt`, `GeneratorExit`)165- Broad `except Exception:` without discrimination (only acceptable at top-level with logging)166- Silent swallowing (`except Exception: pass`)167- String exceptions or bare `raise` outside except168- Missing exception context (`raise NewException()` vs. `raise NewException() from original`)169- Returning error codes (`None`, `-1`, `{"error": ...}`) instead of raising170- Overly granular try/except (wrapping every line instead of letting propagation)171- No custom exception hierarchy (all `Exception`, `ValueError`, `RuntimeError`)172- Missing finally/cleanup (resources not using try/finally or context managers)173- Catching and re-raising without adding context (`except Exception as e: raise e`)174175**Severity:**176- `except: pass` or `except Exception: pass` hiding errors in critical paths: **Critical**177- Bare `except:` in production: **High**178- Missing exception chain across codebase: **Medium**179- No custom exception classes: **Medium**180- Returning error codes in internal APIs: **Medium**181- Broad `except Exception:` with proper logging: **Low**182- Missing `from` in single isolated raise: **Low**183184**Evidence:** File path, line #, try/except block, exception types caught, handler action, impact185186---187188### 7 — Logging189190> *"Print statements are not a logging strategy."*191192**Look for:**193- `print()` for operational output (not CLI tools/scripts)194- No logging configuration (imported but never configured)195- Logging secrets/PII (passwords, tokens, API keys, credit cards, emails)196- Wrong log levels (`logger.info()` for errors, `logger.error()` for info messages)197- No structured logging (plain strings vs. key-value pairs in production services — recommendation not hard rule)198- String formatting in log calls (`logger.info(f"Got {value}")` vs. `logger.info("Got %s", value)`)199- Missing exception info (`logger.error(f"Failed: {e}")` vs. `logger.exception("Failed")` or `exc_info=True`)200- No log correlation (no request ID/correlation ID in multi-user services)201202**Severity:**203- Logging secrets/tokens/PII: **Critical**204- `print()` throughout production as primary output: **High**205- No logging configuration in service/application: **High**206- Missing `exc_info`/`logger.exception()` across codebase: **Medium**207- Wrong log levels systematically: **Medium**208- f-string in log calls (performance): **Low**209- No structured logging in smaller project: **Low**210211**Evidence:** File path, line #, `print()`/`logger.*()` call, info logged (flag if sensitive), logging configured?212213---214215### 8 — Testing Conventions216217> *"Code without tests is broken by design."*218219**Look for:**220- No tests at all (no `tests/` dir, no `pytest`/`unittest` in deps)221- No test runner configured (not in dev deps or `pyproject.toml [tool.pytest]`)222- Tests with no assertions (pass regardless of correctness)223- Tests depend on external services without mocking (require live DB/API/network)224- No test isolation (shared mutable state, fail in different order)225- No fixtures/factories (every test manually constructs complex data)226- Test files not following naming (`test_*.py` or `*_test.py` — may not be discovered)227- No coverage configuration (no `pytest-cov`, `coverage.py`)228- Tests mixed with source code (in source package vs. separate `tests/` dir)229230**Severity:**231- No tests in production project: **Critical**232- Tests assert nothing (false coverage): **High**233- Tests require live external services, no mock/fake: **High**234- No test runner in dependencies: **High**235- Tests share mutable state, break in parallel: **Medium**236- No coverage configuration: **Medium**237- Test files not following naming: **Medium**238- Tests mixed with source: **Low**239- Missing fixtures for complex setup: **Low**240241**Evidence:** `tests/` dir exists?, test runner/coverage in deps, files with no assertions, tests making external calls242243---244245### 9 — Security Hygiene246247> *"Security is a process, not a product."*248249**Look for:**250- Hardcoded secrets (API keys, passwords, tokens, connection strings)251- `eval()`/`exec()` with user input (arbitrary code execution)252- `pickle` with untrusted data (`pickle.loads()` on external data)253- `subprocess` with `shell=True` and user input (command injection)254- SQL injection (string formatting in queries vs. parameterized)255- `yaml.load()` without `Loader=SafeLoader`256- Debug mode in production config (`DEBUG = True`, `app.run(debug=True)`)257- Overly permissive CORS (`allow_origins=["*"]` in production)258- No dependency vulnerability scanning (`safety`, `pip-audit`, `snyk`, `dependabot`)259- Insecure random (`random` vs. `secrets` for tokens/passwords/session IDs)260- `assert` for validation (stripped with `-O` flag)261262**Severity:**263- Hardcoded secrets: **Critical**264- `eval()`/`exec()` with user input: **Critical**265- `pickle.loads()` on external/untrusted data: **Critical**266- SQL injection via string formatting: **Critical**267- `subprocess` with `shell=True` + user input: **Critical**268- `yaml.load()` without safe loader: **High**269- Debug mode in production config: **High**270- `assert` for input validation/security: **High**271- `random` instead of `secrets` for security values: **High**272- Overly permissive CORS in production: **Medium**273- No dependency vulnerability scanning: **Medium**274- Insecure default settings overridden in production: **Low**275276**Evidence:** File path, line #, vulnerable code (redact secret values), attack vector, suggested fix277278---279280## Audit Instructions2812821. **Determine Python version and tooling** — check `pyproject.toml`, `setup.cfg`, `.python-version`, etc. for target version. Check for linters (`ruff`, `flake8`), formatters (`black`), type checkers (`mypy`, `pyright`), test runners (`pytest`).2832. **Traverse source tree** — `.py` files in source directories. Skip venvs (`venv/`, `.venv/`), auto-generated, migrations, vendored code.2843. **For each area (1-9)**, review files using "Look for" patterns.2854. **Collect findings** with: standards area, file path, line #, title, snippet, severity, remediation.2865. **Report only observable violations** — backed by code patterns.2876. **Respect project's configured standards** — defer to project's explicit config (line length, etc.) over default PEP 8.2887. **Classify conservatively** — when in doubt, choose lower severity.289290---291> Source: [EndToEndLabCR/e-commerce-api-python](https://github.com/EndToEndLabCR/e-commerce-api-python) — distributed by [TomeVault](https://tomevault.io).292<!-- tomevault:4.0:skill_md:2026-05-22 -->