stepwise.py


Overview

The [stepwise.py](/projects/286/67474) module implements a pytest plugin that provides **stepwise test execution** functionality. This feature enables running tests sequentially, stopping immediately on the first failing test, and then resuming from that failure in subsequent test runs. It is designed to improve developer productivity by focusing test runs on the problematic parts of the test suite, reducing time spent rerunning already passing tests.

**Key features:**


Classes and Functions

Constants

Name

Description

STEPWISE_CACHE_DIR

Cache key to store stepwise plugin data (`"cache/stepwise"`).


pytest_addoption(parser: Parser) -> None

**Purpose:** Registers command-line options for stepwise execution.

**Options added:**

**Parameters:**

**Example usage:**

pytest --sw
pytest --stepwise-skip
pytest --stepwise-reset

pytest_configure(config: Config) -> None

**Purpose:** Configures the plugin based on command-line options.

**Parameters:**


pytest_sessionfinish(session: Session) -> None

**Purpose:** Session finish hook stub to avoid cache updates in xdist workers.

**Parameters:**


@dataclasses.dataclass StepwiseCacheInfo

**Purpose:** Data structure representing the cached state of stepwise execution.

**Attributes:**

Name

Type

Description

`last_failed`

`str

None`

`last_test_count`

`int

None`

`last_cache_date_str`

`str`

ISO format string of last cache update time.

**Properties:**

**Class Methods:**

**Instance Methods:**


class StepwisePlugin

**Purpose:** Primary plugin class implementing stepwise test execution.

Initialization: __init__(self, config: Config)

Methods:


_load_cached_info(self) -> StepwiseCacheInfo

pytest_sessionstart(self, session: Session) -> None

pytest_collection_modifyitems(self, config: Config, items: list[nodes.Item]) -> None

**Logic:**

  1. Updates last_test_count in cache info with current test count.

  2. If --stepwise-reset is used:

    • Resets last_failed to None, skipping no tests.

  3. If no cached last failed test:

    • Does not skip any tests.

  4. If the test count has changed since last run:

    • Invalidates cache (resets last_failed), skipping no tests.

  5. Otherwise:

    • Finds the index of the last failed test in the collected items.

    • If found, skips all tests before that index.

    • If not found, skips no tests.

  6. Reports status messages for these decisions.


pytest_runtest_logreport(self, report: TestReport) -> None

pytest_report_collectionfinish(self) -> list[str] | None

pytest_sessionfinish(self) -> None

Important Implementation Details


Interactions with the System


Usage Example

# Run tests stepwise, stopping on first failure and resuming from it next time
pytest --sw

# Skip the first failure once, then stop on the next failure
pytest --sw-skip

# Reset stepwise state and start over
pytest --sw-reset

Visual Diagram: Class Diagram of StepwisePlugin and StepwiseCacheInfo

classDiagram
    class StepwiseCacheInfo {
        +str|None last_failed
        +int|None last_test_count
        +str last_cache_date_str
        +datetime last_cache_date
        +classmethod empty() StepwiseCacheInfo
        +update_date_to_now() void
    }

    class StepwisePlugin {
        -Config config
        -Session|None session
        -list~str~ report_status
        -Cache cache
        -bool skip
        -bool reset
        -StepwiseCacheInfo cached_info
        +__init__(config: Config)
        +_load_cached_info() StepwiseCacheInfo
        +pytest_sessionstart(session: Session) void
        +pytest_collection_modifyitems(config: Config, items: list~nodes.Item~) void
        +pytest_runtest_logreport(report: TestReport) void
        +pytest_report_collectionfinish() list~str~|None
        +pytest_sessionfinish() void
    }

    StepwisePlugin --> StepwiseCacheInfo : uses

Summary

[stepwise.py](/projects/286/67474) is a pytest plugin module enabling stepwise test execution by stopping on the first failure and resuming from that failure on the next run. It leverages pytest's caching system and lifecycle hooks to modify test collection and control session flow, providing developers with a time-saving incremental testing workflow. The plugin is configurable, handles edge cases such as test suite changes and parallel execution, and integrates cleanly with pytest’s extensible architecture.