#653·watchdog

python segmentation fault (threading) when using watchdog in conjunction with opencv

Author: mluerigCreated Mar 12, 2020Updated Aug 27, 2026

Hi, I am developing an interactive computer vision program using watchdog and opencv. Users write the CV-functions they want to apply into a yaml file and, after parsing, can see the result in a window created by opencv, and either continue to modify, or save and close the configuration file and the window. This principle is working fine on windows and linux; whenever changes to a yaml file get saved, watchdog triggers parsing and execution of the contained functions.

However, on macOS I run into a python segmentation fault when the yaml file gets loaded and the opencv window closed. I have traced the fault back to watchdog and attach the code and fault handler log (the watchdog class I use is below, show_image essentially contains opencv window handling routines that I have ruled out as the error source).

I am not a full time developer, so I can only guess, but it seems that it has to do with threading (i.e. simultaneous file monitoring, and window closing and opening). Is python organizing CPU resources differently on a mac, and is there a way I can control that?

(pp) moritz@Marias-MacBook-Air ~ % python -Xfaulthandler 
Python 3.7.6 (default, Jan  8 2020, 13:42:34) 
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import faulthandler
>>> import cv2, copy, os
>>> import phenopype as pp
>>> proj = pp.load_project(r"/Users/moritz/Desktop/pp_test/stickle_stained/phenopype/stickle1/project.data")
>>> image = proj.dirpaths[0]
>>> image, df = pp.load_image(proj.filepaths[0], df = True, meta=False)
>>> 
>>> faulthandler.enable()
>>> mon = pp.utils_lowlevel._yaml_file_monitor(os.path.join(proj.dirpaths[0],'pype_config_v1.yaml'))
>>> while True:
...     config = copy.deepcopy(mon.content)
...	pp.show_image(image, config)	

<FileModifiedEvent: src_path='/Users/moritz/Desktop/pp_test/stickle_stained/phenopype/stickle1/data/0__00_stickle_reference/pype_config_v1.yaml'>
Fatal Python error: Segmentation fault

Current thread 0x000070000ccdd000 (most recent call first):
  File "/Users/moritz/Desktop/pp_test/phenopype/phenopype/utils_lowlevel.py", line 371 in on_update
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/site-packages/watchdog/events.py", line 330 in dispatch
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/site-packages/watchdog/events.py", line 452 in dispatch
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/site-packages/watchdog/observers/api.py", line 369 in dispatch_events
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/site-packages/watchdog/observers/api.py", line 196 in run
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/threading.py", line 926 in _bootstrap_inner
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/threading.py", line 890 in _bootstrap

Thread 0x000070000c757000 (most recent call first):
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/site-packages/watchdog/observers/fsevents.py", line 141 in run
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/threading.py", line 926 in _bootstrap_inner
  File "/Users/moritz/opt/anaconda3/envs/pp/lib/python3.7/threading.py", line 890 in _bootstrap

Thread 0x0000000109afedc0 (most recent call first):
  File "/Users/moritz/Desktop/pp_test/phenopype/phenopype/utils_lowlevel.py", line 116 in __init__
  File "/Users/moritz/Desktop/pp_test/phenopype/phenopype/utils.py", line 595 in show_image
  File "<stdin>", line 3 in <module>
zsh: segmentation fault  python -Xfaulthandler
(pp) moritz@Marias-MacBook-Air ~ % 
class _yaml_file_monitor:
    def __init__(self, filepath, **kwargs):

        ## file, location and event action        
        self.dirpath = os.path.dirname(filepath)
        self.filename = os.path.basename(filepath)
        self.filepath = filepath
        self.event_handler = PatternMatchingEventHandler(patterns=["*/" + self.filename])
        self.event_handler.on_any_event = self.on_update
        
        ## intitialize
        self.content = _load_yaml(self.filepath)
        self.observer = Observer()
        self.observer.schedule(self.event_handler, self.dirpath, recursive=False)
        self.observer.start()
        self.ref_time = time.time()

    def on_update(self, event):
        self.content = _load_yaml(self.filepath)
        # if time.time() > self.ref_time + 1:
        cv2.destroyWindow("phenopype")
        for i in range(10):
            cv2.waitKey(1)
        self.ref_time = time.time()
        print("\n\nreload pype_config\n\n")

    def stop(self):
        self.observer.stop()
        self.observer.join()