diff --git a/libtmux/common.py b/libtmux/common.py index 05b85229f..181c77368 100644 --- a/libtmux/common.py +++ b/libtmux/common.py @@ -147,8 +147,7 @@ def show_environment(self, name=None): return vars_dict -class tmux_cmd: - +class TmuxCommand: """ :term:`tmux(1)` command via :py:mod:`subprocess`. @@ -165,7 +164,12 @@ class tmux_cmd: .. code-block:: python - proc = tmux_cmd('new-session', '-s%' % 'my session') + c = tmux_cmd('new-session', '-s%' % 'my session') + + # You can actually see the command in the .cmd attribute + print(c.cmd) + + proc = c.execute() if proc.stderr: raise exc.LibTmuxException( @@ -183,8 +187,8 @@ class tmux_cmd: Notes ----- - .. versionchanged:: 0.8 - Renamed from ``tmux`` to ``tmux_cmd``. + .. versionadded:: 0.8.4 + Wrap to split execution from command from instance of it """ def __init__(self, *args, **kwargs): @@ -205,6 +209,8 @@ def __init__(self, *args, **kwargs): self.cmd = cmd + def execute(self): + cmd = self.cmd try: self.process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE @@ -229,6 +235,39 @@ def __init__(self, *args, **kwargs): self.stdout = self.stderr[0] logger.debug("self.stdout for {}: \n{}".format(" ".join(cmd), self.stdout)) + return self + + +def tmux_cmd(*args, **kwargs): + """Wrapper around TmuxCommand. Executes instantly. + + Examples + -------- + + .. code-block:: python + + proc = tmux_cmd('new-session', '-s%' % 'my session') + + if proc.stderr: + raise exc.LibTmuxException( + 'Command: %s returned error: %s' % (proc.cmd, proc.stderr) + ) + + print('tmux command returned %s' % proc.stdout) + + Equivalent to: + + .. code-block:: bash + + $ tmux new-session -s my session + + Notes + ----- + + .. versionchanged:: 0.8 + Renamed from ``tmux`` to ``tmux_cmd``. + """ + return TmuxCommand(*args, **kwargs).execute() class TmuxMappingObject(MutableMapping): diff --git a/libtmux/server.py b/libtmux/server.py index 11f1c1c90..40615eb10 100644 --- a/libtmux/server.py +++ b/libtmux/server.py @@ -13,11 +13,11 @@ EnvironmentMixin, PaneDict, SessionDict, + TmuxCommand, TmuxRelationalObject, WindowDict, has_gte_version, session_check_name, - tmux_cmd, ) from .session import Session @@ -127,7 +127,7 @@ def cmd(self, *args, **kwargs): else: raise ValueError("Server.colors must equal 88 or 256") - return tmux_cmd(*args, **kwargs) + return TmuxCommand(*args, **kwargs).execute() def _list_sessions(self) -> t.List[SessionDict]: """ @@ -136,7 +136,7 @@ def _list_sessions(self) -> t.List[SessionDict]: Retrieved from ``$ tmux(1) list-sessions`` stdout. The :py:obj:`list` is derived from ``stdout`` in - :class:`common.tmux_cmd` which wraps :py:class:`subprocess.Popen`. + :class:`common.TmuxCommand` which wraps :py:class:`subprocess.Popen`. Returns ------- @@ -199,7 +199,7 @@ def _list_windows(self) -> t.List[WindowDict]: Retrieved from ``$ tmux(1) list-windows`` stdout. The :py:obj:`list` is derived from ``stdout`` in - :class:`common.tmux_cmd` which wraps :py:class:`subprocess.Popen`. + :class:`common.TmuxCommand` which wraps :py:class:`subprocess.Popen`. Returns ------- @@ -261,7 +261,7 @@ def _list_panes(self) -> t.List[PaneDict]: Retrieved from ``$ tmux(1) list-panes`` stdout. The :py:obj:`list` is derived from ``stdout`` in - :class:`util.tmux_cmd` which wraps :py:class:`subprocess.Popen`. + :class:`util.TmuxCommand` which wraps :py:class:`subprocess.Popen`. Returns ------- diff --git a/tests/test_common.py b/tests/test_common.py index a86da3bb0..b44b6bd00 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -27,15 +27,28 @@ version_regex = re.compile(r"([0-9]\.[0-9])|(master)") -def test_allows_master_version(monkeypatch): - def mock_tmux_cmd(param): +@pytest.mark.parametrize("executor", ["mock_tmux_cmd", "mock_TmuxCommand"]) +def test_allows_master_version(monkeypatch, executor): + def mock_TmuxCommand(param): class Hi: stdout = ["tmux master"] stderr = None + def execute(self): + return self + return Hi() - monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) + def mock_tmux_cmd(param): + class Hi(object): + stdout = ["tmux master"] + stderr = None + + return Hi() + + mock_cmd = locals()[executor] + + monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_cmd) assert has_minimum_version() assert has_gte_version(TMUX_MIN_VERSION) @@ -51,6 +64,9 @@ class Hi: stdout = ["tmux next-2.9"] stderr = None + def execute(self): + return self + return Hi() monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) @@ -66,6 +82,9 @@ def mock_tmux_cmd(param): class Hi: stderr = ["tmux: unknown option -- V"] + def execute(self): + return self + return Hi() monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) @@ -83,6 +102,9 @@ def mock_tmux_cmd(param): class Hi: stderr = ["tmux: unknown option -- V"] + def execute(self): + return self + return Hi() monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) @@ -183,6 +205,12 @@ def test_tmux_cmd_unicode(session): session.cmd("new-window", "-t", 3, "-n", "юникод", "-F", "Ελληνικά") +def test_tmux_cmd_makes_cmd_available(): + """tmux_cmd objects should make .cmd attribute available.""" + command = tmux_cmd("-V") + assert hasattr(command, "cmd") + + @pytest.mark.parametrize( "session_name,raises,exc_msg_regex", [