docs: def _handle_interrupt(self, fileno, val):
          """ Internally distributes interrupts to all attached callbacks """
          val = int(val)
  
          # Filter invalid edge values (sometimes 1 comes in when edge=falling)
          edge = self._map_fileno_to_options[fileno]["edge"]
          if (edge == 'rising' and val == 0) or (edge == 'falling' and val == 1):
              return
  
          # If user activated debounce for this callback, check timing now
          debounce = self._map_fileno_to_options[fileno]["debounce_timeout_s"]
          if debounce:
              t = time.time()
              t_last = self._map_fileno_to_options[fileno]["interrupt_last"]
              if t - t_last < debounce:
                  debug("- don't start interrupt callback due to debouncing")
                  return
              self._map_fileno_to_options[fileno]["interrupt_last"] = t
  
          # Start the callback(s) now
          gpio_id = self._map_fileno_to_gpioid[fileno]
          if gpio_id in self._map_gpioid_to_callbacks:
              for cb in self._map_gpioid_to_callbacks[gpio_id]:
                  cb(gpio_id, val)