Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: Tested doc examples #581

Draft
wants to merge 39 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2d40e6c
docs(test-helpers) Update to existing modules
tony Feb 27, 2025
e8b5d7a
docs(test-helpers) Add retry page
tony Feb 27, 2025
76326f3
py(deps[dev]) Bump dev packages
tony Feb 27, 2025
1668b45
chore: Add `__init__.py` for tests/examples
tony Feb 27, 2025
fc3dec2
chore: Add `__init__.py` for tests/examples/test
tony Feb 26, 2025
a438f2d
chore: Add `__init__.py` for tests/examples/_internal/waiter
tony Feb 27, 2025
aa260f2
fix(retry): Improve retry_until_extended function with better error m…
tony Feb 26, 2025
10a37e5
feat(waiter): Enhance terminal content waiting utility with fluent AP…
tony Feb 26, 2025
0c74d33
test(waiter): Fix test cases and improve type safety
tony Feb 26, 2025
a10493a
docs(waiter): Add comprehensive documentation for terminal content wa…
tony Feb 26, 2025
6bdbb5c
pyproject(mypy[exceptions]): examples to ignore `no-untyped-def`
tony Feb 26, 2025
d436d75
test: add conftest.py to register example marker
tony Feb 26, 2025
17d2967
refactor(tests[waiter]): Add waiter test examples into individual files
tony Feb 26, 2025
50081b5
docs(CHANGES) Note `Waiter`
tony Feb 27, 2025
db47652
feat(waiter): Add terminal content waiting utility for testing (#582)
tony Feb 27, 2025
9661039
cursor(rules[git-commits]) Use component name first
tony Feb 28, 2025
677aa96
cursor(rules[git-commits]) Standardize further
tony Feb 28, 2025
60d1386
cursor(rules[dev-loop]) Use `--show-fixes` in `ruff check`
tony Feb 28, 2025
9695bdf
tests(test_waiter[capture_pane]): Add resiliency for CI test grid
tony Feb 28, 2025
cf08043
tests(test_waiter[exact_match]): Skip flaky exact match test on tmux …
tony Feb 28, 2025
7db6426
test(waiter): Replace assertions with warning-based checks in detaile…
tony Feb 28, 2025
463b9c3
pyproject(mypy[test.examples.pytest_plugin]): pytest examples to igno…
tony Feb 26, 2025
f768e53
docs: Improve window.py
tony Feb 1, 2025
9020e14
docs: Improve session.py
tony Feb 1, 2025
5a41553
docs: Improve server.py
tony Feb 1, 2025
ca20738
docs: Improve pane.py
tony Feb 1, 2025
1ccd708
docs: Improve neo.py
tony Feb 1, 2025
2c1182a
docs: Improve test.py
tony Feb 1, 2025
431985e
docs: Improve common.py
tony Feb 1, 2025
002df05
docs: Improve exc.py
tony Feb 1, 2025
355d0bf
docs: Improve pytest_plugin.py
tony Feb 1, 2025
238d6d2
docs: Improve conftest.py
tony Feb 1, 2025
626f024
docs/tests: Add `server` doctest examples
tony Feb 15, 2025
38182be
fix(Server): update Server.windows doctest to be environment-agnostic
tony Feb 26, 2025
73b4a2c
docs: Add new Topics
tony Feb 26, 2025
0add0be
docs(topics): Improve documentation with executable examples
tony Feb 26, 2025
2248328
docs(README): Enhance project README with comprehensive overview
tony Feb 26, 2025
2a2b6ff
docs,tests(pytest plugin) Examples
tony Feb 26, 2025
14c4b27
!squash docs topics
tony Feb 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/rules/dev-loop.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ uv run mypy
Lint:

```
uv run ruff check . --fix; uv run ruff format .;
uv run ruff check . --fix --show-fixes; uv run ruff format .;
```

Check tests:
Expand Down
132 changes: 72 additions & 60 deletions .cursor/rules/git-commits.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,93 @@
description: git-commits: Git commit message standards and AI assistance
globs: git-commits: Git commit message standards and AI assistance | *.git/* .gitignore .github/* CHANGELOG.md CHANGES.md
---
# Git Commit Standards
# Optimized Git Commit Standards

## Format
## Commit Message Format
```
type(scope[component]): concise description
Component/File(commit-type[Subcomponent/method]): Concise description

why: explanation of necessity/impact
what:
- technical changes made
- keep focused on single topic
why: Explanation of necessity or impact.
what:
- Specific technical changes made
- Focused on a single topic

refs: #issue-number, breaking changes, links
refs: #issue-number, breaking changes, or relevant links
```

## Commit Types
- `feat`: New features/enhancements
- `fix`: Bug fixes
- `refactor`: Code restructuring
- `docs`: Documentation changes
- `chore`: Maintenance tasks (deps, tooling)
- `test`: Test-related changes
- `style`: Code style/formatting

## Guidelines
- Subject line: max 50 chars
- Body lines: max 72 chars
- Use imperative mood ("Add" not "Added")
- Single topic per commit
- Blank line between subject and body
- Mark breaking changes with "BREAKING:"
- Use "See also:" for external links

## AI Assistance in Cursor
- Stage changes with `git add`
- Use `@commit` to generate initial message
- Review and adjust the generated message
- Ensure it follows format above

## Examples

Good commit:
## Component Patterns
### General Code Changes
```
Component/File(feat[method]): Add feature
Component/File(fix[method]): Fix bug
Component/File(refactor[method]): Code restructure
```
feat(subprocess[run]): Switch to unicode-only text handling

why: Improve consistency and type safety in subprocess handling
what:
- BREAKING: Changed run() to use text=True by default
- Removed console_to_str() helper and encoding logic
- Simplified output handling
- Updated type hints for better safety
### Packages and Dependencies
| Language | Standard Packages | Dev Packages | Extras / Sub-packages |
|------------|------------------------------------|-------------------------------|-----------------------------------------------|
| General | `lang(deps):` | `lang(deps[dev]):` | |
| Python | `py(deps):` | `py(deps[dev]):` | `py(deps[extra]):` |
| JavaScript | `js(deps):` | `js(deps[dev]):` | `js(deps[subpackage]):`, `js(deps[dev{subpackage}]):` |

refs: #485
See also: https://docs.python.org/3/library/subprocess.html
#### Examples
- `py(deps[dev]): Update pytest to v8.1`
- `js(deps[ui-components]): Upgrade Button component package`
- `js(deps[dev{linting}]): Add ESLint plugin`

### Documentation Changes
Prefix with `docs:`
```
docs(Component/File[Subcomponent/method]): Update API usage guide
```

Bad commit:
### Test Changes
Prefix with `tests:`
```
updated some stuff and fixed bugs
tests(Component/File[Subcomponent/method]): Add edge case tests
```

Cursor Rules: Add development QA and git commit standards (#cursor-rules)
## Commit Types Summary
- **feat**: New features or enhancements
- **fix**: Bug fixes
- **refactor**: Code restructuring without functional change
- **docs**: Documentation updates
- **chore**: Maintenance (dependencies, tooling, config)
- **test**: Test-related updates
- **style**: Code style and formatting

## General Guidelines
- Subject line: Maximum 50 characters
- Body lines: Maximum 72 characters
- Use imperative mood (e.g., "Add", "Fix", not "Added", "Fixed")
- Limit to one topic per commit
- Separate subject from body with a blank line
- Mark breaking changes clearly: `BREAKING:`
- Use `See also:` to provide external references

## AI Assistance Workflow in Cursor
- Stage changes with `git add`
- Use `@commit` to generate initial commit message
- Review and refine generated message
- Ensure adherence to these standards

## Good Commit Example
```
Pane(feat[capture_pane]): Add screenshot capture support

- Add dev-loop.mdc: QA process for code edits
- Type checking with mypy
- Linting with ruff
- Test validation with pytest
- Ensures edits are validated before commits
why: Provide visual debugging capability
what:
- Implement capturePane method with image export
- Integrate with existing Pane component logic
- Document usage in Pane README

- Add git-commits.mdc: Commit message standards
- Structured format with why/what sections
- Defined commit types and guidelines
- Examples of good/bad commits
- AI assistance instructions
refs: #485
See also: https://example.com/docs/pane-capture
```

Note: These rules help maintain code quality and commit history
consistency across the project.
## Bad Commit Example
```
fixed stuff and improved some functions
```

See also: https://docs.cursor.com/context/rules-for-ai
These guidelines ensure clear, consistent commit histories, facilitating easier code review and maintenance.
12 changes: 12 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ $ pip install --user --upgrade --pre libtmux

- _Future release notes will be placed here_

### New features

#### Waiting (#582)

Added experimental `waiter.py` module for polling for terminal content in tmux panes:

- Fluent API inspired by Playwright for better readability and chainable options
- Support for multiple pattern types (exact text, contains, regex, custom predicates)
- Composable waiting conditions with `wait_for_any_content` and `wait_for_all_content`
- Enhanced error handling with detailed timeouts and match information
- Robust shell prompt detection

## libtmux 0.46.0 (2025-02-25)

### Breaking
Expand Down
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ sessions, windows, and panes. Additionally, `libtmux` powers [tmuxp], a tmux wor
[![Code Coverage](https://codecov.io/gh/tmux-python/libtmux/branch/master/graph/badge.svg)](https://codecov.io/gh/tmux-python/libtmux)
[![License](https://img.shields.io/github/license/tmux-python/libtmux.svg)](https://github.com/tmux-python/libtmux/blob/master/LICENSE)

## Key Features

- **Intuitive API**: Control tmux servers, sessions, windows, and panes with a clean, object-oriented interface
- **Complete Automation**: Create and manage complex tmux environments programmatically
- **Type Annotations**: Full typing support for modern Python development
- **Pytest Plugin**: Built-in testing tools for tmux automation
- **Context Managers**: Safe session and window management with Python's context protocol
- **Robust Architecture**: Built on tmux's native concepts of targets and formats

libtmux builds upon tmux's
[target](http://man.openbsd.org/OpenBSD-5.9/man1/tmux.1#COMMANDS) and
[formats](http://man.openbsd.org/OpenBSD-5.9/man1/tmux.1#FORMATS) to
Expand All @@ -19,6 +28,17 @@ View the [documentation](https://libtmux.git-pull.com/),
[API](https://libtmux.git-pull.com/api.html) information and
[architectural details](https://libtmux.git-pull.com/about.html).

## Use Cases

- **Development Environment Automation**: Set up consistent workspaces across projects
- **CI/CD Systems**: Create isolated environments for testing and deployment
- **System Monitoring**: Build interactive dashboards for server administration
- **Remote Pair Programming**: Facilitate collaborative development sessions
- **Data Science Workflows**: Manage complex data processing pipelines
- **Education and Demonstrations**: Create multi-window learning environments

For more detailed examples, see our [use cases documentation](https://libtmux.git-pull.com/topics/use_cases.html).

# Install

```console
Expand Down Expand Up @@ -246,6 +266,64 @@ Window(@1 1:..., Session($1 ...))
Session($1 ...)
```

# Testing with pytest

libtmux includes a pytest plugin that provides fixtures for testing tmux operations:

```python
def test_session_creation(session):
"""Test creating a new window in the session."""
window = session.new_window(window_name="test_window")
assert window.window_name == "test_window"

# Create a new pane
pane = window.split_window()
assert len(window.panes) == 2

# Send keys to the pane
pane.send_keys("echo 'Hello from test'")
```

See [pytest plugin documentation](https://libtmux.git-pull.com/pytest-plugin/index.html) for more details.

# Advanced Usage

libtmux supports a wide range of advanced use cases:

## Context Managers

Safely manage sessions and windows with Python's context protocol:

```python
with Server().new_session(session_name="my_session") as session:
window = session.new_window(window_name="my_window")
# Work with the window...
# Session is properly cleaned up when context exits
```

## Advanced Scripting

Create complex window layouts and integrate with external systems:

```python
session = server.new_session(session_name="dashboard")
main = session.new_window(window_name="main")

# Create a grid layout with 4 panes
top_left = main.attached_pane
top_right = top_left.split_window(vertical=True)
bottom_left = top_left.split_window(vertical=False)
bottom_right = top_right.split_window(vertical=False)

# Configure each pane
top_left.send_keys("htop", enter=True)
top_right.send_keys("watch -n 1 df -h", enter=True)
bottom_left.send_keys("tail -f /var/log/syslog", enter=True)
bottom_right.send_keys("netstat -tunapl", enter=True)
```

See [advanced scripting documentation](https://libtmux.git-pull.com/topics/advanced_scripting.html) for more examples.

# Python support

Unsupported / no security releases or bug fixes:
Expand Down
33 changes: 23 additions & 10 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""Conftest.py (root-level).
"""Configure root-level pytest fixtures for libtmux.

We keep this in root pytest fixtures in pytest's doctest plugin to be available, as well
as avoiding conftest.py from being included in the wheel, in addition to pytest_plugin
for pytester only being available via the root directory.
We keep this file at the root to make these fixtures available to all
tests, while also preventing unwanted inclusion in the distributed
wheel. Additionally, `pytest_plugins` references ensure that the
`pytester` plugin is accessible for test generation and execution.

See "pytest_plugins in non-top-level conftest files" in
https://docs.pytest.org/en/stable/deprecations.html
See Also
--------
pytest_plugins in non-top-level conftest files
https://docs.pytest.org/en/stable/deprecations.html
"""

from __future__ import annotations
Expand Down Expand Up @@ -33,7 +36,13 @@ def add_doctest_fixtures(
request: pytest.FixtureRequest,
doctest_namespace: dict[str, t.Any],
) -> None:
"""Configure doctest fixtures for pytest-doctest."""
"""Configure doctest fixtures for pytest-doctest.

Automatically sets up tmux-related classes and default fixtures,
making them available in doctest namespaces if `tmux` is found
on the system. This ensures that doctest blocks referencing tmux
structures can execute smoothly in the test environment.
"""
if isinstance(request._pyfuncitem, DoctestItem) and shutil.which("tmux"):
request.getfixturevalue("set_home")
doctest_namespace["Server"] = Server
Expand All @@ -54,22 +63,26 @@ def set_home(
monkeypatch: pytest.MonkeyPatch,
user_path: pathlib.Path,
) -> None:
"""Configure home directory for pytest tests."""
"""Set the HOME environment variable to the temporary user directory."""
monkeypatch.setenv("HOME", str(user_path))


@pytest.fixture(autouse=True)
def setup_fn(
clear_env: None,
) -> None:
"""Function-level test configuration fixtures for pytest."""
"""Apply function-level test fixture configuration (e.g., environment cleanup)."""


@pytest.fixture(autouse=True, scope="session")
def setup_session(
request: pytest.FixtureRequest,
config_file: pathlib.Path,
) -> None:
"""Session-level test configuration for pytest."""
"""Apply session-level test fixture configuration for libtmux testing.

If zsh is in use, applies a suppressing `.zshrc` fix to avoid
default interactive messages that might disrupt tmux sessions.
"""
if USING_ZSH:
request.getfixturevalue("zshrc")
1 change: 1 addition & 0 deletions docs/internals/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ If you need an internal API stabilized please [file an issue](https://github.com
```{toctree}
dataclasses
query_list
waiter
```

## Environmental variables
Expand Down
Loading