Skip to content

Commit c1ed3e5

Browse files
committed
libtmux(feat[logging]): add NullHandler, lifecycle logging, clean up unused imports
why: Complete logging standards conformance per AGENTS.md conventions. what: - __init__.py: Add NullHandler to prevent "No handler found" warnings - session.py: Add INFO logging for kill(), rename_session(), new_window() with structured extra (tmux_subcommand, tmux_session, tmux_target) - pane.py: Add INFO logging for kill() and split() with structured extra - neo.py: Add guarded DEBUG logging for fetch_objs() before/after query - Remove unused logger imports from test/retry.py, test/environment.py, test/temporary.py, test/random.py, _internal/constants.py - tests/test/test_random.py: Remove test_logger, test_logger_configured, and logger import; fix test_imports_coverage assertion
1 parent 713b337 commit c1ed3e5

10 files changed

Lines changed: 81 additions & 42 deletions

File tree

src/libtmux/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
import logging
6+
57
from .__about__ import (
68
__author__,
79
__copyright__,
@@ -17,6 +19,8 @@
1719
from .session import Session
1820
from .window import Window
1921

22+
logging.getLogger(__name__).addHandler(logging.NullHandler())
23+
2024
__all__ = (
2125
"Pane",
2226
"Server",

src/libtmux/_internal/constants.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
import io
6-
import logging
76
import typing as t
87
from dataclasses import dataclass, field
98

@@ -19,8 +18,6 @@
1918
TerminalFeatures = dict[str, list[str]]
2019
HookArray: TypeAlias = "dict[str, SparseArray[str]]"
2120

22-
logger = logging.getLogger(__name__)
23-
2421

2522
@dataclass(repr=False)
2623
class ServerOptions(

src/libtmux/neo.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import dataclasses
66
import functools
77
import logging
8+
import shlex
89
import typing as t
910
from collections.abc import Iterable
1011

@@ -305,12 +306,33 @@ def fetch_objs(
305306

306307
tmux_cmds.append(f"-F{format_string}")
307308

309+
if logger.isEnabledFor(logging.DEBUG):
310+
logger.debug(
311+
"tmux list queried",
312+
extra={
313+
"tmux_subcommand": list_cmd,
314+
"tmux_cmd": shlex.join([str(x) for x in tmux_cmds]),
315+
},
316+
)
317+
308318
proc = tmux_cmd(*tmux_cmds) # output
309319

310320
if proc.stderr:
311321
raise exc.LibTmuxException(proc.stderr)
312322

313-
return [parse_output(line) for line in proc.stdout]
323+
outputs = [parse_output(line) for line in proc.stdout]
324+
325+
if logger.isEnabledFor(logging.DEBUG):
326+
logger.debug(
327+
"tmux list parsed",
328+
extra={
329+
"tmux_subcommand": list_cmd,
330+
"tmux_cmd": shlex.join([str(x) for x in tmux_cmds]),
331+
"tmux_stdout_len": len(proc.stdout),
332+
},
333+
)
334+
335+
return outputs
314336

315337

316338
def fetch_obj(

src/libtmux/pane.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,15 @@ def kill(
567567
if proc.stderr:
568568
raise exc.LibTmuxException(proc.stderr)
569569

570+
logger.info(
571+
"pane killed",
572+
extra={
573+
"tmux_subcommand": "kill-pane",
574+
"tmux_pane": self.pane_id,
575+
"tmux_target": self.pane_id,
576+
},
577+
)
578+
570579
"""
571580
Commands ("climber"-helpers)
572581
@@ -769,7 +778,20 @@ def split(
769778
zip(["pane_id"], pane_output.split(FORMAT_SEPARATOR), strict=False),
770779
)
771780

772-
return self.from_pane_id(server=self.server, pane_id=pane_formatters["pane_id"])
781+
pane = self.from_pane_id(server=self.server, pane_id=pane_formatters["pane_id"])
782+
783+
logger.info(
784+
"pane created",
785+
extra={
786+
"tmux_subcommand": "split-window",
787+
"tmux_session": self.session.session_name,
788+
"tmux_window": self.window.window_name,
789+
"tmux_pane": pane.pane_id,
790+
"tmux_target": target,
791+
},
792+
)
793+
794+
return pane
773795

774796
"""
775797
Commands (helpers)

src/libtmux/session.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,15 @@ def kill(
395395
if proc.stderr:
396396
raise exc.LibTmuxException(proc.stderr)
397397

398+
logger.info(
399+
"session killed",
400+
extra={
401+
"tmux_subcommand": "kill-session",
402+
"tmux_session": self.session_name,
403+
"tmux_target": self.session_id,
404+
},
405+
)
406+
398407
def switch_client(self) -> Session:
399408
"""Switch client to session.
400409
@@ -430,6 +439,15 @@ def rename_session(self, new_name: str) -> Session:
430439

431440
self.refresh()
432441

442+
logger.info(
443+
"session renamed",
444+
extra={
445+
"tmux_subcommand": "rename-session",
446+
"tmux_session": new_name,
447+
"tmux_target": self.session_id,
448+
},
449+
)
450+
433451
return self
434452

435453
def new_window(
@@ -561,11 +579,23 @@ def new_window(
561579
zip(["window_id"], window_output.split(FORMAT_SEPARATOR), strict=False),
562580
)
563581

564-
return Window.from_window_id(
582+
window = Window.from_window_id(
565583
server=self.server,
566584
window_id=window_formatters["window_id"],
567585
)
568586

587+
logger.info(
588+
"window created",
589+
extra={
590+
"tmux_subcommand": "new-window",
591+
"tmux_session": self.session_name,
592+
"tmux_window": window_name,
593+
"tmux_target": target,
594+
},
595+
)
596+
597+
return window
598+
569599
def kill_window(self, target_window: str | None = None) -> None:
570600
"""Close a tmux window, and all panes inside it, ``$ tmux kill-window``.
571601

src/libtmux/test/environment.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22

33
from __future__ import annotations
44

5-
import logging
65
import os
76
import typing as t
87

9-
logger = logging.getLogger(__name__)
10-
118
if t.TYPE_CHECKING:
129
import sys
1310
import types

src/libtmux/test/random.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations # pragma: no cover
44

5-
import logging
65
import random
76
import typing as t # pragma: no cover
87

@@ -22,9 +21,6 @@
2221
pass # pragma: no cover
2322

2423

25-
logger = logging.getLogger(__name__)
26-
27-
2824
class RandomStrSequence:
2925
"""Factory to generate random string."""
3026

src/libtmux/test/retry.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import logging
65
import time
76
import typing as t
87

@@ -12,8 +11,6 @@
1211
RETRY_TIMEOUT_SECONDS,
1312
)
1413

15-
logger = logging.getLogger(__name__)
16-
1714
if t.TYPE_CHECKING:
1815
import sys
1916
from collections.abc import Callable

src/libtmux/test/temporary.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
from __future__ import annotations
44

55
import contextlib
6-
import logging
76
import typing as t
87

98
from libtmux.test.random import get_test_session_name, get_test_window_name
109

11-
logger = logging.getLogger(__name__)
12-
1310
if t.TYPE_CHECKING:
1411
import sys
1512
from collections.abc import Generator

tests/test/test_random.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import logging
65
import string
76
import sys
87
import typing as t
@@ -14,7 +13,6 @@
1413
RandomStrSequence,
1514
get_test_session_name,
1615
get_test_window_name,
17-
logger,
1816
namer,
1917
)
2018

@@ -25,12 +23,6 @@
2523
from libtmux.session import Session
2624

2725

28-
def test_logger() -> None:
29-
"""Test that the logger is properly configured."""
30-
assert isinstance(logger, logging.Logger)
31-
assert logger.name == "libtmux.test.random"
32-
33-
3426
def test_random_str_sequence_default() -> None:
3527
"""Test RandomStrSequence with default characters."""
3628
rng = RandomStrSequence()
@@ -295,20 +287,6 @@ def test_random_str_sequence_insufficient_characters() -> None:
295287
next(rng)
296288

297289

298-
def test_logger_configured(caplog: pytest.LogCaptureFixture) -> None:
299-
"""Test that the logger in random.py is properly configured."""
300-
# Verify the logger is set up with the correct name
301-
assert logger.name == "libtmux.test.random"
302-
303-
# Test that the logger functions properly
304-
with caplog.at_level(logging.DEBUG):
305-
logger.debug("Test debug message")
306-
logger.info("Test info message")
307-
308-
assert "Test debug message" in caplog.text
309-
assert "Test info message" in caplog.text
310-
311-
312290
def test_next_method_directly() -> None:
313291
"""Test directly calling __next__ method on RandomStrSequence."""
314292
rng = RandomStrSequence()
@@ -424,7 +402,6 @@ def test_imports_coverage() -> None:
424402
# This test simply ensures the imports are covered
425403
from libtmux.test import random
426404

427-
assert hasattr(random, "logging")
428405
assert hasattr(random, "random")
429406
assert hasattr(random, "t")
430407
assert hasattr(random, "TEST_SESSION_PREFIX")

0 commit comments

Comments
 (0)