Hello wxPython Users,
I am almost done in porting a very large, legacy Python 2 application to Python 3. Everything works all right except I am getting access violation error messages that bring down the whole Python process. I can trace it back to wx.ProgressDialog.Pulse()
using the Python faulthandler environment variable.
I have a very simple subclass of wx.ProgressDialog
, which does not do anything different from the standard wx.ProgressDialog
beside setting an icon for it in the __init__
method. This is my overloaded Pulse
method:
def Pulse(self, *args):
print('I am in thread:', threading.current_thread())
print('I am:', self)
print('Deleted:', self.IsBeingDeleted(), 'Nonzero:', self.__nonzero__())
print()
if not self or self.IsBeingDeleted():
return
wx.ProgressDialog.Pulse(self, *args)
wx.SafeYield()
The Pulse()
method is called from another thread but always using wx.CallAfter
. Just so we are clear, there is no instance in which a separate thread accesses GUI elements.
The presence or absence of wx.SafeYield()
makes no difference to the outcome.
I get the following after a few seconds:
I am in thread: <_MainThread(MainThread, started 22296)>
I am: <mdp_widgets.PhaserProgressDialog object at 0x000001FA9D227670>
Deleted: False Nonzero: True
... more prints, another wx.ProgressDialog is created ...
I am in thread: <_MainThread(MainThread, started 22296)>
I am: <mdp_widgets.PhaserProgressDialog object at 0x000001FABE3A0550>
Deleted: False Nonzero: True
Windows fatal exception: access violation
Current thread 0x00005718 (most recent call first):
File "C:\Users\J0514162\MyProjects\Phaser\refactoring_github\py3_working\mdp_widgets.py", line 11344 in Pulse
File "C:\Users\J0514162\WinPython39\WPy64-39100\python-3.9.10.amd64\lib\site-packages\wx\core.py", line 3427 in <lambda>
File "C:\Users\J0514162\MyProjects\Phaser\refactoring_github\py3_working\mdp_widgets.py", line 11344 in Pulse
File "C:\Users\J0514162\WinPython39\WPy64-39100\python-3.9.10.amd64\lib\site-packages\wx\core.py", line 3427 in <lambda>
File "C:\Users\J0514162\MyProjects\Phaser\refactoring_github\py3_working\mdp_widgets.py", line 11344 in Pulse
File "C:\Users\J0514162\WinPython39\WPy64-39100\python-3.9.10.amd64\lib\site-packages\wx\core.py", line 3427 in <lambda>
File "C:\Users\J0514162\WinPython39\WPy64-39100\python-3.9.10.amd64\lib\site-packages\wx\core.py", line 2262 in MainLoop
File "C:\Users\J0514162\MyProjects\Phaser\refactoring_github\py3_working\Phaser.py", line 57 in phaser_main
File "C:\Users\J0514162\MyProjects\Phaser\refactoring_github\py3_working\Phaser.py", line 69 in <module>
You may notice that line 3427 in core.py (at least on wxPython 4.2) is the implementation of wx.CallAfter
:
This is so fantastically annoying that I have no words to describe the frustration. It has taken me longer to diagnose this issue and trying to find a workaround (which I cannot not find) than it took me to port 150,000 lines of code from Python 2 to Python 3, and from Classic to Phoenix.
Any suggestion on how to address this issue - workarounds, hacks, anything - would be most welcome.
Thank you in advance.
Andrea.