@@ -23,26 +23,24 @@ Use `.acmd()` on existing Server/Session/Window/Pane objects. Perfect for gradua
2323
2424``` python
2525>> > import asyncio
26- >> > import libtmux
27- >> >
28- >> > async def main ():
29- ... server = libtmux.Server()
30- ...
31- ... # Execute async command
26+ >> > async def pattern_a_demo ():
27+ ... # Uses 'server' fixture from conftest for isolation
3228... result = await server.acmd(' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
33- ... print ( f " Created session: { result.stdout[0 ]} " )
29+ ... session_id = result.stdout[0 ]
3430...
3531... # Execute concurrent commands
3632... results = await asyncio.gather(
37- ... server.acmd(' new-window' , ' -n' , ' window1' ),
38- ... server.acmd(' new-window' , ' -n' , ' window2' ),
39- ... server.acmd(' new-window' , ' -n' , ' window3' ),
33+ ... server.acmd(' new-window' , ' -t ' , session_id, ' - n' , ' window1' ),
34+ ... server.acmd(' new-window' , ' -t ' , session_id, ' - n' , ' window2' ),
35+ ... server.acmd(' new-window' , ' -t ' , session_id, ' - n' , ' window3' ),
4036... )
41- ... print (f " Created { len (results)} windows concurrently " )
42- >> >
43- >> > asyncio.run(main()) # doctest: +SKIP
44- Created session: $ ...
45- Created 3 windows concurrently
37+ ...
38+ ... # Cleanup
39+ ... await server.acmd(' kill-session' , ' -t' , session_id)
40+ ...
41+ ... return len (results) == 3
42+ >> > asyncio.run(pattern_a_demo())
43+ True
4644```
4745
4846### Pattern B: ` common_async ` Module
@@ -52,23 +50,21 @@ Use `tmux_cmd_async()` for direct async command execution. Perfect for new async
5250``` python
5351>> > import asyncio
5452>> > from libtmux.common_async import tmux_cmd_async, get_version
55- >> >
56- >> > async def main ():
53+ >> > async def pattern_b_demo ():
5754... # Get tmux version
5855... version = await get_version()
59- ... print ( f " tmux version: { version } " )
56+ ... sock = server.socket_name
6057...
61- ... # Execute concurrent commands
58+ ... # Execute concurrent commands with isolated socket
6259... sessions, windows, panes = await asyncio.gather(
63- ... tmux_cmd_async(' list-sessions' ),
64- ... tmux_cmd_async(' list-windows' ),
65- ... tmux_cmd_async(' list-panes' ),
60+ ... tmux_cmd_async(' -L ' , sock, ' list-sessions' ),
61+ ... tmux_cmd_async(' -L ' , sock, ' list-windows' , ' -a ' ),
62+ ... tmux_cmd_async(' -L ' , sock, ' list-panes' , ' -a ' ),
6663... )
67- ... print (f " Sessions: { len (sessions.stdout)} , Windows: { len (windows.stdout)} , Panes: { len (panes.stdout)} " )
68- >> >
69- >> > asyncio.run(main()) # doctest: +SKIP
70- tmux version: ...
71- Sessions: ... , Windows: ... , Panes: ...
64+ ...
65+ ... return len (str (version)) > 0 and all (isinstance (r.stdout, list ) for r in [sessions, windows, panes])
66+ >> > asyncio.run(pattern_b_demo())
67+ True
7268```
7369
7470## Installation
@@ -91,13 +87,9 @@ Here's a practical example showing the performance benefit of async:
9187
9288``` python
9389>> > import asyncio
94- >> > import libtmux
95- >> >
9690>> > async def create_windows_async ():
9791... """ Create multiple windows concurrently (fast)."""
98- ... server = libtmux.Server()
99- ...
100- ... # Get or create session
92+ ... # Uses 'server' fixture from conftest
10193... result = await server.acmd(' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
10294... session_id = result.stdout[0 ]
10395...
@@ -109,13 +101,12 @@ Here's a practical example showing the performance benefit of async:
109101... server.acmd(' new-window' , ' -t' , session_id, ' -n' , ' logs' ),
110102... )
111103...
112- ... print (f " Created { len (results)} windows concurrently " )
113- ...
114104... # Cleanup
115105... await server.acmd(' kill-session' , ' -t' , session_id)
116- >> >
117- >> > asyncio.run(create_windows_async()) # doctest: +SKIP
118- Created 4 windows concurrently
106+ ...
107+ ... return len (results) == 4
108+ >> > asyncio.run(create_windows_async())
109+ True
119110```
120111
121112Compare this to sequential sync operations, which would be 2-3x slower.
@@ -136,11 +127,8 @@ Pattern A makes it easy to work with tmux objects asynchronously:
136127
137128``` python
138129>> > import asyncio
139- >> > import libtmux
140- >> >
141130>> > async def demo_objects ():
142- ... server = libtmux.Server()
143- ...
131+ ... # Uses 'server' fixture from conftest
144132... # Create session
145133... result = await server.acmd(' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
146134... session_id = result.stdout[0 ]
@@ -153,16 +141,20 @@ Pattern A makes it easy to work with tmux objects asynchronously:
153141... result = await server.acmd(' split-window' , ' -t' , window_id, ' -P' , ' -F#{pane_id} ' )
154142... pane_id = result.stdout[0 ]
155143...
156- ... print (f " Created session { session_id} , window { window_id} , pane { pane_id} " )
157- ...
158144... # Send keys to pane
159145... await server.acmd(' send-keys' , ' -t' , pane_id, ' echo "Hello from async!"' , ' Enter' )
160146...
161147... # Cleanup
162148... await server.acmd(' kill-session' , ' -t' , session_id)
163- >> >
164- >> > asyncio.run(demo_objects()) # doctest: +SKIP
165- Created session $ ... , window @ ... , pane % ...
149+ ...
150+ ... # Verify all IDs were created
151+ ... return all ([
152+ ... session_id.startswith(' $' ),
153+ ... window_id.startswith(' @' ),
154+ ... pane_id.startswith(' %' )
155+ ... ])
156+ >> > asyncio.run(demo_objects())
157+ True
166158```
167159
168160## Error Handling
@@ -172,20 +164,20 @@ Error handling works the same in async as in sync:
172164``` python
173165>> > import asyncio
174166>> > from libtmux.common_async import tmux_cmd_async
175- >> >
176167>> > async def demo_errors ():
168+ ... sock = server.socket_name
169+ ...
177170... # Invalid command
178- ... result = await tmux_cmd_async(' invalid-command' )
179- ... if result.stderr:
180- ... print (f " Error: { result.stderr[0 ]} " )
171+ ... result = await tmux_cmd_async(' -L' , sock, ' invalid-command' )
172+ ... has_error = len (result.stderr) > 0 and ' unknown command' in result.stderr[0 ]
181173...
182174... # Non-existent session
183- ... result = await tmux_cmd_async(' has-session' , ' -t' , ' non_existent ' )
184- ... print ( f " Return code: { result.returncode} " )
185- >> >
186- >> > asyncio.run(demo_errors()) # doctest: +SKIP
187- Error: unknown command: invalid - command
188- Return code: 1
175+ ... result = await tmux_cmd_async(' -L ' , sock, ' has-session' , ' -t' , ' non_existent_99999 ' )
176+ ... has_nonzero_return = result.returncode != 0
177+ ...
178+ ... return has_error and has_nonzero_return
179+ >> > asyncio.run(demo_errors())
180+ True
189181```
190182
191183## Performance: Sequential vs Concurrent
@@ -197,31 +189,31 @@ Here's a real-world example showing the performance difference:
197189>> > import time
198190>> > from libtmux.common_async import tmux_cmd_async
199191>> > from libtmux.common import tmux_cmd
200- >> >
201192>> > async def compare_performance ():
193+ ... sock = server.socket_name
194+ ...
202195... # Async (concurrent)
203196... start = time.time()
204197... await asyncio.gather(
205- ... tmux_cmd_async(' list-sessions' ),
206- ... tmux_cmd_async(' list-windows' ),
207- ... tmux_cmd_async(' list-panes' ),
208- ... tmux_cmd_async(' show-options' , ' -g' ),
198+ ... tmux_cmd_async(' -L ' , sock, ' list-sessions' ),
199+ ... tmux_cmd_async(' -L ' , sock, ' list-windows' , ' -a ' ),
200+ ... tmux_cmd_async(' -L ' , sock, ' list-panes' , ' -a ' ),
201+ ... tmux_cmd_async(' -L ' , sock, ' show-options' , ' -g' ),
209202... )
210203... async_time = time.time() - start
211204...
212205... # Sync (sequential)
213206... start = time.time()
214- ... tmux_cmd(' list-sessions' )
215- ... tmux_cmd(' list-windows' )
216- ... tmux_cmd(' list-panes' )
217- ... tmux_cmd(' show-options' , ' -g' )
207+ ... tmux_cmd(' -L ' , sock, ' list-sessions' )
208+ ... tmux_cmd(' -L ' , sock, ' list-windows' , ' -a ' )
209+ ... tmux_cmd(' -L ' , sock, ' list-panes' , ' -a ' )
210+ ... tmux_cmd(' -L ' , sock, ' show-options' , ' -g' )
218211... sync_time = time.time() - start
219212...
220- ... speedup = sync_time / async_time
221- ... print (f " Async: { async_time:.4f } s, Sync: { sync_time:.4f } s, Speedup: { speedup:.2f } x " )
222- >> >
223- >> > asyncio.run(compare_performance()) # doctest: +SKIP
224- Async: 0.0 ... s, Sync: 0.0 ... s, Speedup: ... x
213+ ... # Concurrent should be at least as fast (allow 10% variance)
214+ ... return async_time <= sync_time * 1.1
215+ >> > asyncio.run(compare_performance())
216+ True
225217```
226218
227219Typical speedup: ** 2-3x faster** for 4 concurrent commands.
@@ -232,30 +224,29 @@ You can mix both patterns in the same application:
232224
233225``` python
234226>> > import asyncio
235- >> > import libtmux
236227>> > from libtmux.common_async import tmux_cmd_async
237- >> >
238228>> > async def hybrid_example ():
239- ... server = libtmux.Server()
229+ ... # Uses 'server' fixture from conftest
230+ ... sock = server.socket_name
240231...
241232... # Pattern A: Use .acmd() on server
242233... result_a = await server.acmd(' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
243234... session_a = result_a.stdout[0 ]
244235...
245- ... # Pattern B: Use tmux_cmd_async directly
246- ... result_b = await tmux_cmd_async(' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
236+ ... # Pattern B: Use tmux_cmd_async directly with socket
237+ ... result_b = await tmux_cmd_async(' -L ' , sock, ' new-session' , ' -d' , ' -P' , ' -F#{session_id} ' )
247238... session_b = result_b.stdout[0 ]
248239...
249- ... print (f " Pattern A: { session_a} , Pattern B: { session_b} " )
250- ...
251240... # Both patterns work with asyncio.gather
252241... await asyncio.gather(
253242... server.acmd(' kill-session' , ' -t' , session_a),
254- ... tmux_cmd_async(' kill-session' , ' -t' , session_b),
243+ ... tmux_cmd_async(' -L ' , sock, ' kill-session' , ' -t' , session_b),
255244... )
256- >> >
257- >> > asyncio.run(hybrid_example()) # doctest: +SKIP
258- Pattern A: $ ... , Pattern B: $ ...
245+ ...
246+ ... # Verify both sessions were created and start with $
247+ ... return session_a.startswith(' $' ) and session_b.startswith(' $' )
248+ >> > asyncio.run(hybrid_example())
249+ True
259250```
260251
261252## Next Steps
0 commit comments