From 9878f60de4c1d54ac2f3b0dc2511c0bfdc8e061c Mon Sep 17 00:00:00 2001 From: Bjoern Hiller Date: Tue, 1 Nov 2022 17:32:05 +0100 Subject: [PATCH 1/4] feat(Session.new_window): set up environment This allows to set up a custom environment when creating a new window. --- src/libtmux/session.py | 11 ++++++++ tests/test_session.py | 57 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/libtmux/session.py b/src/libtmux/session.py index f74c6e2a3..19b1bfd91 100644 --- a/src/libtmux/session.py +++ b/src/libtmux/session.py @@ -19,6 +19,7 @@ TmuxRelationalObject, WindowDict, handle_option_error, + has_gte_version, has_version, session_check_name, ) @@ -202,6 +203,7 @@ def new_window( attach: bool = True, window_index: str = "", window_shell: t.Optional[str] = None, + environment: t.Optional[t.Dict[str, str]] = None, ) -> Window: """ Return :class:`Window` from ``$ tmux new-window``. @@ -259,6 +261,15 @@ def new_window( % (self.id, window_index), ) + if environment: + if has_gte_version("3.0"): + for k, v in environment.items(): + window_args += (f"-e{k}={v}",) + else: + logger.warning( + "Cannot set up environment as tmux 3.0 or newer is required." + ) + if window_shell: window_args += (window_shell,) diff --git a/tests/test_session.py b/tests/test_session.py index c23d17c61..b3db613cb 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -1,11 +1,12 @@ """Test for libtmux Session object.""" import logging +import shutil import typing as t import pytest from libtmux import exc -from libtmux.common import has_gte_version +from libtmux.common import has_gte_version, has_lt_version from libtmux.pane import Pane from libtmux.server import Server from libtmux.session import Session @@ -257,3 +258,57 @@ def test_cmd_inserts_sesion_id(session: Session) -> None: assert "-t" in cmd.cmd assert current_session_id in cmd.cmd assert cmd.cmd[-1] == last_arg + + +@pytest.mark.skipif( + has_lt_version("3.0"), + reason="needs -e flag for new-window which was introduced in 3.0", +) +@pytest.mark.parametrize( + "environment", + [ + {"ENV_VAR": "window"}, + {"ENV_VAR_1": "window_1", "ENV_VAR_2": "window_2"}, + ], +) +def test_new_window_with_environment( + session: Session, + environment: t.Dict[str, str], +) -> None: + env = shutil.which("env") + assert env is not None, "Cannot find usable `env` in PATH." + + window = session.new_window( + attach=True, + window_name="window_with_environment", + window_shell=f"{env} PS1='$ ' sh", + environment=environment, + ) + pane = window.attached_pane + assert pane is not None + for k, v in environment.items(): + pane.send_keys(f"echo ${k}") + assert pane.capture_pane()[-2] == v + + +@pytest.mark.skipif( + has_gte_version("3.0"), + reason="3.0 has the -e flag on new-window", +) +def test_new_window_with_environment_logs_warning_for_old_tmux( + session: Session, + caplog: pytest.LogCaptureFixture, +) -> None: + env = shutil.which("env") + assert env is not None, "Cannot find usable `env` in PATH." + + session.new_window( + attach=True, + window_name="window_with_environment", + window_shell=f"{env} PS1='$ ' sh", + environment={"ENV_VAR": "window"}, + ) + + assert any( + "Cannot set up environment" in record.msg for record in caplog.records + ), "Warning missing" From 4244049b4afbb5d7a5383f2ec010a967c9aab104 Mon Sep 17 00:00:00 2001 From: Bjoern Hiller Date: Tue, 1 Nov 2022 17:37:21 +0100 Subject: [PATCH 2/4] feat(Window.split_window): set up environment This allows to set up a custom environment when creating a new pane. --- src/libtmux/window.py | 12 +++++++++- tests/test_window.py | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/libtmux/window.py b/src/libtmux/window.py index 434dca17c..a6f03733d 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -9,7 +9,7 @@ import shlex import typing as t -from libtmux.common import tmux_cmd +from libtmux.common import has_gte_version, tmux_cmd from libtmux.pane import Pane from . import exc, formats @@ -442,6 +442,7 @@ def split_window( vertical: bool = True, shell: t.Optional[str] = None, percent: t.Optional[int] = None, + environment: t.Optional[t.Dict[str, str]] = None, ) -> Pane: """ Split window and return the created :class:`Pane`. @@ -520,6 +521,15 @@ def split_window( if not attach: tmux_args += ("-d",) + if environment: + if has_gte_version("3.0"): + for k, v in environment.items(): + tmux_args += (f"-e{k}={v}",) + else: + logger.warning( + "Cannot set up environment as tmux 3.0 or newer is required." + ) + if shell: tmux_args += (shell,) diff --git a/tests/test_window.py b/tests/test_window.py index 4c10c9c2a..02fb40552 100644 --- a/tests/test_window.py +++ b/tests/test_window.py @@ -1,5 +1,7 @@ """Test for libtmux Window object.""" import logging +import shutil +import time import typing as t import pytest @@ -310,3 +312,56 @@ def test_empty_window_name(session: Session) -> None: "#{==:#{session_name}," + session.name + "}", ) assert "''" in cmd.stdout + + +@pytest.mark.skipif( + has_lt_version("3.0"), + reason="needs -e flag for split-window which was introduced in 3.0", +) +@pytest.mark.parametrize( + "environment", + [ + {"ENV_VAR": "pane"}, + {"ENV_VAR_1": "pane_1", "ENV_VAR_2": "pane_2"}, + ], +) +def test_split_window_with_environment( + session: Session, + environment: t.Dict[str, str], +) -> None: + env = shutil.which("env") + assert env is not None, "Cannot find usable `env` in Path." + + window = session.new_window(window_name="split_window_with_environment") + pane = window.split_window( + shell=f"{env} PS1='$ ' sh", + environment=environment, + ) + assert pane is not None + # wait a bit for the prompt to be ready as the test gets flaky otherwise + time.sleep(0.05) + for k, v in environment.items(): + pane.send_keys(f"echo ${k}") + assert pane.capture_pane()[-2] == v + + +@pytest.mark.skipif( + has_gte_version("3.0"), + reason="3.0 has the -e flag on split-window", +) +def test_split_window_with_environment_logs_warning_for_old_tmux( + session: Session, + caplog: pytest.LogCaptureFixture, +) -> None: + env = shutil.which("env") + assert env is not None, "Cannot find usable `env` in Path." + + window = session.new_window(window_name="split_window_with_environment") + window.split_window( + shell=f"{env} PS1='$ ' sh", + environment={"ENV_VAR": "pane"}, + ) + + assert any( + "Cannot set up environment" in record.msg for record in caplog.records + ), "Warning missing" From 496b583f8032243fdd552df8bc47d33c8995f3c2 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 6 Nov 2022 14:17:30 -0600 Subject: [PATCH 3/4] docs(window,session): Document environment variable --- src/libtmux/session.py | 3 +++ src/libtmux/window.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/libtmux/session.py b/src/libtmux/session.py index 19b1bfd91..37cd8c122 100644 --- a/src/libtmux/session.py +++ b/src/libtmux/session.py @@ -229,6 +229,9 @@ def new_window( When this command exits the window will close. This feature is useful for long-running processes where the closing of the window upon completion is desired. + environment: dict, optional + Environmental variables for new window. tmux 3.0+ only. Passthrough to + ``-e``. Returns ------- diff --git a/src/libtmux/window.py b/src/libtmux/window.py index a6f03733d..0075b0187 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -469,6 +469,8 @@ def split_window( window upon completion is desired. percent: int, optional percentage to occupy with respect to current window + environment: dict, optional + Environmental variables for new pane. tmux 3.0+ only. Passthrough to ``-e``. Returns ------- From fca7c0d533f007995793da4b6c8961f6aaca6f8f Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 6 Nov 2022 14:17:46 -0600 Subject: [PATCH 4/4] docs(CHANGES): Note environment variable update --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 86d5af26f..df5f059fb 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,11 @@ $ pip install --user --upgrade --pre libtmux +### Features + +- `Window.split_window()` and `Session.new_window()` now support an optional + dictionary of environmental variables, via (#453), credit @zappolowski. + ## libtmux 0.15.10 (2022-11-05) _There will be more improvements over the coming weeks and months to shore up