Exit from wxPython app when run from command line

After getting an wxPython based app running well enough on both Win 11 & Mint 21.2 I seem to have a curious issue, which bothers me.
I have looked at the topics which are shown as similar, and as far as I can tell, I have followed the rules, as outlined in Error message when exiting wxpython application

When run from the command line on either Win 11 or Min 21.2, I have to press an extra Ctrl-C to get the command prompt back.

What is going on and how can I fix/avoid this?
TIA

I normally run my wxPython applications on Mint 21.2 from desktop icons. However, I’ve just tested running a few from the command line and they all shut down cleanly without needing to press an extra Ctrl-C to get the command prompt back.

Could you please post the code for a small, complete application that demonstrates the issue?

1 Like

As soon as I have a sample which I can flip from ‘problematic’ to ‘fixed’.
I do have some code - mainly from examples and Mike Driscoll’s book which do not show the problem - but so far I have been unable to trim code from the examples which show the problem to the point where they don’t - and it seems there is next to nothing left while the code still does not exit cleanly, :slight_smile:
What I have found is that for the ‘bad’ apps, the code

app = wx.App(False) 
frame = MyFrameAui(None) 
import wx.lib.inspection
frame.Show(True) 
#start the applications 
app.MainLoop() 
print( "done")

never returns from the main loop

Without knowing what’s in the MyFrameAui class I’m not able to tell what is happening with your example.

I tried the code below but that did exit cleanly when I pressed Ctrl-C in the terminal (but didn’t print ‘done’).

import wx
import wx.aui

class MyFrameAui(wx.aui.AuiMDIParentFrame):
    pass

app = wx.App(False)
frame = MyFrameAui(None)
import wx.lib.inspection
frame.Show(True)
#start the applications
app.MainLoop()
print( "done")

In the past I have had problems shutting down wxPython applications that either had a child thread still running, or had matplotlib embedded. Do either of those apply to your applications?

I have no restarted my project from a clean base, which exits properly.
before that I had eliminated just about everything I could in the way of code without success. Hence the restart,
When the problem appears, I have determined from my process monitor that a python task remains running whenever I tried to exit my old app. This python task disappeared when I pressed Ctrl-C.

I appreciate your help, but as I intend to carry on from scratch, I will close this task, even though I don’t expect to spend the time to try and resolve the issue directly.
Perhaps as I add features I had in the old app to the new restart code, I may find out just what is at the root of my problem, and then, maybe not.

I now have a small test project which shows the problem on both Windows 11, with Python 3.9.0 and wxPython 4.2.1 and under Mint 21.1 with Python 3.10.12 & wxPython 4.2.1.
The attached zip file contains the project files.
The original project was borrowed from the 'net to build a small ‘calculator’ to square number.
The 'problem can be demonstrated by running the file test.py either from the command line or from within VS Code (latest updates installed on either OS) under both Windows 11 & Mint 21.1
The 2 simple dialogs opened from the first to buttons at the bottom of the main frame do not cause any problems when the main frame is closed down after either of them have been opened and closed down.
But opening the about dialog via the 3rd button and then closing it, shows the ‘problem’ when the main frame is closed
For either OS, the command prompt does not reappear until the user issues a Ctrl-C command.
When debugging or running under VS Code, the same ‘problem’ is present, except, when restarting the app, it seems VS Code takes care of the cleanup

wfbTest.zip (13.8 KB)
Running the task manager under Windows seems to show that when I exit the app after showing the About dialog, a new instance of Python shows up under ‘Background process’ until I issue the Ctrl-C.
At some point, I was running the Sysinterals app procmon & procexp and it seems that when the last Ctrl-C was issued, there was some writing/ to registry items related to the app, though I am not familiar enough with what is expected in any case and what might be related to this issue.
Another item I explored was some function call to the main app instance which relate to shutting down the app after the main frame is closed. The code is still in test.py, but is commented out,since it did not seem to make any difference.

In any case, this is where I am stuck. An app which does not return cleanly is suspect and likely/possibly ‘dangerous’ in some way.

I got the same results as you when I ran test.py and displayed the ‘About’ dialog. I am using Python 3.10.12 + wxPython 4.2.1 gtk3 (phoenix) wxWidgets 3.2.2.1 on Linux Mint 21.2.

The problem was due to how the AboutDialog class was being declared. It should be derived from AboutDlgBase, not wx.Dialog. In its __init__() method it should only call AboutDlgBase.__init__() and not wx.Dialog.__init__().

The version below works for me.

# -----------------------------------------------------------
# adapted from 
#
# Created 
# -----------------------------------------------------------

import os
import sys
from wpAboutDlgBase import AboutDlgBase

import wx

#import wpSkGlobal as gl
#import wpConfig as wpConf

# -------------------------------------------
def version():
    """
    Returns a string containing version and port info
    """
    if wx.Port == '__WXMSW__':
        port = 'msw'
    elif wx.Port == '__WXMAC__':
        if 'wxOSX-carbon' in wx.PlatformInfo:
            port = 'osx-carbon'
        else:
            port = 'osx-cocoa'
    elif wx.Port == '__WXGTK__':
        port = 'gtk'
        if 'gtk2' in wx.PlatformInfo:
            port = 'gtk2'
        elif 'gtk3' in wx.PlatformInfo:
            port = 'gtk3'
    else:
        port = '???'
    return "%s (phoenix)" % ( port) 

########################################################################
class AboutDialog(AboutDlgBase):
    """
    Creates and displays the About dialog 
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """
        """
        AboutDlgBase.__init__(self,None)
        
        from datetime import datetime
        now = datetime.now()
        day = now.strftime(("Date: %m/%d/%Y"))
        self.m_staticTextDate.SetLabelText( str(day))
         
        self.m_staticTextwxPythonVer.SetLabelText(wx.VERSION_STRING )
        
        py_version = sys.version.split()[0]
        self.m_staticTextPythonVer.SetLabelText(str(py_version ))
        
        cpu = version()  
        self.m_staticTextOsName.SetLabelText(cpu)
        
        #sys.version_info(major=3, minor=10, micro=4, releaselevel='final', serial=0)
    #    print(sys.version_info)
    #    print("sys.platform = %s" %(sys.platform))  # 'linux
        
        self.m_staticTextPlatform.SetLabelText(sys.platform)
        # if "__WXGTK__" in wx.PlatformInfo:
        #     pass        # GTK
        # elif "__WXMSW__" in wx.PlatformInfo:
        #     pass        # Windows
        
        # # if run directly as dialog
        # print("sys.argv = %s" %(sys.argv))
        # print("="*60)   # print a separator line
        # print(wx.PlatformInfo )
        # under Mint outputs:
        #('__WXGTK__', 'wxGTK', 'unicode', 'unicode-wchar', 'gtk3', 
        # 'wx-assertions-on', 'phoenix', 'wxWidgets 3.2.0', 'autoidman', 
        # 'sip-6.6.2', 'build-type: development')
          
        
                

# ---------------------------------------------------------------------        
if __name__ == "__main__":
    app = wx.App()
    dlg = AboutDialog()
    dlg.ShowModal()
    dlg.Destroy()
    
# ------------------------------- eof ------------------------------    

Simple as that? :slight_smile:
This had me going for quite some time.
Thank you.

I think the incorrect code in the About dialog caused wxPython’s internal state to become confused as to how many top-level windows had been created.

I added print(wx.GetTopLevelWindows()) calls in various places and noticed that when an AboutDialog object was created the incorrect code caused it to be added to the top-level window list twice.

I suspect that when the About dialog was closed, only one of the entries was removed. Then, when an attempt to close the program was made, it failed because wxPython still had one of the About dialog entries in its top-level window list.

When I did the same test with my corrected version, the AboutDialog object was only added to the list once, and the program was then able to close cleanly.

That reasoning makes sense, but I have no recollection of why I did things that way or what example I might have followed.
Very likely the problem has been around for as long as I have been playing with wxPython. It looks like VSCode will sort of cleanup and hide that issue. It is only recently when I tried to run the apps as a ‘real’ app directly from the command line that I noticed.
Still have a lot to lean about wxPython & Python in general. While with C & C++ and MSVC it is much easier to “look under the hood” when things don’t work or add up, for wxPython so much more of the workings is hidden inside these black boxes :slight_smile: :frowning: and any explanations , and even more so tips, on how to sneak a peek inside the black boxes, help a lot.