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.
- 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
- 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:
- Parameters:
timeout (float) – Maximum time to wait in seconds
- Returns:
Self for method chaining
- Return type:
- with_interval(interval)[source]¶
Set the interval between checks.
- Return type:
- Parameters:
interval (float) – Time between checks in seconds
- Returns:
Self for method chaining
- Return type:
- without_raising()[source]¶
Disable raising exceptions on timeout.
- Return type:
- Returns:
Self for method chaining
- Return type:
- with_line_range(start, end)[source]¶
Specify lines to capture from the pane.
- Return type:
- Parameters:
- Returns:
Self for method chaining
- Return type:
- wait_for_text(text)[source]¶
Wait for text to appear in the pane (contains match).
- Return type:
- Parameters:
text (str) – Text to wait for (contains match)
- Returns:
Result of the wait operation
- Return type:
- wait_for_exact_text(text)[source]¶
Wait for exact text to appear in the pane.
- Return type:
- Parameters:
text (str) – Text to wait for (exact match)
- Returns:
Result of the wait operation
- Return type:
- wait_for_regex(pattern)[source]¶
Wait for text matching a regex pattern.
- Return type:
- Parameters:
pattern (str | re.Pattern) – Regex pattern to match
- Returns:
Result of the wait operation
- Return type:
- 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:
- wait_until_ready(shell_prompt=None)[source]¶
Wait until the pane is ready with a shell prompt.
- Return type:
- 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:
- 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:
- 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:
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:
- Returns:
True if the condition was met, False if timed out (and raises=False)
- Return type:
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:
- Returns:
True if the condition was met, False if timed out (and raises=False)
- Return type:
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:
- Returns:
True if the condition was met, False if timed out (and raises=False)
- Return type:
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:
- Returns:
True if the condition was met, False if timed out (and raises=False)
- Return type:
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:
- 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:
- 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