Skip to content

Commit 6e97f10

Browse files
authored
Server: Behavior when no server exists (#448)
2 parents 268752a + c0d8ae6 commit 6e97f10

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

CHANGES

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ $ pip install --user --upgrade --pre libtmux
1414

1515
<!-- Maintainers and contributors: Insert change notes for the next release above -->
1616

17+
### New features
18+
19+
#### Detect if server active (#448)
20+
21+
- `Server.is_alive()`
22+
- `Server.raise_if_dead()`
23+
1724
### Internal
1825

1926
- Remove unused `sphinx-click` development dependency

src/libtmux/server.py

+57-13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
"""
77
import logging
88
import os
9+
import shutil
10+
import subprocess
911
import typing as t
1012

1113
from libtmux.common import tmux_cmd
@@ -115,6 +117,42 @@ def __init__(
115117
if colors:
116118
self.colors = colors
117119

120+
def is_alive(self) -> bool:
121+
"""If server alive or not.
122+
123+
>>> tmux = Server(socket_name="no_exist")
124+
>>> assert not tmux.is_alive()
125+
"""
126+
try:
127+
res = self.cmd("list-sessions")
128+
return res.returncode == 0
129+
except Exception:
130+
return False
131+
132+
def raise_if_dead(self) -> None:
133+
"""Raise if server not connected.
134+
135+
>>> tmux = Server(socket_name="no_exist")
136+
>>> try:
137+
... tmux.raise_if_dead()
138+
... except Exception as e:
139+
... print(type(e))
140+
<class 'subprocess.CalledProcessError'>
141+
"""
142+
tmux_bin = shutil.which("tmux")
143+
if tmux_bin is None:
144+
raise exc.TmuxCommandNotFound()
145+
146+
cmd_args: t.List[str] = ["list-sessions"]
147+
if self.socket_name:
148+
cmd_args.insert(0, f"-L{self.socket_name}")
149+
if self.socket_path:
150+
cmd_args.insert(0, f"-S{self.socket_path}")
151+
if self.config_file:
152+
cmd_args.insert(0, f"-f{self.config_file}")
153+
154+
subprocess.check_call([tmux_bin] + cmd_args)
155+
118156
def cmd(self, *args: t.Any, **kwargs: t.Any) -> tmux_cmd:
119157
"""
120158
Execute tmux command and return output.
@@ -207,7 +245,10 @@ def list_sessions(self) -> t.List[Session]:
207245
@property
208246
def sessions(self) -> t.List[Session]:
209247
"""Property / alias to return :meth:`~.list_sessions`."""
210-
return self.list_sessions()
248+
try:
249+
return self.list_sessions()
250+
except Exception:
251+
return []
211252

212253
#: Alias :attr:`sessions` for :class:`~libtmux.common.TmuxRelationalObject`
213254
children = sessions # type: ignore
@@ -348,7 +389,7 @@ def _update_panes(self) -> "Server":
348389
return self
349390

350391
@property
351-
def attached_sessions(self) -> t.Optional[t.List[Session]]:
392+
def attached_sessions(self) -> t.List[Session]:
352393
"""
353394
Return active :class:`Session` objects.
354395
@@ -357,19 +398,22 @@ def attached_sessions(self) -> t.Optional[t.List[Session]]:
357398
list of :class:`Session`
358399
"""
359400

360-
sessions = self._sessions
361-
attached_sessions = list()
401+
try:
402+
sessions = self._sessions
403+
attached_sessions = list()
362404

363-
for session in sessions:
364-
attached = session.get("session_attached")
365-
# for now session_active is a unicode
366-
if attached != "0":
367-
logger.debug(f"session {session.get('name')} attached")
368-
attached_sessions.append(session)
369-
else:
370-
continue
405+
for session in sessions:
406+
attached = session.get("session_attached")
407+
# for now session_active is a unicode
408+
if attached != "0":
409+
logger.debug(f"session {session.get('name')} attached")
410+
attached_sessions.append(session)
411+
else:
412+
continue
371413

372-
return [Session(server=self, **s) for s in attached_sessions] or None
414+
return [Session(server=self, **s) for s in attached_sessions] or []
415+
except Exception:
416+
return []
373417

374418
def has_session(self, target_session: str, exact: bool = True) -> bool:
375419
"""

tests/test_server.py

+33
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""Test for libtmux Server object."""
22
import logging
33

4+
import pytest
5+
46
from libtmux.common import has_gte_version
57
from libtmux.server import Server
68
from libtmux.session import Session
@@ -123,3 +125,34 @@ def test_new_session_shell(server: Server) -> None:
123125
assert pane_start_command.replace('"', "") == cmd
124126
else:
125127
assert pane_start_command == cmd
128+
129+
130+
def test_no_server_sessions() -> None:
131+
server = Server(socket_name="test_attached_session_no_server")
132+
assert server.sessions == []
133+
134+
135+
def test_no_server_attached_sessions() -> None:
136+
server = Server(socket_name="test_no_server_attached_sessions")
137+
assert server.attached_sessions == []
138+
139+
140+
def test_no_server_is_alive() -> None:
141+
dead_server = Server(socket_name="test_no_server_is_alive")
142+
assert not dead_server.is_alive()
143+
144+
145+
def test_with_server_is_alive(server: Server) -> None:
146+
server.new_session()
147+
assert server.is_alive()
148+
149+
150+
def test_no_server_raise_if_dead() -> None:
151+
dead_server = Server(socket_name="test_attached_session_no_server")
152+
with pytest.raises(Exception):
153+
dead_server.raise_if_dead()
154+
155+
156+
def test_with_server_raise_if_dead(server: Server) -> None:
157+
server.new_session()
158+
server.raise_if_dead()

0 commit comments

Comments
 (0)