Skip to content

pytest plugin #411

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

Merged
merged 11 commits into from
Sep 10, 2022
25 changes: 15 additions & 10 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
[run]
parallel = 1
branch = 1

omit =
test/*
*/_vendor/*
*/_*
pkg/*
*/log.py
docs/conf.py
*/_compat.py

[report]
skip_covered = True
show_missing = True
exclude_lines =
pragma: no cover
def __repr__
raise NotImplementedError
if __name__ == .__main__.:
def parse_args
\#\s*pragma: no cover
^\s*raise NotImplementedError\b
^\s*return NotImplemented\b
^\s*assert False(,|$)
^\s*assert_never\(

^\s*if TYPE_CHECKING:
^\s*@overload( |$)
6 changes: 5 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ jobs:
export PATH=$HOME/tmux-builds/tmux-${{ matrix.tmux-version }}/bin:$PATH
ls $HOME/tmux-builds/tmux-${{ matrix.tmux-version }}/bin
tmux -V
poetry run py.test --cov=./ --cov-report=xml
poetry run py.test --cov=./ --cov-append --cov-report=xml
env:
COV_CORE_SOURCE: .
COV_CORE_CONFIG: .coveragerc
COV_CORE_DATAFILE: .coverage.eager
- uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"printWidth": 100
"printWidth": 100,
"proseWrap": 'always'
}
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,23 @@ List sessions:

```python
>>> server.list_sessions()
[Session($... libtmux_...), Session($... ...)]
[Session($1 ...), Session($0 ...)]
```

Find session:

```python
>>> server.get_by_id('$0')
Session($... ...)
>>> server.get_by_id('$1')
Session($1 ...)
```

Find session by dict lookup:

```python
>>> server.sessions[0].rename_session('foo')
Session($... foo)
Session($1 foo)
>>> server.find_where({ "session_name": "foo" })
Session($... foo)
Session($1 foo)
```

Control your session:
Expand All @@ -103,7 +103,7 @@ Create new window in the background (don't switch to it):

```python
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@... ...:ha in the bg, Session($... libtmux_...))
Window(@2 2:ha in the bg, Session($1 ...))
```

Close window:
Expand All @@ -118,14 +118,14 @@ Grab remaining tmux window:
```python
>>> window = session.attached_window
>>> window.split_window(attach=False)
Pane(%... Window(@... ...:..., Session($... libtmux_...)))
Pane(%2 Window(@1 1:... Session($1 ...)))
```

Rename window:

```python
>>> window.rename_window('libtmuxower')
Window(@... ...:libtmuxower, Session($... ...))
Window(@1 1:libtmuxower, Session($1 ...))
```

Split window (create a new pane):
Expand All @@ -134,13 +134,13 @@ Split window (create a new pane):
>>> pane = window.split_window()
>>> pane = window.split_window(attach=False)
>>> pane.select_pane()
Pane(%... Window(@... ...:..., Session($... libtmux_...)))
Pane(%3 Window(@1 1:..., Session($1 ...)))
>>> window = session.new_window(attach=False, window_name="test")
>>> window
Window(@... ...:test, Session($...))
Window(@2 2:test, Session($1 ...))
>>> pane = window.split_window(attach=False)
>>> pane
Pane(%... Window(@... ...:..., Session($... libtmux_...)))
Pane(%5 Window(@2 2:test, Session($1 ...)))
```

Type inside the pane (send key strokes):
Expand Down Expand Up @@ -175,9 +175,9 @@ Traverse and navigate:

```python
>>> pane.window
Window(@... ...:..., Session($... ...))
Window(@1 1:..., Session($1 ...))
>>> pane.window.session
Session($... ...)
Session($1 ...)
```

# Python support
Expand Down
5 changes: 4 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@
)
]

intersphinx_mapping = {"http://docs.python.org/": None}
intersphinx_mapping = {
"": ("https://docs.python.org/", None),
"pytest": ("https://docs.pytest.org/en/stable/", None),
}


def linkcode_resolve(
Expand Down
1 change: 1 addition & 0 deletions docs/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from libtmux.conftest import * # NOQA: F4
8 changes: 8 additions & 0 deletions docs/developing.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ Makefile commands prefixed with `watch_` will watch files and rerun.
Helpers: `make test`
Rerun tests on file change: `make watch_test` (requires [entr(1)])

### Pytest plugin

:::{seealso}

See {ref}`pytest_plugin`.

:::

## Documentation

Default preview server: http://localhost:8023
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ api
:hidden:

developing
pytest-plugin
internals/index
history
glossary
Expand Down
98 changes: 98 additions & 0 deletions docs/pytest-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
(pytest_plugin)=

# `pytest` plugin

Testing tmux with libtmux

```{seealso} Using libtmux?

Do you want more flexbility? Correctness? Power? Defaults changed? [Connect with us] on the tracker, we want to know
your case, we won't stabilize APIs until we're sure everything is by the book.

[connect with us]: https://github.com/tmux-python/libtmux/discussions

```

```{module} libtmux.pytest_plugin

```

## Usage

Install `libtmux` via the python package manager of your choosing, e.g.

```console
$ pip install libtmux
```

The pytest plugin will automatically be detected via pytest, and the fixtures will be added.

## Fixtures

`pytest-tmux` works through providing {ref}`pytest fixtures <pytest:fixtures-api>` - so read up on
those!

The plugin's fixtures guarantee a fresh, headless `tmux(1)` server, session, window, or pane is
passed into your test.

(recommended-fixtures)=

## Recommended fixtures

These are fixtures are automatically used when the plugin is enabled and `pytest` is ran.

- Creating temporary, test directories for:
- `/home/` ({func}`home_path`)
- `/home/${user}` ({func}`user_path`)
- Default `.tmux.conf` configuration with these settings ({func}`config_file`):

- `base-index -g 1`

These are set to ensure panes and windows can be reliably referenced and asserted.

## Setting a tmux configuration

If you would like :func:`session` fixture to automatically use a configuration, you have a few
options:

- Pass a `config_file` into :class:`libtmux.server.Server`
- Set the `HOME` directory to a local or temporary pytest path with a configurat configuration file

You could also read the code and override :func:`server`'s fixture in your own doctest. doctest.

(set_home)=

### Setting a temporary home directory

```python
import pathlib
import pytest

@pytest.fixture(autouse=True, scope="function")
def set_home(
monkeypatch: pytest.MonkeyPatch,
user_path: pathlib.Path,
):
monkeypatch.setenv("HOME", str(user_path))
```

## See examples

View libtmux's own [tests/](https://github.com/tmux-python/libtmux/tree/master/tests) as well as
tmuxp's [tests/](https://github.com/tmux-python/tmuxp/tree/master/tests).

libtmux's tests `autouse` the {ref}`recommended-fixtures` above to ensure stable, assertions and
object lookups in the test grid.

## API reference

```{eval-rst}
.. autoapimodule:: libtmux.pytest_plugin
:members:
:inherited-members:
:private-members:
:show-inheritance:
:member-order: bysource
:exclude-members: Server, TEST_SESSION_PREFIX, get_test_session_name,
namer, logger
```
28 changes: 14 additions & 14 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,15 @@ We can list sessions with {meth}`Server.list_sessions`:

```python
>>> server.list_sessions()
[Session($... ...), Session($... ...)]
[Session($1 ...), Session($0 ...)]
```

This returns a list of {class}`Session` objects you can grab. We can
find our current session with:

```python
>>> server.list_sessions()[0]
Session($... ...)
Session($1 ...)
```

However, this isn't guaranteed, libtmux works against current tmux information, the
Expand All @@ -162,7 +162,7 @@ tmux sessions use the `$[0-9]` convention as a way to identify sessions.

```python
>>> server.get_by_id('$1')
Session($... ...)
Session($1 ...)
```

You may `session = server.get_by_id('$<yourId>')` to use the session object.
Expand All @@ -172,10 +172,10 @@ You may `session = server.get_by_id('$<yourId>')` to use the session object.
```python
# Just for setting up the example:
>>> server.sessions[0].rename_session('foo')
Session($... foo)
Session($1 foo)

>>> server.find_where({ "session_name": "foo" })
Session($... foo)
Session($1 foo)
```

With `find_where`, pass in a dict and return the first object found. In
Expand All @@ -188,11 +188,11 @@ So you may now use:
```python
# Prepping the example:
>>> server.sessions[0].rename_session('foo')
Session($... foo)
Session($1 foo)

>>> session = server.find_where({ "session_name": "foo" })
>>> session
Session($... foo)
Session($1 foo)
```

to give us a `session` object to play with.
Expand All @@ -206,7 +206,7 @@ Let's make a {meth}`Session.new_window`, in the background:

```python
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@... ...:ha in the bg, Session($... ...))
Window(@2 ...:ha in the bg, Session($1 ...))
```

So a few things:
Expand Down Expand Up @@ -245,15 +245,15 @@ should have history, so navigate up with the arrow key.

```python
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@... ...:ha in the bg, Session($... ...))
Window(@2 ...:ha in the bg, Session($1 ...))
```

Try to kill the window by the matching id `@[0-9999]`.

```python
# Setup
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@... ...:ha in the bg, Session($... ...))
Window(@1 ...:ha in the bg, Session($1 ...))

>>> session.kill_window('ha in the bg')
```
Expand All @@ -264,7 +264,7 @@ object:
```python
>>> window = session.new_window(attach=False, window_name="check this out")
>>> window
Window(@... ...:check this out, Session($... ...))
Window(@2 2:check this out, Session($1 ...))
```

And kill:
Expand All @@ -291,7 +291,7 @@ Let's create a pane, {meth}`Window.split_window`:

```python
>>> window.split_window(attach=False)
Pane(%... Window(@... ...:..., Session($... ...)))
Pane(%2 Window(@1 ...:..., Session($1 ...)))
```

Powered up. Let's have a break down:
Expand All @@ -304,7 +304,7 @@ Also, since you are aware of this power, let's commemorate the experience:

```python
>>> window.rename_window('libtmuxower')
Window(@... ...:..., Session($... ...))
Window(@1 ...:..., Session($1 ...))
```

You should have noticed {meth}`Window.rename_window` renamed the window.
Expand All @@ -329,7 +329,7 @@ can also use the `.select_*` available on the object, in this case the pane has

```python
>>> pane.select_pane()
Pane(%... Window(@... ...:..., Session($... ...)))
Pane(%1 Window(@1 ...:..., Session($1 ...)))
```

```{eval-rst}
Expand Down
Loading