1
- """Tools for hydrating tmux data into python dataclass objects."""
1
+ """Provide tools for hydrating tmux data into Python dataclass objects.
2
+
3
+ This module defines mechanisms for fetching and converting tmux command outputs
4
+ into Python dataclasses (via the :class:`Obj` base class). This facilitates
5
+ more structured and Pythonic interaction with tmux objects such as sessions,
6
+ windows, and panes.
7
+
8
+ Implementation Notes
9
+ --------------------
10
+ - :func:`fetch_objs` retrieves lists of raw field data from tmux.
11
+ - :func:`fetch_obj` retrieves a single tmux object by its key and ID.
12
+ - :class:`Obj` is a base dataclass that holds common tmux fields.
13
+
14
+ See Also
15
+ --------
16
+ :func:`fetch_objs`
17
+ :func:`fetch_obj`
18
+ """
2
19
3
20
from __future__ import annotations
4
21
12
29
from libtmux .formats import FORMAT_SEPARATOR
13
30
14
31
if t .TYPE_CHECKING :
32
+ from libtmux .server import Server
33
+
15
34
ListCmd = t .Literal ["list-sessions" , "list-windows" , "list-panes" ]
16
35
ListExtraArgs = t .Optional [Iterable [str ]]
17
36
18
- from libtmux .server import Server
19
-
20
37
logger = logging .getLogger (__name__ )
21
38
22
-
23
39
OutputRaw = dict [str , t .Any ]
24
40
OutputsRaw = list [OutputRaw ]
25
41
36
52
37
53
@dataclasses .dataclass ()
38
54
class Obj :
39
- """Dataclass of generic tmux object."""
55
+ """Represent a generic tmux dataclass object with standard fields.
56
+
57
+ Objects extending this base class derive many fields from tmux commands
58
+ via the :func:`fetch_objs` and :func:`fetch_obj` functions.
59
+
60
+ Parameters
61
+ ----------
62
+ server
63
+ The :class:`Server` instance owning this tmux object.
64
+
65
+ Attributes
66
+ ----------
67
+ pane_id, window_id, session_id, etc.
68
+ Various tmux-specific fields automatically populated when refreshed.
69
+
70
+ Examples
71
+ --------
72
+ Subclasses of :class:`Obj` typically represent concrete tmux entities
73
+ (e.g., sessions, windows, and panes).
74
+ """
40
75
41
76
server : Server
42
77
@@ -91,7 +126,7 @@ class Obj:
91
126
mouse_standard_flag : str | None = None
92
127
next_session_id : str | None = None
93
128
origin_flag : str | None = None
94
- pane_active : str | None = None # Not detected by script
129
+ pane_active : str | None = None
95
130
pane_at_bottom : str | None = None
96
131
pane_at_left : str | None = None
97
132
pane_at_right : str | None = None
@@ -146,7 +181,7 @@ class Obj:
146
181
uid : str | None = None
147
182
user : str | None = None
148
183
version : str | None = None
149
- window_active : str | None = None # Not detected by script
184
+ window_active : str | None = None
150
185
window_active_clients : str | None = None
151
186
window_active_sessions : str | None = None
152
187
window_activity : str | None = None
@@ -176,6 +211,24 @@ def _refresh(
176
211
list_cmd : ListCmd = "list-panes" ,
177
212
list_extra_args : ListExtraArgs | None = None ,
178
213
) -> None :
214
+ """Refresh fields for this object by re-fetching from tmux.
215
+
216
+ Parameters
217
+ ----------
218
+ obj_key
219
+ The field name to match (e.g. 'pane_id').
220
+ obj_id
221
+ The object identifier (e.g. '%1').
222
+ list_cmd
223
+ The tmux command to use (e.g. 'list-panes').
224
+ list_extra_args
225
+ Additional arguments to pass to the tmux command.
226
+
227
+ Raises
228
+ ------
229
+ exc.TmuxObjectDoesNotExist
230
+ If the requested object does not exist in tmux's output.
231
+ """
179
232
assert isinstance (obj_id , str )
180
233
obj = fetch_obj (
181
234
obj_key = obj_key ,
@@ -185,50 +238,63 @@ def _refresh(
185
238
server = self .server ,
186
239
)
187
240
assert obj is not None
188
- if obj is not None :
189
- for k , v in obj .items ():
190
- setattr (self , k , v )
241
+ for k , v in obj .items ():
242
+ setattr (self , k , v )
191
243
192
244
193
245
def fetch_objs (
194
246
server : Server ,
195
247
list_cmd : ListCmd ,
196
248
list_extra_args : ListExtraArgs | None = None ,
197
249
) -> OutputsRaw :
198
- """Fetch a listing of raw data from a tmux command."""
250
+ """Fetch a list of raw data from a tmux command.
251
+
252
+ Parameters
253
+ ----------
254
+ server
255
+ The :class:`Server` against which to run the command.
256
+ list_cmd
257
+ The tmux command to run (e.g. 'list-sessions', 'list-windows', 'list-panes').
258
+ list_extra_args
259
+ Any extra arguments (e.g. ['-a']).
260
+
261
+ Returns
262
+ -------
263
+ list of dict
264
+ A list of dictionaries of field-name to field-value mappings.
265
+
266
+ Raises
267
+ ------
268
+ exc.LibTmuxException
269
+ If tmux reports an error in stderr.
270
+ """
199
271
formats = list (Obj .__dataclass_fields__ .keys ())
200
272
201
273
cmd_args : list [str | int ] = []
202
-
203
274
if server .socket_name :
204
275
cmd_args .insert (0 , f"-L{ server .socket_name } " )
205
276
if server .socket_path :
206
277
cmd_args .insert (0 , f"-S{ server .socket_path } " )
207
- tmux_formats = [f"#{{{ f } }}{ FORMAT_SEPARATOR } " for f in formats ]
208
278
209
- tmux_cmds = [
210
- * cmd_args ,
211
- list_cmd ,
212
- ]
279
+ tmux_formats = [f"#{{{ f } }}{ FORMAT_SEPARATOR } " for f in formats ]
280
+ tmux_cmds = [* cmd_args , list_cmd ]
213
281
214
282
if list_extra_args is not None and isinstance (list_extra_args , Iterable ):
215
283
tmux_cmds .extend (list (list_extra_args ))
216
284
217
285
tmux_cmds .append ("-F{}" .format ("" .join (tmux_formats )))
218
-
219
- proc = tmux_cmd (* tmux_cmds ) # output
286
+ proc = tmux_cmd (* tmux_cmds )
220
287
221
288
if proc .stderr :
222
289
raise exc .LibTmuxException (proc .stderr )
223
290
224
291
obj_output = proc .stdout
225
-
226
292
obj_formatters = [
227
293
dict (zip (formats , formatter .split (FORMAT_SEPARATOR )))
228
294
for formatter in obj_output
229
295
]
230
296
231
- # Filter empty values
297
+ # Filter out empty values
232
298
return [{k : v for k , v in formatter .items () if v } for formatter in obj_formatters ]
233
299
234
300
@@ -239,7 +305,31 @@ def fetch_obj(
239
305
list_cmd : ListCmd = "list-panes" ,
240
306
list_extra_args : ListExtraArgs | None = None ,
241
307
) -> OutputRaw :
242
- """Fetch raw data from tmux command."""
308
+ """Fetch a single tmux object by key and ID.
309
+
310
+ Parameters
311
+ ----------
312
+ server
313
+ The :class:`Server` instance to query.
314
+ obj_key
315
+ The field name to look for (e.g., 'pane_id').
316
+ obj_id
317
+ The specific ID to match (e.g., '%0').
318
+ list_cmd
319
+ The tmux command to run ('list-panes', 'list-windows', etc.).
320
+ list_extra_args
321
+ Extra arguments to pass (e.g., ['-a']).
322
+
323
+ Returns
324
+ -------
325
+ dict
326
+ A dictionary of field-name to field-value mappings for the object.
327
+
328
+ Raises
329
+ ------
330
+ exc.TmuxObjectDoesNotExist
331
+ If no matching object is found in tmux's output.
332
+ """
243
333
obj_formatters_filtered = fetch_objs (
244
334
server = server ,
245
335
list_cmd = list_cmd ,
@@ -250,6 +340,7 @@ def fetch_obj(
250
340
for _obj in obj_formatters_filtered :
251
341
if _obj .get (obj_key ) == obj_id :
252
342
obj = _obj
343
+ break
253
344
254
345
if obj is None :
255
346
raise exc .TmuxObjectDoesNotExist (
@@ -259,6 +350,4 @@ def fetch_obj(
259
350
list_extra_args = list_extra_args ,
260
351
)
261
352
262
- assert obj is not None
263
-
264
353
return obj
0 commit comments