How to use subprocess to run a program without a window showing? - python

I am using subprocess.call() to programatically launch a software on my PC (the Meta Trader platform for forex trading, to be exact). The call works fine, the terminal is launched properly, however I now want to improve the experience by removing the popping up Meta Trader window. I know that in web scraping it is possible to use a headless browser, enabling that scraping be done without an actual(ly visible) web browser window showing on the screen. I was wondering if there is some way to achieve the same functionality using subprocess.call() (or else).

There doesn't seem to be built-in support on other platforms, but it's possible on Windows by passing a STARTUPINFO instance to the Popen constructor.
The following example starts the Notepad editor in the background. Its window is hidden, but the program is running as the Task Manager would show. Pressing Ctrl+C stops the program and terminates the background process.
import subprocess
from time import sleep
process = subprocess.Popen(
'notepad',
startupinfo=subprocess.STARTUPINFO(
dwFlags=subprocess.STARTF_USESHOWWINDOW,
wShowWindow=subprocess.SW_HIDE,
),
)
try:
while process.poll() is None:
sleep(1)
except KeyboardInterrupt:
process.kill()
Note that this may not work for more complex applications that start their own subprocesses, such as the Chrome browser to name but one example. One may then have to go through the Windows API in order to hide the application windows after they were created.

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 subprocess kill is working for "notepad.exe" but not working for "calc.exe"

OS: Windows 10
Python: 3.5.2
I am trying to open calc.exe do some actions and than close it.
Here is my code sample
import subprocess, os, time
p = subprocess.Popen('calc.exe')
#Some actions
time.sleep(2)
p.kill()
So this is not working for calc.exe, it just opens the calculator, but does not close it, But same code is working fine for "notepad.exe".
I am guessing that there is a bug in subprocess lib for process kill method. so the notepad.exe process name in task manager is notepad.exe, but the calc.exe process name is calculator.exe, so I am guessing it is trying to kill by name and do not find it.
There's no bug in subprocess.kill. If you're really worried about that, just check the source, which is linked from the docs. The kill method just calls send_signal, which just calls os.kill unless the process is already done, and you can see the Windows implementation for that function. In short: subprocess.Process.kill doesn't care what name the process has in the kernel's process table (or the Task Manager); it remembers the PID (process ID) of the process it started, and kills it that way.
The most likely problem is that, like many Windows apps, calc.exe has some special "single instance" code: when you launch it, if there's already a copy of calc.exe running in your session, it just tells that copy to come to the foreground (and open a window, if it doesn't have one), and then exits. So, by the time you try to kill it 2 seconds later, the process has already exited.
And if the actual running process is calculator.exe, that means calc.exe is just a launcher for the real program, so it always tells calculator.exe to come to the foreground, launching it if necessary, and then exits.
So, how can you kill the new calculator you started? Well, you can't, because you didn't start a new one. You can kill all calc.exe and/or calculator.exe processes (the easiest way to do this is with a third-party library like psutil—see the examples on filtering and then kill the process once you've found it), but that will kill any existing calculator process you had open before running your program, not just the new one you started. Since calc.exe makes it impossible to tell if you've started a new process or not, there's really no way around that.
This is one way to kill it, but it will close every open calculator.
It calls a no window command prompt and gives the command to close the Calculator.exe process.
import subprocess, os, time
p = subprocess.Popen('calc.exe')
print(p)
#Some actions
time.sleep(2)
CREATE_NO_WINDOW = 0x08000000
subprocess.call('taskkill /F /IM Calculator.exe', creationflags=CREATE_NO_WINDOW)

py2app application is working but Mac OS X shows it as not responding

I have a python script (no GUI) that spawns a child thread, while parent thread is preventing the app from finishing using this method:
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
pass
finally:
cleanup()
When I create an application from this script with py2app and run it, it is staying in Dock and working as expected, but when I right click, it shows that "Application Not Responding" (the same in Activity Monitor) and to finish it I can only select "Force Quit" which results in a crash report dialog afterwards.
Why is it not responding and, if the reason is sleep(), how can I keep the app open without it?
It's showing as "not responding" because it's not responding. An application on OS X (as opposed to just a plain "Unix executable"/script, agent, or daemon) has to respond to messages from the operating system.
Normally, you do this by using a Cocoa run loop. PyObjC offers some high-level helpers that make it even simpler, or just lets you access the same Cocoa methods that the Apple docs describe from Python.
Another option is to use a script-wrapper that just runs your script while maintaining a run loop (with or without a GUI) for you.
Finally, do you actually need to be an application in the first place?

How to open an application in Python, and then let the rest of the script run?

I have been trying to create a script which reloads a web browser called Midori if the internet flickers. But, it seems only to work if I open Midori through the CLI - otherwise, the program crashes after I reload it. I have decided that the best idea is thus to have the script open Midori through the subprocess module. So, I put this as one of the first arguments in my code:
import subprocess as sub
sub.call(["midori"])
The browser opens, but the rest of the program freezes until I quit Midori. I have tried to use threading, but it doesn't seem to work.
Is there any way to open an application through Python, and then let the rest of the script continue to run once said application has been opened?
From the docs:
Run the command described by args. Wait for command to complete, then return the returncode attribute.
(Emphasis added)
You can see this is the behaviour we should expect. To get around this, use subprocess.Popen instead. This will not block in the same way:
from subprocess import Popen
midori_process = Popen(["midori"])

GUI program with toggable console?

I've seen some apps allow you to show/hide the console when you need to read log messages. For example Blender3D allows that (blender.org).
I was wondering if this can be done in Python and how.
My main window is a Panda3D (panda3d.org) window.
I've read somewhere that one option is to hide the "real" console (pythonw) and create another console and just redirect everything from the "real" one to it, every time you want to "show" the "real" console. No idea how this can be done.
Or at least a way to choose whether to start the program with the console or without it by reading a configuration file or something.
I'm assuming you are talking about Windows because this console toggling in blender is Windows exclusive. I'm guessing Blender uses GetConsoleWindow and ShowWindow on Windows.
This is how you could do it in python with pywin32:
import win32gui, win32console, win32api, win32con
import time
console_window = win32console.GetConsoleWindow()
time.sleep(1)
win32gui.ShowWindow(console_window, win32con.SW_HIDE)
time.sleep(1)
win32gui.ShowWindow(console_window, win32con.SW_SHOW)
time.sleep(1)
If you run this program with python and not pythonw it will show the console, sleep for a second, hide the console, sleep for another second and then hide it again.
Mind that this code only works on Windows. On other platforms silly stuff like this is not necessary because if you want a program to show a console then you run it from the console.

Categories