Python & subprocess - Open terminal session as user and execute one/two commands - python

As much as I hate regurgitating questions, it's a necessary evil to achieve a result to the next issue I'll present.
Using python3, tkinter and the subprocess package, my goal is to write a control panel to start and stop different terminal windows with a specific set of commands to run applications/sessions of the ROS application stack, including the core.
As such, the code would look like this per executable I wish to control:
class TestProc(object):
def __init__(self):
pass
def start(self):
self.process = subprocess.Popen(["gnome-terminal", "-c", "'cd /path/to/executable/script.sh; ./script.sh'"])
print("Process started.")
def stop(self):
self.process.terminate()
print("Process terminated.")
Currently, it is possible to start a terminal window and the assigned commands/processes, yet two issues persist:
gnome-terminal is set to launch a terminal window, then relieve control to the processes inside; as such, I have no further control once it has started. A possible solution for this is to use xterm yet that poses a slew of other issues. I am required to have variables from the user's .bashrc and/or export
Certain "global commands" eg. cd or roslaunch would be unavailable to the terminal sessions, perhaps due to the order of execution (eg. the commands are run before the bash profile is loaded) preventing any usable terminal at all
Thus, the question rings: How would I be able to start and stop a new terminal window that would run up to two commands/processes in the user environment?

There are a couple approaches you can take, the most flexible here is also the most complicated, so you'd want to consider whether you need to do it.
If you only need to show the output of the script, you can simply pipe the output to a file or to a named pipe. You can then capture that output by reading/tailing the file. This is simplest, as long as the script don't actually need to have any user interaction.
If you really only need to spawn a script that runs in the background, and you need to simulate user interaction but you don't actually need to accept actual user input, you can use expect approach (using the pexpect library).
If you need to actually allow the real user to interact with the program, then you have two approaches. First is that you can embed the VTE widget into your application, this is the most seamless integration as it'll make the terminal look seamless with your application, however it's also the most heavy.
Another approach is to start gnome-terminal as you've done here, this necessarily spawns a new window.
If you need to both script some interaction while also allowing some user input, you can do this by spawning your script in a tmux session. Using tmux send-keys command to automate the moon interactive part, and then spawn a terminal emulator for users to interact with tmux attach. If you need to go back and forth between automated part and interactive part, you can combine this approach with expect.

Related

How to catch a process in python?

I'm currently making a lil' launcher for PortableMu while in an internship.
We (company and I) modeled a special mode for the Mu-Editor and we are shipping it with PortableMu so that users don't need to install Mu and/or Python to use it.
The problem of PortableMu for Windows is, that you start it with a .bat and this doesnt give you any feedback.
You click, you wait ~1-2min and maybe Mu-Editor will popup.
This is not very userfriendly.
So my duty is to create a launcher.
My launcher is a simple thing: Only lil "welcome" a picture and a button to start PortableMu. It works on my private windows10.
Now I want to add in randomly picked messages for simulating "loading" which shall stop when the Mu-Editor pops up. Simply to bridge the time
Is there a method to catch when this happens?
Alas:
Can Python catch the moment when Windows opens the task/process for Mu-Editor?
If, how?
use the tasklist
subprocess.Popen('tasklist').comunicate()[0] will return all the tasks currently happening in windows, simply do this every minute or so and check for your task. There are ways to make this pass without a command window popping up, here's one that i use often
command =subprocess.Popen(["ping","-n","1","-w","100", str(ip)], stdout=subprocess.PIPE, shell=False, creationflags = 0x08000000)
reply = str(command.communicate()[0])

Python restart script in another cmd's window

is there a way to restart another script in another shell?
i have script that sometimes stuck waiting to read email from gmail and imap. from another script i would like to restart the main one but without stopping the execution of the second
i have tried:
os.system("C:\Users\light\Documents\Python\BOTBOL\Gmail\V1\send.py")
process = subprocess.Popen(["python", "C:\Users\light\Documents\Python\BOTBOL\Gmail\V1\send.py"])
but both run the main in the second's shell
EDIT:
sorry, for shell i mean terminal window
After your last comment and as the syntax show that you are using Windows, I assume that you want to launch a Python script in another console. The magic word here is START if you want that the launching execute in parallel with the new one, or START /W if you want to wait for the end of the subprocess.
In your case, you could use:
subprocess.call(["cmd.exe", "/c", "START", "C:\Path\To\PYTHON.EXE",
"C:\Users\light\Documents\Python\BOTBOL\Gmail\V1\send.py"])
Subprocess has an option called shell which is what you want. Os calls are blocking which means that only after the command is completed will the interpreter move to the next line. On the other hand subprocess popens are non blocking, however both these commands will spawn off child process from the process running this code. If you want to run in shell and get access shell features to execute this , try the shell = True in subprocess.
I could try and explain everything you need but I think this video will do it better: Youtube Video about multithreading
This will allow you to run 2 things f.e.
Have 1 run on checkin email and the other one on inputs so it wont stop at those moments and making multiple 'shelves' possible, as they are parallel.
If you really want to have a different window for this, i am sorry and I can not help.
Hope this was were you were looking for.

How do i pass on control on to different terminal tab using perl?

I am trying to automate a scenario in which, I have a terminal window open with multiple tabs open in it. I am able to migrate between the tabs, but my problem is how do i pass control to another terminal tab while i run my perl script in a different tab.
Example: I have a terminal open with Tab1,Tab2,Tab3,Tab4 open in the same terminal, i run the perl script in Tab3 and i would want to pass some commands onto Tab1. Could you please tell me how can i do this ??
I use GUI tool to switch between tabs X11::GUITest and use keyboard shortcuts to switch between tabs, any alternative suggestion is welcome, my ultimate aim is to pass control on to a different tab.
The main thing to understand is that each tab has a different instance of terminal running, more importantly a different instance of shell (just thought I would mention as it didnt seem like you were clear about that from your choice of words). So "passing control" in such a scenario could most probably entail inter-process communication (IPC).
Now that opens up a range of possibilities. You could, for example, have a python/perl script running in the target shell (tab) to listen on a unix socket for commands in the form of text, which the script can then execute. In Python, you have modules subprocess (call, Popen) and os (exec*) for this. If you have to transfer control back to the calling process, then I would suggest using subprocess as you would be able to send back return codes too.
Switching between tabs is a different action and has no consequences on the calling/called processes. And you have already mentioned how you intend on doing that.

How to unhide and show a process created with subprocess.popen()?

I am trying to create a simple command-line process and show it to the user (I do NOT want the process to be hidden):
import subprocess
import win32con
kwargs = {}
info = subprocess.STARTUPINFO()
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = win32con.SW_SHOWMAXIMIZED
ExecuteString = ('process.cmd')
kwargs['startupinfo'] = info
sp = subprocess.Popen(ExecuteString, **kwargs)
It works with e.g. notepad.exe but not with the simple process.cmd:
echo "This is a process run from python"
pause
I run out of ideas, how to achieve this. I find all kind of stuff, how to HIDE a process. But I want to achieve the opposite.
Any idea?
Thanks!
You seem to be confusing the notions of process and window. All windows are associated to a process, but a certain process may not be associated with any window.
Your simple batch script is interpreted from the cmd.exe process. If you're used to the behaviour of windows when you open batch scripts with a double-click, might believe cmd.exe is always associated with a window, but that is not true. You can check this yourself by simply running cmd.exe inside a existing command prompt - it doesn't open a new window (as running notepad.exe, for example, would).
In python, processes run "as if" they were run from a command prompt - which is why you don't get another window.
This doesn't actually answer the question, but it might be useful in understanding the problem.
For Windowed applications, you simply need to use the SW_HIDE constant instead of SW_SHOWMAXIMIZED.
If you also want to cover console applications that start up a terminal window, I'm guessing that you would want to run something like this:
start the process;
use EnumWindows();
in your EnumWindowsProc implementation, check for a top-level window (using GetParent()) that is owned by the process you just launched (use GetWindowThreadProcessId()).
This will allow you to find the top-level window(s) of the process you just launched. From there, you can call ShowWindow() to show/hide the Window.
Note that this may be subject to some timing issues (if your search runs before the child process can create its window, the search will yield no results) as well as flicker (because you'll hide the window after it displays).

Sending commands from one xterm window to another with Python

So I have a Python app that starts different xterm windows and in one window after the operation is finished it asks the user "Do you want to use these settings? y/n".
How can I send y to that xterm window, so that the user doesn't needs to type anything.
Thanks
If you are on linux (kde) and you just want to control the xterms by sending commands between them, you could try using dcop:
http://www.linuxjournal.com/content/start-and-control-konsole-dcop
http://www.riverbankcomputing.co.uk/static/Docs/PyKDE3/dcopext.html
Otherwise you would need to actually use an inter-process communication (IPC) method between the two scripts as opposed to controlling the terminals:
http://docs.python.org/library/xmlrpclib.html
http://docs.python.org/library/ipc.html
Some other IPC or RPC library
Simply listen on a basic socket and wait for ANYTHING. And then from the other app open a socket and write SOMETHING to signal.
Or at a very very basic level, you could have one script wait on file output from the other. So once your first xterm finishes, it could write a file that the other script sees.
These are all varying difficulties of solutions.

Categories