Skip to content

Commit dac2873

Browse files
committed
Server(feat): add lock_server, lock_client, refresh_client, suspend_client, server_access
why: Complete coverage of remaining server-level commands that work with a control-mode client. what: - Add Server.lock_server() wrapping lock-server - Add Server.lock_client() wrapping lock-client with target_client (-t) - Add Server.refresh_client() wrapping refresh-client with target_client (-t) - Add Server.suspend_client() wrapping suspend-client with target_client (-t) - Add Server.server_access() wrapping server-access with allow (-a), deny (-d), list_access (-l) parameters - All client-dependent tests use ControlMode context manager
1 parent ac1f464 commit dac2873

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

src/libtmux/server.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,145 @@ def list_commands(self, *, command_name: str | None = None) -> list[str]:
673673

674674
return proc.stdout
675675

676+
def lock_server(self) -> None:
677+
"""Lock the tmux server via ``$ tmux lock-server``.
678+
679+
Requires an attached client.
680+
681+
Examples
682+
--------
683+
>>> with control_mode() as ctl:
684+
... server.lock_server()
685+
"""
686+
proc = self.cmd("lock-server")
687+
688+
if proc.stderr:
689+
raise exc.LibTmuxException(proc.stderr)
690+
691+
def server_access(
692+
self,
693+
*,
694+
allow: str | None = None,
695+
deny: str | None = None,
696+
list_access: bool | None = None,
697+
) -> list[str] | None:
698+
"""Manage server access control via ``$ tmux server-access``.
699+
700+
Parameters
701+
----------
702+
allow : str, optional
703+
Allow a user (``-a`` flag).
704+
deny : str, optional
705+
Deny a user (``-d`` flag).
706+
list_access : bool, optional
707+
List access rules (``-l`` flag).
708+
709+
Returns
710+
-------
711+
list[str] | None
712+
Access list when *list_access* is True, None otherwise.
713+
714+
Examples
715+
--------
716+
>>> result = server.server_access(list_access=True)
717+
>>> isinstance(result, list)
718+
True
719+
"""
720+
tmux_args: tuple[str, ...] = ()
721+
722+
if allow is not None:
723+
tmux_args += ("-a", allow)
724+
725+
if deny is not None:
726+
tmux_args += ("-d", deny)
727+
728+
if list_access:
729+
tmux_args += ("-l",)
730+
731+
proc = self.cmd("server-access", *tmux_args)
732+
733+
if proc.stderr:
734+
raise exc.LibTmuxException(proc.stderr)
735+
736+
if list_access:
737+
return proc.stdout
738+
return None
739+
740+
def refresh_client(self, *, target_client: str | None = None) -> None:
741+
"""Refresh a client's display via ``$ tmux refresh-client``.
742+
743+
Requires an attached client.
744+
745+
Parameters
746+
----------
747+
target_client : str, optional
748+
Target client (``-t`` flag).
749+
750+
Examples
751+
--------
752+
>>> with control_mode() as ctl:
753+
... server.refresh_client()
754+
"""
755+
tmux_args: tuple[str, ...] = ()
756+
757+
if target_client is not None:
758+
tmux_args += ("-t", target_client)
759+
760+
proc = self.cmd("refresh-client", *tmux_args)
761+
762+
if proc.stderr:
763+
raise exc.LibTmuxException(proc.stderr)
764+
765+
def suspend_client(self, *, target_client: str | None = None) -> None:
766+
"""Suspend a client via ``$ tmux suspend-client``.
767+
768+
Requires an attached client.
769+
770+
Parameters
771+
----------
772+
target_client : str, optional
773+
Target client (``-t`` flag).
774+
775+
Examples
776+
--------
777+
>>> with control_mode() as ctl:
778+
... server.suspend_client()
779+
"""
780+
tmux_args: tuple[str, ...] = ()
781+
782+
if target_client is not None:
783+
tmux_args += ("-t", target_client)
784+
785+
proc = self.cmd("suspend-client", *tmux_args)
786+
787+
if proc.stderr:
788+
raise exc.LibTmuxException(proc.stderr)
789+
790+
def lock_client(self, *, target_client: str | None = None) -> None:
791+
"""Lock a client via ``$ tmux lock-client``.
792+
793+
Requires an attached client.
794+
795+
Parameters
796+
----------
797+
target_client : str, optional
798+
Target client (``-t`` flag).
799+
800+
Examples
801+
--------
802+
>>> with control_mode() as ctl:
803+
... server.lock_client()
804+
"""
805+
tmux_args: tuple[str, ...] = ()
806+
807+
if target_client is not None:
808+
tmux_args += ("-t", target_client)
809+
810+
proc = self.cmd("lock-client", *tmux_args)
811+
812+
if proc.stderr:
813+
raise exc.LibTmuxException(proc.stderr)
814+
676815
def start_server(self) -> None:
677816
"""Start the tmux server if not already running.
678817

tests/test_server.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,49 @@ def test_tmux_bin_invalid_path_raise_if_dead() -> None:
461461
s.raise_if_dead()
462462

463463

464+
def test_lock_server(
465+
control_mode: t.Callable[..., t.Any],
466+
server: Server,
467+
) -> None:
468+
"""Test Server.lock_server() runs without error."""
469+
with control_mode():
470+
server.lock_server()
471+
472+
473+
def test_lock_client(
474+
control_mode: t.Callable[..., t.Any],
475+
server: Server,
476+
) -> None:
477+
"""Test Server.lock_client() runs without error."""
478+
with control_mode():
479+
server.lock_client()
480+
481+
482+
def test_refresh_client(
483+
control_mode: t.Callable[..., t.Any],
484+
server: Server,
485+
) -> None:
486+
"""Test Server.refresh_client() runs without error."""
487+
with control_mode():
488+
server.refresh_client()
489+
490+
491+
def test_suspend_client(
492+
control_mode: t.Callable[..., t.Any],
493+
server: Server,
494+
) -> None:
495+
"""Test Server.suspend_client() runs without error."""
496+
with control_mode():
497+
server.suspend_client()
498+
499+
500+
def test_server_access_list(server: Server) -> None:
501+
"""Test Server.server_access() list mode."""
502+
server.new_session(session_name="access_test")
503+
result = server.server_access(list_access=True)
504+
assert isinstance(result, list)
505+
506+
464507
def test_start_server(server: Server) -> None:
465508
"""Test Server.start_server() runs without error."""
466509
server.new_session(session_name="startsvr_test")

0 commit comments

Comments
 (0)