pypi xonsh 0.23.0
v0.23.0

10 hours ago

0.23.0 (2026-04-19)

Xonsh 0.23 REFORGED

Release Description

Overview

A major release focused on reliability and language capabilities. The process subsystem has been reworked with proper thread safety, file descriptor management, and pipe handling across all platforms. The parser now supports PEP 701 f-strings, the walrus operator for env variables, and positional-only arguments. Completions are smarter — sorted by substring match position with visual highlighting. Callable aliases gained a local env overlay, decorator-based configuration, and full help/superhelp support. Globbing is unified under $DOTGLOB with a new regex match glob m. Over 100 potential breaking cases were identified and resolved, making this the most stable release of xonsh to date.

Changes requiring attention

Process subsystem reworked (#6159)

Pipe file descriptor management, thread safety, and signal handling have been extensively investigated, rigorously tested, and corrected. The internal thread management mechanisms for callable aliases have been stabilized and thoroughly stress-tested. Terminal handshake has been added, along with additional OS signal handling to improve behavior when xonsh process groups run in the foreground, background, or as child processes. We ask you to report any issues related to I/O and file descriptors to the issue tracker, so we can catch potential edge cases.

Error handling for subprocess chains enabled by default (#6267)

Xonsh now treats subprocess commands like real code. Every subprocess chain raises an exception on non-zero exit by default ($XONSH_SUBPROC_RAISE_ERROR=True), so a failing command in a function or loop stops execution immediately instead of silently letting subsequent logic run on invalid state:

ls nofile                          # exception
ls nofile || echo fallback         # no exception — chain handled the error
echo ok && ls nofile ; echo done   # exception on the first chain

def func():
    echo Start
    ls nofile    # exception
    echo End
func()
# BEFORE: Start <stderr> End
# NOW: Start <stderr> <exception>

Captured subprocess !() does not raise — full control is on the user:

if !(ls nofile):    # no exception — user handles the result
    pass

For granular error handling, use command decorators and env swap:

@error_ignore ls nofile                        # suppress for this command
with @.env.swap(XONSH_SUBPROC_RAISE_ERROR=False):
    ls nofile                                  # suppress for this block
!(@error_raise ls nofile)                      # raise exception

The old $RAISE_SUBPROC_ERROR (raise exception on every command) is renamed to $XONSH_SUBPROC_CMD_RAISE_ERROR (default False).

Globbing: $DOTGLOB now controls all globs including regex (#6234)

Previously regex globs (r`\..*`) and backtick globs always matched dotfiles regardless of $DOTGLOB. Now all glob forms respect it uniformly. Since $DOTGLOB defaults to False, existing scripts that use regex globs to match hidden files will stop finding them. Set $DOTGLOB = True if you want to match hidden files.

Prompt: Completions match by substring, not just prefix (#6125)

Completions now match by substring, not just by prefix. Typing deploy will find dev-xonsh-deploy, and results are sorted by the position of the match — earlier occurrences rank higher.

Don’t forget about $COMPLETION_MODE = "menu-complete" if you want to select the first option immediately.

Shining Features

Substring Completions (#6125)

aliases |= {'dev-xonsh-deploy': 'echo'}
deploy<Tab>
# dev-xonsh-deploy    # matched by substring, sorted by position

PEP 701 f-strings (#6202)

echo f"{"$HOME"}"
# /home/snail
echo f"{'hello':>10}"
#      hello

Compile XSH Files, Xontribs and Imports (#6167)

# ~/.xonshrc compiled on first load
import mymod           # mymod.xsh compiled and cached
xontrib load gitinfo   # xontrib gitinfo.xsh compiled and cached

Non-blocking Prompt (#6183)

Syntax highlighting is now non-blocking — typing, completion and navigating through history feel instant regardless of $PATH size. Especially noticeable on Windows with slow directories. Slow $PATH directories can be cached using $XONSH_COMMANDS_CACHE_READ_DIR_ONCE.

Regex glob m with match groups and chain processing (#6235)

for parent, file in m`src/(.*)/(.*\.png)`:  # return match groups
    print(parent, file)

m`src/.*`.files().paths()  # chain processing
m`src/(.*)/(.*\.py)`.select(1).unique().sorted()  # group chain processing

Help and Superhelp for Environment Variables and Aliases (#6222, #6263)

$PATH?     # shows variable description

my-ls?               # shows alias, resolved alias and executable path
my-callable-alias??  # + shows source code and file location of callable alias

Instant Click CLI for Callable Aliases (#6265)

@aliases.register_click_command
@aliases.click.option('--name', default='World')
def _hello(ctx, name):
    """Greet someone."""
    print(f'Hello {name}!', file=ctx.stdout)
    print(f'Callable alias args like stdout are available in ctx.', file=ctx.stdout)
    ctx.click.echo('And click too.')

hello --name Snail    # Hello Snail
hello --help          # shows usage, options, description
hello??               # shows source code and file location if it was imported

Command Decorators List Extended (#6212)

Added @path, @paths, @error_ignore, @error_raise.

$(@path echo '/bin')                 # Path('/bin')
echo 1 && @error_ignore ls nonono    # no exception that stopped the script execution

Take a look at the documentation if you want to create your own.

Emoji and Symbols (#6246)

Activate completer:

$XONSH_COMPLETER_EMOJI_PREFIX = "::"     # disabled by default
$XONSH_COMPLETER_SYMBOLS_PREFIX = ":::"  # disabled by default

::<Tab>        # shows emoji picker: 🌓✨
::cat<Tab>     # shows 🐈 related emoji
::<Tab>        # shows symbols picker: ⚝
:::arr<Tab>    # shows arr symbols: →, ↔, ↗.

Take a look at the documentation if you want to add random emoji to prompt.

Prompt: Tab/Shift-Tab indent and Shift+Enter newline (#6213)

IDE-like experience in the prompt: select lines of a multiline command with Shift+Arrow, then Tab/Shift-Tab to indent/dedent the selection. Shift+Enter inserts a newline without submitting.

Cursor Position for Next Command (#6244)

$XONSH_PROMPT_NEXT_CMD = 'echo My name is @(<edit>)'

Windows Script Execution (#6180)

$PATHEXT = ['.xsh', '.py']
./myscript.xsh    # runs in xonsh
./myscript.py     # runs in python
./myscript        # resolved by PATHEXT

Xonsh Activator in virtualenv

Support for the xonsh activator will be restored in virtualenv soon.

Xonsh Packaging for Nix (#6288)

Now we have Nix Flake that builds xonsh from git source (thanks @SamLukeYes!):

nix build 'github:xonsh/xonsh'

Xonsh Installer for Windows

Experimental. Now we have Xonsh installers for Windows 8.1+.

Xonsh Nightly Build

We introduced continuous nightly build that has Xonsh AppImage, Windows Installers and experimental Flatpak and Linux Nuitka Binary.

Xonsh Documentation

Now xonsh documentation has much more information, examples and code.

Xonsh Merch

Our friends at HELLOTUX have created an awesome collection for us — including bags, backpacks, T-shirts, and hoodies. Check it out - https://www.hellotux.com/xonsh

Release Notes

Important changes

  • Error Handling: Raising exceptions for subprocess chains is enabled by default. Logical operations (||, &&) are handled correctly. $RAISE_SUBPROC_ERROR deprecated in favor of $XONSH_SUBPROC_CMD_RAISE_ERROR (#6267)
  • Processes: Major improvements to core logic for threads, pipes, file descriptors, and process output management across all platforms (#6159)
  • Parser: First version with support of PEP 701 f-strings (#6202)
  • Completer: Order completions by both prefix and substring matches, sort by substring position. Remove $CASE_SENSITIVE_COMPLETIONS (#6125)
  • Glob: $DOTGLOB now controls all forms of globbing uniformly (normal, regex) with a dedicated documentation page (#6234)
  • Performance: Compile xsh xontribs and imports (#6167)
  • Windows/WSL: Improved execution performance and prompt highlighting with commands cache (#6183)
  • Windows: Fixed executing scripts and binary files (#6180)

Features

Fixes

  • Processes: Major improvements to core logic for threads, pipes, file descriptors, and process output management across all platforms (#6159), @anki-code (@gforsyth, @jaraco, @jnoortheen, @scopatz, @AstraLuma, @Qyriad, @doronz88, @AdamJamil, @davidxmoody, @andry81, @blahgeek, @wlritchi, @Harding-Stardust, @arkhan, @mitnk, @whitelynx, @junegunn, @dev2718, @deeuu, @laloch, @beetleb, @cottrell, @ediphy-dwild, @nedsociety, @gnat, @nahoj, @andrew222651, @lambda-abstraction, @lunrenyi, @greenbech, @taw, @bestlem, @jlevy, @kokeshing, @FlyingWombat, @rosalogia, @CaremOstor, @krissik, @Techcable, @tkossak, @inmaldrerah, @Cadair, @720415, @Minabsapi, @dyuri, @raddessi, @zscholl)
  • Process: Close only writer in case of reading from stdin in callable alias (#6266), @anki-code
  • Process: Implement post command error handling (b07d831), @anki-code
  • Process: Reopen stdin from /dev/tty so that child processes (e.g. fzf, vim) can interact with the terminal when xonsh reads a script from stdin (#6274), @anki-code
  • Parser: Fix check_for_partial_string: unmatched/unclosed quotes inside # comments prevent the prompt from being submitted (#6264), @anki-code
  • Parser: Fix error handling in case of wrong dict {'A':5,6} (#6269), @anki-code (@yaxollum, @Techcable)
  • Parser: Fix loop on \ sequence (#6194), @anki-code (@MajoranaOedipus, @sharktide)
  • Parser: Fix parsing macro block with comments (#6216), @anki-code (@yaxollum, @alextremblay)
  • Parser: Fix parsing path with num in case cd /tmp/123 && ... (#6193), @anki-code (@JamesParrott, @PodioSpaz)
  • Parser: Fix single word gulping after block with indent (#6217), @anki-code
  • Parser: Fix try_subproc_toks issue with wrong wrapping a command with parentheses (#6233), @anki-code (@jun0, @gnewson, @cyb3rmonk)
  • Parser: Fix ValueError in typed inline env variables e.g. $QWE=False xonsh --no-rc (#6221), @anki-code (@jnoortheen)
  • Parser: Fix regress with parsing a#b;c (#6168), @anki-code (@azazel75, @jnoortheen, @Cadair)
  • Parser: PEP 570 positional-only args support (#6268), @anki-code (@lambda-abstraction)
  • Callable Alias: Treat unthreadable callable alias exiting (#6252), @anki-code
  • Callable Alias: Added exception with workaround in case of using explicit unthreadable callable alias in pipe (#6165), @anki-code (@Qyriad, @gforsyth, @jnoortheen)
  • Completer: Add @aliases.completer decorator and fix FuncAlias support (#6238), @anki-code
  • Completer: Fix CommandPipeline completion: no hanging on blocking properties (#6229), @anki-code (@vadym-shavalda)
  • Completer: Fix xpip completion. Add public API for python modules completion. Add API to register file matching (#6239), @anki-code (@nahoj)
  • Completer: Fixed completion of file names with newlines (#6335), @anki-code (@luziferius)
  • Completer: Fixed TAB path completion creating multiple single quotes. (#5102), @anki-code (@kouhe3)
  • Completer: Added modern locations to bash completions: Nix, Linuxbrew, Darwin (#6347), @anki-code
  • Prompt: Fix async prompt race condition when $ENABLE_ASYNC_PROMPT=True (#6250), @anki-code
  • Prompt: Restore terminal state after using captured subprocess in key bindings (#6182), @anki-code (@wotsushi, @bobhy, @deeuu, @laloch, @melund, @scopatz, @pigasus55)
  • Prompt: Support retry on EINTR (errno 4) in ptk. Fix exceptions when xonsh runs as a child process (#6192), @anki-code (@vrzh, @dysfungi)
  • Prompt: Now MULTILINE_PROMPT supports ptk {COLOR} notation as well as ANSI escape codes and callable has line number and width #6308, @anki-code (@deftasparagusanaconda)
  • Readline: Fix the case when output disappears in case of no newline character (#6177), @anki-code (@ladyrick, @JamesParrott, @yaxollum)
  • Readline: Fix the case when completion can remove prefix (#6230), @anki-code (@Nesar21)
  • History: Switch JSON history backend to atomic file replacing and remove race condition on flushing history at exit (#6249), @anki-code (@hplar, @InfiniteCoder01, @jaraco)
  • History: Reimplement sqlite history backend erasedups and add json history backend support #6293 @anki-code (@FlyingWombat)
  • Glob: $DOTGLOB now controls all forms of globbing uniformly (normal, regex) with a dedicated documentation page (#6234), @anki-code (@inventhouse, @AstraLuma, @gforsyth, @scopatz)
  • Glob: Remove legacy glob logic that produced issue (#6231), @anki-code (@t184256, @agoose77)
  • Env: Fix empty path in $PATH (#6169), @anki-code
  • Env: Fix EnvPath (e.g. $PATH) mirroring to os.environ in case of update and $UPDATE_OS_ENVIRON=True (#6171), @anki-code (@NorthIsUp, @AstraLuma, @jaraco, @scopatz)
  • Env: Detype and detype_all now in sync (#6195), @anki-code (@dconeybe)
  • Env: Fix TERM environment variable not set in xonsh --no-env (#6220), @anki-code
  • Env: Fix RESET in $XONSH_STDERR_POSTFIX to colorize stderr properly (#6218), @anki-code (@alvarv, @slacksystem)
  • Env: Fix $XONSH_STDERR_PREFIX (b7d3298), @anki-code
  • Events: Edge case: subprocess call in @events.on_post_rc leads to suspension by the OS (#5244), @anki-code (@skaphi, @bestlem, @lf-, @Lunaphied)
  • Mac: Fix xonsh.platforms.sysctlbyname returns bytes instead of string when return_str=True (#6190), @Manhhoangvp95
  • Exec: Fix exec alias to prevent issues with recursive calls and ENOEXEC processing (#6198), @anki-code (@sae13, @g33kex, @lexbailey, @tacaswell, @FlyingWombat, @MajoranaOedipus)
  • Import: Fix CPython sys_path_init requirement to have current directory in sys.path for executed script (#6219), @anki-code
  • Builtins: xcontext is working on Windows without exception (#6199), @anki-code
  • Style: Fix #5163 (register_custom_style KeyError) (ae0c54e), @anki-code (@andrew222651, @dysfungi, @thallium)
  • Performance: Reduce expensive operations around getting VCS branch on every prompt (#6184), @anki-code
  • Performance: Reduce startup time for non-interactive running by ptk shape lazy loading (#6185), @anki-code
  • Stability: Fix code issues: #6191, #6215, #6254, #6257, #6251, #6276, #6281, #6282, @anki-code (@jaraco, @SirNickolas, @Juncheng-wq)
  • Stability: Fix _xhj_get_data_dir_files: skip unreadable file instead of exit (bfacf94), @anki-code
  • Stability: Fix is_file check (38162f4), @anki-code
  • Stability: Handle broken pygments plugins in cache discovery #6295 @anki-code (@Marin-Kitagawa)
  • Stability: Use getuid to detect root instead of user #6296, @anki-code (@jaymehta-g)
  • Windows: Fix executing scripts and binary files (#6180), @anki-code (@gforsyth, @kalyan860, @jaraco, @dawidsowa, @samueldg, @tahir-hassan)
  • Windows: Fix raw paths completion (#6179), @anki-code (@zstg, @mwiebe, @adqm, @jaraco, @scopatz, @Ethkuil)
  • Windows: Fix unstable tests (#6163), @anki-code
  • Windows: Fix CDLL exception in MSYS2 when running xonsh (#6176), @anki-code
  • Install: Update mamba git+extras install docs and script (#6151), @ReinerBRO (@jdjohnston, @MrIridescent, @anki-code)
  • Tests: Add strict check of using python -m pytest instead of pytest (#6173), @anki-code (@rautyrauty)
  • Tests: Fix unwanted output and exceptions from tests (#6178), @anki-code
  • Tests: If you actually read this huge amount of awesome release notes, you're amazing, thanks, @anki-code
  • Tests: Split integration tests into fast integration tests and slow stress tests (#6224), @anki-code
  • Docs: Fix envvars page and update the main page (#6214), @anki-code
  • Python 3.14: Fix DeprecationWarning on Python 3.14 (#6279), @anki-code (@jaraco, @JamesParrott, @simonLeary42)
  • Python 3.15: Fix ResourceWarning in sqlite history backend (#6323), @anki-code
  • Python 3.15: Fix ResourceWarning in procs/specs (#6324), @anki-code

Documentation

  • Website: Added dark mode on landing (#6261), @anki-code
  • Docs: Complete update: new pages, the sections structure, xonshcon blocks parser, @anki-code

Don't miss a new xonsh release

NewReleases is sending notifications on new releases.