From 3a39200f7070b7ad62ea24752659dc27fb2e2a42 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Tue, 25 Feb 2025 19:02:57 -0600 Subject: [PATCH 01/13] pyproject(mypy[exceptions]): pytest examples to ignore `no-untyped-def` --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 1115cd419..d22d26a3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -128,6 +128,11 @@ files = [ "tests", ] +[[tool.mypy.overrides]] +module = "tests.examples.pytest_plugin.*" +disallow_untyped_defs = false +disallow_incomplete_defs = false + [tool.coverage.run] branch = true parallel = true From 1bcdfb4806d3e82a7356747c2d5ef0f2fcd84c01 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 1 Feb 2025 05:59:20 -0600 Subject: [PATCH 02/13] docs: Improve window.py --- src/libtmux/window.py | 579 +++++++++++++++++++++--------------------- 1 file changed, 287 insertions(+), 292 deletions(-) diff --git a/src/libtmux/window.py b/src/libtmux/window.py index 121c7ea03..968e9e21f 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -1,8 +1,12 @@ """Pythonization of the :term:`tmux(1)` window. +This module provides the :class:`Window` class, representing a tmux window +capable of containing multiple panes. The class includes methods for splitting, +resizing, renaming, killing, and moving windows, as well as a variety of +property accessors for tmux window attributes. + libtmux.window ~~~~~~~~~~~~~~ - """ from __future__ import annotations @@ -45,13 +49,14 @@ @dataclasses.dataclass() class Window(Obj): - """:term:`tmux(1)` :term:`Window` [window_manual]_. + """Represent a :term:`tmux(1)` window [window_manual]_. Holds :class:`Pane` objects. Parameters ---------- session : :class:`Session` + Parent session of this window (conceptual parameter). Examples -------- @@ -146,7 +151,7 @@ def refresh(self) -> None: @classmethod def from_window_id(cls, server: Server, window_id: str) -> Window: - """Create Window from existing window_id.""" + """Create a new :class:`Window` from an existing window_id.""" window = fetch_obj( obj_key="window_id", obj_id=window_id, @@ -158,7 +163,7 @@ def from_window_id(cls, server: Server, window_id: str) -> Window: @property def session(self) -> Session: - """Parent session of window.""" + """Return the parent :class:`Session` of this window.""" assert isinstance(self.session_id, str) from libtmux.session import Session @@ -166,7 +171,7 @@ def session(self) -> Session: @property def panes(self) -> QueryList[Pane]: - """Panes contained by window. + """Return a :class:`QueryList` of :class:`Pane` objects contained by window. Can be accessed via :meth:`.panes.get() ` and @@ -184,9 +189,7 @@ def panes(self) -> QueryList[Pane]: return QueryList(panes) - """ - Commands (pane-scoped) - """ + # Commands (pane-scoped) def cmd( self, @@ -194,10 +197,19 @@ def cmd( *args: t.Any, target: str | int | None = None, ) -> tmux_cmd: - """Execute tmux subcommand within window context. + """Execute a tmux subcommand within the context of this window. + + Automatically binds ``-t `` to the command unless + overridden by the `target` parameter. - Automatically binds target by adding ``-t`` for object's window ID to the - command. Pass ``target`` to keyword arguments to override. + Parameters + ---------- + cmd + The tmux subcommand to execute. + *args + Additional arguments for the tmux command. + target, optional + Custom target override. By default, the target is this window's ID. Examples -------- @@ -208,41 +220,43 @@ def cmd( Magic, directly to a `Pane`: - >>> Pane.from_pane_id(pane_id=session.cmd( - ... 'split-window', '-P', '-F#{pane_id}').stdout[0], server=session.server) + >>> Pane.from_pane_id( + ... pane_id=session.cmd('split-window', '-P', '-F#{pane_id}').stdout[0], + ... server=session.server + ... ) Pane(%... Window(@... ...:..., Session($1 libtmux_...))) - Parameters - ---------- - target : str, optional - Optional custom target override. By default, the target is the window ID. - Returns ------- - :meth:`server.cmd` + tmux_cmd + The result of the tmux command execution. """ if target is None: target = self.window_id return self.server.cmd(cmd, *args, target=target) - """ - Commands (tmux-like) - """ + # Commands (tmux-like) def select_pane(self, target_pane: str | int) -> Pane | None: - """Select pane and return selected :class:`Pane`. + """Select a pane within this window and return the now-active :class:`Pane`. - ``$ tmux select-pane``. + Wrapper for ``tmux select-pane``. Parameters ---------- - target_pane : str - 'target_pane', '-U' ,'-D', '-L', '-R', or '-l'. + target_pane + Pane specifier (e.g., '-l', '-U', '-D', '-L', '-R', or an ID). Returns ------- - :class:`Pane` + Pane or None + The active :class:`Pane` after selection. + + Raises + ------ + exc.LibTmuxException + If tmux reports an error (see stderr output). """ if target_pane in {"-l", "-U", "-D", "-L", "-R"}: proc = self.cmd("select-pane", target_pane) @@ -267,32 +281,34 @@ def split( size: str | int | None = None, environment: dict[str, str] | None = None, ) -> Pane: - """Split window on active pane and return the created :class:`Pane`. + """Split the active pane in this window and return newly created :class:`Pane`. Parameters ---------- - attach : bool, optional - make new window the current window after creating it, default - True. - start_directory : str, optional - specifies the working directory in which the new window is created. - direction : PaneDirection, optional - split in direction. If none is specified, assume down. - full_window_split: bool, optional - split across full window width or height, rather than active pane. - zoom: bool, optional - expand pane - shell : str, optional - execute a command on splitting the window. The pane will close - when the command exits. - - NOTE: When this command exits the pane will close. This feature - is useful for long-running processes where the closing of the - window upon completion is desired. - size: int, optional - Cell/row or percentage to occupy with respect to current window. - environment: dict, optional - Environmental variables for new pane. tmux 3.0+ only. Passthrough to ``-e``. + target, optional + Custom target override (defaults to the active pane in this window). + start_directory, optional + Working directory in which to create the new pane. + attach, optional + Whether to make the new pane the current pane. Default is False. + direction, optional + Direction in which to split. Defaults to splitting downwards. + full_window_split, optional + If True, split across the full window width/height rather than active pane. + zoom, optional + Whether to zoom (expand) the newly created pane. + shell, optional + Shell command to execute immediately in the new pane. The pane + closes when the command exits. + size, optional + Size of the new pane (cells/rows or a percentage). Example: "50%", 10, etc. + environment, optional + Dictionary of environment variables for the new pane (tmux 3.0+). + + Returns + ------- + Pane + The newly created pane object. """ active_pane = self.active_pane or self.panes[0] return active_pane.split( @@ -310,50 +326,50 @@ def split( def resize( self, /, - # Adjustments adjustment_direction: ResizeAdjustmentDirection | None = None, adjustment: int | None = None, - # Manual height: int | None = None, width: int | None = None, - # Expand / Shrink expand: bool | None = None, shrink: bool | None = None, ) -> Window: - """Resize tmux window. + """Resize this tmux window. + + This method supports three types of resizing: + 1. Adjustments (direction + amount) + 2. Manual resizing (explicit height or width) + 3. Expand or shrink (full window) Parameters ---------- - adjustment_direction : ResizeAdjustmentDirection, optional - direction to adjust, ``Up``, ``Down``, ``Left``, ``Right``. - adjustment : ResizeAdjustmentDirection, optional - - height : int, optional - ``resize-window -y`` dimensions - width : int, optional - ``resize-window -x`` dimensions + adjustment_direction, optional + Direction to adjust (Up, Down, Left, Right). + adjustment, optional + Number of cells/rows to adjust in the given direction. + height, optional + Set the window height (in cells). + width, optional + Set the window width (in cells). + expand, optional + Expand the window to the maximum size. + shrink, optional + Shrink the window to the minimum size. - expand : bool - expand window - shrink : bool - shrink window + Returns + ------- + Window + This :class:`Window` instance (for chaining). Raises ------ - :exc:`exc.LibTmuxException`, - :exc:`exc.PaneAdjustmentDirectionRequiresAdjustment` - - Returns - ------- - :class:`Window` + exc.LibTmuxException + If tmux reports an error (see stderr). + exc.WindowAdjustmentDirectionRequiresAdjustment + If `adjustment_direction` is given but `adjustment` is None. Notes ----- - Three types of resizing are available: - - 1. Adjustments: ``adjustment_direction`` and ``adjustment``. - 2. Manual resizing: ``height`` and / or ``width``. - 3. Expand or shrink: ``expand`` or ``shrink``. + This method requires tmux 2.9 or newer. """ if not has_gte_version("2.9"): warnings.warn("resize() requires tmux 2.9 or newer", stacklevel=2) @@ -390,43 +406,40 @@ def resize( return self def last_pane(self) -> Pane | None: - """Return last pane.""" + """Select and return the last active :class:`Pane` in this window. + + Wrapper for ``tmux select-pane -l``. + + Returns + ------- + Pane or None + The newly selected active pane, or None if none found. + """ return self.select_pane("-l") def select_layout(self, layout: str | None = None) -> Window: - """Select layout for window. + """Select a layout for this window. - Wrapper for ``$ tmux select-layout ``. + Wrapper for ``tmux select-layout ``. Parameters ---------- - layout : str, optional - string of the layout, 'even-horizontal', 'tiled', etc. Entering - None (leaving this blank) is same as ``select-layout`` with no - layout. In recent tmux versions, it picks the most recently - set layout. - - 'even-horizontal' - Panes are spread out evenly from left to right across the - window. - 'even-vertical' - Panes are spread evenly from top to bottom. - 'main-horizontal' - A large (main) pane is shown at the top of the window and the - remaining panes are spread from left to right in the leftover - space at the bottom. - 'main-vertical' - Similar to main-horizontal but the large pane is placed on the - left and the others spread from top to bottom along the right. - 'tiled' - Panes are spread out as evenly as possible over the window in - both rows and columns. - 'custom' - custom dimensions (see :term:`tmux(1)` manpages). + layout, optional + The layout name (e.g. 'even-horizontal', 'tiled'). If None, + tmux will use the most recently set layout. + + Returns + ------- + Window + This :class:`Window` instance (for chaining). + + Raises + ------ + exc.LibTmuxException + If tmux reports an error (see stderr). """ cmd = ["select-layout"] - - if layout: # tmux allows select-layout without args + if layout: cmd.append(layout) proc = self.cmd(*cmd) @@ -437,64 +450,63 @@ def select_layout(self, layout: str | None = None) -> Window: return self def set_window_option(self, option: str, value: int | str) -> Window: - """Set option for tmux window. + """Set a tmux window option. - Wraps ``$ tmux set-window-option