diff --git a/src/libtmux/common.py b/src/libtmux/common.py index d914d536d..48a74eea9 100644 --- a/src/libtmux/common.py +++ b/src/libtmux/common.py @@ -5,6 +5,7 @@ ~~~~~~~~~~~~~~ """ +import dataclasses import logging import os import re @@ -320,6 +321,15 @@ def __len__(self) -> int: return len(self._info.keys()) def __getattr__(self, key: str) -> str: + try: + # val = self._info[self.formatter_prefix + key] + val = object.__getattribute__(self, key) + assert val is not None + assert isinstance(val, str) + return val + except AttributeError: + pass + try: val = self._info[self.formatter_prefix + key] assert val is not None @@ -405,9 +415,12 @@ def where(self, attrs: D, first: bool = False) -> t.Union[List[O], O]: # from https://github.com/serkanyersen/underscore.py def by(val: O) -> bool: + val2: t.Dict[str, str] = {} + if dataclasses.is_dataclass(val): + val2 = dataclasses.asdict(val) for key in attrs.keys(): try: - if attrs[key] != val[key]: + if attrs[key] != val[key] and attrs[key] != val2[key]: return False except KeyError: return False diff --git a/src/libtmux/pane.py b/src/libtmux/pane.py index 469a0d9b3..b4062ffae 100644 --- a/src/libtmux/pane.py +++ b/src/libtmux/pane.py @@ -5,14 +5,18 @@ ~~~~~~~~~~~~ """ +from __future__ import annotations + +import dataclasses import logging import typing as t from typing import overload +import libtmux from libtmux.common import tmux_cmd from . import exc -from .common import PaneDict, TmuxMappingObject, TmuxRelationalObject +from .common import PaneDict, TmuxMappingObject if t.TYPE_CHECKING: from typing_extensions import Literal @@ -24,8 +28,14 @@ logger = logging.getLogger(__name__) +__all__ = ["Pane"] + -class Pane(TmuxMappingObject): +@dataclasses.dataclass +# <<<<<<< HEAD:src/libtmux/pane.py +# class Pane(TmuxMappingObject): +# ======= +class Pane: """ A :term:`tmux(1)` :term:`Pane` [pane_manual]_. @@ -68,35 +78,90 @@ class Pane(TmuxMappingObject): Accessed April 1st, 2018. """ - formatter_prefix = "pane_" + window: libtmux.window.Window + session_name: str = dataclasses.field(init=True) + session_id: str = dataclasses.field(init=True) + window_index: str = dataclasses.field(init=True) + window_id: str = dataclasses.field(init=True) + history_size: str + history_limit: str + history_bytes: str + pane_index: str + pane_width: str + pane_height: str + pane_title: str + _pane_id: str = dataclasses.field(init=False) # Legacy, relational + pane_id: str + pane_active: str + pane_dead: str + pane_in_mode: str + pane_synchronized: str + pane_tty: str + pane_pid: str + pane_current_path: str + pane_current_command: str + cursor_x: str + cursor_y: str + scroll_region_upper: str + scroll_region_lower: str + alternate_on: str + alternate_saved_x: str + alternate_saved_y: str + cursor_flag: str + insert_flag: str + keypad_cursor_flag: str + keypad_flag: str + wrap_flag: str + mouse_standard_flag: str + mouse_button_flag: str + mouse_any_flag: str + mouse_utf8_flag: str + session: libtmux.session.Session = dataclasses.field(init=False) + server: libtmux.server.Server = dataclasses.field(init=False) + window_name: str = dataclasses.field(init=True, default="") + pane_start_command: t.Optional[str] = dataclasses.field(init=True, default=None) + + formatter_prefix: str = "pane_" """Namespace used for :class:`~libtmux.common.TmuxMappingObject`""" - window: "Window" - """:class:`libtmux.Window` pane is linked to""" - session: "Session" - """:class:`libtmux.Session` pane is linked to""" - server: "Server" - """:class:`libtmux.Server` pane is linked to""" - - def __init__( - self, - window: "Window", - pane_id: t.Union[str, int], - **kwargs: t.Any, - ) -> None: - self.window = window + + def __post_init__(self, **kwargs: t.Any) -> None: + # if not window: + # raise ValueError("Pane must have ``Window`` object") + # + # self.window = window self.session = self.window.session self.server = self.session.server - self._pane_id = pane_id + self._pane_id = kwargs.get("pane_id", self.pane_id) + + try: + info = self._info + except IndexError: + info = {} + for k, v in info.items(): + if not hasattr(k, v): + setattr(self, k, v) self.server._update_panes() + def refresh(self) -> None: + try: + info = self._info + except IndexError: + info = {} + for k, v in info.items(): + if not hasattr(k, v): + setattr(self, k, v) + @property def _info(self) -> PaneDict: # type: ignore # mypy#1362 - attrs = {"pane_id": self._pane_id} + # attrs = {"pane_id": self._pane_id} + attrs = {"pane_id": object.__getattribute__(self, "_pane_id")} # from https://github.com/serkanyersen/underscore.py def by(val: PaneDict) -> bool: + if dataclasses.is_dataclass(val): + val = dataclasses.asdict(val) for key in attrs.keys(): try: if attrs[key] != val[key]: @@ -122,7 +187,7 @@ def cmd(self, cmd: str, *args: t.Any, **kwargs: t.Any) -> tmux_cmd: :class:`Server.cmd` """ if not any(arg.startswith("-t") for arg in args): - args = ("-t", self.get("pane_id")) + args + args = ("-t", self.pane_id) + args return self.server.cmd(cmd, *args, **kwargs) @@ -251,7 +316,7 @@ def split_window( :class:`Pane` """ return self.window.split_window( - target=self.get("pane_id"), + target=self.pane_id, start_directory=start_directory, attach=attach, vertical=vertical, @@ -315,6 +380,7 @@ def resize_pane(self, *args: t.Any, **kwargs: t.Any) -> "Pane": raise exc.LibTmuxException(proc.stderr) self.server._update_panes() + self.refresh() return self def enter(self) -> None: @@ -349,12 +415,11 @@ def select_pane(self) -> "Pane": ------- :class:`pane` """ - pane = self.window.select_pane(self._pane_id) - if pane is None: - raise exc.LibTmuxException(f"Pane not found: {self}") - return pane + # pane = self.window.select_pane(self._pane_id) + # if pane is None: + # raise exc.LibTmuxException(f"Pane not found: {self}") + # return pane + return self.window.select_pane(self.pane_id) def __repr__(self) -> str: - return "{}({} {})".format( - self.__class__.__name__, self.get("pane_id"), self.window - ) + return "{}({} {})".format(self.__class__.__name__, self.pane_id, self.window) diff --git a/src/libtmux/session.py b/src/libtmux/session.py index f996286de..99e91936e 100644 --- a/src/libtmux/session.py +++ b/src/libtmux/session.py @@ -86,7 +86,8 @@ def __init__(self, server: "Server", session_id: str, **kwargs: t.Any) -> None: @property def _info(self) -> t.Optional[SessionDict]: # type: ignore # mypy#1362 - attrs = {"session_id": str(self._session_id)} + # attrs = {"session_id": str(self._session_id)} + attrs = {"session_id": object.__getattribute__(self, "_session_id")} def by(val: SessionDict) -> bool: for key in attrs.keys(): diff --git a/src/libtmux/window.py b/src/libtmux/window.py index 434dca17c..0edfb686a 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -103,7 +103,8 @@ def __repr__(self) -> str: @property def _info(self) -> WindowDict: # type: ignore # mypy#1362 - attrs = {"window_id": self._window_id} + # attrs = {"window_id": self._window_id} + attrs = {"window_id": object.__getattribute__(self, "_window_id")} # from https://github.com/serkanyersen/underscore.py def by(val: WindowDict) -> bool: @@ -500,7 +501,7 @@ def split_window( if target: tmux_args += ("-t%s" % target,) else: - tmux_args += ("-t%s" % self.panes[0].get("pane_id"),) + tmux_args += ("-t%s" % self.panes[0].pane_id,) if vertical: tmux_args += ("-v",) diff --git a/tests/test_pane.py b/tests/test_pane.py index ef33cca48..ce5eb146d 100644 --- a/tests/test_pane.py +++ b/tests/test_pane.py @@ -14,15 +14,15 @@ def test_resize_pane(session: Session) -> None: pane1 = window.attached_pane assert pane1 is not None - pane1_height = pane1["pane_height"] + pane1_height = pane1.pane_height window.split_window() pane1.resize_pane(height=4) - assert pane1["pane_height"] != pane1_height - assert int(pane1["pane_height"]) == 4 + assert pane1.pane_height != pane1_height + assert int(pane1.pane_height) == 4 pane1.resize_pane(height=3) - assert int(pane1["pane_height"]) == 3 + assert int(pane1.pane_height) == 3 def test_send_keys(session: Session) -> None: @@ -42,11 +42,11 @@ def test_set_height(session: Session) -> None: window.split_window() pane1 = window.attached_pane assert pane1 is not None - pane1_height = pane1["pane_height"] + pane1_height = pane1.pane_height pane1.set_height(4) - assert pane1["pane_height"] != pane1_height - assert int(pane1["pane_height"]) == 4 + assert pane1.pane_height != pane1_height + assert int(pane1.pane_height) == 4 def test_set_width(session: Session) -> None: @@ -56,11 +56,11 @@ def test_set_width(session: Session) -> None: window.select_layout("main-vertical") pane1 = window.attached_pane assert pane1 is not None - pane1_width = pane1["pane_width"] + pane1_width = pane1.pane_width pane1.set_width(10) - assert pane1["pane_width"] != pane1_width - assert int(pane1["pane_width"]) == 10 + assert pane1.pane_width != pane1_width + assert int(pane1.pane_width) == 10 pane1.reset() diff --git a/tests/test_server.py b/tests/test_server.py index 782150086..d75ce6dd1 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -116,7 +116,7 @@ def test_new_session_shell(server: Server) -> None: assert mysession.get("session_name") == "test_new_session" assert server.has_session("test_new_session") - pane_start_command = pane.get("pane_start_command") + pane_start_command = pane.pane_start_command assert pane_start_command is not None if has_gte_version("3.2"): diff --git a/tests/test_tmuxobject.py b/tests/test_tmuxobject.py index 992c73d3f..3824a98c3 100644 --- a/tests/test_tmuxobject.py +++ b/tests/test_tmuxobject.py @@ -34,7 +34,7 @@ def test_find_where(server: Server, session: Session) -> None: # window.find_where for pane in window.panes: pane_id = pane.get("pane_id") - assert pane_id is not None + pane_id = pane.pane_id assert window.find_where({"pane_id": pane_id}) == pane assert isinstance(window.find_where({"pane_id": pane_id}), Pane) @@ -84,9 +84,9 @@ def test_find_where_multiple_infos(server: Server, session: Session) -> None: # window.find_where for pane in window.panes: - pane_id = pane.get("pane_id") + pane_id = pane.pane_id assert pane_id is not None - pane_tty = pane.get("pane_tty") + pane_tty = pane.pane_tty assert pane_tty is not None find_where = window.find_where( @@ -137,10 +137,10 @@ def test_where(server: Server, session: Session) -> None: # window.where for pane in window.panes: - pane_id = pane.get("pane_id") + pane_id = pane.pane_id assert pane_id is not None - pane_tty = pane.get("pane_tty") + pane_tty = pane.pane_tty assert pane_tty is not None window_panes = window.where({"pane_id": pane_id, "pane_tty": pane_tty}) @@ -181,7 +181,7 @@ def test_get_by_id(server: Server, session: Session) -> None: # window.get_by_id for pane in window.panes: - pane_id = pane.get("pane_id") + pane_id = pane.pane_id assert pane_id is not None get_pane_by_id = window.get_by_id(pane_id)