# pm3py Refactor Progress **Design:** [2026-03-18-refactor-design.md](2026-03-18-refactor-design.md) **Branch:** merged to `master` **Started:** 2026-03-18 ## Phase 1 — Create `core/`, normalize names, fix imports **Status: Complete** ### What was done - Created `pm3py/core/` sub-package - Moved all source modules into `core/`: - `protocol.py`, `transport.py`, `client.py`, `hw.py`, `hf.py`, `lf.py` — moved as-is - `hf_14a.py` → `hf_iso14a.py` (renamed) - `hf_15.py` → `hf_iso15.py` (renamed) - `hf_mf.py` → `hf_mfc.py` (renamed) - Normalized client attributes: - `hf.a14` → `hf.iso14a` - `hf.mf` → `hf.mfc` - `hf.iso15` — unchanged - Created `core/__init__.py` re-exporting: `Proxmark3`, `FirmwareInfo`, `PM3Transport`, `PM3Error`, `PM3Response`, `PM3Status`, `Cmd` - Updated `pm3py/__init__.py` to import from `.core.*` - Updated all 10 test files (imports + attribute references) - **30/30 tests passing** ### Backward compatibility - `from pm3py import Proxmark3` still works (re-exported) - **Breaking:** `hf.a14` → `hf.iso14a`, `hf.mf` → `hf.mfc` - **Breaking:** Direct imports like `from pm3py.hf_14a import ...` → `from pm3py.core.hf_iso14a import ...` ## Phase 2 — Extract `sniff/` **Status: Complete** Extracted sniff infrastructure from `core/hf_iso15.py` (615→130 lines) into dedicated modules: - `sniff/trace.py` — `parse_tracelog()`, `TRACELOG_HDR_SIZE` (protocol-agnostic) - `sniff/ndef.py` — NDEF TLV/record decode (`decode_ndef_annotation()`) - `sniff/decode_iso15.py` — ISO 15693 command/response decoders, command tables - `sniff/format.py` — ANSI color formatting, `format_sniff_line()` - `sniff/session.py` — `SniffSession` with `iso15()` method (replaces `sniff_decoded()`) - `sniff/__init__.py` — re-exports all public symbols `core/hf_iso15.py` retains `HF15Commands` (scan/rdbl/wrbl/sniff) and re-exports sniff symbols for backward compat. `download_trace()` and `sniff_decoded()` delegate to `SniffSession`. **65/65 tests passing** (35 sniff tests work through re-exports, no test changes needed). ## Phase 3 — Scaffold `transponders/` **Status: Complete (scaffolded)** Created full directory tree per design: - `transponders/hf/iso14443a3/nxp/` — MIFARE Classic, Ultralight, NTAG - `transponders/hf/iso14443a4/nxp/` — DESFire - `transponders/hf/iso15693/nxp/` — ICODE SLIX2, NTAG 5 - `transponders/hf/iso15693/st/` — ST25TV - `transponders/lf/atmel/` — T55xx - `transponders/lf/em/` — EM4100, EM4x05 All directories have `__init__.py`. Model migration from sim worktree is a separate effort — the sim framework has ~7.8k LOC with deep inheritance chains (`Transponder` → `Tag15693` → `NxpIcodeTag` → `IcodeSlix2Tag`, etc.) and auth mixins (`NxpPasswordAuth`, `NxpAesAuth`). Base class extraction needs to happen alongside model migration. ## Phase 4 — Scaffold `reader/` and `sim/` **Status: Complete (scaffolded)** Created directory trees per design: - `reader/hf/nxp/` — NXP reader ICs (CLRC663, PN5xx) - `reader/hf/st/` — ST reader ICs - `reader/lf/` - `reader/modes/` — inventory, programming, access control workflows - `sim/` — sim session, table compiler, relay (migrate from worktree) All directories have `__init__.py`. Sim migration (~41 files, 7.8k LOC) is a separate effort. ## Next Steps - Transponder migration: extract base classes from sim worktree, populate `transponders/` modules - Sim migration: move sim session, table compiler, relay into `sim/` - Reader modes: implement inventory, programming, access workflows in `reader/modes/` - Sniff: add `decode_iso14a.py` stub when 14443-A sniff support is added