How to avoid console window with .pyw file containing os.system call?
Asked Answered
H

6

14

If I save my code files as .pyw, no console window appears - which is what I want - but if the code includes a call to os.system, I still get a pesky console window. I assume it's caused by the call to os.system. Is there a way to execute other files from within my .pyw script without raising the console window at all?

Hysell answered 19/11, 2009 at 17:28 Comment(3)
Related: Running a process in pythonw with Popen without a consoleRacial
I believe os.system() opens a NEW cmd process. Try os.execl() to REPLACE the new cmd process with your pythonw.exe process.Forecast
I am experiencing this behavior in Python 3.11.1 without the usage of os.system. Must stem from logging, telnetlib, tkinter, threading, or winsound.Timothy
J
6

You could try using the subprocess module (subprocess.Popen, subprocess.call or whatever) with the argument shell=True if you want to avoid starting a console window.

Jubilation answered 19/11, 2009 at 17:31 Comment(7)
subprocess.check_call makes a good replacement for os.system in this case.Mckibben
Be sure to set subprocess.check_call(args, shell=True) where args is the command string that you would ordinarily type in a console. I'm not sure why shell=True is needed when I don't want a console to appear, but that's what occurred in my experiment.Yippee
Indeed; subprocess.Popen(...) will open a console window, subprocess.Popen(..., shell=True) will not open a console window. My belief is that with shell=True it is run in the current process's subsystem---which will be "window" rather than "console" for pythonw---rather than being launched entirely separately, where as a console subsystem executable it will open a new console window.Querist
I've improved the answer to be more accurate and more specific about what needs doing.Querist
@ChrisMorgan My belief is (...) I think it's not what happens. In fact with shell=True every subprocess opens its own console but it's hidden. See startup parameter, subprocess.CREATE_NEW_CONSOLE flag, subprocess.STARTUPINFO.wShowWindow attribute and this line of subprocess.py.Racial
shell=True is not necessary here. See my answer and question How do I eliminate Windows consoles from spawned processes in Python (2.7)?Racial
@PiotrDobrogost: you're absolutely right. I had forgotten I had written that or I would have corrected it - I had occasion to come across the real explanation earlier this year. Thanks for offering the correction!Querist
R
17

You should use subprocess.Popen class passing as startupinfo parameter's value instance of subprocess.STARTUPINFO class with dwFlags attribute holding subprocess.STARTF_USESHOWWINDOW flag and wShowWindow attribute holding subprocess.SW_HIDE flag. This can be inferred from reading lines 866-868 of subprocess.py source code. It might be necessary to also pass subprocess.CREATE_NEW_CONSOLE flag as a value of creationflags parameter as you run under pythonw.exe which does not open a console.

When you use shell=True it just happens that all of the above is set correctly but that doesn't mean it's a proper solution. I would argue it's not because it adds overhead of running command interpreter and parsing arguments. In addition you should keep in mind that (...) the use of shell=True is strongly discouraged in cases where the command string is constructed from external input according to documentation of subprocess module.

Racial answered 18/10, 2012 at 22:44 Comment(4)
The input wasn't from an external source and I couldn't care less about overhead from parsing the shell command, especially if avoiding it involves the over-complicated solution you describe above.Hysell
Using shell=True is not the right thing to do here and the (alleged) complexity of the right solution doesn't change this.Racial
I can't believe this is not the highest voted answer. All because people can't be bothered to write 3 lines of code in order to do things properly. +1Highams
Can you also add an example?V
D
17

The solution that Piotr describes is actually not as complicated as it may sound. Here is an example where a startupinfo is passed to a check_call invocation to suppress the console window:

startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

subprocess.check_call(cmd, startupinfo=startupinfo)

Since the convenience functions call, check_call, and check_output forward their **kwargs to the Popen constructor, it is not required to use Popen directly.

Dibble answered 17/4, 2013 at 10:33 Comment(3)
@ArtOfWarfare This question is specific to Windows, so it is no surprise that it could fail on other operating systems. If you want to help, you should state the exact error you get on Mac OS.Dibble
It's an elaborate work around (relative to how much code is otherwise necessary) so that one system (Windows) can behave the same as the others, but in the process breaks the others. I'm going with shell=true - it's short, it's sweet, and it works on all platforms. Oh, and the issue on Mac (and I assume *nix) is it throws an exception over STARTUPINFO() not being recognized.Heavyfooted
@Heavyfooted 1. It's not elaborate as it's only 3 simple additional lines in comparision to shell=Truestartupinfo = subprocess.STARTUPINFO(); startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW; startupinfo.wShowWindow = _subprocess.SW_HIDE). 2. It's Windows specific and as such should only be applied on Windows. Because of this, talking about breaking other systems does not make sense.Racial
C
8

People are a bit lazy... I would thx @Piotr Dobrogost and @Frank S. Thomas for their answers.

I came with this code who is runinng on Linux and Windows:

import platform
import subprocess
startupinfo = None
if platform.system() == 'Windows':
    import _subprocess  # @bug with python 2.7 ?
    startupinfo = subprocess.STARTUPINFO()
    startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
    startupinfo.wShowWindow = _subprocess.SW_HIDE

Later...

args = [exe, ...]
out = subprocess.check_output(args, startupinfo=startupinfo)

Thx guys ;)

Additionally: just to note that the following code using 'call' also works on Python 2.7 (on Windows) with the 'startupinfo' code above:

def run_command(cmd, sin, sout):
    print "Running cmd : %s"%(" ".join(cmd) )
    return subprocess.call( cmd, stdin=sin, stdout=sout, startupinfo=startupinfo)
Chaplet answered 6/10, 2013 at 3:11 Comment(1)
This worked perfectly for me, thanks. I can't understand why anyone would want to use shell=True, it's just a bug waiting to happen.Glavin
J
6

You could try using the subprocess module (subprocess.Popen, subprocess.call or whatever) with the argument shell=True if you want to avoid starting a console window.

Jubilation answered 19/11, 2009 at 17:31 Comment(7)
subprocess.check_call makes a good replacement for os.system in this case.Mckibben
Be sure to set subprocess.check_call(args, shell=True) where args is the command string that you would ordinarily type in a console. I'm not sure why shell=True is needed when I don't want a console to appear, but that's what occurred in my experiment.Yippee
Indeed; subprocess.Popen(...) will open a console window, subprocess.Popen(..., shell=True) will not open a console window. My belief is that with shell=True it is run in the current process's subsystem---which will be "window" rather than "console" for pythonw---rather than being launched entirely separately, where as a console subsystem executable it will open a new console window.Querist
I've improved the answer to be more accurate and more specific about what needs doing.Querist
@ChrisMorgan My belief is (...) I think it's not what happens. In fact with shell=True every subprocess opens its own console but it's hidden. See startup parameter, subprocess.CREATE_NEW_CONSOLE flag, subprocess.STARTUPINFO.wShowWindow attribute and this line of subprocess.py.Racial
shell=True is not necessary here. See my answer and question How do I eliminate Windows consoles from spawned processes in Python (2.7)?Racial
@PiotrDobrogost: you're absolutely right. I had forgotten I had written that or I would have corrected it - I had occasion to come across the real explanation earlier this year. Thanks for offering the correction!Querist
T
1

It seems that 'os.popen' doesn't produce console window. Script is running under 'pythonw'. Not sure about all cases but in my case it works well.

os.popen(command)
Tiloine answered 27/5, 2013 at 18:12 Comment(0)
F
0

Similar to what @firsthand said, I've read on the wxPython-user forums that you "replace" the current running application, that would be "command.com" or "CMD.exe", with pyw.exe or pythonw.exe when you use something like the following:

os.execl(sys.executable, *([sys.executable]+sys.argv))

see another post

Although I do not know how you would pipe io in this case.

I believe one benefit of this approach is if you run your script multiple times your OS taskbar with not fill up with CMD icons. The other way if you have several CMD minimized in the taskbar and start closing them, it is impossible to tell which CMD goes with which pythonw script.

Forecast answered 17/7, 2014 at 1:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.