From 1a5e69a2f7ac2abd3276c60b73eb760eb2d4cf22 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:10:20 -0600 Subject: [PATCH 1/6] tmux_cmd: Remove `console_to_str()`, use text=True See also: - https://docs.python.org/3/library/subprocess.html#subprocess.run - https://github.com/python/cpython/blob/3.12/Lib/subprocess.py#L508-L575 --- src/libtmux/common.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libtmux/common.py b/src/libtmux/common.py index 83bfb5cd2..d7fc9e768 100644 --- a/src/libtmux/common.py +++ b/src/libtmux/common.py @@ -15,7 +15,7 @@ import typing as t from . import exc -from ._compat import LooseVersion, console_to_str, str_from_console +from ._compat import LooseVersion, str_from_console if t.TYPE_CHECKING: from collections.abc import Callable @@ -235,6 +235,7 @@ def __init__(self, *args: t.Any) -> None: cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + text=True, ) stdout, stderr = self.process.communicate() returncode = self.process.returncode @@ -244,14 +245,12 @@ def __init__(self, *args: t.Any) -> None: self.returncode = returncode - stdout_str = console_to_str(stdout) - stdout_split = stdout_str.split("\n") + stdout_split = stdout.split("\n") # remove trailing newlines from stdout while stdout_split and stdout_split[-1] == "": stdout_split.pop() - stderr_str = console_to_str(stderr) - stderr_split = stderr_str.split("\n") + stderr_split = stderr.split("\n") self.stderr = list(filter(None, stderr_split)) # filter empty values if "has-session" in cmd and len(self.stderr) and not stdout_split: From 755cf416fde265fece36038c567235e155428a8e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:23:24 -0600 Subject: [PATCH 2/6] compat: Remove `console_to_str()` function --- src/libtmux/_compat.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/libtmux/_compat.py b/src/libtmux/_compat.py index fd6fab772..80060737e 100644 --- a/src/libtmux/_compat.py +++ b/src/libtmux/_compat.py @@ -7,14 +7,6 @@ console_encoding = sys.stdout.encoding -def console_to_str(s: bytes) -> str: - """From pypa/pip project, pip.backwardwardcompat. License MIT.""" - try: - return s.decode(console_encoding, "ignore") - except UnicodeDecodeError: - return s.decode("utf_8", "ignore") - - # TODO Consider removing, reraise does not seem to be called anywhere def reraise( tp: t.Type[BaseException], From 2f7286187b5a4bdea2d4ff3d697c74747a4a7408 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:30:26 -0600 Subject: [PATCH 3/6] tmux_cmd: Remove `console_from_str()` With `text=True` being used we can now wrap in `str()` for bytes to be handled as `str`. --- src/libtmux/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtmux/common.py b/src/libtmux/common.py index d7fc9e768..ddb23931f 100644 --- a/src/libtmux/common.py +++ b/src/libtmux/common.py @@ -15,7 +15,7 @@ import typing as t from . import exc -from ._compat import LooseVersion, str_from_console +from ._compat import LooseVersion if t.TYPE_CHECKING: from collections.abc import Callable @@ -226,7 +226,7 @@ def __init__(self, *args: t.Any) -> None: cmd = [tmux_bin] cmd += args # add the command arguments to cmd - cmd = [str_from_console(c) for c in cmd] + cmd = [str(c) for c in cmd] self.cmd = cmd From 4ae24ee4f171f4f3376c46d5b304243876237255 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:31:06 -0600 Subject: [PATCH 4/6] compat: Remove `str_from_console()` --- src/libtmux/_compat.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libtmux/_compat.py b/src/libtmux/_compat.py index 80060737e..acf5ddbe6 100644 --- a/src/libtmux/_compat.py +++ b/src/libtmux/_compat.py @@ -18,13 +18,6 @@ def reraise( raise value -def str_from_console(s: t.Union[str, bytes]) -> str: - try: - return str(s) - except UnicodeDecodeError: - return str(s, encoding="utf_8") if isinstance(s, bytes) else s - - import re from typing import Iterator, List, Tuple From 83629ad10812fbd4f01e0eed5a3f78ffa1429f1e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:46:33 -0600 Subject: [PATCH 5/6] tmux_cmd: Pass `backslashreplace` for `errors` in `subprocess` More resilience for `tmux` command across systems. Ability to debug because escape sequences preserves the byte value for debugging. --- src/libtmux/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtmux/common.py b/src/libtmux/common.py index ddb23931f..db0b4151f 100644 --- a/src/libtmux/common.py +++ b/src/libtmux/common.py @@ -236,6 +236,7 @@ def __init__(self, *args: t.Any) -> None: stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, + errors="backslashreplace", ) stdout, stderr = self.process.communicate() returncode = self.process.returncode From 2a4901df5352c84a17ea2865c6145112050f48d2 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 2 Feb 2025 05:38:42 -0600 Subject: [PATCH 6/6] docs(CHANGES) Note `tmux_cmd` modernization --- CHANGES | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index 31565cee6..312bf3d5f 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,18 @@ $ pip install --user --upgrade --pre libtmux +### Bug fixes + +- `tmux_cmd`: Migrate to to `text=True` + + This deprecates usage of `console_to_str()` and `str_from_console()`. + + Resolves #558 via #560. + +- compat: Remove `console_to_str()` and `str_from_console()` + + These are both deprecated artifacts of libtmux' Python 2.x compatiblity layer. + ## libtmux 0.41.0 (2025-02-02) ### Fixes