tmux-python / libtmux Goto Github PK
View Code? Open in Web Editor NEW⚙️ Python API / wrapper for tmux
Home Page: https://libtmux.git-pull.com
License: MIT License
⚙️ Python API / wrapper for tmux
Home Page: https://libtmux.git-pull.com
License: MIT License
When I use the library to split window, I use win.cmd('split-window', '-h')
which let me spend a lot of time.
At last, I suggest to use bash script instead of this library.
#!/usr/bin/env python3
# coding=utf-8
# author: thinkycx
# date: 2018-01-11
# Usage:
# run several commands in tmux panel, every window have 4 panes
# $ pip3 install libtmux
# $ python tmux.py
import libtmux
import math
import os
import logging
def create_session(session_name, commands):
'''
create session with 2*2 panes and run commands
:param session_name: tmux session name
:param commands: bash commands
:return:
'''
logging.info(commands)
# pane_NUM = 3
# WINDOW_NUM = int(math.ceil(len(commands)/4.0)) # in python3, we can use 4 also
server = libtmux.Server()
session = server.new_session(session_name)
# create windows
windows = []
panes = []
for i in range(len(commands)):
# create window to store 4 panes
if i % 4 == 0:
win = session.new_window(attach=False, window_name="win"+str(int(i/4)))
windows.append(win)
# tmux_args = ('-h',)
win.cmd('split-window', '-h')
win.cmd('split-window', '-f')
win.cmd('split-window', '-h')
panes.extend(win.list_panes())
panes[i].send_keys(commands[i])
logging.info(panes)
logging.info(windows)
if __name__ == '__main__':
commands = []
for i in range(10):
commands.append("echo " + str(i))
os.system("tmux kill-session -t session")
create_session("session", commands)
At https://libtmux.git-pull.com/about.html one reads the following
What is a {pane,window}_index vs a {pane,window,session}_id?
Pane index refers to the order of a pane on the screen.
Window index refers to the # of the window in the session.
It is hard to read.
The first thing is I took {x,y} automatically to mean a pair and {x,y,z} to mean a triple.
The second thing is you mention _index
vs _id
and then you refer to both with index? After reading this I still do not now which is which.
seems like the window.kill_pane()
function is missing?
What is the recommended way to close a pane?
Hi 👊
This is my first visit to this fine repo, but it seems you have been working hard to keep all dependencies updated so far.
Once you have closed this issue, I'll create separate pull requests for every update as soon as I find one.
That's it for now!
Happy merging! 🤖
Hello. I need to run this on Django. My django has his own virtual enviroment. I'm trying to start another python project (with his own virtual enviroment)in a tmux pane.
I've tried to run source venv/bin/activate inside pane, but seems like it's locked to actual running python virtual enviroment.
This is my code:
def startproc(path): tmux = libtmux.Server() session = tmux.new_session('myproc', True, False, path) pane = session.attached_pane cmd = pane.send_keys('source ../venv/bin/activate') cmd = pane.send_keys('python __main__.py start') return cmd
Paths are OK.
When i connect to the tmux via terminal, i see an import error, since virtual enviroment isn't loaded.
If i try the exact same commands in tmux without python, everythings works ok.
I any way to fix this?
Thank you!
Steps to reproduce:
test_tmux.py
import libtmux
import pytest
@pytest.fixture
def server():
server = libtmux.Server()
return server
def test_can_start_tmux_session(server):
server.new_session("test")
assert server.has_session("test")
server.kill_session("test")
Dockerfile:
FROM ubuntu:18.04
RUN apt-get update && apt install -y tmux python-pip
RUN pip install libtmux pytest
COPY test_tmux.py .
RUN pytest test_tmux.py
then docker build .
fails with
if 'session_id' not in kwargs:
> raise ValueError('Session requires a `session_id`')
E ValueError: Session requires a `session_id`
Interestingly, replacing 'ubuntu:18.04' with 'python:3.7-slim' works. I thought this might mean it was an issue with the apt version of pip (which I know is dodgy), but adding a 'pip install --upgrade pip' didn't help.
Restructure how commands are passed in
This will probably be by creating a command factory where the command is built, then an execute() for it. But to the user in a tmux object, .cmd
should still execute immediately, _cmd()
could leave an object where the user can see the exact command tmux is running before hand.
There should be more options to toggle debug settings
tmux from MacPorts (on macOS 10.12.6), recently updated to tmux 2.5.
Tmuxp erroneously reports the session already exists when trying to load the session.
Some light debugging points to libtmux/server.py:Server.has_sessions() does not account for 'tmux has-session' now responds with 'no current session'.
Hi,
The following test:
def test_show_option_unknown(session):
"""Session.show_option raises UnknownOption for invalid option."""
with pytest.raises(exc.UnknownOption):
session.show_option('moooz')
in tests/test_session.py
fails because my version of tmux (3.1b) prints "invalid option: moooz" when given an invalid option.
I have no easy way to test whether tmux 2's behaviour was to throw an "unknown option" instead.
I don't know how you want to fix this. Shall we throw a UnknownOption to maintain backwards compatibility (is any one try...excepting for this specifically anyway ?) Shall we remove this test now that tmux has changed its ways ?
File "/home/gabriel/.local/lib/python3.5/site-packages/libtmux/server.py", line 426, in new_session
if self.has_session(session_name):
File "/home/gabriel/.local/lib/python3.5/site-packages/libtmux/server.py", line 326, in has_session
proc = self.cmd('has-session', '-t%s' % target_session)
File "/home/gabriel/.local/lib/python3.5/site-packages/libtmux/server.py", line 100, in cmd
return tmux_cmd(*args, **kwargs)
File "/home/gabriel/.local/lib/python3.5/site-packages/libtmux/common.py", line 153, in __init__
cmd = [which('tmux')]
File "/home/gabriel/.local/lib/python3.5/site-packages/libtmux/common.py", line 398, in which
logger.trace(
AttributeError: 'Logger' object has no attribute 'trace'
It seems libtmux uses a non-existing trace
method on the logger to log the error. It's probably easy to forget to test this codepath ;)
Hello! I have a python script that is running inside of a tmux session. This runs and creates a tmux session. However when I run it everything works great except the new session is created on a seperate tmux server. When I run ps -e | grep tmux
I have 1 instance of a tmux: client and two tmux: server. Is there any solution to this? Could I give the PID to the Server() function to have it connect like that?
I'm getting the error ModuleNotFoundError: No module named 'libtmux' when trying to run. I definitely have the module installed but still get the error.
Has anyone else had this issue?
I noticed that libtmux sends keys to a window pane literally. A minimal reproduction:
import libtmux
server = libtmux.Server()
session = server.new_session('happy_session')
window = session.new_window('happy_window')
pane = window.attached_pane
# instead of KeyboardInterrupt, libtmux sends 'C-c'
pane.send_keys('C-c')
tmux uses -l
to specifiy if the keys are to be sent literally:
# not literally
tmux send-keys -t happy_session C-c
# literally
tmux send-keys -l -t happy_session C-c
It would be nice if there were an option to override this behavior in libtmux and preferably set as defaults Pane.send_keys(literal=False)
just as in tmux.
This could have a potential break in the API, commands would be required to have .execute()
to run.
On the other hand, you would be able to view and even alter the raw string output of the command before running it. Highly valuable for debugging.
But it gets better, this could allow the use of chained commands separated by semicolons. This could substantially improve the performance of libtmux and tmuxp downstream.
Any feedback would be appreciated. I don't like breaking API's, but this seems like one that could be worth the investment.
I really like the look of this project. However, for something that I need to do, I need to be able to send a modifier key, Ctrl to be exact.
I've tried a few different things and I'll continue looking around for a solution, but I figured I would post an issue here in case this is not currently possible.
The tmux respawn-pane command changed the tty of the pane, but pane['pane_tty'] stays the same before and after the respawn-pane.
print(cmd_daemux.pane['pane_tty'])
cmd_daemux.pane.cmd('respawn-pane', '-k', cmd_daemux.cmd)
print(cmd_daemux.pane['pane_tty'])
I'm running tmux 2.7 on ArchLinux
It's use logging
in function __init__
of Class tmux_cmd
logging.debug('self.stdout for %s: \n%s' % (' '.join(cmd), self.stdout))
The tmux tests will raise "no current client" because we are raising exceptions if stderr is returned.
https://github.com/tmux-python/libtmux/blob/v0.8.0/libtmux/session.py#L128
Related links:
Hello,
Is it possible to create a new session using this module?
At the moment i have to do a os.system("tmux -S {0}/tmux new -s netcat -d".format(locatie))
to create a new session on a socket. when it seems like libtmux.Server("netcat", "{0}/tmux".format(locatie))
doesnt create a session.
Hello, i am trying to run the code either from
#170 or from documentation
but in both cases i can't see any window is created. Code is executing without errors but there are just no windows / GUI.
Am i doing something wrong or i am missing some dependencies or something else... I don't have installed ptpython, but it's optional as far as i understood.
In tmux_cmd https://github.com/tony/libtmux/blob/189114cde7e125a482ab984749637fa44d66b284/libtmux/common.py#L132
the func receives args and kwargs but only args are added to form the cmd str
https://github.com/tony/libtmux/blob/189114cde7e125a482ab984749637fa44d66b284/libtmux/common.py#L176
Here is some IPDB output showing this, from tracking down tmux-python/tmuxp#184
# Reach tmux_cmd() with args and kwargs
> /usr/local/var/pyenv/versions/2.7.11/lib/python2.7/site-packages/libtmux/server.py(99)cmd()
97 raise ValueError('Server.colors must equal 88 or 256')
98
---> 99 return tmux_cmd(*args, **kwargs)
100
101 def _list_sessions(self):
ipdb> args
self = <libtmux.server.Server object at 0x10fd11350>
args = [u'-2', 'set-environment', 'FOO', 'bar']
kwargs = {u'-t': u'$8'}
# Reach cmd and kwargs not included
ipdb>
> /usr/local/var/pyenv/versions/2.7.11/lib/python2.7/site-packages/libtmux/common.py(179)__init__()
177 cmd = [str(c) for c in cmd]
178
--> 179 self.cmd = cmd
180
181 try:
ipdb> cmd
['/usr/local/bin/tmux', '-2', 'set-environment', 'FOO', 'bar']
So this seems pretty big; any command using tmux_cmd would apply in the current session instead of the target session. Maybe it hasn't been noticed since a common use case isn't use tmuxp inside of an existing TMUX session?
The bot created this issue to inform you that pyup.io has been set up on this repo.
Once you have closed it, the bot will open pull requests for updates as soon as they are available.
We're looking for some people to help with spare time, issues, QA'ing, and general maintenance. Answer in the tmuxp issue if you're available to help out!
assert s.show_options('default-shell', g=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../libtmux/libtmux/session.py:374: in show_options
return self.show_option(option, g=g)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Session($1 libtmux_XxTayh), option = [], g = True
def show_option(self, option, g=False):
"""Return a list of options for the window.
:todo: test and return True/False for on/off string
:param option: option to return.
:type option: string
:rtype: string, int or bool
"""
tmux_args = tuple()
if g:
tmux_args += ('-g',)
option = self.cmd(
'show-options', option, *tmux_args
).stdout
> option = [tuple(item.split(' ')) for item in option][0]
E IndexError: list index out of range
Have a raise=False
argument. If not raising, return None
.
I'd love to be able to have an application spying on a tmux session and waiting for particular things to happen (particularly, subprocesses ending, panes closing). To do this concurrently though the API would have to be non-blocking. Is this a possibility?
Creating new-windows/sessions can -P
updated information as of recent tmux versions.
As of right now, the refreshing of session/window/pane information isn't very performant. There is room to refactor safely since the test bed has good coverage
While running in tmux session 0, window 3, I run a script with the following contents:
MWE:
import libtmux as tmux
t = tmux.Server()
sess = t.new_session('uut')
win0 = sess.select_window(0)
Expected Result: tmux session 'uut' has window 0 selected, and a handle to it is returned in win0
Actual Result: tmux session 0 switches to window 0, but win0 is also a handle to window 0 in session 'uut'.
Relevant configuration: macOS 10.14
tmux: 2.4
python: 2.7.15 and 3.7.0 (issue occurs in both)
libtmux: cloned from pypi on 16 Nov. 2018.
Due to this issue we cannot have any args with -t
in them. A quick workaround would be to check for -t
with ==
instead of in
. Like this ->
if not any('-t' == text_type(x) for x in args):
This will not affect any args like variable-temp
...
Allow use of capture_pane
as a property and automatically return stdout.
>>> import libtmux
>>> server = libtmux.Server()
>>> server.findWhere({'session_name': 'foo'})
Session($5 foo)
>>> session = server.findWhere({'session_name': 'foo'})
>>> session.attached_pane().cmd('capture-pane', '-p').stdout
[u' ______________________________________________________________', u'/ A light wife doth make a heavy husband. \\', u'\\ -- Wm. Shakespeare, "The Merchant of Venice" /', u' --------------------------------------------------------------', u' \\ ^__^', u' \\ (oo)\\_______', u' (__)\\ )\\/\\', u' ||----w |', u' || ||', u'~', u'\u276f']
Calling the attached_sesssions
method of a Server
object raises the following exception:
In [20]: import libtmux
In [21]: server = libtmux.Server()
In [22]: server.attached_sessions
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-22-aee9c49879f2> in <module>()
----> 1 server.attached_sessions
/dccstor/faceid/code/anaconda3/x86_64/envs/mxnet/lib/python2.7/site-packages/libtmux/server.pyc in attached_sessions(self)
336 if 'session_attached' in session:
337 # for now session_active is a unicode
--> 338 if session.attached == '1':
339 logger.debug('session %s attached', session.name)
340 attached_sessions.append(session)
AttributeError: 'dict' object has no attribute 'attached'
Seems that line 338
above expects an object of type Session
while it is actually a dict
.
Using libtmux=0.81
and python=2.7
Its very valuable to know that you can have a window object and automatically be entering commands within the -t
(target) context.
From tmux manual:
This section contains a list of the commands supported by tmux. Most
commands accept the optional -t argument with one of target-client,
target-session target-window, or target-pane. These specify the
client, session, window or pane which a command should affect.
target-client is the name of the pty(7) file to which the client is
connected, for example either of /dev/ttyp1 or ttyp1 for the client
attached to /dev/ttyp1. If no client is specified, the current client
is chosen, if possible, or an error is reported. Clients may be listed
with the list-clients command.
target-session is the session id prefixed with a $, the name of a ses‐
sion (as listed by the list-sessions command), or the name of a client
with the same syntax as target-client, in which case the session
attached to the client is used. When looking for the session name,
tmux initially searches for an exact match; if none is found, the ses‐
sion names are checked for any for which target-session is a prefix or
for which it matches as an fnmatch(3) pattern. If a single match is
found, it is used as the target session; multiple matches produce an
error. If a session is omitted, the current session is used if avail‐
able; if no current session is available, the most recently used is
chosen.
target-window specifies a window in the form session:window. session
follows the same rules as for target-session, and window is looked for
in order: as a window index, for example mysession:1; as a window ID,
such as @1; as an exact window name, such as mysession:mywindow; then
as an fnmatch(3) pattern or the start of a window name, such as myses‐
sion:mywin* or mysession:mywin. An empty window name specifies the
next unused index if appropriate (for example the new-window and
link-window commands) otherwise the current window in session is cho‐
sen. The special character ‘!’ uses the last (previously current) win‐
dow, ‘^’ selects the highest numbered window, ‘$’ selects the lowest
numbered window, and ‘+’ and ‘-’ select the next window or the previous
window by number. When the argument does not contain a colon, tmux
first attempts to parse it as window; if that fails, an attempt is made
to match a session.
target-pane takes a similar form to target-window but with the optional
addition of a period followed by a pane index, for example: myses‐
sion:mywindow.1. If the pane index is omitted, the currently active
pane in the specified window is used. If neither a colon nor period
appears, tmux first attempts to use the argument as a pane index; if
that fails, it is looked up as for target-window. A ‘+’, ‘-’ or ‘!’
indicate the next, previous or last pane. One of the strings top,
bottom, left, right, top-left, top-right, bottom-left or bottom-right
may be used instead of a pane index.
The special characters ‘+’ and ‘-’ may be followed by an offset, for
example:
select-window -t:+2
When dealing with a session that doesn't contain sequential window
indexes, they will be correctly skipped.
Deprecation warnings are raised due to invalid escape sequences. This can be fixed by using raw strings or escaping the literals. pyupgrade also helps in automatic conversion : https://github.com/asottile/pyupgrade/
find . -iname '*.py' | grep -v example | xargs -P4 -I{} python3.8 -Wall -m py_compile {}
./libtmux/pane.py:156: DeprecationWarning: invalid escape sequence \;
self.cmd('send-keys', '-R \; clear-history')
./libtmux/common.py:236: DeprecationWarning: invalid escape sequence \_
"""Base: :py:class:`collections.MutableMapping`.
Love the work you've put into this!
There one thing bothering me, however, couldn't find it in the docs ... is it currently possible to create a new server? When I do, I get a no such file or directory
-error pointing to the path of the (supposed socket).
Thanks,
Sam
It would be great to be able to use the pypi tarball for packaging (on Arch Linux). Unfortunately the tests are missing. Please add them! :)
When using tmux on the command-line, I can get the current session by running tmux ls
.
It would be useful if libtmux could do the same.
The suggested approach of using server.list_sessions()[0]
does not work. It returns whichever session is at the top of tmux's listing, not necessarily the current one.
I'm trying to expand the capture_pane
functionality.
I'm using libtmux master on python3.7 with tmux 3.0 -
The following snippet hangs on some panes, while the same command works when run from bash;
>>> import libtmux; s = libtmux.Server(); s.children[0].children[0].children[1].cmd("capture-pane", '-p', '-J', '-e', '-E-', '-S-').stdout
<omitted command noise>
DEBUG: ['/etc/profiles/per-user/myuser/bin/tmux', 'capture-pane', '-t', '%4', '-p', '-J', '-e', '-E-', '-S-']
<no output till ^C>
(I added some simple print debugging.)
list-panes
gives the following:
$ tmux list-panes -t 0:
0: [135x17] [history 1952/2000, 939964 bytes] %0
1: [135x17] [history 928/2000, 431099 bytes] %4
2: [135x21] [history 1869/2000, 1194568 bytes] %5
3: [135x21] [history 0/2000, 0 bytes] %7
4: [271x13] [history 1816/2000, 269415 bytes] %1 (active)
5: [271x12] [history 6/2000, 1537 bytes] %132
The hang only seems to happen if I pass the -S-
argument.
P.S.: previously at tmux-python/tmuxp#529
When a new session is created via the tmux new-session -t "name" command and a session with that name already exists, a new group will be created with both the original and the new session as members or the new session will be added to the already existing group. This is useful when you want to attach a window within the original session without actually changing the selected window of the original session. Let this new session be called clone session.
Now my approach of getting the name of the 'clone' session would be to filter sessions by group id, but group ids are currently not featured in the server.list_sessions() call, thus it would be nice if this could be added.
Building on that, a call to 'clone' a session with the option of implicit renaming could be implemented.
I created a tmux session called 'minecraft' and a window named 'server' manually. also there's a 'bash' window. anything i do to search panes or show _panes or list_panes() or attached_pane gives the same error:
>>> import libtmux
>>>
>>> tmux = libtmux.Server()
>>> ses = tmux.find_where({'session_name': 'minecraft'})
>>> win = ses.find_where({'window_name': 'server'})
>>> win
Window(@1 1:server, Session($0 minecraft))
>>> win.attached_pane
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/libtmux/window.py", line 441, in attached_pane
for pane in self._panes:
File "/usr/local/lib/python2.7/dist-packages/libtmux/window.py", line 466, in _panes
return self._list_panes()
File "/usr/local/lib/python2.7/dist-packages/libtmux/window.py", line 455, in _list_panes
p for p in panes if p['session_id'] == self.get('session_id')
KeyError: u'session_id'
>>>
In my daily work, I need to run tens of command repeatedly, So it will be better to load the command from file into the copy buffer, then I could just select the command to run, instead of copy/paste from my file.
HI,
Did i miss something ?
This little script works with the python console, but display the 'send_keys' parameter instead of executing it.
bash-4.4$ cat test.py
import libtmux
tmux_session_name = 'test'
server = libtmux.Server()
session = server.new_session(tmux_session_name)
window = session.attached_window
pane = window.split_window(shell='PROMPT_COMMAND= bash --norc --noprofile')
pane.send_keys('cowsay hello')
print('\n'.join(pane.cmd('capture-pane', '-p').stdout))
bash-4.4$
bash-4.4$ python test.py
bash-4.4$ cowsay hello
bash-4.4$
bash-4.4$ pkill tmux
bash-4.4$
bash-4.4$ python
Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import libtmux
>>> tmux_session_name = 'test'
>>> server = libtmux.Server()
>>> session = server.new_session(tmux_session_name)
>>> window = session.attached_window
>>> pane = window.split_window(shell='PROMPT_COMMAND= bash --norc --noprofile')
>>> pane.send_keys('cowsay hello')
>>> print('\n'.join(pane.cmd('capture-pane', '-p').stdout))
bash-4.4$ cowsay hello
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
bash-4.4$
>>>
bash-4.4$
Regards,
Every thing works as expected but sending escape sequences with "send_keys" method for setting the pane title where "p" is the pane object:
p.send_keys("printf '\033]2;" + names[i] + "\033\\'")
when I do the same in a shell script with:
tmux send-keys -t 0 " printf '\033]2;%s\033\\' 'A'" C-m
it works as expected. How to do it with libtmux?
For some odd reason there is no "rename-pane" like "rename-window" in tmux.
I ran into the issue described in #36, and I've managed to track down the cause/a reproduction scenario. I initially posted this as a reply to that issue, but later noticed that it is preferred to create a new issue instead (according to the stale bot), so I've moved it here.
I started a new tmux server instance, and from the first window, I launched a new-window with a command with a newline in it: tmux new-window -t :2 -k $'echo foo\nread'
. I then switched back to the first window, and ran the following in Python:
>>> import libtmux
>>> libtmux.__version__
'0.8.2'
>>> tmux = libtmux.Server()
>>> tmux.find_where({'session_name': '0'}).find_where({'window_name': 'python'}).attached_pane
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/maienm/.asdf/installs/python/utils/lib/python3.8/site-packages/libtmux/window.py", line 490, in attached_pane
for pane in self._panes:
File "/home/maienm/.asdf/installs/python/utils/lib/python3.8/site-packages/libtmux/window.py", line 514, in _panes
return self._list_panes()
File "/home/maienm/.asdf/installs/python/utils/lib/python3.8/site-packages/libtmux/window.py", line 506, in _list_panes
panes = [p for p in panes if p['session_id'] == self.get('session_id')]
File "/home/maienm/.asdf/installs/python/utils/lib/python3.8/site-packages/libtmux/window.py", line 506, in <listcomp>
panes = [p for p in panes if p['session_id'] == self.get('session_id')]
KeyError: 'session_id'
>>> tmux._update_panes()._panes
[{'session_name': '0', 'session_id': '$0', 'window_index': '1', 'window_id': '@0', 'window_name': 'python', 'history_size': '137', 'history_limit': '100000', 'history_bytes': '100636', 'pane_index': '1', 'pane_width': '240', 'pane_height': '66', 'pane_title': 'HOSTNAME', 'pane_id': '%0', 'pane_active': '1', 'pane_dead': '0', 'pane_in_mode': '0', 'pane_synchronized': '0', 'pane_tty': '/dev/pts/41', 'pane_pid': '337481', 'pane_current_path': '/home/maienm', 'pane_current_command': 'python', 'cursor_x': '0', 'cursor_y': '65', 'scroll_region_upper': '0', 'scroll_region_lower': '65', 'alternate_on': '0', 'alternate_saved_x': '0', 'alternate_saved_y': '0', 'cursor_flag': '1', 'insert_flag': '0', 'keypad_cursor_flag': '0', 'keypad_flag': '0', 'wrap_flag': '1', 'mouse_standard_flag': '0', 'mouse_button_flag': '0', 'mouse_any_flag': '0'}, {'session_name': '0', 'session_id': '$0', 'window_index': '2', 'window_id': '@2', 'window_name': 'zsh', 'history_size': '0', 'history_limit': '100000', 'history_bytes': '0', 'pane_index': '1', 'pane_width': '240', 'pane_height': '66', 'pane_title': 'HOSTNAME', 'pane_id': '%2', 'pane_active': '1', 'pane_dead': '0', 'pane_in_mode': '0', 'pane_synchronized': '0', 'pane_tty': '/dev/pts/42', 'pane_pid': '338918', 'pane_start_command': 'echo foo'}, {'session_name': 'read', 'window_index': '/home/maienm', 'window_id': 'zsh', 'window_name': '0', 'history_size': '1', 'history_limit': '0', 'history_bytes': '65', 'pane_height': '0', 'pane_title': '0', 'pane_id': '0', 'pane_active': '1', 'pane_dead': '0', 'pane_in_mode': '0', 'pane_synchronized': '0', 'pane_tty': '1', 'pane_pid': '0', 'pane_start_command': '0', 'pane_start_path': '0', 'pane_current_path': ''}]
It looks like the newline in pane_start_command causes the information for the second window to be broken into two dictionaries, each with part of the information.
I also tried this with a directory that contains a newline, which didn't result in an error, but did result in two panes with incorrect information (there was only one pane in this case):
[{'session_name': '0', 'session_id': '$0', 'window_index': '1', 'window_id': '@0', 'window_name': 'python', 'history_size': '3', 'history_limit': '100000', 'history_bytes': '2832', 'pane_index': '1', 'pane_width': '240', 'pane_height': '66', 'pane_title': 'HOSTNAME', 'pane_id': '%0', 'pane_active': '1', 'pane_dead': '0', 'pane_in_mode': '0', 'pane_synchronized': '0', 'pane_tty': '/dev/pts/41', 'pane_pid': '18834', 'pane_current_path': '/home/maienm/foo'}, {'session_name': 'bar', 'session_id': 'python', 'window_index': '0', 'window_id': '10', 'window_name': '0', 'history_size': '65', 'pane_index': '0', 'pane_width': '0', 'pane_height': '0', 'pane_title': '1', 'pane_id': '0', 'pane_active': '0', 'pane_dead': '0', 'pane_in_mode': '1', 'pane_synchronized': '0', 'pane_tty': '0', 'pane_pid': '0'}]
I get the above deprecation warning when importing libtmux
import libtmux
File "env/lib/python3.8/site-packages/libtmux/__init__.py", line 16, in <module>
from .pane import Pane
File "env/lib/python3.8/site-packages/libtmux/pane.py", line 13, in <module>
from .common import TmuxMappingObject, TmuxRelationalObject
File "env/lib/python3.8/site-packages/libtmux/common.py", line 221, in <module>
class TmuxMappingObject(collections.MutableMapping):
File "/usr/lib/python3.8/collections/__init__.py", line 49, in __getattr__
warnings.warn("Using or importing the ABCs from 'collections' instead "
DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working
Works from terminal:
tmux send-key -t 0 Enter
->
user@host$
user@host$
Doesn't work in libtmux:
>>> import libtmux
>>> pane = libtmux.Server().get_by_id('$1').attached_pane
>>> pane
Pane(%5 Window(@4 2:a, Session($1 foo)))
>>> pane.send_keys('Enter')
->
user@host$ Enter
Enter: command not found
up. oh, #13 -_-
For all objects passing "-t" somewhere in the cmd overrides the object being referenced.
This breaks running commands that have -t in them (e.g. ssh).
pane.cmd('respawn-pane', 'ssh', '-t', 'user@host')
(See also tmux-python/tmuxp#264)
This project is currently licensed BSD 3-Clause. Apologies if this causes any interruption.
I would like to relicense the project under MIT. If you agree to licensing your contribution(s) to libtmux under the MIT license, please reply.
Python 3.6.1 (default, Aug 23 2017, 20:07:59)
[GCC 5.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import libtmux
>>> server = libtmux.Server()
>>> server.new_session(session_name="pa")
Session($0 pa)
>>> session = server.find_where({"session_name":"pa"})
>>> session
Session($0 pa)
>>> session.new_window(window_name="telegram")
Window(@1 1:telegram, Session($0 pa))
>>> window = session.find_where({"window_name":"telegram"})
>>> window
>>> window is None
True
Explicitly calling rename_window
works:
>>> session.windows[1].rename_window("telegram")
Window(@1 1:telegram, Session($0 pa))
>>> session.find_where({"window_name":"telegram"})
Window(@1 1:telegram, Session($0 pa))
But not when called "too soon":
>>> window=session.new_window(); window.rename_window("test")
Window(@2 2:aragaer@netbook:~/Projects/pa/router, Session($0 pa))
>>> session.find_where({"window_name":"test"})
I don't see any errors in logging or tmux stderr. However windows are not actually renamed - tmux list-windows
shows generic names.
Trying to manually run the command I'm getting the following error:
/usr/bin/tmux new-window -P -c/home/aragaer/Projects/pa/tg -F"#{session_name}#{session_id}#{window_id}#{window_name}#{window_width}#{window_height}#{window_layout}#{window_panes}#{window_index}#{window_flags}#{window_active}#{window_bell_flag}#{window_activity_flag}#{window_silence_flag}" -ntelegram -t$0:
can't find session bash
Using tmux with Python means we lose the ability to interact with tmux. libtmux is a great tool, though currently my biggest worry is that I create a bunch of sessions, windows and panes.
Exiting out of panes is easy, since if you do && exit
at the end of the command you execute it closes that terminal and hence closes that pane.
However, I find that there is no easy way to close windows or sessions. Im currently contemplating writing my own script with some simple logic like...
if does_window_contain_pane(window-number) == False:
tmux kill-window -t window-number
if session_contains_windows(sesh) == False:
tmux kill-session -t sesh
Think this is possible to implement? I have noticed a lot of scripts floating around trying to accomplish this. It would make libtmux all the more powerful and all the helper scripts obsolete.
Thanks for the great tool!!
Hi, thanks for this library.
In tmux we can create a new window and immediately run a command in it using:
tmux new-session -d -s cool_session
tmux new-window -t cool_session -n fun_window "echo kills fun_window after 5s && sleep 5"
This is useful when one wants the window to automatically kill itself once the command has finished running.
It would be nice to have this feature in libtmux as well. Maybe an optional parameter like Session.new_window(cmd=None)
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.