tyc trace
tyc trace [TRACEBACK_FILE] [--map-dir DIR]Reads a Python traceback (from the given file, or from stdin when the argument is omitted), locates the matching .py.map v2 source maps, and rewrites File "build/main.py", line N frames to File "src/main.ty", line M.
Examples
python build/main.py 2>err.logtyc trace err.log
# Or pipe directly (no argument → read stdin):python build/main.py 2>&1 | tyc traceWhat it does
- Parse the traceback text (standard Python traceback shape).
- For each frame referring to a
build/*.py, find the matching.py.mapv2. - Look up the
out_line → ty_linemapping for the frame’s line number. - Rewrite the frame to point at
src/*.tyline M. - Replace the source row CPython printed under the frame with the real
.tyrow, and drop the column anchors (~~~~^^^^) — their columns refer to the emitted line, not this one. - Print the remapped traceback.
The output looks like a normal Python traceback, but the frames are .ty paths and line numbers. Frames inside an ExceptionGroup traceback (every failed gather: block prints one) are rewritten too, keeping CPython’s | gutter.
Step 5 matters as much as step 4. Rewriting only the header leaves a frame reading File "src/main.ty", line 10 above a row of emitted Python — sometimes a generated name like __typhon_qi_0__ — that does not exist at main.ty:10, so opening the line named in the traceback shows something else. Where the .ty file is not readable from where tyc trace runs (a traceback pasted from another machine), the original row is kept rather than dropped.
When to use
- After a production crash, on the captured
stderr. - During development, to make pdb frames legible.
- In CI logs, to show team members the
.tysource rather than the emitted.py.
Flags
| Flag | Default | Effect |
|---|---|---|
--map-dir DIR | — | Extra directory to search for .py.map files (<DIR>/.sourcemaps/<file>.py.map, then the legacy adjacent <DIR>/<file>.py.map). Without it, each frame’s map is located from the frame’s own .py path: <dir>/.sourcemaps/<rel>.py.map, walking up to the build root, then a legacy <file>.py.map next to the .py. |
There is no --no-color flag; the remapped traceback is printed as plain text.
Limitations
- Works per-statement (the
.py.mapv2 granularity). Column-level remapping is a future enhancement. - Only frames whose
.pyhas a.py.mapsidecar are rewritten; stdlib and third-party frames are left alone.
A worked example
A program that raises:
def divide(a: int, b: int) -> int: return a // b
def main() -> None: print(divide(10, 0)) # line 5
if __name__ == "__main__": main()Run and capture:
python build/main.py 2>err.logerr.log:
Traceback (most recent call last): File "build/main.py", line 7, in <module> main() File "build/main.py", line 5, in main print(divide(10, 0)) File "build/main.py", line 2, in divide return a // bZeroDivisionError: integer division or modulo by zeroAfter tyc trace err.log:
Traceback (most recent call last): File "src/main.ty", line 7, in <module> main() File "src/main.ty", line 5, in main print(divide(10, 0)) File "src/main.ty", line 2, in divide return a // bZeroDivisionError: integer division or modulo by zeroWhere next
- Source Maps (lowering) —
.py.mapv2 format. tyc debug— pair withtyc tracefor stepping.