Skip to content

Commit aefef02

Browse files
authored
Tests: Coverage for libtmux.test helpers (#580)
This PR completes the refactoring of test helpers started in PR #578 by removing direct imports from the `libtmux.test` root module. Users must now import from specific submodules like `libtmux.test.named` and `libtmux.test.constants`. Improvements include: - Enhanced `EnvironmentVarGuard` for more reliable environment variable handling - Added comprehensive test suites for constants and environment utilities - Improved code coverage with proper exclusion markers for type checking blocks - Better docstrings and examples in the random module These changes improve maintainability and robustness of test helpers that are used both internally and by downstream packages that depend on libtmux.
2 parents 0c9231c + a4658c9 commit aefef02

11 files changed

+1073
-73
lines changed

CHANGES

+48
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,54 @@ $ pip install --user --upgrade --pre libtmux
1515

1616
- _Future release notes will be placed here_
1717

18+
### Breaking
19+
20+
#### Imports removed from libtmux.test (#580)
21+
22+
Root-level of imports from `libtmux.test` are no longer possible.
23+
24+
```python
25+
# Before 0.46.0
26+
from libtmux.test import namer
27+
```
28+
29+
```python
30+
# From 0.46.0 onward
31+
from libtmux.test.named import namer
32+
```
33+
34+
Same thing with constants:
35+
36+
```python
37+
# Before 0.46.0
38+
from libtmux.test import (
39+
RETRY_INTERVAL_SECONDS,
40+
RETRY_TIMEOUT_SECONDS,
41+
TEST_SESSION_PREFIX
42+
)
43+
```
44+
45+
```python
46+
# From 0.46.0 onward
47+
from libtmux.test.constants import (
48+
RETRY_INTERVAL_SECONDS,
49+
RETRY_TIMEOUT_SECONDS,
50+
TEST_SESSION_PREFIX
51+
)
52+
```
53+
54+
### Development
55+
56+
#### Test helpers: Increased coverage (#580)
57+
58+
Several improvements to the test helper modules:
59+
60+
- Enhanced `EnvironmentVarGuard` in `libtmux.test.environment` to better handle variable cleanup
61+
- Added comprehensive test suites for test constants and environment utilities
62+
- Improved docstrings and examples in `libtmux.test.random` with test coverage annotations
63+
- Fixed potential issues with environment variable handling during tests
64+
- Added proper coverage markers to exclude type checking blocks from coverage reports
65+
1866
## libtmux 0.45.0 (2025-02-23)
1967

2068
### Breaking Changes

MIGRATION

+34
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,40 @@ _Detailed migration steps for the next version will be posted here._
2525

2626
<!-- To the maintainers and contributors: please add migration details for the upcoming release here -->
2727

28+
#### Imports removed from libtmux.test (#580)
29+
30+
Root-level of imports from `libtmux.test` are no longer possible.
31+
32+
```python
33+
# Before 0.46.0
34+
from libtmux.test import namer
35+
```
36+
37+
```python
38+
# From 0.46.0 onward
39+
from libtmux.test.named import namer
40+
```
41+
42+
Same thing with constants:
43+
44+
```python
45+
# Before 0.46.0
46+
from libtmux.test import (
47+
RETRY_INTERVAL_SECONDS,
48+
RETRY_TIMEOUT_SECONDS,
49+
TEST_SESSION_PREFIX
50+
)
51+
```
52+
53+
```python
54+
# From 0.46.0 onward
55+
from libtmux.test.constants import (
56+
RETRY_INTERVAL_SECONDS,
57+
RETRY_TIMEOUT_SECONDS,
58+
TEST_SESSION_PREFIX
59+
)
60+
```
61+
2862
## libtmux 0.45.0 (2025-02-23)
2963

3064
### Test helpers: Module moves

pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ exclude_lines = [
150150
"if TYPE_CHECKING:",
151151
"if t.TYPE_CHECKING:",
152152
"@overload( |$)",
153+
'class .*\bProtocol\):',
153154
"from __future__ import annotations",
155+
"import typing as t",
154156
]
155157

156158
[tool.ruff]

src/libtmux/test/__init__.py

-35
Original file line numberDiff line numberDiff line change
@@ -1,36 +1 @@
11
"""Helper methods for libtmux and downstream libtmux libraries."""
2-
3-
from __future__ import annotations
4-
5-
import contextlib
6-
import logging
7-
import os
8-
import pathlib
9-
import random
10-
import time
11-
import typing as t
12-
13-
from libtmux.exc import WaitTimeout
14-
from libtmux.test.constants import (
15-
RETRY_INTERVAL_SECONDS,
16-
RETRY_TIMEOUT_SECONDS,
17-
TEST_SESSION_PREFIX,
18-
)
19-
20-
from .random import namer
21-
22-
logger = logging.getLogger(__name__)
23-
24-
if t.TYPE_CHECKING:
25-
import sys
26-
import types
27-
from collections.abc import Callable, Generator
28-
29-
from libtmux.server import Server
30-
from libtmux.session import Session
31-
from libtmux.window import Window
32-
33-
if sys.version_info >= (3, 11):
34-
from typing import Self
35-
else:
36-
from typing_extensions import Self

src/libtmux/test/environment.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ def set(self, envvar: str, value: str) -> None:
5252
def unset(self, envvar: str) -> None:
5353
"""Unset environment variable."""
5454
if envvar in self._environ:
55-
self._reset[envvar] = self._environ[envvar]
55+
# If we previously set this variable in this context, remove it from _unset
56+
if envvar in self._unset:
57+
self._unset.remove(envvar)
58+
# If we haven't saved the original value yet, save it
59+
if envvar not in self._reset:
60+
self._reset[envvar] = self._environ[envvar]
5661
del self._environ[envvar]
5762

5863
def __enter__(self) -> Self:
@@ -69,4 +74,5 @@ def __exit__(
6974
for envvar, value in self._reset.items():
7075
self._environ[envvar] = value
7176
for unset in self._unset:
72-
del self._environ[unset]
77+
if unset not in self._reset: # Don't delete variables that were reset
78+
del self._environ[unset]

src/libtmux/test/random.py

+22-25
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
11
"""Random helpers for libtmux and downstream libtmux libraries."""
22

3-
from __future__ import annotations
3+
from __future__ import annotations # pragma: no cover
44

55
import logging
66
import random
7-
import typing as t
7+
import typing as t # pragma: no cover
88

99
from libtmux.test.constants import (
1010
TEST_SESSION_PREFIX,
1111
)
1212

13-
logger = logging.getLogger(__name__)
14-
15-
if t.TYPE_CHECKING:
16-
import sys
13+
if t.TYPE_CHECKING: # pragma: no cover
14+
import sys # pragma: no cover
1715

18-
from libtmux.server import Server
19-
from libtmux.session import Session
16+
from libtmux.server import Server # pragma: no cover
17+
from libtmux.session import Session # pragma: no cover
2018

21-
if sys.version_info >= (3, 11):
22-
pass
19+
if sys.version_info >= (3, 11): # pragma: no cover
20+
pass # pragma: no cover
21+
else: # pragma: no cover
22+
pass # pragma: no cover
2323

2424

2525
logger = logging.getLogger(__name__)
2626

27-
if t.TYPE_CHECKING:
28-
import sys
29-
30-
if sys.version_info >= (3, 11):
31-
pass
32-
3327

3428
class RandomStrSequence:
3529
"""Factory to generate random string."""
@@ -40,12 +34,12 @@ def __init__(
4034
) -> None:
4135
"""Create a random letter / number generator. 8 chars in length.
4236
43-
>>> rng = RandomStrSequence()
44-
>>> next(rng)
37+
>>> rng = RandomStrSequence() # pragma: no cover
38+
>>> next(rng) # pragma: no cover
4539
'...'
46-
>>> len(next(rng))
40+
>>> len(next(rng)) # pragma: no cover
4741
8
48-
>>> type(next(rng))
42+
>>> type(next(rng)) # pragma: no cover
4943
<class 'str'>
5044
"""
5145
self.characters: str = characters
@@ -81,11 +75,13 @@ def get_test_session_name(server: Server, prefix: str = TEST_SESSION_PREFIX) ->
8175
8276
Examples
8377
--------
84-
>>> get_test_session_name(server=server)
78+
>>> get_test_session_name(server=server) # pragma: no cover
8579
'libtmux_...'
8680
8781
Never the same twice:
88-
>>> get_test_session_name(server=server) != get_test_session_name(server=server)
82+
>>> name1 = get_test_session_name(server=server) # pragma: no cover
83+
>>> name2 = get_test_session_name(server=server) # pragma: no cover
84+
>>> name1 != name2 # pragma: no cover
8985
True
9086
"""
9187
while True:
@@ -119,12 +115,13 @@ def get_test_window_name(
119115
120116
Examples
121117
--------
122-
>>> get_test_window_name(session=session)
118+
>>> get_test_window_name(session=session) # pragma: no cover
123119
'libtmux_...'
124120
125121
Never the same twice:
126-
127-
>>> get_test_window_name(session=session) != get_test_window_name(session=session)
122+
>>> name1 = get_test_window_name(session=session) # pragma: no cover
123+
>>> name2 = get_test_window_name(session=session) # pragma: no cover
124+
>>> name1 != name2 # pragma: no cover
128125
True
129126
"""
130127
assert prefix is not None

tests/test/test_constants.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""Tests for libtmux's test constants."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
from libtmux.test.constants import (
8+
RETRY_INTERVAL_SECONDS,
9+
RETRY_TIMEOUT_SECONDS,
10+
TEST_SESSION_PREFIX,
11+
)
12+
13+
if TYPE_CHECKING:
14+
import pytest
15+
16+
17+
def test_test_session_prefix() -> None:
18+
"""Test TEST_SESSION_PREFIX is correctly defined."""
19+
assert TEST_SESSION_PREFIX == "libtmux_"
20+
21+
22+
def test_retry_timeout_seconds_default() -> None:
23+
"""Test RETRY_TIMEOUT_SECONDS default value."""
24+
assert RETRY_TIMEOUT_SECONDS == 8
25+
26+
27+
def test_retry_timeout_seconds_env(monkeypatch: pytest.MonkeyPatch) -> None:
28+
"""Test RETRY_TIMEOUT_SECONDS can be configured via environment variable."""
29+
monkeypatch.setenv("RETRY_TIMEOUT_SECONDS", "10")
30+
from importlib import reload
31+
32+
import libtmux.test.constants
33+
34+
reload(libtmux.test.constants)
35+
assert libtmux.test.constants.RETRY_TIMEOUT_SECONDS == 10
36+
37+
38+
def test_retry_interval_seconds_default() -> None:
39+
"""Test RETRY_INTERVAL_SECONDS default value."""
40+
assert RETRY_INTERVAL_SECONDS == 0.05
41+
42+
43+
def test_retry_interval_seconds_env(monkeypatch: pytest.MonkeyPatch) -> None:
44+
"""Test RETRY_INTERVAL_SECONDS can be configured via environment variable."""
45+
monkeypatch.setenv("RETRY_INTERVAL_SECONDS", "0.1")
46+
from importlib import reload
47+
48+
import libtmux.test.constants
49+
50+
reload(libtmux.test.constants)
51+
assert libtmux.test.constants.RETRY_INTERVAL_SECONDS == 0.1

0 commit comments

Comments
 (0)