class_docstr: OpenImagesReader supports reading the images directly from the original
  data source which is hosted in Google Cloud Storage.
  
  Before using it you have to request and configure access following the
  instructions here: https://github.com/cvdfoundation/open-images-dataset
docstr: Read annotations from file and queue them.
  
  Annotations are stored in a CSV file where each line has one
  annotation. Since images can have multiple annotations (boxes), we read
  lines and merge all the annotations for one image into a single record.
  We do it this way to avoid loading the complete file in memory.
  
  It is VERY important that the annotation file is sorted by image_id,
  otherwise this way of reading them will not work.
docstr_tok: ["Read","annotations","from","file","and","queue","them",".","Annotations","are","stored","in","a","CSV","file","where","each","line","has","one","annotation",".","Since","images","can","have","multiple","annotations","(","boxes",")",",","we","read","lines","and","merge","all","the","annotations","for","one","image","into","a","single","record",".","We","do","it","this","way","to","avoid","loading","the","complete","file","in","memory",".","It","is","VERY","important","that","the","annotation","file","is","sorted","by","image_id",",","otherwise","this","way","of","reading","them","will","not","work","."]
code: def _queue_partial_records(
      self, partial_records_queue, records_queue
  ):
      """
      Read annotations from file and queue them.
  
      Annotations are stored in a CSV file where each line has one
      annotation. Since images can have multiple annotations (boxes), we read
      lines and merge all the annotations for one image into a single record.
      We do it this way to avoid loading the complete file in memory.
  
      It is VERY important that the annotation file is sorted by image_id,
      otherwise this way of reading them will not work.
      """
      annotations_file = self._get_annotations_path()
  
      with tf.gfile.Open(annotations_file) as af:
          reader = csv.DictReader(af)
  
          current_image_id = None
          partial_record = {}
  
          # Number of records we have queued so far, which should be
          # completed by another thread.
          num_queued_records = 0
  
          for line in reader:
              if num_queued_records == self.total:
                  # Reached the max number of records we can or want to
                  # process.
                  break
  
              if self._all_maxed_out():
                  break
  
              if self._should_skip(line["ImageID"]):
                  continue
  
              # Filter group annotations (we only want single instances)
              if line["IsGroupOf"] == "1":
                  continue
  
              # Append annotation to current record.
              try:
                  # LabelName may not exist because not all labels are
                  # trainable
                  label = self.trainable_labels.index(line["LabelName"])
              except ValueError:
                  continue
  
              if line["ImageID"] != current_image_id:
                  # Yield if image changes and we have current image.
                  if current_image_id is not None:
                      num_queued_records += 1
                      self._queue_record(
                          partial_records_queue, partial_record
                      )
  
                  # Start new record.
                  current_image_id = line["ImageID"]
                  partial_record = {
                      "filename": current_image_id,
                      "gt_boxes": [],
                  }
  
              partial_record["gt_boxes"].append(
                  {
                      "xmin": float(line["XMin"]),
                      "ymin": float(line["YMin"]),
                      "xmax": float(line["XMax"]),
                      "ymax": float(line["YMax"]),
                      "label": label,
                  }
              )
  
          else:
              # No data we care about in dataset -- nothing to queue
              if partial_record:
                  num_queued_records += 1
                  self._queue_record(
                      partial_records_queue, partial_record
                  )
  
      tf.logging.debug("Stopped queuing records.")
  
      # Wait for all records to be consumed by the threads that complete them
      partial_records_queue.join()
  
      tf.logging.debug("All records consumed!")
  
      # Signal the main thread that we have finished producing and every
      # record in the the queues has been consumed.
      records_queue.put(None)
  
imports: import csv
  import os
  import signal
  import six
  import sys
  import tensorflow
  import threading
  from six.moves import queue
  from PIL import Image
  from luminoth.tools.dataset.readers import InvalidDataDirectory
  from luminoth.tools.dataset.readers.object_detection import ObjectDetectionReader
  from luminoth.utils.dataset import read_image
label_desc: Use image node_id 10 for calling the OpenImagesReader obj's underlying member method code with example usage: obj._queue_partial_records(partial_records_queue, records_queue) without return types