Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add fgmacedo/agent-skills --skill porting-py2-to-py3git clone --depth 1 https://github.com/fgmacedo/agent-skillsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/fgmacedo/agent-skills/porting-py2-to-py3)<a href="https://agentmods.dev/skills/fgmacedo/agent-skills/porting-py2-to-py3"><img src="https://agentmods.dev/badge/skills/fgmacedo/agent-skills/porting-py2-to-py3/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/fgmacedo/agent-skills/porting-py2-to-py3"><img src="https://agentmods.dev/badge/skills/fgmacedo/agent-skills/porting-py2-to-py3.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00166 | $0.06736 |
| Opus 5.5 | $0.00066 | $0.02694 |
| Sonnet 5.5 | $0.00033 | $0.01347 |
| Haiku 4.5 | $0.00017 | $0.00674 |
Grade A, and why
porting-py2-to-py3 scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 4d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 240 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Porting Python 2 to Python 3
Core principle: the port lands on the main branch as Python-2-compatible commits, behind CI gates that only ratchet forward; the interpreter switch is the last, smallest step. Code changes are cheap. What is expensive is production risk, calendar (soak windows, other teams' reviews) and the attention of the team that keeps shipping on the same tree.
Before you start
- Read
references/target-version.mdto choose the target. Default in late 2026: 3.13, with 3.14 as a go/no-go once the suite is green. Never pick an EOL version, and never assume a framework version "won't run" on a newer interpreter: measure it (Phase 0, step 5). - Read
references/tooling.mdfor the converter, the interpreter flags, the pins of the last py2-compatible versions, and which tools are dead (do not recommendcaniusepython3,pylint --py3kon pylint 2.x,futurize --stage2, or thefutureruntime). - Read
references/catalog.mdwhen fixing a specific idiom. It classifies every change as M (a tool rewrites it) or J (decide per site with the stated procedure). references/case-studies.mdhas the tactics behind this workflow (Instagram, Dropbox, Yelp, Mercurial).- OPTIONAL PRE-PHASE: removing-dead-code (sibling skill). Every function, route, job and dependency removed is one fewer to port and verify.
Phase 0: safety net and measurements (on main)
Done when: the environment is reproducible, CI publishes coverage and fails on regression, golden tests exist for every persisted invariant, and the spike has answered which interpreter the current framework chain runs on.
- Freeze what production really runs.
pip freezeinside the production image becomes a versioned lockfile. Base images maintained elsewhere often install unpinned packages that the repo never names (SQLAlchemy, DB drivers, memcache clients). Those are dependencies too. If the base image belongs to another team, build your own frompython:2.7.18-slimplus the lockfile now: the py3 image needs the same layout, and the switch stops depending on their calendar. - Pick the target version with the decision rule in
references/target-version.md. Write it into the project's README and agent instructions file in the same PR. - Coverage as a gate. Run the suite with
coverage(5.5 on py2, 7.x on py3) in CI, publish the number, setfail_underto the current value. Single-source code has lines only one interpreter can execute (if six.PY2:, anexcept ImportErrorfallback for a backport), so exclude them per leg with# pragma: py2 only/# pragma: py3 onlyand the.coveragercinreferences/tooling.md, section 5; otherwise the number is capped below 100 and the gate cannot ratchet to the end. Start collecting coverage from production or staging now (see removing-dead-code for the multi-service design); the window must be long before Phase 2 needs it. - Golden tests for cross-version invariants. Record outputs under py2 as fixtures and assert byte-equality under both interpreters: IDs derived from hashes or
sys.maxint, signed tokens, encrypted payloads, cache keys, serialized exports (JSON, CSV, XLSX, PDF), URLs built from user data, anything parsed by another system. These are the tests that catchb'...'leaks and rounding drift before a deploy does. - One-day spike. Build a py3 image on the target with the py2-compatible framework chain pinned (
references/tooling.md, section 6) and import the chain in isolation, since the application still has py2 syntax at this point:python3 -c "import flask, flask_sqlalchemy, sqlalchemy, <driver>, <rest layer>, <event loop lib>"(Django:django.setup()plusmigrateagainst sqlite) plus a minimal app factory smoke test. Expect the ceiling to differ by stack: the Flask 1.1 chain runs on 3.13, Django 1.11 stops at 3.9 (references/tooling.md, section 6). Check wheels for the target withpip download --only-binary=:all: --python-version 3XY --platform manylinux2014_x86_64 -r requirements.txtbefore building; a C extension without a wheel for the target either builds from source in the image or forces a split pin (step 6). If the chain imports on the target, the cutover changes only the interpreter. If it does not, cut over on the newest version it runs on and make the framework upgrade the next project. One variable at a time. The-t testsstage of the compile gate only becomes meaningful after Phase 1. - Dependency inventory. For every package: last version with 2.7, first without, whether the pinned version imports on the target, and whether a wheel exists for the target. Internal packages without py3 builds go to their owners now; they are the calendar risk. Archived upstreams get a fork (
references/tooling.md, section 7). A package that cannot straddle both interpreters (its last py2 release has no build for the target: pandas 0.24, numpy 1.16, often psycopg2 2.8 and mysqlclient 1.4 without source builds) gets a split pin by environment marker,pkg==old; python_version<"3"andpkg==new; python_version>="3", code restricted to the API subset both versions share, and golden tests for its outputs. From this point: no new package without py3 support. - Baseline the census.
python3 scripts/py2ism_census.py SRC --save py2ism-baseline.jsonand add--checkto CI. Teammates cannot add Python 2 idioms from now on.
What ships with it
7 files beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 4d ago Changed · +31 lines 03a929b8f286
- 5d ago First seen · 209 lines · 166 tokens per session scan A 1a07baf188f1
porting-py2-to-py3 is a skill published in the GitHub repository fgmacedo/agent-skills (10 stars, last pushed 5d ago), licensed MIT. It adds 166 tokens to every session and 6,736 once invoked, about $0.0007 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-10-13.
Other skills, from other repositories
temporal-python-testing
Test Temporal workflows with pytest, time-skipping, and mocking strategies. Covers unit testing, integration testing, replay testing, and local development setup. Use when implementing Temporal workflow tests or debugging test failures.
test-corpus
The testdocuments submodule is a bucket-fetched fixture corpus that is not committed. This skill covers readtestfixture, missing fixtures, valid A/B controls, and submodule push order. Load before running Rust tests on a fresh clone, setting up an A/B control, adding a fixture-backed test, or diagnosing…
python-providers
Create, modify, test, or package Python provider adapters under python/providers, including framework-specific dependencies, public imports, type inference, and provider metadata. Use for Python provider work only; use python-sdk for core SDK changes.
adk-verify-snippets
Checks that every Python code block in a Markdown file actually compiles and runs, by extracting each block to a temporary file, executing it in an isolated subprocess, and writing a pass/fail report with per-snippet coverage. Use when the user asks to verify, test, or validate the code samples in a README, a guide…
adk-setup
Sets up a local ADK Python development environment in a git clone of the open-source adk-python repository: a uv virtual environment, all dependency extras, pre-commit hooks, and a first unit-test run. Runs only when explicitly requested, never on its own. Use when asked to set up, bootstrap, or repair a development…
maintaining-python-tests
Maintains existing pytest and Django test suites without weakening correctness. Use when asked to reduce Python test runtime or CI work, investigate slow pytest families, remove stale migration tests, consolidate repeated setup, improve Python test ownership, or measure whether a test optimization worked after merge.…