class_docstr: Linux inotify(7) API wrapper class.
  
  :param path:
      The directory path for which we want an inotify object.
  :type path:
      :class:`bytes`
  :param recursive:
      ``True`` if subdirectories should be monitored; ``False`` otherwise.
class_docstr_tok: ["Linux","inotify","(","7",")","API","wrapper","class",".",":","param","path",":","The","directory","path","for","which","we","want","an","inotify","object",".",":","type","path",":",":","class",":","`","bytes","`",":","param","recursive",":","``","True","``","if","subdirectories","should","be","monitored",";","``","False","``","otherwise","."]
docstr: Reads events from inotify and yields them.
code: def read_events(self, event_buffer_size=DEFAULT_EVENT_BUFFER_SIZE):
      """
      Reads events from inotify and yields them.
      """
      # HACK: We need to traverse the directory path
      # recursively and simulate events for newly
      # created subdirectories/files. This will handle
      # mkdir -p foobar/blah/bar; touch foobar/afile
  
      def _recursive_simulate(src_path):
          events = []
          for root, dirnames, filenames in os.walk(src_path):
              for dirname in dirnames:
                  try:
                      full_path = os.path.join(root, dirname)
                      wd_dir = self._add_watch(
                          full_path, self._event_mask
                      )
                      e = InotifyEvent(
                          wd_dir,
                          InotifyConstants.IN_CREATE
                          | InotifyConstants.IN_ISDIR,
                          0,
                          dirname,
                          full_path,
                      )
                      events.append(e)
                  except OSError:
                      pass
              for filename in filenames:
                  full_path = os.path.join(root, filename)
                  wd_parent_dir = self._wd_for_path[
                      os.path.dirname(full_path)
                  ]
                  e = InotifyEvent(
                      wd_parent_dir,
                      InotifyConstants.IN_CREATE,
                      0,
                      filename,
                      full_path,
                  )
                  events.append(e)
          return events
  
      event_buffer = None
      while True:
          try:
              event_buffer = os.read(
                  self._inotify_fd, event_buffer_size
              )
          except OSError as e:
              if e.errno == errno.EINTR:
                  continue
          break
  
      with self._lock:
          event_list = []
          for wd, mask, cookie, name in Inotify._parse_event_buffer(
              event_buffer
          ):
              if wd == -1:
                  continue
              wd_path = self._path_for_wd[wd]
              src_path = (
                  os.path.join(wd_path, name) if name else wd_path
              )  # avoid trailing slash
              inotify_event = InotifyEvent(
                  wd, mask, cookie, name, src_path
              )
  
              if inotify_event.is_moved_from:
                  self.remember_move_from_event(inotify_event)
              elif inotify_event.is_moved_to:
                  move_src_path = self.source_for_move(inotify_event)
                  if move_src_path in self._wd_for_path:
                      moved_wd = self._wd_for_path[move_src_path]
                      del self._wd_for_path[move_src_path]
                      self._wd_for_path[
                          inotify_event.src_path
                      ] = moved_wd
                      self._path_for_wd[
                          moved_wd
                      ] = inotify_event.src_path
                  src_path = os.path.join(wd_path, name)
                  inotify_event = InotifyEvent(
                      wd, mask, cookie, name, src_path
                  )
  
              if inotify_event.is_ignored:
                  # Clean up book-keeping for deleted watches.
                  path = self._path_for_wd.pop(wd)
                  if self._wd_for_path[path] == wd:
                      del self._wd_for_path[path]
                  continue
  
              event_list.append(inotify_event)
  
              if (
                  self.is_recursive
                  and inotify_event.is_directory
                  and inotify_event.is_create
              ):
                  # TODO: When a directory from another part of the
                  # filesystem is moved into a watched directory, this
                  # will not generate events for the directory tree.
                  # We need to coalesce IN_MOVED_TO events and those
                  # IN_MOVED_TO events which don't pair up with
                  # IN_MOVED_FROM events should be marked IN_CREATE
                  # instead relative to this directory.
                  try:
                      self._add_watch(src_path, self._event_mask)
                  except OSError:
                      continue
  
                  event_list.extend(_recursive_simulate(src_path))
  
      return event_list
  
imports: from __future__ import with_statement
  import os
  import errno
  import struct
  import threading
  import ctypes
  import ctypes.util
  from functools import reduce
  from ctypes import c_int, c_char_p, c_uint32
  from wandb_watchdog.utils import has_attribute
  from wandb_watchdog.utils import UnsupportedLibc
label_desc: Use image node_id 12 for calling the Inotify obj's underlying member method code with example usage: obj.read_events(event_buffer_size) and returns: event_list, events