prod-python — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited prod-python (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Write Python like a senior developer — simple, readable, PEP-compliant. No AI slop. No over-engineering. No unnecessary abstractions.
Core principle: The best code is the simplest code that solves the problem correctly.
# SLOP
"""User authentication module for handling login and registration."""
from flask import request
# CLEAN — filename says it all
from flask import requestOnly add module docstrings for genuinely complex algorithms or non-obvious design decisions. Never add # src/path/file.py path comments.
# SLOP — 20 lines to say "sum prices"
def calculate_total(items: List[Dict[str, Any]]) -> float:
"""
Calculate the total price of items.
Args:
items: List of item dictionaries containing prices
Returns:
float: The total sum of all item prices
Raises:
ValueError: If items is empty
KeyError: If price key missing
"""
total = 0.0
for item in items:
total += item['price']
return total
# CLEAN
def calculate_total(items: list[dict]) -> float:
return sum(item['price'] for item in items)Docstrings: one line max for obvious functions. Skip entirely if the signature tells the story.
# SLOP
# Initialize the user list
users = []
# Loop through each record
for record in records:
# Create user object
user = User(record)
# Append to list
users.append(user)
# CLEAN
users = [User(r) for r in records]Comments explain WHY, never WHAT. If you need to explain what code does, rewrite the code.
typing Imports# SLOP — pre-3.9 style
from typing import List, Dict, Optional, Union, Tuple, Any
def process(data: List[Dict[str, Any]]) -> Optional[Dict[str, Union[str, int]]]:
...
# CLEAN — modern builtins + PEP 604
def process(data: list[dict]) -> dict | None:
...Never import from `typing` for: List, Dict, Tuple, Set, FrozenSet, Type, Optional, Union. Use builtins and | syntax.
# SLOP
class DataProcessor:
def __init__(self, config):
self.config = config
def process(self, data):
return self._transform(self._validate(data))
def _validate(self, data):
return data
def _transform(self, data):
return [x * 2 for x in data]
# CLEAN
def process_data(data: list[int]) -> list[int]:
return [x * 2 for x in data]Classes are for state. If your class has one method or no meaningful state, it's a function.
# SLOP
class ValidationResult:
def __init__(self, is_valid: bool, error: str | None = None):
self.is_valid = is_valid
self.error = error
def validate(user: dict) -> ValidationResult:
if not user.get('email'):
return ValidationResult(False, "Email required")
return ValidationResult(True)
# CLEAN
def validate(user: dict) -> str | None:
"""Return error message or None if valid."""
if not user.get('email'):
return "Email required"
return None# SLOP
def get_user_by_email(email: str) -> dict | None:
"""Retrieve a user record from the database by their email address."""
query = "SELECT * FROM users WHERE email = :email"
result = db.execute(query, {"email": email}).fetchone()
return dict(result) if result else None
# CLEAN
def get_user(email: str) -> dict | None:
return db.execute(
"SELECT * FROM users WHERE email = :email", {"email": email}
).fetchone()# SLOP
logger.info("Starting user processing")
logger.info(f"Found {len(users)} users")
for user in users:
logger.debug(f"Processing user {user.id}")
process(user)
logger.info("Finished processing users")
# CLEAN
logger.info("Processing %d users", len(users))
for user in users:
process(user)
if failures:
logger.error("Failed %d users: %s", len(failures), failures[:5])Log events that matter: errors, warnings, key metrics. Not every step.
# SLOP — checking for things that can't happen
def process_order(order: Order) -> None:
if order is None:
raise ValueError("Order cannot be None")
if not isinstance(order, Order):
raise TypeError("Expected Order instance")
if not hasattr(order, 'items'):
raise AttributeError("Order must have items")
# actual logic starts here...
# CLEAN — trust your own code, validate at boundaries
def process_order(order: Order) -> None:
for item in order.items:
item.fulfill()Validate at system boundaries (user input, external APIs). Trust internal code.
# Builtins as generics (3.9+)
names: list[str] = []
config: dict[str, int] = {}
pair: tuple[str, int] = ("a", 1)
ids: set[int] = set()
# Union with | (3.10+)
def find(id: int) -> User | None: ...
def parse(value: str | bytes) -> dict: ...
# type statement for aliases (3.12+)
type JSON = dict[str, 'JSON'] | list['JSON'] | str | int | float | bool | None
type Handler = Callable[[Request], Response]
# TypeVar with defaults (3.13+)
from typing import TypeVar
type T = TypeVar('T', default=int)
# Generic classes — modern syntax (3.12+)
class Stack[T]:
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()# SKIP type hints — signature is obvious
def double(x):
return x * 2
def greet(name):
return f"Hello, {name}"
# ADD type hints — return type isn't obvious
def fetch_user(user_id: int) -> User | None: ...
def parse_config(path: str) -> dict[str, str]: ...
def connect(url: str, *, timeout: float = 30) -> Connection: ...Type-hint when the types clarify. Skip when they're noise.
# Use match for complex dispatch — not if/elif chains
match command:
case {"action": "create", "name": str(name)}:
create_resource(name)
case {"action": "delete", "id": int(id_)}:
delete_resource(id_)
case {"action": str(action)}:
raise ValueError(f"Unknown action: {action}")
# For HTTP status handling
match response.status_code:
case 200 | 201:
return response.json()
case 404:
return None
case 429:
raise RateLimitError(response.headers.get("Retry-After"))
case status if status >= 500:
raise ServerError(f"Server error: {status}")# Collect multiple errors, raise together
async def validate_all(items: list[dict]) -> list[dict]:
errors = []
valid = []
for i, item in enumerate(items):
try:
valid.append(validate(item))
except ValueError as e:
errors.append(e)
if errors:
raise ExceptionGroup("Validation failed", errors)
return valid# Use f-strings, never % or .format()
name = f"{first} {last}"
path = f"/api/v{version}/users/{user_id}"
msg = f"Processed {count:,} items in {elapsed:.2f}s"# Assign and test in one expression
if (match := pattern.search(text)) is not None:
process(match.group(1))
if (user := get_user(email)) is not None:
send_welcome(user)
# In while loops
while (chunk := f.read(8192)):
process(chunk)
# In comprehensions
results = [
cleaned
for raw in data
if (cleaned := clean(raw)) is not None
]# Specific exceptions with context
def load_config(path: str) -> dict:
try:
with open(path) as f:
return json.load(f)
except FileNotFoundError:
raise ValueError(f"Config not found: {path}") from None
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in {path}: {e}") from e
# Custom exceptions — only when callers need to catch them
class PaymentError(Exception):
def __init__(self, amount: float, reason: str):
self.amount = amount
self.reason = reason
super().__init__(f"Payment of {amount} failed: {reason}")Never catch bare Exception unless re-raising. Never silently swallow errors.
# When you need structured data with known fields
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class User:
name: str
email: str
active: bool = True
# For config / settings
@dataclass(frozen=True, slots=True)
class DBConfig:
host: str
port: int = 5432
pool_size: int = 10Use slots=True for memory efficiency. Use frozen=True when immutability makes sense.
import asyncio
import httpx
async def fetch_users(urls: list[str]) -> list[dict]:
async with httpx.AsyncClient() as client:
tasks = [client.get(url) for url in urls]
responses = await asyncio.gather(*tasks, return_exceptions=True)
results = []
for resp in responses:
if isinstance(resp, Exception):
logger.error("Fetch failed: %s", resp)
continue
results.append(resp.json())
return resultsfrom contextlib import contextmanager
@contextmanager
def db_transaction(conn):
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
# Usage
with db_transaction(conn) as tx:
tx.execute("INSERT INTO users ...")# YES — simple transforms and filters
active = [u for u in users if u.active]
by_id = {u.id: u for u in users}
emails = {u.email for u in users}
# NO — too complex, use a loop
# SLOP
results = [
transform(item)
for group in data
for item in group.items
if item.valid and item.category in allowed
and not item.archived
]
# CLEAN
results = []
for group in data:
for item in group.items:
if item.valid and item.category in allowed and not item.archived:
results.append(transform(item))If a comprehension needs more than one if or is hard to read in 2 seconds, use a loop.
from pathlib import Path
config_dir = Path.home() / ".config" / "myapp"
config_dir.mkdir(parents=True, exist_ok=True)
for py_file in Path("src").rglob("*.py"):
process(py_file)
content = Path("data.json").read_text()
Path("output.txt").write_text(result)from enum import StrEnum
class Status(StrEnum):
PENDING = "pending"
ACTIVE = "active"
SUSPENDED = "suspended"
# Use StrEnum so values serialize naturally
user.status = Status.ACTIVE
assert user.status == "active" # works# 1. Standard library
import json
import logging
from pathlib import Path
# 2. Third-party
import httpx
from fastapi import FastAPI
# 3. Local
from .models import User
from .config import settingsNo blank lines within groups. One blank line between groups. Alphabetical within each group. Absolute imports preferred. Use isort for automation.
project/
src/
project_name/
__init__.py
main.py
models.py
config.py
tests/
test_main.py
test_models.py
conftest.py
pyproject.tomlUse pyproject.toml for all config. No setup.py, no setup.cfg, no requirements.txt for libraries (use pyproject.toml dependencies). requirements.txt is acceptable for applications that pin exact versions.
| Situation | Do | Don't | |
|---|---|---|---|
| Types | list[str], `dict | None` | List[str], Optional[Dict] |
| Module docstrings | Skip | """Module for X.""" everywhere | |
| Function docstrings | One line or skip | Multi-paragraph for simple code | |
| Comments | Explain WHY | Narrate WHAT | |
| Functions | One clear purpose | _helper, _util suffixes | |
| Classes | When state is needed | Single-method wrappers | |
| Errors | Specific + context | Bare except Exception | |
| Logging | Errors + key events | Every step | |
| Strings | f-strings | .format() or % | |
| Paths | pathlib.Path | os.path.join | |
| Data | @dataclass(slots=True) | Plain dicts for structured data | |
| Config | pyproject.toml | setup.py + setup.cfg | |
| Constants | StrEnum / IntEnum | Magic strings/numbers | |
| Validation | At boundaries only | Defensive checks everywhere |
from typing import List, Dict, Optional, Union — use builtins + |from __future__ import annotations — unnecessary on 3.13+# src/path/file.py comment at top_helper, _util, _internal suffixisinstance checks in internal codeif x is not None: return x / else: return None → just return x**kwargs when you know the exact parameters__init__.py with docstringstry: ... except Exception: passBefore (AI slop — 45 lines):
from typing import List, Dict, Any, Optional
class UserValidator:
"""Validator for user data."""
def __init__(self) -> None:
self.required_fields: List[str] = ['email', 'name']
def validate(self, user: Dict[str, Any]) -> Dict[str, Any]:
"""
Validate user data.
Args:
user: User dictionary to validate
Returns:
Validation result with is_valid and errors
"""
errors: List[str] = []
for field in self.required_fields:
if not user.get(field):
errors.append(f"{field} is required")
return {
'is_valid': len(errors) == 0,
'errors': errors
}
validator = UserValidator()
result = validator.validate(user_data)
if not result['is_valid']:
handle_errors(result['errors'])After (clean — 8 lines):
def validate_user(user: dict) -> list[str]:
errors = []
if not user.get('email'):
errors.append("Email required")
if not user.get('name'):
errors.append("Name required")
return errors
if errors := validate_user(user_data):
handle_errors(errors)Result: 82% less code. More readable. Same functionality. No imports needed.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.