CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pytest-xdist

pytest xdist plugin for distributed testing, most importantly across multiple CPUs

Pending
Overview
Eval results
Files

loop-on-fail.mddocs/

Loop-on-Fail (Deprecated)

Legacy functionality for automatically re-running failed tests when files change. This feature is deprecated and will be removed in pytest-xdist 4.0.

⚠️ DEPRECATION WARNING: The --looponfail command line argument and looponfailroots config variable are deprecated. The loop-on-fail feature will be removed in pytest-xdist 4.0.

Capabilities

Loop-on-Fail Main Function

Entry point for loop-on-fail functionality that continuously monitors for file changes and re-runs failed tests.

def pytest_cmdline_main(config: pytest.Config) -> int | None:
    """
    Handle looponfail command line option.
    
    Args:
        config: pytest configuration object
        
    Returns:
        int: Exit code 2 for looponfail mode, None for normal processing
        
    Raises:
        pytest.UsageError: If --pdb is used with --looponfail (incompatible)
    """

def looponfail_main(config: pytest.Config) -> None:
    """
    Main loop-on-fail functionality.
    
    Continuously monitors files for changes and re-runs failed tests
    until all tests pass or interrupted with Ctrl-C.
    
    Args:
        config: pytest configuration object
    """

Remote Control

Controls remote test execution in a subprocess for loop-on-fail mode.

class RemoteControl:
    """Controls remote test execution for loop-on-fail."""
    
    def __init__(self, config: pytest.Config) -> None:
        """
        Initialize remote control.
        
        Args:
            config: pytest configuration object
        """
    
    def setup(self) -> None:
        """Set up remote worker session for test execution."""
    
    def teardown(self) -> None:
        """Tear down remote worker session."""
    
    def loop_once(self) -> None:
        """Execute one iteration of the test loop."""

File System Monitoring

Monitors file system changes to trigger test re-runs.

class StatRecorder:
    """Records and monitors file system changes."""
    
    def __init__(self, rootdirs: Sequence[Path]) -> None:
        """
        Initialize file system monitor.
        
        Args:
            rootdirs: directories to monitor for changes
        """
    
    def waitonchange(self, checkinterval: float = 1.0) -> None:
        """
        Wait for file system changes.
        
        Args:
            checkinterval: interval in seconds between checks
        """

Configuration Options

Command line options for loop-on-fail functionality.

def pytest_addoption(parser: pytest.Parser) -> None:
    """
    Add looponfail command line option.
    
    Adds the -f/--looponfail option to pytest's argument parser.
    
    Args:
        parser: pytest argument parser
    """

Options:

  • -f/--looponfail: Run tests in subprocess, wait for file modifications, then re-run failing test set until all pass

Configuration:

  • looponfailroots: List of directories to monitor for changes (ini file setting)

Usage Examples

Basic Loop-on-Fail Usage

# DEPRECATED - will be removed in pytest-xdist 4.0
pytest -f

# With specific directories to monitor
pytest -f --looponfailroots=src,tests

Configuration File Setup

# In pytest.ini or tox.ini - DEPRECATED
[tool:pytest]
looponfailroots = src tests lib

Programmatic Usage (Not Recommended)

# DEPRECATED - for reference only
import pytest
from xdist.looponfail import looponfail_main

def run_loop_on_fail():
    """Example of programmatic loop-on-fail usage."""
    # Create pytest config
    config = pytest.Config()
    config.option.looponfail = True
    
    try:
        looponfail_main(config)
    except KeyboardInterrupt:
        print("Loop-on-fail interrupted by user")

Migration Path

Since loop-on-fail is deprecated, consider these alternatives:

Alternative 1: pytest-watch

# Install pytest-watch as replacement
pip install pytest-watch

# Use ptw instead of pytest -f
ptw --runner "pytest -x"

Alternative 2: File Watching Scripts

# custom_watch.py - Simple replacement
import time
import subprocess
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class TestRunner(FileSystemEventHandler):
    def __init__(self):
        self.last_run = 0
        
    def on_modified(self, event):
        if event.is_directory:
            return
            
        # Debounce rapid file changes
        now = time.time()
        if now - self.last_run < 2:
            return
            
        self.last_run = now
        
        # Run tests
        print(f"File {event.src_path} changed, running tests...")
        result = subprocess.run(['pytest', '--tb=short'], 
                              capture_output=True, text=True)
        
        if result.returncode == 0:
            print("All tests passed!")
        else:
            print("Tests failed, watching for changes...")

if __name__ == "__main__":
    event_handler = TestRunner()
    observer = Observer()
    observer.schedule(event_handler, path='.', recursive=True)
    observer.start()
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

Alternative 3: IDE Integration

Modern IDEs provide built-in test watching functionality:

# VS Code with Python extension
# - Enable "python.testing.autoTestDiscoverOnSaveEnabled"
# - Use Test Explorer for continuous testing

# PyCharm Professional
# - Use "Run with Coverage" in continuous mode
# - Enable "Rerun tests automatically"

Migration Guide

  1. Replace -f/--looponfail:

    # Old (deprecated)
    pytest -f
    
    # New alternatives
    pip install pytest-watch
    ptw --runner "pytest -x"
    
    # Or use IDE integration
  2. Replace looponfailroots configuration:

    # Old pytest.ini
    [tool:pytest]
    looponfailroots = src tests
    
    # New with pytest-watch
    ptw --runner "pytest -x" src tests
  3. Update CI/CD pipelines:

    # Remove looponfail from CI scripts
    # It was never intended for CI use anyway
    
    # Old
    - run: pytest -f  # Don't do this in CI
    
    # Correct
    - run: pytest     # Standard test execution
  4. Development workflow adjustment:

    # Instead of pytest -f, use:
    # Option 1: pytest-watch
    ptw
    
    # Option 2: IDE auto-test features
    # Configure your IDE for automatic test execution
    
    # Option 3: Custom file watching
    # Implement custom solution using watchdog or similar

Install with Tessl CLI

npx tessl i tessl/pypi-pytest-xdist

docs

distribution-scheduling.md

hook-specifications.md

index.md

loop-on-fail.md

plugin-configuration.md

session-management.md

worker-detection.md

tile.json