def changes(self, timeout_ms=0):
    """Return paths for changed files and directories.

    start() must be called before this method.

    Args:
      timeout_ms: a timeout in milliseconds on which this watcher will block
                  waiting for a change. It allows for external polling threads
                  to react immediately on a change instead of waiting for
                  a random polling delay.

    Returns:
      A set of strings representing file and directory paths that have changed
      since the last call to get_changed_paths.
    """
    paths = set()
    while True:
      with self._inotify_fd_lock:
        if self._inotify_fd < 0:
          return set()
        # Don't wait to detect subsequent changes after the initial one.
        if not self._inotify_poll.poll(
            _AGGREGATE_CHANGES_MS_APART if paths else timeout_ms):
          break

        self._inotify_events += os.read(self._inotify_fd, 1024)
        while len(self._inotify_events) > _INOTIFY_EVENT_SIZE:
          wd, mask, cookie, length = _INOTIFY_EVENT.unpack(
              self._inotify_events[:_INOTIFY_EVENT_SIZE])
          if len(self._inotify_events) < _INOTIFY_EVENT_SIZE + length:
            break

          name = self._inotify_events[
              _INOTIFY_EVENT_SIZE:_INOTIFY_EVENT_SIZE + length]
          name = name.rstrip('\0')

          logging.debug(
              'wd=%s, mask=%s, cookie=%s, length=%s, name=%r', wd,
              _bit_str(mask, _ATTRIBUTE_MASK_NAMES), cookie, length, name)

          self._inotify_events = self._inotify_events[
              _INOTIFY_EVENT_SIZE + length:]

          if mask & IN_IGNORED:
            continue
          try:
            directory = self._watch_to_directory[wd]
          except KeyError:
            logging.debug('Watch deleted for watch descriptor=%d', wd)
            continue

          path = os.path.join(directory, name)
          if os.path.isdir(path) or path in self._directory_to_watch_descriptor:
            if mask & IN_DELETE:
              self._remove_watch_for_path(path)
            elif mask & IN_MOVED_FROM:
              self._remove_watch_for_path(path)
            elif mask & IN_CREATE:
              self._add_watch_for_path(path)
            elif mask & IN_MOVED_TO:
              self._add_watch_for_path(path)
          if path not in paths and not watcher_common.ignore_file(path):
            paths.add(path)
    return paths
dataset/ETHPy150Open GoogleCloudPlatform/python-compat-runtime/appengine-compat/exported_appengine_sdk/google/appengine/tools/devappserver2/inotify_file_watcher.py/InotifyFileWatcher.changes/original