python
Use when writing Python command-line tools, automation scripts, data pipelines, small web dashboards or machine-learning code — project layout with uv, standard-library-first CLIs, subprocess and API
SKILL.mdskills/languages/python/SKILL.md
GitHubPython
Default: the current stable CPython, uv for environments and dependencies, standard library first, unittest or pytest, one entry point per tool.
Setup
uv init(oruv venvfor scripts),uv add <pkg>, commituv.lock. Run withuv run.- For single-file tools, declare dependencies inline (PEP 723
# /// scriptblock) and run withuv run script.py; nothing to install globally. - Pin the interpreter (
.python-version,requires-python). A hosted runtime may default to an older version than your machine; check before relying on new syntax.
Writing tools that other tools can call
- Parse arguments with
argparse; provide--help,--dry-runand--json. - Write results to stdout, diagnostics to stderr, and return meaningful exit codes (0 ok, 1 findings, 2 usage error).
- Make reruns safe: write to a temporary file and
os.replaceit into place; check state before acting. - Prefer
pathlib,subprocess.run([...], check=False, capture_output=True, text=True)and explicit encodings (encoding="utf-8"). - Wrap network calls with bounded retries and exponential backoff on transient errors only (5xx, rate limits, timeouts); do not retry on 4xx.
- Keep a local cache of the last good response so a tool can still produce output when the network is down, and say in the output that the cache was used.
Testing
python -m unittest discoverneeds nothing extra; usepytestwhen fixtures or parametrisation help.- Mock the boundary (HTTP, subprocess, clock), not internal functions.
- For anything printed to users, test the text that matters, not formatting noise.
- Add a regression test for each bug before fixing it.
Data and ML
pandasfor tabular work, but load with explicitdtypes and parse dates deliberately; silent type inference is a common source of wrong numbers.- CPU-only machine learning: install the CPU wheel index of PyTorch so CUDA libraries are not pulled in, and cap threads (
torch.set_num_threads) on shared machines. - Keep random seeds explicit and log them with results.
Verification loop
uv run ruff check(orpython -m pyflakes) — no errors.- Tests pass.
- Run the tool end to end once with real input and once with
--dry-run. - Run with
python -Iwhen executing code near untrusted files: isolated mode ignores the current directory and user site-packages, so a planted module cannot shadow the standard library.
Pitfalls
- Module shadowing: a local file named
json.py,random.pyortest.pysilently replaces the standard module. importlib.reloaddoes not reload modules that were imported by name into other modules; in hosted app runners it can raise. Restructure instead of reloading.- Package
__init__.pywith side effects: if a runner imports a package as the entry point, code meant for__main__runs (or does not). Guard withif __name__ == "__main__":. - Tkinter is optional in many distributions; a GUI tool must fall back to a CLI when it is missing.
- Mutable default arguments (
def f(x=[])) persist between calls. - Time zones: use aware datetimes (
datetime.now(tz=...)); naive ones break around scheduling and comparisons. - Scheduled runs (cron, systemd timers) have a minimal environment: no shell profile, different
PATH, no virtualenv activation. Use absolute paths anduv run. - Long-running jobs on a shared PC: use a lock file (
fcntl.flock) so a second run does not start, and log progress so a killed run can resume.