HuidaeCho / getosm

GetOSM is an OpenStreetMap tile downloader written in Python that is agnostic of GUI frameworks.
GNU General Public License v3.0
3 stars 1 forks source link

WxPython - thread on zoom is not started before #1

Closed ocsmit closed 3 years ago

ocsmit commented 3 years ago

Working on GRASS pull request for ProjPicker and encountered issues when zooming OSM. Tested further with base getosm and got the following RuntimeError.

Traceback (most recent call last):
  File "/Users/osmith2/dev/getosm/getosm/./osmwx.py", line 326, in on_zoom
    zoomer.join()
  File "/opt/homebrew/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 1048, in join
    raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started

I don't remember encountering this error in the past on either Linux or Windows, but I was given an M1 Mac by my lab head and started encountering the issue on macOSX.

HuidaeCho commented 3 years ago

Does it only happen with wxPython? What about tkinter?

ocsmit commented 3 years ago

Happens only with wxPython

HuidaeCho commented 3 years ago

and every time?

ocsmit commented 3 years ago

Correct. Both in the GRASS session and with just getosm.

HuidaeCho commented 3 years ago

OK.. My hypothesis.. zoomer.checker = wx.CallLater(0, check_zoomer) invokes check_zoomer almost immediately even before the next line zoomer.start(). How can that happen is... I don't know.. I mean.. how calling check_zoomer triggers on_zoom.

HuidaeCho commented 3 years ago

Please try wx.CallLater(1, check_zoomer) or other delays.

ocsmit commented 3 years ago

Works like a charm! Appears I need to do some reading regarding threading and async software design :wink:

ocsmit commented 3 years ago

This traceback slipped through the gaps. It only happens once at the first zoom.

Traceback (most recent call last):
  File "/Users/osmith2/dev/getosm/getosm/./osmwx.py", line 344, in on_zoom
    zoomer.checker = wx.CallLater(0, check_zoomer)
  File "/opt/homebrew/lib/python3.9/site-packages/wx/core.py", line 3451, in __init__
    self.Start()
  File "/opt/homebrew/lib/python3.9/site-packages/wx/core.py", line 3472, in Start
    self.timer.Start(self.millis, wx.TIMER_ONE_SHOT)
wx._core.wxAssertionError: C++ assertion ""m_milli > 0"" failed at /private/tmp/wxpython-20210622-43091-8tf3sx/wxPython-4.1.1/ext/wxWidgets/src/osx/core/timer.cpp(69) in Start(): invalid value for timer timeout

Currently trying to figure out why. Very few instances of it on the internet. Main one is at https://github.com/suurjaak/Skyperious/issues/64 and even then the solution used was to increase delay to 1 milsec. There has to be a concrete reason though.

ocsmit commented 3 years ago

The original C++ function in timer.cpp for OSX explicitly only allows for the timer to be above zero apparently.

bool wxOSXTimerImpl::Start( int milliseconds, bool mode )
{
    (void)wxTimerImpl::Start(milliseconds, mode);

    wxCHECK_MSG( m_milli > 0, false, wxT("invalid value for timer timeout") );

// -- snip --
 }

I believe then that a delay of 1 will suffice.

HuidaeCho commented 3 years ago
m_milli > 0

This is interesting.. so this check for a positive m_milli is only for macOS? If so, yes, it would be better to check the platform.

Anyway, I think you nailed it down!

HuidaeCho commented 3 years ago

So basically, zoomer.start() failed in the main thread and zoomer.join() caused your initial error whthout a thread. Makes sense.

HuidaeCho commented 3 years ago

Please close it once you confirm the merged PR works on your Mac.

ocsmit commented 3 years ago

Confirmed PR works