Waiters - libtmux._internal.waiter

The waiter module provides utilities for waiting on specific content to appear in tmux panes, making it easier to write reliable tests that interact with terminal output.

Key Features

  • Fluent API: Playwright-inspired chainable API for expressive, readable test code

  • Multiple Match Types: Wait for exact matches, substring matches, regex patterns, or custom predicate functions

  • Composable Waiting: Wait for any of multiple conditions or all conditions to be met

  • Flexible Timeout Handling: Configure timeout behavior and error handling to suit your needs

  • Shell Prompt Detection: Easily wait for shell readiness with built-in prompt detection

  • Robust Error Handling: Improved exception handling and result reporting

  • Clean Code: Well-formatted, linted code with proper type annotations

Basic Concepts

When writing tests that interact with tmux sessions and panes, it’s often necessary to wait for specific content to appear before proceeding with the next step. The waiter module provides a set of functions to help with this.

There are multiple ways to match content:

  • Exact match: The content exactly matches the specified string

  • Contains: The content contains the specified string

  • Regex: The content matches the specified regular expression

  • Predicate: A custom function that takes the pane content and returns a boolean

Quick Start Examples

Simple Waiting

Wait for specific text to appear in a pane:

"""Example of waiting for text in a pane."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import wait_for_pane_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_wait_for_text(session: Session) -> None:
    """Demonstrate waiting for text in a pane."""
    # Create a window and pane for testing
    window = session.new_window(window_name="test_wait_for_text")
    pane = window.active_pane
    assert pane is not None

    # Send a command to the pane
    pane.send_keys("echo 'hello world'")

    # Wait for text to appear
    result = wait_for_pane_content(pane, "hello world")
    assert result.success

    # Cleanup
    window.kill()

Advanced Matching

Use regex patterns or custom predicates for more complex matching:

"""Example of waiting for text matching a regex pattern."""

from __future__ import annotations

import re
from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_for_pane_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_wait_for_regex(session: Session) -> None:
    """Demonstrate waiting for text matching a regular expression."""
    window = session.new_window(window_name="test_regex_matching")
    pane = window.active_pane
    assert pane is not None

    # Send a command to the pane
    pane.send_keys("echo 'hello world'")

    # Wait for text matching a regular expression
    pattern = re.compile(r"hello \w+")
    result = wait_for_pane_content(pane, pattern, match_type=ContentMatchType.REGEX)
    assert result.success

    # Cleanup
    window.kill()
"""Example of using a custom predicate function for matching."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_for_pane_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_custom_predicate(session: Session) -> None:
    """Demonstrate using a custom predicate function for matching."""
    window = session.new_window(window_name="test_custom_predicate")
    pane = window.active_pane
    assert pane is not None

    # Send multiple lines of output
    pane.send_keys("echo 'line 1'")
    pane.send_keys("echo 'line 2'")
    pane.send_keys("echo 'line 3'")

    # Define a custom predicate function
    def check_content(lines):
        return len(lines) >= 3 and "error" not in "".join(lines).lower()

    # Use the custom predicate
    result = wait_for_pane_content(
        pane,
        check_content,
        match_type=ContentMatchType.PREDICATE,
    )
    assert result.success

    # Cleanup
    window.kill()

Timeout Handling

Control how long to wait and what happens when a timeout occurs:

"""Example of timeout handling with libtmux waiters."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import wait_for_pane_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_timeout_handling(session: Session) -> None:
    """Demonstrate handling timeouts gracefully without exceptions."""
    window = session.new_window(window_name="test_timeout")
    pane = window.active_pane
    assert pane is not None

    # Clear the pane
    pane.send_keys("clear")

    # Handle timeouts gracefully without exceptions
    # Looking for content that won't appear (with a short timeout)
    result = wait_for_pane_content(
        pane,
        "this text will not appear",
        timeout=0.5,
        raises=False,
    )

    # Should not raise an exception
    assert not result.success
    assert result.error is not None
    assert "Timed out" in result.error

    # Cleanup
    window.kill()

Waiting for Shell Readiness

A common use case is waiting for a shell prompt to appear, indicating the command has completed. The example below uses a regular expression to match common shell prompt characters ($, %, >, #):

"""Example of waiting for shell prompt readiness."""

from __future__ import annotations

import contextlib
import re
from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_until_pane_ready

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
@pytest.mark.skip(reason="Test is unreliable in CI environment due to timing issues")
def test_wait_until_ready(session: Session) -> None:
    """Demonstrate waiting for shell prompt."""
    window = session.new_window(window_name="test_shell_ready")
    pane = window.active_pane
    assert pane is not None

    # Force shell prompt by sending a few commands and waiting
    pane.send_keys("echo 'test command'")
    pane.send_keys("ls")

    # For test purposes, look for any common shell prompt characters
    # The wait_until_pane_ready function works either with:
    # 1. A string to find (will use CONTAINS match_type)
    # 2. A predicate function taking lines and returning bool
    # (will use PREDICATE match_type)

    # Using a regex to match common shell prompt characters: $, %, >, #

    # Try with a simple string first
    result = wait_until_pane_ready(
        pane,
        shell_prompt="$",
        timeout=10,  # Increased timeout
    )

    if not result.success:
        # Fall back to regex pattern if the specific character wasn't found
        result = wait_until_pane_ready(
            pane,
            shell_prompt=re.compile(r"[$%>#]"),  # Using standard prompt characters
            match_type=ContentMatchType.REGEX,
            timeout=10,  # Increased timeout
        )

    assert result.success

    # Only kill the window if the test is still running
    with contextlib.suppress(Exception):
        window.kill()

Note: This test is skipped in CI environments due to timing issues but works well for local development.

Fluent API (Playwright-inspired)

For a more expressive and chainable API, you can use the fluent interface provided by the PaneContentWaiter class:

"""Example of using the fluent API in libtmux waiters."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import expect

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_fluent_basic(session: Session) -> None:
    """Demonstrate basic usage of the fluent API."""
    window = session.new_window(window_name="test_fluent_basic")
    pane = window.active_pane
    assert pane is not None

    # Send a command
    pane.send_keys("echo 'hello world'")

    # Basic usage of the fluent API
    result = expect(pane).wait_for_text("hello world")
    assert result.success

    # Cleanup
    window.kill()
"""Example of method chaining with the fluent API in libtmux waiters."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import expect

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_fluent_chaining(session: Session) -> None:
    """Demonstrate method chaining with the fluent API."""
    window = session.new_window(window_name="test_fluent_chaining")
    pane = window.active_pane
    assert pane is not None

    # Send a command
    pane.send_keys("echo 'completed successfully'")

    # With method chaining
    result = (
        expect(pane)
        .with_timeout(5.0)
        .with_interval(0.1)
        .without_raising()
        .wait_for_text("completed successfully")
    )
    assert result.success

    # Cleanup
    window.kill()

Multiple Conditions

The waiter module also supports waiting for multiple conditions at once:

"""Example of waiting for any of multiple conditions."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_for_any_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_wait_for_any_content(session: Session) -> None:
    """Demonstrate waiting for any of multiple conditions."""
    window = session.new_window(window_name="test_any_content")
    pane = window.active_pane
    assert pane is not None

    # Send a command
    pane.send_keys("echo 'Success'")

    # Wait for any of these patterns
    result = wait_for_any_content(
        pane,
        ["Success", "Error:", "timeout"],
        ContentMatchType.CONTAINS,
    )
    assert result.success
    assert result.matched_content == "Success"
    assert result.matched_pattern_index == 0

    # Cleanup
    window.kill()
"""Example of waiting for all conditions to be met."""

from __future__ import annotations

from typing import TYPE_CHECKING, cast

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_for_all_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_wait_for_all_content(session: Session) -> None:
    """Demonstrate waiting for all conditions to be met."""
    window = session.new_window(window_name="test_all_content")
    pane = window.active_pane
    assert pane is not None

    # Send commands with both required phrases
    pane.send_keys("echo 'Database connected'")
    pane.send_keys("echo 'Server started'")

    # Wait for all conditions to be true
    result = wait_for_all_content(
        pane,
        ["Database connected", "Server started"],
        ContentMatchType.CONTAINS,
    )
    assert result.success
    # For wait_for_all_content, the matched_content will be a list of matched patterns
    assert result.matched_content is not None
    matched_content = cast("list[str]", result.matched_content)
    assert len(matched_content) == 2
    assert "Database connected" in matched_content
    assert "Server started" in matched_content

    # Cleanup
    window.kill()
"""Example of using different pattern types and match types."""

from __future__ import annotations

import re
from typing import TYPE_CHECKING

import pytest

from libtmux._internal.waiter import ContentMatchType, wait_for_any_content

if TYPE_CHECKING:
    from libtmux.session import Session


@pytest.mark.example
def test_mixed_pattern_types(session: Session) -> None:
    """Demonstrate using different pattern types and match types."""
    window = session.new_window(window_name="test_mixed_patterns")
    pane = window.active_pane
    assert pane is not None

    # Send commands that will match different patterns
    pane.send_keys("echo 'exact match'")
    pane.send_keys("echo '10 items found'")

    # Create a predicate function
    def has_enough_lines(lines):
        return len(lines) >= 2

    # Wait for any of these patterns with different match types
    result = wait_for_any_content(
        pane,
        [
            "exact match",  # String for exact match
            re.compile(r"\d+ items found"),  # Regex pattern
            has_enough_lines,  # Predicate function
        ],
        [ContentMatchType.EXACT, ContentMatchType.REGEX, ContentMatchType.PREDICATE],
    )
    assert result.success

    # Cleanup
    window.kill()

Implementation Notes

Error Handling

The waiting functions are designed to be robust and handle timing and error conditions gracefully:

  • All wait functions properly calculate elapsed time for performance tracking

  • Functions handle exceptions consistently and provide clear error messages

  • Proper handling of return values ensures consistent behavior whether or not raises=True

Type Safety

The waiter module is fully type-annotated to ensure compatibility with static type checkers:

  • All functions include proper type hints for parameters and return values

  • The ContentMatchType enum ensures that only valid match types are used

  • Combined with runtime checks, this prevents type-related errors during testing

Example Usage in Documentation

All examples in this documentation are actual test files from the libtmux test suite. The examples are included using literalinclude directives, ensuring that the documentation remains synchronized with the actual code.

API Reference

Terminal content waiting utility for libtmux tests.

This module provides functions to wait for specific content to appear in tmux panes, making it easier to write reliable tests that interact with terminal output.

class libtmux._internal.waiter.ContentMatchType[source]

Bases: Enum

Type of content matching to use when waiting for pane content.

Examples

>>> # Using content match types with their intended patterns
>>> ContentMatchType.EXACT
<ContentMatchType.EXACT: 1>
>>> ContentMatchType.CONTAINS
<ContentMatchType.CONTAINS: 2>
>>> ContentMatchType.REGEX
<ContentMatchType.REGEX: 3>
>>> ContentMatchType.PREDICATE
<ContentMatchType.PREDICATE: 4>
>>> # These match types are used to specify how to match content in wait functions
>>> def demo_match_types():
...     # For exact matching (entire content must exactly match)
...     exact_type = ContentMatchType.EXACT
...     # For substring matching (content contains the specified string)
...     contains_type = ContentMatchType.CONTAINS
...     # For regex pattern matching
...     regex_type = ContentMatchType.REGEX
...     # For custom predicate functions
...     predicate_type = ContentMatchType.PREDICATE
...     return [exact_type, contains_type, regex_type, predicate_type]
>>> match_types = demo_match_types()
>>> len(match_types)
4
EXACT = 1
CONTAINS = 2
REGEX = 3
PREDICATE = 4
class libtmux._internal.waiter.WaitResult[source]

Bases: object

Result from a wait operation.

success

Whether the wait operation succeeded

Type:

bool

content

The content of the pane at the time of the match

Type:

list[str] | None

matched_content

The content that matched the pattern

Type:

str | list[str] | None

match_line

The line number of the match (0-indexed)

Type:

int | None

elapsed_time

Time taken for the wait operation

Type:

float | None

error

Error message if the wait operation failed

Type:

str | None

matched_pattern_index

Index of the pattern that matched (only for wait_for_any_content)

Type:

int | None

Examples

>>> # Create a successful wait result
>>> result = WaitResult(
...     success=True,
...     content=["line 1", "hello world", "line 3"],
...     matched_content="hello world",
...     match_line=1,
...     elapsed_time=0.5,
... )
>>> result.success
True
>>> result.matched_content
'hello world'
>>> result.match_line
1
>>> # Create a failed wait result with an error message
>>> error_result = WaitResult(
...     success=False,
...     error="Timed out waiting for 'pattern' after 5.0 seconds",
... )
>>> error_result.success
False
>>> error_result.error
"Timed out waiting for 'pattern' after 5.0 seconds"
>>> error_result.content is None
True
>>> # Wait result with matched_pattern_index (from wait_for_any_content)
>>> multi_pattern = WaitResult(
...     success=True,
...     content=["command output", "success: operation completed", "more output"],
...     matched_content="success: operation completed",
...     match_line=1,
...     matched_pattern_index=2,
... )
>>> multi_pattern.matched_pattern_index
2
success: bool
content: list[str] | None = None
matched_content: str | list[str] | None = None
match_line: int | None = None
elapsed_time: float | None = None
error: str | None = None
matched_pattern_index: int | None = None
__init__(success, content=None, matched_content=None, match_line=None, elapsed_time=None, error=None, matched_pattern_index=None)[source]
Parameters:
  • success (bool)

  • content (list[str] | None)

  • matched_content (str | list[str] | None)

  • match_line (int | None)

  • elapsed_time (float | None)

  • error (str | None)

  • matched_pattern_index (int | None)

Return type:

None

class libtmux._internal.waiter.PaneContentWaiter[source]

Bases: object

Fluent interface for waiting on pane content.

This class provides a more fluent API for waiting on pane content, allowing method chaining for better readability.

Examples

>>> # Basic usage - assuming pane is a fixture from conftest.py
>>> waiter = PaneContentWaiter(pane)
>>> isinstance(waiter, PaneContentWaiter)
True
>>> # Method chaining to configure options
>>> waiter = (
...     PaneContentWaiter(pane)
...     .with_timeout(10.0)
...     .with_interval(0.5)
...     .without_raising()
... )
>>> waiter.timeout
10.0
>>> waiter.interval
0.5
>>> waiter.raises
False
>>> # Configure line range for capture
>>> waiter = PaneContentWaiter(pane).with_line_range(0, 10)
>>> waiter.start_line
0
>>> waiter.end_line
10
>>> # Create a checker for demonstration
>>> import re
>>> def is_ready(content):
...     return any("ready" in line.lower() for line in content)
>>> # Methods available for different match types
>>> hasattr(waiter, 'wait_for_text')
True
>>> hasattr(waiter, 'wait_for_exact_text')
True
>>> hasattr(waiter, 'wait_for_regex')
True
>>> hasattr(waiter, 'wait_for_predicate')
True
>>> hasattr(waiter, 'wait_until_ready')
True

A functional example: send text to the pane and wait for it:

>>> # First, send "hello world" to the pane
>>> pane.send_keys("echo 'hello world'", enter=True)
>>>
>>> # Then wait for it to appear in the pane content
>>> result = PaneContentWaiter(pane).wait_for_text("hello world")
>>> result.success
True
>>> "hello world" in result.matched_content
True
>>>

With options:

>>> result = (
...     PaneContentWaiter(pane)
...     .with_timeout(5.0)
...     .wait_for_text("hello world")
... )

Wait for text with a longer timeout:

>>> pane.send_keys("echo 'Operation completed'", enter=True)
>>> try:
...     result = (
...         expect(pane)
...         .with_timeout(1.0)  # Reduce timeout for faster doctest execution
...         .wait_for_text("Operation completed")
...     )
...     print(f"Result success: {result.success}")
... except Exception as e:
...     print(f"Caught exception: {type(e).__name__}: {e}")
Result success: True

Wait for regex pattern:

>>> pane.send_keys("echo 'Process 0 completed.'", enter=True)
>>> try:
...     result = (
...         PaneContentWaiter(pane)
...         .with_timeout(1.0)  # Reduce timeout for faster doctest execution
...         .wait_for_regex(r"Process \d+ completed")
...     )
...     # Print debug info about the result for doctest
...     print(f"Result success: {result.success}")
... except Exception as e:
...     print(f"Caught exception: {type(e).__name__}: {e}")
Result success: True

Custom predicate:

>>> pane.send_keys("echo 'We are ready!'", enter=True)
>>> def is_ready(content):
...     return any("ready" in line.lower() for line in content)
>>> result = PaneContentWaiter(pane).wait_for_predicate(is_ready)

Timeout:

>>> try:
...     result = (
...         PaneContentWaiter(pane)
...         .with_timeout(0.01)
...         .wait_for_exact_text("hello world")
...     )
... except WaitTimeout:
...     print('No exact match')
No exact match

Initialize with a tmux pane.

Parameters:

pane (Pane) – The tmux pane to check

__init__(pane)[source]

Initialize with a tmux pane.

Parameters:

pane (Pane) – The tmux pane to check

Return type:

None

with_timeout(timeout)[source]

Set the timeout for waiting.

Return type:

PaneContentWaiter

Parameters:

timeout (float) – Maximum time to wait in seconds

Returns:

Self for method chaining

Return type:

PaneContentWaiter

with_interval(interval)[source]

Set the interval between checks.

Return type:

PaneContentWaiter

Parameters:

interval (float) – Time between checks in seconds

Returns:

Self for method chaining

Return type:

PaneContentWaiter

without_raising()[source]

Disable raising exceptions on timeout.

Return type:

PaneContentWaiter

Returns:

Self for method chaining

Return type:

PaneContentWaiter

with_line_range(start, end)[source]

Specify lines to capture from the pane.

Return type:

PaneContentWaiter

Parameters:
  • start (int | "-" | None) – Starting line for capture_pane (passed to pane.capture_pane)

  • end (int | "-" | None) – End line for capture_pane (passed to pane.capture_pane)

Returns:

Self for method chaining

Return type:

PaneContentWaiter

wait_for_text(text)[source]

Wait for text to appear in the pane (contains match).

Return type:

WaitResult

Parameters:

text (str) – Text to wait for (contains match)

Returns:

Result of the wait operation

Return type:

WaitResult

wait_for_exact_text(text)[source]

Wait for exact text to appear in the pane.

Return type:

WaitResult

Parameters:

text (str) – Text to wait for (exact match)

Returns:

Result of the wait operation

Return type:

WaitResult

wait_for_regex(pattern)[source]

Wait for text matching a regex pattern.

Return type:

WaitResult

Parameters:

pattern (str | re.Pattern) – Regex pattern to match

Returns:

Result of the wait operation

Return type:

WaitResult

wait_for_predicate(predicate)[source]

Wait for a custom predicate function to return True.

Return type:

WaitResult

Parameters:

predicate (callable) – Function that takes pane content lines and returns boolean

Returns:

Result of the wait operation

Return type:

WaitResult

wait_until_ready(shell_prompt=None)[source]

Wait until the pane is ready with a shell prompt.

Return type:

WaitResult

Parameters:

shell_prompt (str | re.Pattern | None) – The shell prompt pattern to look for, or None to auto-detect

Returns:

Result of the wait operation

Return type:

WaitResult

libtmux._internal.waiter.expect(pane)[source]

Fluent interface for waiting on pane content.

This function provides a more fluent API for waiting on pane content, allowing method chaining for better readability.

Return type:

PaneContentWaiter

Parameters:

pane (Pane)

Examples

Basic usage with pane fixture:

>>> waiter = expect(pane)
>>> isinstance(waiter, PaneContentWaiter)
True

Method chaining to configure the waiter:

>>> configured_waiter = expect(pane).with_timeout(15.0).without_raising()
>>> configured_waiter.timeout
15.0
>>> configured_waiter.raises
False

Equivalent to PaneContentWaiter but with a more expressive name:

>>> expect(pane) is not PaneContentWaiter(pane)  # Different instances
True
>>> type(expect(pane)) == type(PaneContentWaiter(pane))  # Same class
True

A functional example showing actual usage:

>>> # Send a command to the pane
>>> pane.send_keys("echo 'testing expect'", enter=True)
>>>
>>> # Wait for the output using the expect function
>>> result = expect(pane).wait_for_text("testing expect")
>>> result.success
True
>>>

Wait for text with a longer timeout:

>>> pane.send_keys("echo 'Operation completed'", enter=True)
>>> try:
...     result = (
...         expect(pane)
...         .with_timeout(1.0)  # Reduce timeout for faster doctest execution
...         .without_raising()  # Don't raise exceptions
...         .wait_for_text("Operation completed")
...     )
...     print(f"Result success: {result.success}")
... except Exception as e:
...     print(f"Caught exception: {type(e).__name__}: {e}")
Result success: True

Wait for a regex match without raising exceptions on timeout: >>> pane.send_keys(“echo ‘Process 19 completed’”, enter=True) >>> try: … result = ( … expect(pane) … .with_timeout(1.0) # Reduce timeout for faster doctest execution … .without_raising() # Don’t raise exceptions … .wait_for_regex(r”Process d+ completed”) … ) … print(f”Result success: {result.success}”) … except Exception as e: … print(f”Caught exception: {type(e).__name__}: {e}”) Result success: True

libtmux._internal.waiter.wait_for_pane_content(pane, content_pattern, match_type=ContentMatchType.CONTAINS, timeout=8, interval=0.05, start=None, end=None, raises=True)[source]

Wait for specific content to appear in a pane.

Return type:

WaitResult

Parameters:
  • pane (Pane) – The tmux pane to wait for content in

  • content_pattern (str | re.Pattern | callable) – Content to wait for. This can be: - A string to match exactly or check if contained (based on match_type) - A compiled regex pattern to match against - A predicate function that takes the pane content lines and returns a boolean

  • match_type (ContentMatchType) – How to match the content_pattern against pane content

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • start (int | "-" | None) – Starting line for capture_pane (passed to pane.capture_pane)

  • end (int | "-" | None) – End line for capture_pane (passed to pane.capture_pane)

  • raises (bool) – Whether to raise an exception on timeout

Returns:

Result object with success status and matched content information

Return type:

WaitResult

Raises:

WaitTimeout – If raises=True and the timeout is reached before content is found

Examples

Wait with contains match (default), for testing purposes with a small timeout and no raises:

>>> result = wait_for_pane_content(
...     pane=pane,
...     content_pattern=r"$",  # Look for shell prompt
...     timeout=0.5,
...     raises=False
... )
>>> isinstance(result, WaitResult)
True

Using exact match:

>>> result_exact = wait_for_pane_content(
...     pane=pane,
...     content_pattern="exact text to match",
...     match_type=ContentMatchType.EXACT,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_exact, WaitResult)
True

Using regex pattern:

>>> import re
>>> pattern = re.compile(r"\$|%|>")  # Common shell prompts
>>> result_regex = wait_for_pane_content(
...     pane=pane,
...     content_pattern=pattern,
...     match_type=ContentMatchType.REGEX,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_regex, WaitResult)
True

Using predicate function:

>>> def has_at_least_1_line(content):
...     return len(content) >= 1
>>> result_pred = wait_for_pane_content(
...     pane=pane,
...     content_pattern=has_at_least_1_line,
...     match_type=ContentMatchType.PREDICATE,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_pred, WaitResult)
True

Wait for a $ written on the screen (unsubmitted):

>>> pane.send_keys("$")
>>> result = wait_for_pane_content(pane, "$", ContentMatchType.CONTAINS)

Wait for exact text (unsubmitted, and fails):

>>> try:
...     pane.send_keys("echo 'Success'")
...     result = wait_for_pane_content(
...         pane,
...         "Success",
...         ContentMatchType.EXACT,
...         timeout=0.01
...     )
... except WaitTimeout:
...     print("No exact match.")
No exact match.

Use regex pattern matching:

>>> import re
>>> pane.send_keys("echo 'Error: There was a problem.'")
>>> result = wait_for_pane_content(
...     pane,
...     re.compile(r"Error: .*"),
...     ContentMatchType.REGEX
... )

Use custom predicate function:

>>> def has_at_least_3_lines(content):
...     return len(content) >= 3
>>> for _ in range(5):
...     pane.send_keys("echo 'A line'", enter=True)
>>> result = wait_for_pane_content(
...     pane,
...     has_at_least_3_lines,
...     ContentMatchType.PREDICATE
... )
libtmux._internal.waiter.wait_until_pane_ready(pane, shell_prompt=None, match_type=ContentMatchType.CONTAINS, timeout=8, interval=0.05, raises=True)[source]

Wait until pane is ready with shell prompt.

This is a convenience function for the common case of waiting for a shell prompt.

Return type:

WaitResult

Parameters:
  • pane (Pane) – The tmux pane to check

  • shell_prompt (str | re.Pattern | callable) – The shell prompt pattern to look for, or None to auto-detect

  • match_type (ContentMatchType) – How to match the shell_prompt

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • raises (bool) – Whether to raise an exception on timeout

Returns:

Result of the wait operation

Return type:

WaitResult

Examples

Basic usage - auto-detecting shell prompt:

>>> result = wait_until_pane_ready(
...     pane=pane,
...     timeout=0.5,
...     raises=False
... )
>>> isinstance(result, WaitResult)
True

Wait with specific prompt pattern:

>>> result_prompt = wait_until_pane_ready(
...     pane=pane,
...     shell_prompt=r"$",
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_prompt, WaitResult)
True

Using regex pattern:

>>> import re
>>> pattern = re.compile(r"[$%#>]")
>>> result_regex = wait_until_pane_ready(
...     pane=pane,
...     shell_prompt=pattern,
...     match_type=ContentMatchType.REGEX,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_regex, WaitResult)
True

Using custom predicate function:

>>> def has_prompt(content):
...     return any(line.endswith("$") for line in content)
>>> result_predicate = wait_until_pane_ready(
...     pane=pane,
...     shell_prompt=has_prompt,
...     match_type=ContentMatchType.PREDICATE,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result_predicate, WaitResult)
True
libtmux._internal.waiter.wait_for_server_condition(server, condition, timeout=8, interval=0.05, raises=True)[source]

Wait for a condition on the server to be true.

Return type:

bool

Parameters:
  • server (Server) – The tmux server to check

  • condition (callable) – A function that takes the server and returns a boolean

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • raises (bool) – Whether to raise an exception on timeout

Returns:

True if the condition was met, False if timed out (and raises=False)

Return type:

bool

Examples

Basic usage with a simple condition:

>>> def has_sessions(server):
...     return len(server.sessions) > 0

Assuming server has at least one session:

>>> result = wait_for_server_condition(
...     server,
...     has_sessions,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Using a lambda for a simple condition:

>>> result = wait_for_server_condition(
...     server,
...     lambda s: len(s.sessions) >= 1,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Condition that checks for a specific session:

>>> def has_specific_session(server):
...     return any(s.name == "specific_name" for s in server.sessions)

This will likely timeout since we haven’t created that session:

>>> result = wait_for_server_condition(
...     server,
...     has_specific_session,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True
libtmux._internal.waiter.wait_for_session_condition(session, condition, timeout=8, interval=0.05, raises=True)[source]

Wait for a condition on the session to be true.

Return type:

bool

Parameters:
  • session (Session) – The tmux session to check

  • condition (callable) – A function that takes the session and returns a boolean

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • raises (bool) – Whether to raise an exception on timeout

Returns:

True if the condition was met, False if timed out (and raises=False)

Return type:

bool

Examples

Basic usage with a simple condition:

>>> def has_windows(session):
...     return len(session.windows) > 0

Assuming session has at least one window:

>>> result = wait_for_session_condition(
...     session,
...     has_windows,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Using a lambda for a simple condition:

>>> result = wait_for_session_condition(
...     session,
...     lambda s: len(s.windows) >= 1,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Condition that checks for a specific window:

>>> def has_specific_window(session):
...     return any(w.name == "specific_window" for w in session.windows)

This will likely timeout since we haven’t created that window:

>>> result = wait_for_session_condition(
...     session,
...     has_specific_window,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True
libtmux._internal.waiter.wait_for_window_condition(window, condition, timeout=8, interval=0.05, raises=True)[source]

Wait for a condition on the window to be true.

Return type:

bool

Parameters:
  • window (Window) – The tmux window to check

  • condition (callable) – A function that takes the window and returns a boolean

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • raises (bool) – Whether to raise an exception on timeout

Returns:

True if the condition was met, False if timed out (and raises=False)

Return type:

bool

Examples

Basic usage with a simple condition:

>>> def has_panes(window):
...     return len(window.panes) > 0

Assuming window has at least one pane:

>>> result = wait_for_window_condition(
...     window,
...     has_panes,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Using a lambda for a simple condition:

>>> result = wait_for_window_condition(
...     window,
...     lambda w: len(w.panes) >= 1,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Condition that checks window layout:

>>> def is_tiled_layout(window):
...     return window.window_layout == "tiled"

Check for a specific layout:

>>> result = wait_for_window_condition(
...     window,
...     is_tiled_layout,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True
libtmux._internal.waiter.wait_for_window_panes(window, expected_count, timeout=8, interval=0.05, raises=True)[source]

Wait until window has a specific number of panes.

Return type:

bool

Parameters:
  • window (Window) – The tmux window to check

  • expected_count (int) – The number of panes to wait for

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • raises (bool) – Whether to raise an exception on timeout

Returns:

True if the condition was met, False if timed out (and raises=False)

Return type:

bool

Examples

Basic usage - wait for a window to have exactly 1 pane:

>>> result = wait_for_window_panes(
...     window,
...     expected_count=1,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

Wait for a window to have 2 panes (will likely timeout in this example):

>>> result = wait_for_window_panes(
...     window,
...     expected_count=2,
...     timeout=0.1,
...     raises=False
... )
>>> isinstance(result, bool)
True

In a real test, you might split the window first:

>>> # window.split_window()  # Create a new pane
>>> # Then wait for the pane count to update:
>>> # result = wait_for_window_panes(window, 2)
libtmux._internal.waiter.wait_for_any_content(pane, content_patterns, match_types, timeout=8, interval=0.05, start=None, end=None, raises=True)[source]

Wait for any of the specified content patterns to appear in a pane.

This is useful for handling alternative expected outputs.

Return type:

WaitResult

Parameters:
  • pane (Pane) – The tmux pane to check

  • content_patterns (list[str | re.Pattern | callable]) – List of content patterns to wait for, any of which can match

  • match_types (list[ContentMatchType] | ContentMatchType) – How to match each content_pattern against pane content

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • start (int | "-" | None) – Starting line for capture_pane (passed to pane.capture_pane)

  • end (int | "-" | None) – End line for capture_pane (passed to pane.capture_pane)

  • raises (bool) – Whether to raise an exception on timeout

Returns:

Result object with success status and matched pattern information

Return type:

WaitResult

Raises:
  • WaitTimeout – If raises=True and the timeout is reached before any pattern is found

  • TypeError – If a match type is incompatible with the specified pattern

  • ValueError – If match_types list has a different length than content_patterns

Examples

Wait for any of the specified patterns:

>>> pane.send_keys("echo 'pattern2'", enter=True)
>>> result = wait_for_any_content(
...     pane,
...     ["pattern1", "pattern2"],
...     ContentMatchType.CONTAINS
... )

Wait for any of the specified regex patterns:

>>> import re
>>> pane.send_keys("echo 'Error: this did not do the trick'", enter=True)
>>> pane.send_keys("echo 'Success: But subsequently this worked'", enter=True)
>>> result = wait_for_any_content(
...     pane,
...     [re.compile(r"Error: .*"), re.compile(r"Success: .*")],
...     ContentMatchType.REGEX
... )

Wait for any of the specified predicate functions:

>>> def has_at_least_3_lines(content):
...     return len(content) >= 3
>>>
>>> def has_at_least_5_lines(content):
...     return len(content) >= 5
>>>
>>> for _ in range(5):
...     pane.send_keys("echo 'A line'", enter=True)
>>> result = wait_for_any_content(
...     pane,
...     [has_at_least_3_lines, has_at_least_5_lines],
...     ContentMatchType.PREDICATE
... )
libtmux._internal.waiter.wait_for_all_content(pane, content_patterns, match_types, timeout=8, interval=0.05, start=None, end=None, raises=True)[source]

Wait for all patterns to appear in a pane.

This function waits until all specified patterns are found in a pane. It supports mixed match types, allowing different patterns to be matched in different ways.

Return type:

WaitResult

Parameters:
  • pane (Pane) – The tmux pane to check

  • content_patterns (list[str | re.Pattern | callable]) – List of patterns to wait for

  • match_types (list[ContentMatchType] | ContentMatchType) – How to match each pattern. Either a single match type for all patterns, or a list of match types, one for each pattern.

  • timeout (float) – Maximum time to wait in seconds

  • interval (float) – Time between checks in seconds

  • start (int | "-" | None) – Starting line for capture_pane (passed to pane.capture_pane)

  • end (int | "-" | None) – End line for capture_pane (passed to pane.capture_pane)

  • raises (bool) – Whether to raise an exception on timeout

Returns:

Result object with status and match information

Return type:

WaitResult

Raises:
  • WaitTimeout – If raises=True and the timeout is reached before all patterns are found

  • TypeError – If match types and patterns are incompatible

  • ValueError – If match_types list has a different length than content_patterns

Examples

Wait for all of the specified patterns:

>>> # Send some text to the pane that will match both patterns
>>> pane.send_keys("echo 'pattern1 pattern2'", enter=True)
>>>
>>> result = wait_for_all_content(
...     pane,
...     ["pattern1", "pattern2"],
...     ContentMatchType.CONTAINS,
...     timeout=0.5,
...     raises=False
... )
>>> isinstance(result, WaitResult)
True
>>> result.success
True

Using regex patterns:

>>> import re
>>> # Send content that matches both regex patterns
>>> pane.send_keys("echo 'Error: something went wrong'", enter=True)
>>> pane.send_keys("echo 'Success: but we fixed it'", enter=True)
>>>
>>> result = wait_for_all_content(
...     pane,
...     [re.compile(r"Error: .*"), re.compile(r"Success: .*")],
...     ContentMatchType.REGEX,
...     timeout=0.5,
...     raises=False
... )
>>> isinstance(result, WaitResult)
True

Using predicate functions:

>>> def has_at_least_3_lines(content):
...     return len(content) >= 3
>>>
>>> def has_at_least_5_lines(content):
...     return len(content) >= 5
>>>
>>> # Send enough lines to satisfy both predicates
>>> for _ in range(5):
...     pane.send_keys("echo 'Adding a line'", enter=True)
>>>
>>> result = wait_for_all_content(
...     pane,
...     [has_at_least_3_lines, has_at_least_5_lines],
...     ContentMatchType.PREDICATE,
...     timeout=0.5,
...     raises=False
... )
>>> isinstance(result, WaitResult)
True

Extended Retry Functionality