class_docstr: Listen to folder events. If certain paths change, fire a callback.
  
  The super class, FileSystemEventHandler, listens to changes to *folders*,
  but we need to listen to changes to *both* folders and files. I believe
  this is a limitation of the Mac FSEvents system API, and the watchdog
  library takes the lower common denominator.
  
  So in this class we watch for folder events and then filter them based
  on whether or not we care for the path the event is about.
docstr: Handle when a path (corresponding to a file or dir) is changed.
  
  The events that can call this are modification, creation or moved
  events.
code: def handle_path_change_event(
      self, event: events.FileSystemEvent
  ) -> None:
      """Handle when a path (corresponding to a file or dir) is changed.
  
      The events that can call this are modification, creation or moved
      events.
      """
  
      # Check for both modified and moved files, because many programs write
      # to a backup file then rename (i.e. move) it.
      if event.event_type == events.EVENT_TYPE_MODIFIED:
          changed_path = event.src_path
      elif event.event_type == events.EVENT_TYPE_MOVED:
          # Teach mypy that this event has a dest_path, because it can't infer
          # the desired subtype from the event_type check
          event = cast(events.FileSystemMovedEvent, event)
  
          LOGGER.debug(
              "Move event: src %s; dest %s",
              event.src_path,
              event.dest_path,
          )
          changed_path = event.dest_path
      # On OSX with VI, on save, the file is deleted, the swap file is
      # modified and then the original file is created hence why we
      # capture EVENT_TYPE_CREATED
      elif event.event_type == events.EVENT_TYPE_CREATED:
          changed_path = event.src_path
      else:
          LOGGER.debug(
              "Don't care about event type %s", event.event_type
          )
          return
  
      changed_path = os.path.abspath(changed_path)
  
      changed_path_info = self._watched_paths.get(changed_path, None)
      if changed_path_info is None:
          LOGGER.debug(
              "Ignoring changed path %s.\nWatched_paths: %s",
              changed_path,
              self._watched_paths,
          )
          return
  
      modification_time = util.path_modification_time(
          changed_path, changed_path_info.allow_nonexistent
      )
  
      # We add modification_time != 0.0 check since on some file systems (s3fs/fuse)
      # modification_time is always 0.0 because of file system limitations.
      if (
          modification_time != 0.0
          and modification_time == changed_path_info.modification_time
      ):
          LOGGER.debug(
              "File/dir timestamp did not change: %s", changed_path
          )
          return
  
      changed_path_info.modification_time = modification_time
  
      new_md5 = util.calc_md5_with_blocking_retries(
          changed_path,
          glob_pattern=changed_path_info.glob_pattern,
          allow_nonexistent=changed_path_info.allow_nonexistent,
      )
      if new_md5 == changed_path_info.md5:
          LOGGER.debug("File/dir MD5 did not change: %s", changed_path)
          return
  
      LOGGER.debug("File/dir MD5 changed: %s", changed_path)
      changed_path_info.md5 = new_md5
      changed_path_info.on_changed.send(changed_path)
  
imports: import os
  import threading
  from typing import Callable, Dict, Optional, cast
  from blinker import ANY, Signal
  from watchdog import events
  from watchdog.observers import Observer
  from watchdog.observers.api import ObservedWatch
  from streamlit.logger import get_logger
  from streamlit.util import repr_
  from streamlit.watcher import util
label_desc: Use image node_id 6 for calling the _FolderEventHandler obj's underlying member method code with example usage: obj.handle_path_change_event(event) without return types