Skip to content

Commit 88efa36

Browse files
committed
refactor(control-mode): Clarify internal session naming and filters
1 parent 32038c4 commit 88efa36

File tree

6 files changed

+36
-31
lines changed

6 files changed

+36
-31
lines changed

CHANGES

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ _Future release notes will be placed here_
4343
- Control mode engine's internal connection session is now automatically filtered from
4444
`Server.sessions` and `Server.has_session()`, making engine choice transparent to
4545
users. Advanced users can access all sessions via `Server._sessions_all()`. (#605)
46-
- `ControlModeEngine` accepts optional `session_name` and `attach_to` parameters for
47-
advanced session management scenarios. (#605)
46+
- `ControlModeEngine` accepts optional `internal_session_name` and `attach_to`
47+
parameters for advanced session management scenarios. (#605)
4848
- `Server.connect()`: New convenience method for session management. Returns an
4949
existing session if found, otherwise creates a new detached session. Simplifies
5050
common session reuse patterns and works transparently with both subprocess and

docs/topics/control_mode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ For testing or advanced scenarios, you can customize the internal session name:
8080
from libtmux._internal.engines.control_mode import ControlModeEngine
8181
from libtmux.server import Server
8282

83-
engine = ControlModeEngine(session_name="my_control_session")
83+
engine = ControlModeEngine(internal_session_name="my_control_session")
8484
server = Server(engine=engine)
8585

8686
# Internal session is still filtered

src/libtmux/_internal/engines/base.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,18 @@ def iter_notifications(
161161
return
162162

163163
# Optional hooks ---------------------------------------------------
164-
def filter_attached_sessions(
164+
@property
165+
def internal_session_names(self) -> set[str]:
166+
"""Names of sessions reserved for engine internals."""
167+
return set()
168+
169+
def exclude_internal_sessions(
165170
self,
166171
sessions: list[Session],
172+
*,
173+
server_args: tuple[str | int, ...] | None = None,
167174
) -> list[Session]: # pragma: no cover - overridden by control mode
168-
"""Allow engines to hide internal clients from attached session lists."""
175+
"""Allow engines to hide internal/management sessions from user lists."""
169176
return sessions
170177

171178
def get_stats(self) -> EngineStats: # pragma: no cover - default noop

src/libtmux/_internal/engines/control_mode.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(
4444
self,
4545
command_timeout: float | None = 10.0,
4646
notification_queue_size: int = 4096,
47-
session_name: str | None = None,
47+
internal_session_name: str | None = None,
4848
attach_to: str | None = None,
4949
) -> None:
5050
"""Initialize control mode engine.
@@ -55,7 +55,7 @@ def __init__(
5555
Timeout for tmux commands in seconds. Default: 10.0
5656
notification_queue_size : int
5757
Size of notification queue. Default: 4096
58-
session_name : str, optional
58+
internal_session_name : str, optional
5959
Custom name for internal control session.
6060
Default: "libtmux_control_mode"
6161
@@ -81,7 +81,7 @@ def __init__(
8181
notification_queue_size=notification_queue_size,
8282
)
8383
self._restarts = 0
84-
self._session_name = session_name or "libtmux_control_mode"
84+
self._internal_session_name = internal_session_name or "libtmux_control_mode"
8585
self._attach_to = attach_to
8686

8787
# Lifecycle ---------------------------------------------------------
@@ -183,7 +183,14 @@ def get_stats(self) -> EngineStats:
183183
"""Return diagnostic statistics for the engine."""
184184
return self._protocol.get_stats(restarts=self._restarts)
185185

186-
def filter_attached_sessions(
186+
@property
187+
def internal_session_names(self) -> set[str]:
188+
"""Session names reserved for the engine's control connection."""
189+
if self._attach_to:
190+
return set()
191+
return {self._internal_session_name}
192+
193+
def exclude_internal_sessions(
187194
self,
188195
sessions: list[Session],
189196
*,
@@ -217,7 +224,7 @@ def filter_attached_sessions(
217224

218225
# Never expose the internal control session we create to hold the
219226
# control client when attach_to is unset.
220-
if not self._attach_to and sess_name == self._session_name:
227+
if not self._attach_to and sess_name == self._internal_session_name:
221228
continue
222229

223230
clients = pid_map.get(sess_name, [])
@@ -314,15 +321,15 @@ def _start_process(self, server_args: tuple[str | int, ...]) -> None:
314321
"new-session",
315322
"-A",
316323
"-s",
317-
self._session_name,
324+
self._internal_session_name,
318325
]
319326
bootstrap_argv = [
320327
tmux_bin,
321328
*[str(a) for a in server_args],
322329
"new-session",
323330
"-A",
324331
"-s",
325-
self._session_name,
332+
self._internal_session_name,
326333
]
327334

328335
logger.debug("Starting Control Mode process: %s", cmd)

src/libtmux/server.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def attached_sessions(self) -> list[Session]:
362362
sessions = list(self.sessions.filter(session_attached__noeq="1"))
363363

364364
# Let the engine hide its own internal client if it wants to.
365-
filter_fn = getattr(self.engine, "filter_attached_sessions", None)
365+
filter_fn = getattr(self.engine, "exclude_internal_sessions", None)
366366
if callable(filter_fn):
367367
server_args = tuple(self._build_server_args())
368368
try:
@@ -743,23 +743,14 @@ def new_session(
743743
# Relations
744744
#
745745
def _get_internal_session_names(self) -> set[str]:
746-
"""Get session names used internally by the engine.
747-
748-
These sessions are used for engine management (e.g., control mode
749-
connection) and should be hidden from user-facing APIs.
750-
751-
Returns
752-
-------
753-
set[str]
754-
Set of internal session names to filter.
755-
"""
756-
from libtmux._internal.engines.control_mode import ControlModeEngine
757-
758-
if isinstance(self.engine, ControlModeEngine) and not self.engine._attach_to:
759-
# Only filter if not attaching to user session
760-
return {self.engine._session_name}
761-
762-
return set()
746+
"""Get session names used internally by the engine for management."""
747+
internal_names: set[str] = set(
748+
getattr(self.engine, "internal_session_names", set()),
749+
)
750+
try:
751+
return set(internal_names)
752+
except Exception: # pragma: no cover - defensive
753+
return set()
763754

764755
@property
765756
def sessions(self) -> QueryList[Session]:

tests/test_control_mode_engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def fake_start(server_args: t.Sequence[str | int] | None) -> None:
115115
def test_control_mode_custom_session_name(tmp_path: pathlib.Path) -> None:
116116
"""Control mode engine can use custom internal session name."""
117117
socket_path = tmp_path / "tmux-custom-session-test"
118-
engine = ControlModeEngine(session_name="my_control_session")
118+
engine = ControlModeEngine(internal_session_name="my_control_session")
119119
server = Server(socket_path=socket_path, engine=engine)
120120

121121
# Cleanup if exists

0 commit comments

Comments
 (0)