Debug¶
Xonsh supports two complementary ways to debug xonsh code:
Debug in IDE — attach a full graphical debugger from an editor like VS Code.
Instant debugging — drop into a debugger at the exact call site with
@.debug, with automatic engine selection and a xonsh-syntax REPL when no external debugger is installed.
Debug in IDE¶
Xonsh extension for VS Code provides syntax highlighting and basic language support for .xsh files.
Install via the extensions menu.
Instant debugging¶
When you need to stop execution at a specific call site without wiring up
an IDE, xonsh ships a debugging helper attached to every session as
@.debug. It works like Python’s builtin breakpoint(), but with
automatic engine selection, session-aware fallbacks, and a xonsh-syntax
REPL when no external debugger is installed.
Quick Start¶
Drop into a debugger at any point in your xonsh code:
@.debug.breakpoint()
The engine is chosen automatically in priority order:
pdbp → ipdb → pdb → execer → eval.
The first one that is importable (or, for execer, available on the
session) wins.
To force a specific engine for a single call:
@.debug.breakpoint(engine='pdbp')
@.debug.breakpoint(engine='ipdb')
@.debug.breakpoint(engine='pdb')
@.debug.breakpoint(engine='execer') # xonsh REPL at the call site
@.debug.breakpoint(engine='eval') # plain-Python REPL
Setting the Default Engine¶
Set $XONSH_DEBUG_BREAKPOINT_ENGINE in your xonsh RC to
change the default used when engine is not passed (or is 'auto'):
$XONSH_DEBUG_BREAKPOINT_ENGINE = 'pdbp'
Allowed values: 'auto' (default), 'pdbp', 'ipdb', 'pdb',
'execer', 'eval'.
An explicit argument to breakpoint() always beats the env var.
Engines¶
Engine |
Description |
|---|---|
|
pdbp — enhanced pdb (sticky mode,
syntax highlighting, |
|
ipdb - IPython-flavored pdb. Install with |
|
Stdlib |
|
A REPL at the caller’s frame backed by the session’s
|
|
A minimal REPL using plain Python |
When engine='auto' resolves to an engine, @.debug prints a short
banner identifying the choice and a one-line hint about how to continue or
abort, then drops into that engine.
REPL Commands (execer and eval engines)¶
Both execer and eval engines start a small REPL at the caller’s
frame. The REPL accepts any Python/xonsh expression or statement, and
recognizes the following control commands:
Command |
Effect |
|---|---|
|
Resume execution after the breakpoint. |
|
Abort execution — raises |
|
Same as |
Expression results are printed automatically. Statements (assignments, loops, etc.) run in the caller’s frame, so local variables are visible and modifiable:
execer> @.env['HOME']
'/Users/you'
execer> ls *.py | head -3
debug.py
environ.py
tools.py
execer> my_local_var = 42
execer> c
Routing Python’s builtin breakpoint() Through @.debug¶
PEP 553 makes Python’s builtin breakpoint() go through
sys.breakpointhook. @.debug can install a hook that routes every
builtin breakpoint() call through the same engine as
@.debug.breakpoint(). Add the following to your
xonsh RC:
$XONSH_DEBUG_BREAKPOINT_ENGINE = 'pdbp'
@.debug.replace_builtin_breakpoint()
After this, breakpoint() anywhere in xonsh code — or in any plain
Python module loaded inside the session — drops into the configured engine
at the call site. To restore Python’s default behavior:
import sys
sys.breakpointhook = sys.__breakpointhook__