CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-xonsh

Python-powered shell providing superset of Python with shell primitives for cross-platform command execution and automation.

Overview
Eval results
Files

scripting.mddocs/

Scripting

Overview

Xonsh provides seamless integration between Python and shell scripting, allowing execution of xonsh code (Python + shell syntax), subprocess management, and pipeline creation. The Execer class handles code parsing and execution, while the API modules provide clean interfaces for subprocess operations.

Code Execution Engine

Execer Class

from xonsh.execer import Execer

class Execer:
    """Executes xonsh code in a context-aware manner."""
    
    def __init__(self, filename: str = "<xonsh-code>", 
                 debug_level: int = 0,
                 parser_args: dict = None,
                 scriptcache: bool = True,
                 cacheall: bool = False):
        """Initialize code executer.
        
        Parameters
        ----------
        filename : str, default "<xonsh-code>"
            Name for executed code (error reporting)
        debug_level : int, default 0
            Debug level for parsing (0-2)
        parser_args : dict, optional
            Additional parser configuration
        scriptcache : bool, default True
            Whether to cache compiled bytecode
        cacheall : bool, default False
            Whether to cache all code including interactive input
        """
        
    def parse(self, input: str, ctx: dict, mode: str = "exec", 
              filename: str = None, transform: bool = True) -> object:
        """Parse xonsh code with context awareness.
        
        Parameters
        ----------
        input : str
            Code string to parse
        ctx : dict
            Execution context/namespace
        mode : str, default "exec"
            Parsing mode ("exec", "eval", "single")
        filename : str, optional
            Filename for error reporting
        transform : bool, default True
            Whether to apply context-aware transformations
            
        Returns
        -------
        object
            Parsed AST or None if parsing failed
        """
        
    def eval(self, input: str, ctx: dict = None, filename: str = None) -> object:
        """Evaluate xonsh expression and return result.
        
        Parameters
        ----------
        input : str
            Expression to evaluate
        ctx : dict, optional
            Execution context
        filename : str, optional
            Filename for error reporting
            
        Returns
        -------
        object
            Evaluation result
        """
        
    def exec(self, input: str, ctx: dict = None, filename: str = None) -> None:
        """Execute xonsh code statement(s).
        
        Parameters
        ----------
        input : str
            Code to execute
        ctx : dict, optional
            Execution context
        filename : str, optional
            Filename for error reporting
        """

# Usage examples
execer = Execer()

# Execute shell commands
execer.exec("ls -la")
execer.exec("echo 'Hello World'")

# Execute Python code
execer.exec("x = 10")
result = execer.eval("x * 2")  # Returns 20

# Mixed Python and shell
execer.exec("""
import os
files = $(ls).strip().split('\n')
for f in files:
    print(f"File: {f}")
""")

Context-Aware Execution

from xonsh.built_ins import XSH

# Execute with custom context
context = {
    'my_var': 'hello',
    'my_func': lambda x: x.upper()
}

# Code that uses the context
code = """
result = my_func(my_var)
echo @(result)  # Outputs: HELLO
"""

XSH.execer.exec(code, ctx=context)

# Access results from context
final_context = context.copy()
XSH.execer.exec("output = $(date)", ctx=final_context)
date_output = final_context['output']

Subprocess API

High-Level Subprocess Functions

from xonsh.api.subprocess import run, check_call, check_output

def run(cmd: str|list[str], cwd: str = None, check: bool = False) -> object:
    """Execute subprocess with xonsh syntax.
    
    Parameters
    ----------
    cmd : str or list[str]
        Command to execute
    cwd : str, optional
        Working directory for command
    check : bool, default False
        Whether to raise exception on non-zero exit
        
    Returns
    -------
    object
        Process object with returncode, stdout, stderr
    """

def check_call(cmd: str|list[str], cwd: str = None) -> int:
    """Execute subprocess, raise exception on failure.
    
    Parameters
    ----------
    cmd : str or list[str]
        Command to execute
    cwd : str, optional
        Working directory
        
    Returns
    -------
    int
        Return code (0 on success)
        
    Raises
    ------
    XonshCalledProcessError
        If command returns non-zero exit code
    """

def check_output(cmd: str|list[str], cwd: str = None) -> bytes:
    """Execute subprocess and return stdout.
    
    Parameters
    ----------
    cmd : str or list[str]
        Command to execute
    cwd : str, optional
        Working directory
        
    Returns
    -------
    bytes
        Captured stdout content
        
    Raises
    ------
    XonshCalledProcessError
        If command returns non-zero exit code
    """

# Usage examples
import tempfile

# Basic subprocess execution
result = run(['ls', '-la'])
print(f"Exit code: {result.returncode}")

# Execute in specific directory
with tempfile.TemporaryDirectory() as tmpdir:
    result = run('touch test.txt', cwd=tmpdir)
    
# Check command success
try:
    check_call(['git', 'status'])
    print("Git repository detected")
except Exception:
    print("Not a git repository")
    
# Capture command output
try:
    output = check_output(['git', 'branch', '--show-current'])
    branch = output.decode().strip()
    print(f"Current branch: {branch}")
except Exception:
    print("Could not get git branch")

Low-Level Subprocess Control

from xonsh.procs.specs import SubprocSpec
from xonsh.procs.pipelines import run_subproc

def create_subprocess_spec(cmd: list[str], **kwargs) -> SubprocSpec:
    """Create subprocess specification.
    
    Parameters
    ----------
    cmd : list[str]
        Command and arguments
    **kwargs
        Additional subprocess options
        
    Returns
    -------
    SubprocSpec
        Subprocess specification object
    """

# Create and run subprocess
spec = SubprocSpec(['ls', '-la'], 
                   captured='stdout',
                   stack=None)
result = run_subproc(spec)

Pipeline Management

Pipeline Creation and Execution

from xonsh.procs.pipelines import Pipeline

class Pipeline:
    """Manages subprocess pipelines."""
    
    def __init__(self, specs: list[SubprocSpec]):
        """Initialize pipeline.
        
        Parameters
        ----------
        specs : list[SubprocSpec]
            List of subprocess specifications
        """
        
    def run(self) -> object:
        """Execute the pipeline.
        
        Returns
        -------
        object
            Pipeline execution result
        """

# Pipeline examples using built-in functions
from xonsh.built_ins import subproc_captured_stdout

# Simple pipeline (command | command)
output = subproc_captured_stdout(['ls', '-la'])
lines = output.strip().split('\n')
python_files = [line for line in lines if '.py' in line]

# Multi-stage pipeline simulation
def pipeline_ls_grep_wc():
    """Simulate: ls | grep .py | wc -l"""
    files = subproc_captured_stdout(['ls']).strip().split('\n')
    py_files = [f for f in files if '.py' in f]
    return len(py_files)

count = pipeline_ls_grep_wc()

Process Communication

from xonsh.procs.proxies import ProcProxy

# Process proxy for advanced control
def create_interactive_process(cmd: list[str]) -> ProcProxy:
    """Create interactive process proxy.
    
    Parameters
    ----------
    cmd : list[str]
        Command to execute
        
    Returns
    -------
    ProcProxy
        Process proxy for interaction
    """
    from xonsh.procs.specs import SubprocSpec
    spec = SubprocSpec(cmd, captured=False)
    return ProcProxy(spec)

# Usage with interactive commands
# proc = create_interactive_process(['python', '-i'])
# proc.communicate(input=b"print('hello')\n")

Script Execution

File-Based Script Execution

from xonsh.codecache import run_script_with_cache, run_code_with_cache

def run_script_with_cache(filename: str, glb: dict = None, 
                         loc: dict = None) -> None:
    """Execute xonsh script file with caching.
    
    Parameters
    ----------
    filename : str
        Path to xonsh script file
    glb : dict, optional
        Global namespace
    loc : dict, optional
        Local namespace
    """

def run_code_with_cache(code: str, filename: str = "<code>",
                       glb: dict = None, loc: dict = None) -> None:
    """Execute xonsh code with bytecode caching.
    
    Parameters
    ----------
    code : str
        Code string to execute
    filename : str, default "<code>"
        Filename for caching and error reporting
    glb : dict, optional
        Global namespace
    loc : dict, optional
        Local namespace
    """

# Execute script files
run_script_with_cache('my_script.xsh')
run_script_with_cache('/path/to/script.py', glb=globals())

# Execute code with caching
script_code = """
echo "Starting process..."
files = $(ls *.py)
echo f"Found {len(files.split())} Python files"
"""
run_code_with_cache(script_code, filename="list_files.xsh")

Dynamic Code Generation

from xonsh.built_ins import XSH

def generate_and_execute_script(template: str, **kwargs) -> object:
    """Generate and execute xonsh script from template.
    
    Parameters
    ----------
    template : str
        Script template with {variable} placeholders
    **kwargs
        Variables to substitute in template
        
    Returns
    -------
    object
        Execution result
    """
    script = template.format(**kwargs)
    return XSH.execer.eval(script)

# Template-based script generation
file_template = """
import os
target_dir = "{directory}"
if os.path.exists(target_dir):
    files = $(ls {directory})
    echo f"Directory {target_dir} contains: {{files}}"
else:
    echo f"Directory {target_dir} does not exist"
"""

result = generate_and_execute_script(file_template, directory="/tmp")

Advanced Scripting Features

Error Handling in Scripts

from xonsh.tools import XonshError, XonshCalledProcessError

def safe_execute(cmd: str) -> tuple[bool, str]:
    """Safely execute command with error handling.
    
    Parameters
    ----------
    cmd : str
        Command to execute
        
    Returns
    -------
    tuple[bool, str]
        (success, output_or_error)
    """
    try:
        result = XSH.execer.eval(f"$({cmd})")
        return True, result
    except XonshCalledProcessError as e:
        return False, f"Command failed: {e}"
    except XonshError as e:
        return False, f"Xonsh error: {e}"
    except Exception as e:
        return False, f"Unexpected error: {e}"

# Usage
success, output = safe_execute("git status")
if success:
    print(f"Git status: {output}")
else:
    print(f"Error: {output}")

Environment-Aware Scripting

from xonsh.built_ins import XSH

def conditional_execution():
    """Execute commands based on environment."""
    env = XSH.env
    
    # Platform-specific execution
    if env.get('ON_WINDOWS'):
        XSH.execer.exec('dir')
    else:
        XSH.execer.exec('ls -la')
    
    # Conditional tool usage
    if 'VIRTUAL_ENV' in env:
        print("Running in virtual environment")
        XSH.execer.exec('pip list')
    else:
        print("No virtual environment active")

# Configuration-based scripting
def load_config_and_execute():
    """Load configuration and execute based on settings."""
    env = XSH.env
    
    # Set defaults
    env.setdefault('PROJECT_ROOT', '.')
    env.setdefault('BUILD_TYPE', 'debug')
    
    # Execute based on configuration
    build_cmd = f"make {env['BUILD_TYPE']}"
    XSH.execer.exec(f"cd {env['PROJECT_ROOT']} && {build_cmd}")

Macro Integration

from xonsh.built_ins import call_macro

def script_with_macros():
    """Integrate macros in scripting."""
    
    # Define macro (would typically be in xonshrc)
    macro_code = """
def backup_files(pattern):
    files = $(find . -name @(pattern))
    for f in files.split():
        cp @(f) @(f + '.bak')
    return f"Backed up {len(files.split())} files"
"""
    
    XSH.execer.exec(macro_code)
    
    # Use macro in script
    result = call_macro('backup_files', '*.py')
    print(result)

The scripting API provides powerful tools for automating tasks, integrating shell commands with Python logic, and creating sophisticated command-line applications that leverage both Python's capabilities and shell command efficiency.

Install with Tessl CLI

npx tessl i tessl/pypi-xonsh

docs

aliases.md

api-package.md

builtins-api.md

completion.md

configuration.md

directory-management.md

events.md

index.md

scripting.md

shell-interface.md

tile.json