Skip to content

Commit 565bf76

Browse files
committed
ControlModeEngine(api): Rename attach_to to control_session
Rename parameter for clarity and consistency with libtmux naming: - `attach_to` was ambiguous (what are we attaching to?) - `control_session` clearly indicates: existing session for control client to attach to Updated in: - control_mode.py: parameter, internal variable, docstrings - pytest_plugin.py: _build_engine() parameter - docs/topics/control_mode.md: example code - Tests: test names and assertions - CHANGES: release notes
1 parent ff5d4eb commit 565bf76

File tree

7 files changed

+38
-38
lines changed

7 files changed

+38
-38
lines changed

CHANGES

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ _Future release notes will be placed here_
4444
`Server.has_session()`; advanced users can inspect all sessions via
4545
`Server._sessions_all()`.
4646
- `ControlModeEngine` accepts `internal_session_name` (default `libtmux_control_mode`)
47-
and `attach_to` for advanced connection strategies.
47+
and `control_session` for advanced connection strategies.
4848

4949
Example:
5050

docs/topics/control_mode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ creating an internal one:
101101
server.new_session("shared")
102102

103103
# Control mode attaches to it for its connection
104-
engine = ControlModeEngine(attach_to="shared")
104+
engine = ControlModeEngine(control_session="shared")
105105
server = Server(engine=engine)
106106

107107
# The shared session is visible (not filtered)

src/libtmux/_internal/engines/control_mode.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def __init__(
8989
command_timeout: float | None = 10.0,
9090
notification_queue_size: int = 4096,
9191
internal_session_name: str | None = None,
92-
attach_to: str | None = None,
92+
control_session: str | None = None,
9393
process_factory: _ProcessFactory | None = None,
9494
max_retries: int = 1,
9595
start_threads: bool = True,
@@ -109,7 +109,7 @@ def __init__(
109109
The internal session is used for connection management and is
110110
automatically filtered from user-facing APIs. A unique name is
111111
generated automatically to avoid collisions with user sessions.
112-
attach_to : str, optional
112+
control_session : str, optional
113113
Attach to existing session instead of creating internal one.
114114
When set, control mode attaches to this session for its connection.
115115
@@ -142,7 +142,7 @@ def __init__(
142142
self._internal_session_name = (
143143
internal_session_name or f"libtmux_ctrl_{uuid.uuid4().hex[:8]}"
144144
)
145-
self._attach_to = attach_to
145+
self._control_session = control_session
146146
self._process_factory = process_factory
147147
self._max_retries = max(0, max_retries)
148148
self._start_threads = start_threads
@@ -273,7 +273,7 @@ def drain_notifications(
273273
274274
This helper is useful when you need to wait for notification activity
275275
to settle after an operation that may generate multiple notifications
276-
(e.g., attach-session in attach_to mode).
276+
(e.g., attach-session in control_session mode).
277277
278278
Parameters
279279
----------
@@ -318,7 +318,7 @@ def get_stats(self) -> EngineStats:
318318
@property
319319
def internal_session_names(self) -> set[str]:
320320
"""Session names reserved for the engine's control connection."""
321-
if self._attach_to:
321+
if self._control_session:
322322
return set()
323323
return {self._internal_session_name}
324324

@@ -376,8 +376,8 @@ def filter_sessions(
376376
sess_name = sess_obj.session_name or ""
377377

378378
# Never expose the internal control session we create to hold the
379-
# control client when attach_to is unset.
380-
if not self._attach_to and sess_name == self._internal_session_name:
379+
# control client when control_session is unset.
380+
if not self._control_session and sess_name == self._internal_session_name:
381381
continue
382382

383383
clients = pid_map.get(sess_name, [])
@@ -444,22 +444,22 @@ def _start_process(self, server_args: tuple[str | int, ...]) -> None:
444444
)
445445

446446
# Build command based on configuration
447-
if self._attach_to:
447+
if self._control_session:
448448
# Fail fast if attach target is missing before starting control mode.
449449
has_session_cmd = [
450450
tmux_bin,
451451
*[str(a) for a in server_args],
452452
"has-session",
453453
"-t",
454-
self._attach_to,
454+
self._control_session,
455455
]
456456
probe = subprocess.run(
457457
has_session_cmd,
458458
capture_output=True,
459459
text=True,
460460
)
461461
if probe.returncode != 0:
462-
msg = f"attach_to session not found: {self._attach_to}"
462+
msg = f"control_session not found: {self._control_session}"
463463
raise exc.ControlModeConnectionError(msg)
464464

465465
# Attach to existing session (advanced mode)
@@ -469,14 +469,14 @@ def _start_process(self, server_args: tuple[str | int, ...]) -> None:
469469
"-C",
470470
"attach-session",
471471
"-t",
472-
self._attach_to,
472+
self._control_session,
473473
]
474474
bootstrap_argv = [
475475
tmux_bin,
476476
*[str(a) for a in server_args],
477477
"attach-session",
478478
"-t",
479-
self._attach_to,
479+
self._control_session,
480480
]
481481
else:
482482
# Create or attach to internal session (default)

src/libtmux/neo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def fetch_objs(
198198
199199
Routes all commands through the server's engine, enabling:
200200
- Control mode persistent connection for fetch operations
201-
- Engine-specific validation (e.g., attach_to preflight checks)
201+
- Engine-specific validation (e.g., control_session preflight checks)
202202
- Consistent error handling across all tmux operations
203203
"""
204204
formats = list(Obj.__dataclass_fields__.keys())

src/libtmux/pytest_plugin.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def server(
157157
check=False, # Ignore if already exists
158158
capture_output=True,
159159
)
160-
engine = _build_engine(engine_name, attach_to="tmuxp")
160+
engine = _build_engine(engine_name, control_session="tmuxp")
161161
else:
162162
engine = _build_engine(engine_name)
163163

@@ -349,16 +349,16 @@ def engine_name(request: pytest.FixtureRequest) -> str:
349349
return "subprocess"
350350

351351

352-
def _build_engine(engine_name: str, attach_to: str | None = None) -> Engine:
352+
def _build_engine(engine_name: str, control_session: str | None = None) -> Engine:
353353
"""Return engine instance by name.
354354
355355
Parameters
356356
----------
357357
engine_name : str
358358
Name of engine: "control" or "subprocess"
359-
attach_to : str, optional
359+
control_session : str, optional
360360
For control mode: session name to attach to instead of creating internal session
361361
"""
362362
if engine_name == "control":
363-
return ControlModeEngine(attach_to=attach_to)
363+
return ControlModeEngine(control_session=control_session)
364364
return SubprocessEngine()

tests/test_control_mode_engine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def test_control_mode_custom_session_name(tmp_path: pathlib.Path) -> None:
193193
engine.process.wait(timeout=2)
194194

195195

196-
def test_control_mode_attach_to_existing(tmp_path: pathlib.Path) -> None:
196+
def test_control_mode_control_session_existing(tmp_path: pathlib.Path) -> None:
197197
"""Control mode can attach to existing session (advanced opt-in)."""
198198
socket_path = tmp_path / "tmux-attach-test"
199199

@@ -209,7 +209,7 @@ def test_control_mode_attach_to_existing(tmp_path: pathlib.Path) -> None:
209209
server1.new_session(session_name="shared_session")
210210

211211
# Control mode attaches to existing session (no internal session created)
212-
control_engine = ControlModeEngine(attach_to="shared_session")
212+
control_engine = ControlModeEngine(control_session="shared_session")
213213
server2 = Server(socket_path=socket_path, engine=control_engine)
214214

215215
# Should see the shared session

tests/test_control_mode_regressions.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ class TrailingOutputFixture(t.NamedTuple):
3232

3333

3434
class AttachFixture(t.NamedTuple):
35-
"""Fixture for attach_to behaviours."""
35+
"""Fixture for control_session behaviours."""
3636

3737
test_id: str
38-
attach_to: str
38+
control_session: str
3939
expect_attached: bool
4040
expect_notification: bool = False
4141

@@ -779,31 +779,31 @@ def test_internal_session_name_collision(case: InternalNameCollisionFixture) ->
779779
[
780780
AttachFixture(
781781
test_id="attach_existing",
782-
attach_to="shared_session",
782+
control_session="shared_session",
783783
expect_attached=True,
784784
expect_notification=True,
785785
),
786786
AttachFixture(
787787
test_id="attach_missing",
788-
attach_to="missing_session",
788+
control_session="missing_session",
789789
expect_attached=False,
790790
),
791791
],
792792
ids=lambda c: c.test_id,
793793
)
794-
def test_attach_to_existing_session(case: AttachFixture) -> None:
795-
"""Control mode attach_to should not create/hide a management session."""
794+
def test_control_session_existing(case: AttachFixture) -> None:
795+
"""Control mode control_session should not create/hide a management session."""
796796
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
797797
bootstrap = Server(socket_name=socket_name)
798798
try:
799799
if case.expect_attached:
800800
# Create the target session via subprocess engine
801801
bootstrap.new_session(
802-
session_name=case.attach_to,
802+
session_name=case.control_session,
803803
attach=False,
804804
kill_session=True,
805805
)
806-
engine = ControlModeEngine(attach_to=case.attach_to)
806+
engine = ControlModeEngine(control_session=case.control_session)
807807
server = Server(socket_name=socket_name, engine=engine)
808808
if not case.expect_attached:
809809
with pytest.raises(exc.ControlModeConnectionError):
@@ -812,7 +812,7 @@ def test_attach_to_existing_session(case: AttachFixture) -> None:
812812

813813
sessions = server.sessions
814814
assert len(sessions) == 1
815-
assert sessions[0].session_name == case.attach_to
815+
assert sessions[0].session_name == case.control_session
816816

817817
# Only the control client is attached; attached_sessions should be empty
818818
# because we filter control clients from "attached" semantics.
@@ -823,7 +823,7 @@ def test_attach_to_existing_session(case: AttachFixture) -> None:
823823
# Drain notifications to confirm control stream is flowing.
824824
notif = next(server.engine.iter_notifications(timeout=0.5), None)
825825
if notif is None:
826-
pytest.xfail("attach_to did not emit notification within timeout")
826+
pytest.xfail("control_session did not emit notification within timeout")
827827
finally:
828828
with contextlib.suppress(Exception):
829829
bootstrap.kill()
@@ -863,25 +863,25 @@ def test_list_clients_control_flag_filters_attached() -> None:
863863

864864

865865
@pytest.mark.engines(["control"])
866-
def test_attach_to_can_drain_notifications() -> None:
867-
"""drain_notifications() provides explicit sync point for attach_to notifications.
866+
def test_control_session_can_drain_notifications() -> None:
867+
"""drain_notifications() provides explicit sync for control_session notifications.
868868
869-
When using attach_to mode, the control client may receive many notifications
870-
from pane output. The drain_notifications() helper waits until the notification
871-
queue is idle, providing a deterministic sync point.
869+
When using control_session mode, the control client may receive many
870+
notifications from pane output. The drain_notifications() helper waits until
871+
the notification queue is idle, providing a deterministic sync point.
872872
"""
873873
socket_name = f"libtmux_test_{uuid.uuid4().hex[:8]}"
874874
bootstrap = Server(socket_name=socket_name)
875875
try:
876-
# Create a session for attach_to to connect to
876+
# Create a session for control_session to connect to
877877
bootstrap.new_session(
878878
session_name="drain_test",
879879
attach=False,
880880
kill_session=True,
881881
)
882882

883883
# Control mode will attach to existing session
884-
engine = ControlModeEngine(attach_to="drain_test")
884+
engine = ControlModeEngine(control_session="drain_test")
885885
server = Server(socket_name=socket_name, engine=engine)
886886

887887
# Start the engine by accessing sessions

0 commit comments

Comments
 (0)