Skip to content

Commit 886e63d

Browse files
committed
fix(util,cli[stop]): Require pane resolution for destructive get_session
Add require_pane_resolution parameter to get_session(). When True, raises SessionNotFound instead of falling back to server.sessions[0] when TMUX_PANE is unset/stale. tmuxp stop now uses strict mode to prevent killing an unrelated session. Non-destructive commands (shell, freeze) retain the fallback behavior.
1 parent 984bc15 commit 886e63d

4 files changed

Lines changed: 55 additions & 12 deletions

File tree

conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def socket_name(request: pytest.FixtureRequest) -> str:
102102
DOCTEST_NEEDS_TMUX = {
103103
"tmuxp.cli.load",
104104
"tmuxp.cli.stop",
105+
"tmuxp.util",
105106
"tmuxp.workspace.builder",
106107
}
107108

src/tmuxp/cli/stop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def command_stop(
112112
default=None,
113113
)
114114
elif os.environ.get("TMUX"):
115-
session = util.get_session(server)
115+
session = util.get_session(server, require_pane_resolution=True)
116116
else:
117117
tmuxp_echo(
118118
colors.error("No session name given and not inside tmux."),

src/tmuxp/util.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,28 +212,57 @@ def get_session(
212212
server: Server,
213213
session_name: str | None = None,
214214
current_pane: Pane | None = None,
215+
require_pane_resolution: bool = False,
215216
) -> Session:
216-
"""Get tmux session for server by session name, respects current pane, if passed."""
217-
session: Session | None = None
217+
"""Get tmux session for server by session name, respects current pane, if passed.
218+
219+
Parameters
220+
----------
221+
server : Server
222+
tmux server to search.
223+
session_name : str, optional
224+
Explicit session name to look up.
225+
current_pane : Pane, optional
226+
Pane to infer session from.
227+
require_pane_resolution : bool
228+
If True, raise SessionNotFound when TMUX_PANE cannot be resolved
229+
instead of falling back to server.sessions[0]. Use for destructive
230+
operations like ``tmuxp stop``.
231+
232+
Examples
233+
--------
234+
>>> from tmuxp.util import get_session
235+
>>> get_session(server, session_name=session.name) == session
236+
True
237+
"""
238+
session_result: Session | None = None
218239
try:
219240
if session_name:
220-
session = server.sessions.get(session_name=session_name)
241+
session_result = server.sessions.get(session_name=session_name)
221242
elif current_pane is not None:
222-
session = server.sessions.get(session_id=current_pane.session_id)
243+
session_result = server.sessions.get(
244+
session_id=current_pane.session_id,
245+
)
223246
else:
224247
current_pane = get_current_pane(server)
225248
if current_pane:
226-
session = server.sessions.get(session_id=current_pane.session_id)
249+
session_result = server.sessions.get(
250+
session_id=current_pane.session_id,
251+
)
252+
elif require_pane_resolution:
253+
pass # session_result stays None → raises below
254+
elif server.sessions:
255+
session_result = server.sessions[0]
227256
except Exception as e:
228257
if session_name:
229258
raise exc.SessionNotFound(session_name) from e
230259
raise exc.SessionNotFound from e
231260

232-
if session is None:
261+
if session_result is None:
233262
if session_name:
234263
raise exc.SessionNotFound(session_name)
235264
raise exc.SessionNotFound
236-
return session
265+
return session_result
237266

238267

239268
def get_window(

tests/test_util.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,20 +162,33 @@ def test_get_session_should_default_to_local_attached_session(
162162
assert get_session(server) == second_session
163163

164164

165-
def test_get_session_raises_when_no_active_pane(
165+
def test_get_session_falls_back_to_first_when_no_pane(
166166
server: Server,
167167
monkeypatch: pytest.MonkeyPatch,
168168
) -> None:
169-
"""get_session() should raise SessionNotFound when TMUX_PANE is unset."""
170-
# Clear outer tmux environment to ensure no active pane interferes
169+
"""get_session() falls back to first session when TMUX_PANE is unset."""
170+
monkeypatch.delenv("TMUX_PANE", raising=False)
171+
monkeypatch.delenv("TMUX", raising=False)
172+
173+
first_session = server.new_session(session_name="myfirstsession")
174+
server.new_session(session_name="mysecondsession")
175+
176+
assert get_session(server) == first_session
177+
178+
179+
def test_get_session_strict_raises_when_no_active_pane(
180+
server: Server,
181+
monkeypatch: pytest.MonkeyPatch,
182+
) -> None:
183+
"""get_session(require_pane_resolution=True) raises when TMUX_PANE unset."""
171184
monkeypatch.delenv("TMUX_PANE", raising=False)
172185
monkeypatch.delenv("TMUX", raising=False)
173186

174187
server.new_session(session_name="myfirstsession")
175188
server.new_session(session_name="mysecondsession")
176189

177190
with pytest.raises(exc.SessionNotFound):
178-
get_session(server)
191+
get_session(server, require_pane_resolution=True)
179192

180193

181194
def test_get_pane_logs_debug_on_failure(

0 commit comments

Comments
 (0)