python — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited 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.
<!-- target: ~2200 tokens (real tiktoken count) | 20 rules with severity classification -->
Purpose: Prevents the Python-specific mistakes LLMs make on autopilot — mutable defaults, bare excepts, missing guards, and subtle performance traps that pass review but break in production.
Where these rules don't strictly apply: test fixtures, generated code, throwaway scripts, REPL exploration, and tutorial snippets may legitimately differ. The rules below apply to production code paths and reusable libraries.
def process(data) tells callers nothing. Use def process(data: list[str]) -> dict[str, int]:. Return type None should be explicit too. Exception: lambdas and short generator helpers in private scope.list[str], dict[str, int], tuple[int, ...] rather than List, Dict, Tuple from typing.def find(id: int) -> User | None: not def find(id):.Any silences the type checker and hides bugs. Exception: third-party libraries without stubs and explicit dynamic-data boundaries (e.g. JSON decode at the API edge).SystemExit, KeyboardInterrupt, and GeneratorExit. Always catch except Exception: at minimum, or a specific exception class. # Wrong
try:
risky()
except:
pass
# Correct
try:
risky()
except ValueError as e:
logger.warning("Invalid value: %s", e)raise NewError("msg") from original_error to preserve the traceback chain, not raise NewError("msg") alone. # Wrong — items accumulates across calls
def append_item(val, items=[]):
items.append(val)
return items
# Correct
def append_item(val, items=None):
if items is None:
items = []
items.append(val)
return itemsf = open(...) without with leaks handles on exceptions. # Wrong
f = open("data.txt")
data = f.read()
f.close()
# Correct
with open("data.txt") as f:
data = f.read()+= on a string creates a new object. Collect into a list and call "".join(parts) at the end. # Wrong — O(n^2) memory
result = ""
for word in words:
result += word + " "
# Correct
result = " ".join(words)% formatting or "Hello " + name. F-strings are faster, safer, and readable. # Avoid
msg = "User %s has %d items" % (name, count)
# Prefer
msg = f"User {name} has {count} items"{} is faster and more idiomatic. dict(key=value) is only justified when keys are dynamic or come from variables. # Avoid
result = list(map(lambda x: x * 2, items))
# Prefer
result = [x * 2 for x in items]
# For large data, use a generator
total = sum(x * 2 for x in items)x in list is O(n). x in set is O(1). Convert once, query many times. # Wrong for repeated lookups
valid_ids = [1, 2, 3, ...]
if user_id in valid_ids: # O(n) every call
# Correct
valid_ids = {1, 2, 3, ...}
if user_id in valid_ids: # O(1)test_process_returns_empty_dict_on_empty_input not test_process.assert is stripped with python -O. Use explicit if checks with raise ValueError(...) for runtime validation. # Wrong
def test_bad_input():
try:
process(None)
except ValueError:
pass # test passes even if no exception is raised
# Correct
def test_bad_input():
with pytest.raises(ValueError, match="input cannot be None"):
process(None)conftest.py at every level.scope="session" or scope="module" for expensive shared resources with proper teardown via yield.__init__.py as a re-export surface only, not a logic file.setup.py and setup.cfg for new projects. Modern tooling (pip, build, hatch, uv) all read pyproject.toml natively.uv.lock, poetry.lock) ensure reproducibility; flexible ranges in project metadata allow resolver to find compatible versions.These rules target the exact failure modes that appear in LLM-generated Python:
__main__ guards are invisible bugs that only surface at runtime.except: and silent pass blocks make debugging take 10x longer.Any shortcuts defeat the entire value of static analysis.with for file handles causes resource leaks under load.None of these are caught by syntax checkers. All of them appear in production incidents. The MUST/SHOULD/AVOID classification means the security/correctness rules are strict and the stylistic rules respect context.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.