Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent a console app from closing when not invoked from an existing terminal?

There are many variants on this kind of question. However I am specifically after a way to prevent a console application in Python from closing when it is not invoked from a terminal (or other console, as it may be called on Windows). An example where this could occur is double clicking a .py file from the Windows explorer.

Typically I use something like the following code snippet, but it has the unfortunate side effect of operating even if the application is invoked from an existing terminal:

def press_any_key():
    if os.name == "nt":
        os.system("pause")
atexit.register(press_any_key)

It's also making the assumption that all Windows users are invoking the application from the Windows "shell", and that only Windows users can execute the program from a location other than an existing terminal.

Is there a (preferably cross platform) way to detect if my application has been invoked from a terminal, and/or whether it is necessary to provide a "press any key..." functionality for the currently running instance? Note that resorting to batch, bash or any other "wrapper process" workarounds are highly undesirable.

Update0

Using Alex Martelli's answer below, I've produced this function:

def register_pause_before_closing_console():
    import atexit, os
    if os.name == 'nt':
        from win32api import GetConsoleTitle
        if not GetConsoleTitle().startswith(os.environ["COMSPEC"]):
            atexit.register(lambda: os.system("pause"))

if __name__ == '__main__':
    register_pause_before_closing_console()

If other suitable answers arise, I'll append more code for other platforms and desktop environments.

Update1

In the vein of using pywin32, I've produced this function, which improves on the one above, using the accepted answer. The commented out code is an alternative implementation as originating in Update0. If using pywin32 is not an option, follow the link in the accepted answer. Pause or getch() to taste.

def _current_process_owns_console():
    #import os, win32api
    #return not win32api.GetConsoleTitle().startswith(os.environ["COMSPEC"])

    import win32console, win32process
    conswnd = win32console.GetConsoleWindow()
    wndpid = win32process.GetWindowThreadProcessId(conswnd)[1]
    curpid = win32process.GetCurrentProcessId()
    return curpid == wndpid

def register_pause_before_closing_console():
    import atexit, os, pdb
    if os.name == 'nt':
        if _current_process_owns_console():
            atexit.register(lambda: os.system("pause"))

if __name__ == '__main__':
    register_pause_before_closing_console()
like image 209
Matt Joiner Avatar asked Feb 13 '10 19:02

Matt Joiner


People also ask

How do I stop C# console applications from closing automatically?

The Console. ReadLine method is one way of doing that. Adding this line to the end of your code (just before the return statement) will cause the application to wait for you to press a key before exiting.

How do you prevent a program from closing immediately after running?

Try to add system("pause"); to your program to keep it opened.

How do I keep the console open in Visual Studio?

Run Application Without Debugging To Keep Console Window Open. To keep the console window open in Visual Studio without using the Console. ReadLine() method, you should run the application without debug mode by pressing Ctrl+F5 or by clicking on the menu Debug > Start without Debugging option.


1 Answers

First, an attempt to disuade you from clever hacks. It's perfectly appropriate to have a seperate shortcut designed to be run from Explorer that does slightly different things (like holding the console open) from the script to be used from the commandline. As Alex has already pointed out, this is not an issue on nix, and the right thing to do there is always exit cleanly or your users will complain.

If you still want a workaround, here's code to detect when the console needs to be prevented from closing that's reasonably clean. Requires Windows 2000 or later, the logic is contained in this function:

def owns_console():
    wnd = GetConsoleWindow()
    if wnd is None:
        return False
    return GetCurrentProcessId() == GetWindowThreadProcessId(wnd)

Basically, it gets the PIDs of the process that owns the console Python is using, and of our process. If they are the same, then when we exit the console will go away, so it needs to be held open. If they are different, or if there's no console attached, Python should exit normally.

like image 161
gz. Avatar answered Oct 20 '22 21:10

gz.