Python-powered shell providing superset of Python with shell primitives for cross-platform command execution and automation.
Xonsh provides extensive configuration through environment variables, aliases, and xontribs (extensions). The environment system enhances standard environment variables with type validation, conversion functions, and event-driven updates. Configuration can be managed through the interactive shell, configuration files, or programmatically.
from xonsh.environ import Env
from xonsh.built_ins import XSH
class Env:
"""Enhanced environment variable management."""
def __init__(self, **kwargs):
"""Initialize environment.
Parameters
----------
**kwargs
Initial environment variables
"""
def __getitem__(self, key: str) -> object:
"""Get environment variable value.
Parameters
----------
key : str
Variable name
Returns
-------
object
Variable value (type-converted)
"""
def __setitem__(self, key: str, value: object) -> None:
"""Set environment variable.
Parameters
----------
key : str
Variable name
value : object
Variable value (will be type-validated)
"""
def get(self, key: str, default=None) -> object:
"""Get environment variable with default.
Parameters
----------
key : str
Variable name
default : object, optional
Default value if key not found
Returns
-------
object
Variable value or default
"""
def setdefault(self, key: str, default: object) -> object:
"""Set default value if key doesn't exist.
Parameters
----------
key : str
Variable name
default : object
Default value to set
Returns
-------
object
Existing or newly set value
"""
def swap(self, **kwargs):
"""Context manager for temporary environment changes.
Parameters
----------
**kwargs
Temporary variable assignments
Returns
-------
contextmanager
Context manager for temporary changes
"""
# Environment usage examples
env = XSH.env
# Basic variable access
home = env['HOME']
path = env.get('PATH', '')
# Type-converted variables
debug = env['XONSH_DEBUG'] # Auto-converts to bool
history_size = env['HISTSIZE'] # Auto-converts to int
# Temporary environment changes
with env.swap(DEBUG=True, VERBOSE=1):
# Code runs with temporary environment
print(f"Debug mode: {env['DEBUG']}")
# Environment restored after contextfrom xonsh.built_ins import XSH
env = XSH.env
# Shell behavior
env['SHELL_TYPE'] = 'prompt_toolkit' # Shell backend ('prompt_toolkit', 'readline', 'dumb')
env['XONSH_SHOW_TRACEBACK'] = True # Show Python tracebacks on errors
env['XONSH_STORE_STDOUT'] = False # Store command output in history
env['XONSH_DEBUG'] = 0 # Debug level (0-2)
# Prompt configuration
env['PROMPT'] = '{cwd} $ ' # Primary prompt format
env['MULTILINE_PROMPT'] = ' ' # Continuation prompt
env['TITLE'] = '{user}@{hostname}: {cwd}' # Terminal title format
# History settings
env['HISTSIZE'] = 8128 # Number of commands to store
env['HISTFILE'] = '~/.xonsh_history' # History file location
env['XONSH_HISTORY_BACKEND'] = 'json' # History storage backend
# Completion configuration
env['CASE_SENSITIVE_COMPLETIONS'] = False # Case sensitivity for completions
env['COMPLETIONS_CONFIRM'] = True # Confirm ambiguous completions
env['COMPLETION_QUERY_LIMIT'] = 100 # Max completions to show
env['COMPLETIONS_DISPLAY_VALUE'] = 'single' # Completion display mode
env['COMPLETIONS_MENU_ROWS'] = 5 # Completion menu height
# Subprocess behavior
env['RAISE_SUBPROC_ERROR'] = False # Raise exceptions on command failure
env['XONSH_SUBPROC_CAPTURED_PRINT_STDERR'] = True # Print captured stderr
env['XONSH_PROC_FREQUENCY'] = 1e-4 # Process polling frequency
# Color and styling
env['FORCE_POSIX_PATHS'] = False # Force POSIX path separators on Windows
env['INTENSIFY_COLORS_ON_WIN'] = True # Enhance colors on Windows
env['XONSH_COLOR_STYLE'] = 'default' # Color style theme# Xonsh automatically handles type conversion for environment variables
# Boolean variables (accept: True/False, 1/0, "true"/"false", "yes"/"no")
env['XONSH_DEBUG'] = True
env['CASE_SENSITIVE_COMPLETIONS'] = "false" # Converted to False
# Integer variables
env['HISTSIZE'] = 1000
env['COMPLETION_QUERY_LIMIT'] = "50" # Converted to 50
# Float variables
env['XONSH_PROC_FREQUENCY'] = 0.001
# Path variables (support expansion and validation)
env['HISTFILE'] = '~/.xonsh_history' # Expands ~ to home directory
env['XONSHRC'] = '${HOME}/.xonshrc' # Expands environment variables
# List variables (colon-separated on Unix, semicolon on Windows)
env['PATH'] = ['/usr/bin', '/usr/local/bin'] # List of paths
env['XONTRIBS'] = ['vox', 'whole_word_jumping'] # List of xontrib names
# Dictionary variables (JSON or key=value format)
env['LS_COLORS'] = {'*.py': 'bold blue', '*.txt': 'green'}from xonsh.aliases import FuncAlias, aliases
from xonsh.built_ins import XSH
class FuncAlias:
"""Function-based alias."""
def __init__(self, name: str, func: callable = None):
"""Create function alias.
Parameters
----------
name : str
Alias name
func : callable, optional
Function to wrap
"""
def __call__(self, args=None, stdin=None, stdout=None,
stderr=None, spec=None, stack=None, decorators=None):
"""Execute alias with subprocess-like interface.
Parameters
----------
args : list[str], optional
Command line arguments
stdin : file-like, optional
Input stream
stdout : file-like, optional
Output stream
stderr : file-like, optional
Error stream
spec : SubprocSpec, optional
Subprocess specification
stack : list, optional
Call stack
decorators : list, optional
Decorators to apply
Returns
-------
object
Alias execution result
"""
# Access alias registry
aliases = XSH.aliases
# Simple function alias
def ll_func(args, stdin=None):
"""List files in long format."""
from xonsh.built_ins import subproc_uncaptured
subproc_uncaptured(['ls', '-la'] + (args or []))
aliases['ll'] = FuncAlias('ll', ll_func)
# Python function alias with return value
def count_files(args, stdin=None):
"""Count files in directory."""
import os
directory = args[0] if args else '.'
count = len(os.listdir(directory))
return f"Files in {directory}: {count}"
aliases['countfiles'] = FuncAlias('countfiles', count_files)from xonsh.built_ins import XSH
aliases = XSH.aliases
# String aliases (simple command replacement)
aliases['l'] = 'ls -CF'
aliases['la'] = 'ls -A'
aliases['ll'] = 'ls -alF'
aliases['grep'] = 'grep --color=auto'
# Executable aliases (path to external programs)
aliases['vi'] = '/usr/bin/vim'
aliases['python'] = '/usr/bin/python3'
# Complex string aliases with arguments
aliases['mygrep'] = 'grep -n --color=auto'
aliases['diskusage'] = 'df -h'
aliases['meminfo'] = 'cat /proc/meminfo'
# Conditional aliases based on platform
import sys
if sys.platform.startswith('linux'):
aliases['open'] = 'xdg-open'
elif sys.platform == 'darwin':
aliases['open'] = '/usr/bin/open'
elif sys.platform.startswith('win'):
aliases['open'] = 'start'from xonsh.aliases import FuncAlias
def create_git_alias(subcommand: str) -> FuncAlias:
"""Create git subcommand alias.
Parameters
----------
subcommand : str
Git subcommand name
Returns
-------
FuncAlias
Configured git alias
"""
def git_func(args, stdin=None):
from xonsh.built_ins import subproc_uncaptured
cmd = ['git', subcommand] + (args or [])
subproc_uncaptured(cmd)
git_func.__name__ = f'git_{subcommand}'
git_func.__doc__ = f'Git {subcommand} shortcut'
return FuncAlias(f'g{subcommand[0]}', git_func)
# Create git aliases dynamically
git_commands = ['status', 'add', 'commit', 'push', 'pull', 'branch']
for cmd in git_commands:
aliases[f'g{cmd[0]}'] = create_git_alias(cmd)
# Usage: gs -> git status, ga -> git add, etc.from xonsh.xontribs import xontribs_load, get_xontribs, Xontrib
def xontribs_load(names: list[str]) -> list[str]:
"""Load xontribs by name.
Parameters
----------
names : list[str]
List of xontrib names to load
Returns
-------
list[str]
List of successfully loaded xontrib names
"""
def get_xontribs() -> dict[str, Xontrib]:
"""Get available xontribs.
Returns
-------
dict[str, Xontrib]
Dictionary mapping names to xontrib metadata
"""
class Xontrib:
"""Xontrib metadata container."""
module: str # Module name
distribution: object = None # Package distribution info
@property
def is_loaded(self) -> bool:
"""Check if xontrib is loaded."""
@property
def is_auto_loaded(self) -> bool:
"""Check if xontrib is auto-loaded."""
def get_description(self) -> str:
"""Get xontrib description."""
# Load xontribs
loaded = xontribs_load(['vox', 'whole_word_jumping'])
print(f"Loaded: {loaded}")
# List available xontribs
available = get_xontribs()
for name, xontrib in available.items():
print(f"{name}: {xontrib.get_description()}")
# Check xontrib status
vox_info = available.get('vox')
if vox_info:
print(f"Vox loaded: {vox_info.is_loaded}")# Virtual environment management
xontribs_load(['vox'])
# Usage: vox new myenv, vox activate myenv, vox deactivate
# Enhanced navigation
xontribs_load(['whole_word_jumping'])
# Enables Alt+Left/Right word jumping
# Directory bookmarks
xontribs_load(['jump'])
# Usage: jump add mybook /path/to/directory, jump mybook
# Auto-completion enhancements
xontribs_load(['fzf-widgets'])
# Adds fuzzy finding widgets
# Package manager integration
xontribs_load(['apt', 'dnf', 'homebrew'])
# Auto-completion for package managers
# Git integration
xontribs_load(['gitinfo'])
# Adds git status to prompt
# Performance monitoring
xontribs_load(['schedule'])
# Task scheduling functionality# File: my_xontrib.py
"""Custom xontrib example."""
from xonsh.built_ins import XSH
def _load_xontrib_(xsh, **kwargs):
"""Load custom xontrib.
Parameters
----------
xsh : XonshSession
Current xonsh session
**kwargs
Additional loading arguments
"""
# Add custom aliases
def hello(args, stdin=None):
name = args[0] if args else 'World'
print(f"Hello, {name}!")
xsh.aliases['hello'] = hello
# Add custom environment variable
xsh.env['MY_XONTRIB_LOADED'] = True
# Register custom completer
def my_completer(context):
if context.command and context.command.name == 'hello':
return {'Alice', 'Bob', 'Charlie'}
return set()
xsh.completers['my_completer'] = my_completer
print("My custom xontrib loaded!")
def _unload_xontrib_(xsh, **kwargs):
"""Unload custom xontrib."""
# Clean up aliases
if 'hello' in xsh.aliases:
del xsh.aliases['hello']
# Clean up environment
if 'MY_XONTRIB_LOADED' in xsh.env:
del xsh.env['MY_XONTRIB_LOADED']
# Clean up completers
if 'my_completer' in xsh.completers:
del xsh.completers['my_completer']
print("My custom xontrib unloaded!")
# Load the custom xontrib
# xontribs_load(['my_xontrib'])from xonsh.environ import get_home_xonshrc_path, xonshrc_context
def get_home_xonshrc_path() -> str:
"""Get default xonshrc file path.
Returns
-------
str
Path to default xonshrc file
"""
def xonshrc_context() -> dict:
"""Get context for xonshrc execution.
Returns
-------
dict
Execution context for RC files
"""
# Default RC file locations (in order of preference):
# 1. ~/.config/xonsh/rc.xsh
# 2. ~/.xonshrc
# 3. ~/.config/xonsh/rc.py
# 4. ~/.xonshrc.py
# Example xonshrc content
"""
# ~/.xonshrc
# Environment configuration
$EDITOR = 'vim'
$PAGER = 'less'
$BROWSER = 'firefox'
# Aliases
aliases['ll'] = 'ls -la'
aliases['grep'] = 'grep --color=auto'
aliases['..'] = 'cd ..'
# Load xontribs
xontribs = ['vox', 'whole_word_jumping']
for xontrib in xontribs:
try:
xontrib_load([xontrib])
except Exception as e:
print(f"Failed to load {xontrib}: {e}")
# Custom prompt
$PROMPT = '{env_name}{BOLD_GREEN}{user}@{hostname}{BOLD_BLUE} {cwd}{RESET} {BOLD_RED}{git_branch}{RESET} $ '
# Custom functions
def mkcd(args):
\"\"\"Create directory and change to it.\"\"\"
if args:
mkdir -p @(args[0])
cd @(args[0])
else:
print("Usage: mkcd <directory>")
aliases['mkcd'] = mkcd
"""from xonsh.built_ins import XSH
import os
import platform
def configure_environment():
"""Configure environment based on system."""
env = XSH.env
# Platform-specific configuration
if platform.system() == 'Darwin': # macOS
env['HOMEBREW_PREFIX'] = '/opt/homebrew' if os.path.exists('/opt/homebrew') else '/usr/local'
env.setdefault('BROWSER', 'open')
elif platform.system() == 'Linux':
env.setdefault('BROWSER', 'xdg-open')
elif platform.system() == 'Windows':
env.setdefault('BROWSER', 'start')
# Development environment
if 'VIRTUAL_ENV' in env:
env['VIRTUAL_ENV_PROMPT'] = f"({os.path.basename(env['VIRTUAL_ENV'])})"
# Git configuration
if os.path.exists(os.path.expanduser('~/.gitconfig')):
env['GIT_CONFIGURED'] = True
def load_project_config():
"""Load project-specific configuration."""
project_config = os.path.join(os.getcwd(), '.xonshrc')
if os.path.exists(project_config):
from xonsh.codecache import run_script_with_cache
run_script_with_cache(project_config)
# Auto-load configuration
configure_environment()
load_project_config()Configuration in xonsh is highly flexible, supporting everything from simple environment variables to complex dynamic configuration that adapts to the current system and project context.
Install with Tessl CLI
npx tessl i tessl/pypi-xonsh