Skip to content

Commit 4cad449

Browse files
authored
refactor!: Deprecate legacy APIs with DeprecatedError (#611)
Convert deprecated APIs to raise DeprecatedError instead of DeprecationWarning Breaking change: Legacy APIs deprecated in 0.16-0.33 now raise hard errors instead of soft warnings to encourage migration to new APIs. Changes: - Add DeprecatedError exception class in exc.py - Server: kill_server, get_by_id, where, find_where, list_sessions raise errors - Session: attach_session, kill_session, attached_window/pane raise errors - Window: split_window, select_window, kill_window, attached_pane raise errors - Pane: resize_pane, select_pane, split_window, dict access raise errors - Keep 0.50 deprecations (g param, window options) as soft warnings - Update all tests to expect DeprecatedError or use new APIs - Add comprehensive deprecation reference tables in MIGRATION - Document breaking changes in CHANGES
2 parents d6a8838 + d87f185 commit 4cad449

21 files changed

+844
-1398
lines changed

CHANGES

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ _Upcoming changes will be written here._
4444
- Fix incorrect return type annotations for `capture_pane()` and `display_message()` methods
4545
(changed from `str | list[str]` to `list[str]` - the methods always return a list).
4646

47+
#### APIs deprecated (#611)
48+
49+
Legacy API methods (deprecated in 0.16-0.33) now raise {exc}`~libtmux.exc.DeprecatedError` (hard error) instead of emitting {class}`DeprecationWarning`.
50+
51+
See {doc}`migration` for full context and examples.
52+
53+
| Deprecated API | Replacement | Deprecated | Raises | Note |
54+
|----------------|-------------|------------|--------|------|
55+
| `kill_server()` | {meth}`~libtmux.Server.kill` | 0.30.0 | 0.51.0 | Server |
56+
| `attach_session()`, `kill_session()` | {meth}`~libtmux.Session.attach`, {meth}`~libtmux.Session.kill` | 0.30.0 | 0.51.0 | Session |
57+
| `select_window()`, `kill_window()`, `split_window()` | {meth}`~libtmux.Window.select`, {meth}`~libtmux.Window.kill`, {meth}`~libtmux.Window.split` | 0.30.0 / 0.33.0 | 0.51.0 | Window |
58+
| `resize_pane()`, `select_pane()`, `split_window()` | {meth}`~libtmux.Pane.resize`, {meth}`~libtmux.Pane.select`, {meth}`~libtmux.Pane.split` | 0.28.0 / 0.30.0 / 0.33.0 | 0.51.0 | Pane |
59+
| `attached_window`, `attached_pane` | {attr}`~libtmux.Session.active_window`, {attr}`~libtmux.Session.active_pane` / {attr}`~libtmux.Window.active_pane` | 0.31.0 | 0.51.0 | Session/Window |
60+
| `list_*()`, `_list_*()`, `_update_*()`, `children`, `where()`, `find_where()`, `get_by_id()` | {attr}`~libtmux.Server.sessions` / {attr}`~libtmux.Session.windows` / {attr}`~libtmux.Window.panes` with {meth}`~libtmux.common.QueryList.filter` / {meth}`~libtmux.common.QueryList.get` | 0.16.0 / 0.17.0 | 0.51.0 | Query/filter helpers |
61+
| Dict-style access (`obj["key"]`, `obj.get(...)`) | Attribute access (e.g., {attr}`~libtmux.window.Window.window_name`) | 0.17.0 | 0.51.0 | All tmux objects |
62+
63+
The following deprecations from 0.50.0 continue to emit {class}`DeprecationWarning` (soft deprecation):
64+
65+
| Deprecated API | Replacement | Deprecated | Note |
66+
|----------------|-------------|------------|------|
67+
| `set_window_option()`, `show_window_option()`, `show_window_options()` | {meth}`~libtmux.window.Window.set_option`, {meth}`~libtmux.window.Window.show_option`, {meth}`~libtmux.window.Window.show_options` | 0.50.0 | Window |
68+
| `g` parameter on options/hooks methods | `global_` on {meth}`~libtmux.options.OptionsMixin.set_option`, {meth}`~libtmux.options.OptionsMixin.show_option`, {meth}`~libtmux.options.OptionsMixin.show_options` | 0.50.0 | Options & hooks |
69+
4770
## libtmux 0.50.0 (2025-11-30)
4871

4972
### Overview

MIGRATION

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,94 @@ well.
1919
[tracker]: https://github.com/tmux-python/libtmux/discussions
2020
```
2121

22+
## Complete Deprecation Reference
23+
24+
This table provides a quick reference for all deprecated APIs. See version-specific
25+
sections below for detailed migration examples and code samples.
26+
27+
### Method Renamings
28+
29+
| Class | Deprecated | Replacement | Since | Raises |
30+
|-------|------------|-------------|-------|--------|
31+
| Server | `kill_server()` | `kill()` | 0.30.0 (2024-02-16) | 0.51.0 |
32+
| Session | `attach_session()` | `attach()` | 0.30.0 (2024-02-16) | 0.51.0 |
33+
| Session | `kill_session()` | `kill()` | 0.30.0 (2024-02-16) | 0.51.0 |
34+
| Window | `select_window()` | `select()` | 0.30.0 (2024-02-16) | 0.51.0 |
35+
| Window | `kill_window()` | `kill()` | 0.30.0 (2024-02-16) | 0.51.0 |
36+
| Window | `split_window()` | `split()` | 0.33.0 (2024-03-17) | 0.51.0 |
37+
| Window | `set_window_option()` | `set_option()` | 0.50.0 (2025-11-30) | _(warning)_ |
38+
| Window | `show_window_option()` | `show_option()` | 0.50.0 (2025-11-30) | _(warning)_ |
39+
| Window | `show_window_options()` | `show_options()` | 0.50.0 (2025-11-30) | _(warning)_ |
40+
| Pane | `select_pane()` | `select()` | 0.30.0 (2024-02-16) | 0.51.0 |
41+
| Pane | `resize_pane()` | `resize()` | 0.28.0 (2024-02-14) | 0.51.0 |
42+
| Pane | `split_window()` | `split()` | 0.33.0 (2024-03-17) | 0.51.0 |
43+
44+
### Property Renamings
45+
46+
| Class | Deprecated | Replacement | Since | Raises |
47+
|-------|------------|-------------|-------|--------|
48+
| Session | `attached_window` | `active_window` | 0.31.0 (2024-02-17) | 0.51.0 |
49+
| Session | `attached_pane` | `active_pane` | 0.31.0 (2024-02-17) | 0.51.0 |
50+
| Window | `attached_pane` | `active_pane` | 0.31.0 (2024-02-17) | 0.51.0 |
51+
52+
### Parameter Changes
53+
54+
| Method(s) | Deprecated | Replacement | Since | Raises |
55+
|-----------|------------|-------------|-------|--------|
56+
| Options/hooks methods | `g` | `global_` | 0.50.0 (2025-11-30) | _(warning)_ |
57+
| `split_window()` / `split()` | `percent` | `size` | 0.28.0 (2024-02-14) | 0.51.0 |
58+
| `split_window()` / `split()` | `vertical`/`horizontal` | `direction` (PaneDirection) | 0.33.0 (2024-03-17) | 0.51.0 |
59+
| `resize_pane()` | `-U`, `-D`, `-L`, `-R` | `adjustment_direction` | 0.28.0 (2024-02-14) | 0.51.0 |
60+
| `Server.get_by_id()` | `id` | `session_id` | 0.16.0 (2022-12-10) | 0.51.0 |
61+
| `Session.get_by_id()` | `id` | `window_id` | 0.16.0 (2022-12-10) | 0.51.0 |
62+
| `Window.get_by_id()` | `id` | `pane_id` | 0.16.0 (2022-12-10) | 0.51.0 |
63+
64+
### Query/Filter API Changes
65+
66+
| Class | Deprecated | Replacement | Since | Raises |
67+
|-------|------------|-------------|-------|--------|
68+
| Server | `list_sessions()` / `_list_sessions()` | `sessions` property | 0.17.0 (2022-12-26) | 0.51.0 |
69+
| Server | `where({...})` | `sessions.filter(**kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
70+
| Server | `find_where({...})` | `sessions.get(default=None, **kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
71+
| Server | `_list_panes()` / `_update_panes()` | `panes` property | 0.17.0 (2022-12-26) | 0.51.0 |
72+
| Server | `_list_windows()` / `_update_windows()` | `windows` property | 0.17.0 (2022-12-26) | 0.51.0 |
73+
| Server | `get_by_id(id)` | `sessions.get(session_id=..., default=None)` | 0.16.0 (2022-12-10) | 0.51.0 |
74+
| Session | `list_windows()` / `_list_windows()` | `windows` property | 0.17.0 (2022-12-26) | 0.51.0 |
75+
| Session | `where({...})` | `windows.filter(**kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
76+
| Session | `find_where({...})` | `windows.get(default=None, **kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
77+
| Session | `get_by_id(id)` | `windows.get(window_id=..., default=None)` | 0.16.0 (2022-12-10) | 0.51.0 |
78+
| Window | `list_panes()` / `_list_panes()` | `panes` property | 0.17.0 (2022-12-26) | 0.51.0 |
79+
| Window | `where({...})` | `panes.filter(**kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
80+
| Window | `find_where({...})` | `panes.get(default=None, **kwargs)` | 0.17.0 (2022-12-26) | 0.51.0 |
81+
| Window | `get_by_id(id)` | `panes.get(pane_id=..., default=None)` | 0.16.0 (2022-12-10) | 0.51.0 |
82+
| All | `children` property | `sessions`/`windows`/`panes` | 0.17.0 (2022-12-26) | 0.51.0 |
83+
84+
### Attribute Access Changes
85+
86+
| Pattern | Deprecated | Replacement | Since | Raises |
87+
|---------|------------|-------------|-------|--------|
88+
| Dict key access | `obj['key']` | `obj.key` | 0.17.0 (2022-12-26) | 0.51.0 |
89+
| Dict get | `obj.get('key')` | `obj.key` | 0.17.0 (2022-12-26) | 0.51.0 |
90+
| Dict get w/ default | `obj.get('key', None)` | `getattr(obj, 'key', None)` | 0.17.0 (2022-12-26) | 0.51.0 |
91+
92+
### Removed Items
93+
94+
| Item | Removed In | Migration |
95+
|------|------------|-----------|
96+
| tmux < 3.2a support | 0.49.0 (2025-11-29) | Upgrade tmux or use libtmux 0.48.x |
97+
| `console_to_str()` | 0.42.0 (2025-02-02) | Use `text=True` in subprocess |
98+
| `str_from_console()` | 0.42.0 (2025-02-02) | Use `text=True` in subprocess |
99+
| `common.which()` | 0.12.0 (2022-07-13) | Use `shutil.which()` |
100+
101+
### Default Behavior Changes
102+
103+
| Method | Old Default | New Default | Since |
104+
|--------|-------------|-------------|-------|
105+
| `Session.new_window()` | `attach=True` | `attach=False` | 0.28.0 (2024-02-14) |
106+
| `Window.split_window()` | `attach=True` | `attach=False` | 0.28.0 (2024-02-14) |
107+
108+
---
109+
22110
## Upcoming Release
23111

24112
_Detailed migration steps for the next version will be posted here._

src/libtmux/exc.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,35 @@ class LibTmuxException(Exception):
1919
"""Base Exception for libtmux Errors."""
2020

2121

22+
class DeprecatedError(LibTmuxException):
23+
"""Raised when a deprecated function, method, or parameter is used.
24+
25+
This exception provides clear guidance on what to use instead.
26+
27+
Parameters
28+
----------
29+
deprecated : str
30+
The name of the deprecated API (e.g., "Pane.resize_pane()")
31+
replacement : str
32+
The recommended replacement API to use instead
33+
version : str
34+
The version when the API was deprecated (e.g., "0.28.0")
35+
"""
36+
37+
def __init__(
38+
self,
39+
*,
40+
deprecated: str,
41+
replacement: str,
42+
version: str,
43+
) -> None:
44+
msg = (
45+
f"{deprecated} was deprecated in {version} and has been removed. "
46+
f"Use {replacement} instead."
47+
)
48+
super().__init__(msg)
49+
50+
2251
class TmuxSessionExists(LibTmuxException):
2352
"""Session does not exist in the server."""
2453

src/libtmux/options.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,9 @@ def _show_options_raw(
797797
798798
Parameters
799799
----------
800-
g : str, optional
801-
Pass ``-g`` flag for global variable, default False.
800+
g : bool, optional
801+
.. deprecated:: 0.50.0
802+
Use ``global_`` instead.
802803
803804
Examples
804805
--------
@@ -834,8 +835,9 @@ def _show_options_raw(
834835
category=DeprecationWarning,
835836
stacklevel=2,
836837
)
837-
flags += ("-g",)
838-
elif global_:
838+
global_ = g
839+
840+
if global_:
839841
flags += ("-g",)
840842

841843
if scope is not None and not isinstance(scope, _DefaultOptionScope):
@@ -864,8 +866,9 @@ def _show_options_dict(
864866
865867
Parameters
866868
----------
867-
g : str, optional
868-
Pass ``-g`` flag for global variable, default False.
869+
g : bool, optional
870+
.. deprecated:: 0.50.0
871+
Use ``global_`` instead.
869872
870873
Examples
871874
--------
@@ -913,8 +916,9 @@ def _show_options(
913916
914917
Parameters
915918
----------
916-
g : str, optional
917-
Pass ``-g`` flag for global variable, default False.
919+
g : bool, optional
920+
.. deprecated:: 0.50.0
921+
Use ``global_`` instead.
918922
919923
Examples
920924
--------
@@ -1013,7 +1017,8 @@ def _show_option_raw(
10131017
----------
10141018
option : str
10151019
g : bool, optional
1016-
Pass ``-g`` flag, global. Default False.
1020+
.. deprecated:: 0.50.0
1021+
Use ``global_`` instead.
10171022
10181023
Raises
10191024
------
@@ -1063,8 +1068,9 @@ def _show_option_raw(
10631068
category=DeprecationWarning,
10641069
stacklevel=2,
10651070
)
1066-
flags += ("-g",)
1067-
elif global_:
1071+
global_ = g
1072+
1073+
if global_:
10681074
flags += ("-g",)
10691075

10701076
if scope is not None and not isinstance(scope, _DefaultOptionScope):
@@ -1104,7 +1110,8 @@ def _show_option(
11041110
----------
11051111
option : str
11061112
g : bool, optional
1107-
Pass ``-g`` flag, global. Default False.
1113+
.. deprecated:: 0.50.0
1114+
Use ``global_`` instead.
11081115
11091116
Raises
11101117
------
@@ -1206,7 +1213,8 @@ def show_option(
12061213
----------
12071214
option : str
12081215
g : bool, optional
1209-
Pass ``-g`` flag, global. Default False.
1216+
.. deprecated:: 0.50.0
1217+
Use ``global_`` instead.
12101218
12111219
Raises
12121220
------

src/libtmux/pane.py

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import logging
1212
import pathlib
1313
import typing as t
14-
import warnings
1514

1615
from libtmux import exc
1716
from libtmux.common import tmux_cmd
@@ -554,16 +553,11 @@ def select_pane(self) -> Pane:
554553
555554
Deprecated in favor of :meth:`.select()`.
556555
"""
557-
warnings.warn(
558-
"Pane.select_pane() is deprecated in favor of Pane.select()",
559-
category=DeprecationWarning,
560-
stacklevel=2,
556+
raise exc.DeprecatedError(
557+
deprecated="Pane.select_pane()",
558+
replacement="Pane.select()",
559+
version="0.30.0",
561560
)
562-
assert isinstance(self.pane_id, str)
563-
pane = self.window.select_pane(self.pane_id)
564-
if pane is None:
565-
raise exc.PaneNotFound(pane_id=self.pane_id)
566-
return pane
567561

568562
def split(
569563
self,
@@ -731,7 +725,7 @@ def set_width(self, width: int) -> Pane:
731725
:class:`Pane`
732726
Self, for method chaining.
733727
"""
734-
self.resize_pane(width=width)
728+
self.resize(width=width)
735729
return self
736730

737731
def set_height(self, height: int) -> Pane:
@@ -747,7 +741,7 @@ def set_height(self, height: int) -> Pane:
747741
:class:`Pane`
748742
Self, for method chaining.
749743
"""
750-
self.resize_pane(height=height)
744+
self.resize(height=height)
751745
return self
752746

753747
def enter(self) -> Pane:
@@ -915,54 +909,41 @@ def split_window(
915909
916910
Deprecated in favor of :meth:`.split`.
917911
"""
918-
warnings.warn(
919-
"Pane.split_window() is deprecated in favor of Pane.split()",
920-
category=DeprecationWarning,
921-
stacklevel=2,
922-
)
923-
if size is None and percent is not None:
924-
size = f"{str(percent).rstrip('%')}%"
925-
return self.split(
926-
target=target,
927-
attach=attach,
928-
start_directory=start_directory,
929-
direction=PaneDirection.Below if vertical else PaneDirection.Right,
930-
shell=shell,
931-
size=size,
932-
environment=environment,
912+
raise exc.DeprecatedError(
913+
deprecated="Pane.split_window()",
914+
replacement="Pane.split()",
915+
version="0.33.0",
933916
)
934917

935918
def get(self, key: str, default: t.Any | None = None) -> t.Any:
936919
"""Return key-based lookup. Deprecated by attributes.
937920
938-
.. deprecated:: 0.16
921+
.. deprecated:: 0.17
939922
940923
Deprecated by attribute lookup, e.g. ``pane['window_name']`` is now
941924
accessed via ``pane.window_name``.
942925
943926
"""
944-
warnings.warn(
945-
"Pane.get() is deprecated",
946-
category=DeprecationWarning,
947-
stacklevel=2,
927+
raise exc.DeprecatedError(
928+
deprecated="Pane.get()",
929+
replacement="direct attribute access (e.g., pane.pane_id)",
930+
version="0.17.0",
948931
)
949-
return getattr(self, key, default)
950932

951933
def __getitem__(self, key: str) -> t.Any:
952934
"""Return item lookup by key. Deprecated in favor of attributes.
953935
954-
.. deprecated:: 0.16
936+
.. deprecated:: 0.17
955937
956938
Deprecated in favor of attributes. e.g. ``pane['window_name']`` is now
957939
accessed via ``pane.window_name``.
958940
959941
"""
960-
warnings.warn(
961-
f"Item lookups, e.g. pane['{key}'] is deprecated",
962-
category=DeprecationWarning,
963-
stacklevel=2,
942+
raise exc.DeprecatedError(
943+
deprecated="Pane[key] lookup",
944+
replacement="direct attribute access (e.g., pane.pane_id)",
945+
version="0.17.0",
964946
)
965-
return getattr(self, key)
966947

967948
def resize_pane(
968949
self,
@@ -985,17 +966,8 @@ def resize_pane(
985966
986967
Deprecated by :meth:`Pane.resize`.
987968
"""
988-
warnings.warn(
989-
"Deprecated: Use Pane.resize() instead of Pane.resize_pane()",
990-
category=DeprecationWarning,
991-
stacklevel=2,
992-
)
993-
return self.resize(
994-
adjustment_direction=adjustment_direction,
995-
adjustment=adjustment,
996-
height=height,
997-
width=width,
998-
zoom=zoom,
999-
mouse=mouse,
1000-
trim_below=trim_below,
969+
raise exc.DeprecatedError(
970+
deprecated="Pane.resize_pane()",
971+
replacement="Pane.resize()",
972+
version="0.28.0",
1001973
)

0 commit comments

Comments
 (0)