Recently I’ve created Python add-ins for data entry for our staff. Most of these have a toolbar with a “Help” button that opens a help file in .pdf format.
The first add-in was for ArcCatalog and this worked splendidly. I was using os.startfile(path to help.pdf).
However, when I started doing ArcMap add-ins, clicking the Help button would open the help.pdf but ArcMap would crash. Oops!
They report that the root of the problem is “conflicts in the way the Windows libraries expect to be called, they can fail or crash when called within ArcGIS for Desktop in an add-in script or geoprocessing script tool”. But this can be overcome by using a decorator function that calls os.startfile from a new thread. Another function effected by these conflicts is webbrowser.open.
Example code is shown below:
import functools import os import threading import webbrowser # A decorator that will run its wrapped function in a new thread def run_in_other_thread(function): # functool.wraps will copy over the docstring and some other metadata # from the original function @functools.wraps(function) def fn_(*args, **kwargs): thread = threading.Thread(target=function, args=args, kwargs=kwargs) thread.start() thread.join() return fn_ # Our new wrapped versions of os.startfile and webbrowser.open startfile = run_in_other_thread(os.startfile) openbrowser = run_in_other_thread(webbrowser.open)
Then whenever you call startfile or openbrowser, it will be routed through your decorator function and, as far as I’ve been able to tell, works fine without crashing your ArcMap session.