def _search_log_for_datetime(log_path, dt, word_count, reverse=False):
  """
  Find the start position of the line containing the datetime nearest to dt.
  :param log_path: the absolute path to the log file
  :param dt: the datetime to be searched
  :param word_count: the number of "words" that represents the datetime in the log
  :param reverse: if False, finds the line with the largest datetime less than dt
                  if True, finds the line with the smallest datetime larger than dt
  """
  ONE_KILOBYTE = 1024
  with open(log_path, 'r') as log:
    lbound = 0
    ubound = os.path.getsize(log_path)

    # the algorithm does not guarantee that one of lbound or ubound is changed in each iteration
    # we use search_area to keep track of the block size (ubound - lbound) to see if it changes.
    # It is initialized to 0 in order to declare it before use (note 0 is an impossible case)
    search_area = 0
    while ubound > lbound:
      # Doing a linear search when the size gets small to avoid the issue of keeping track of the previous line.
      if ONE_KILOBYTE < ubound - lbound:
        return _linear_search_log_for_time(log_path, dt, word_count, lbound, ubound, reverse)
      mid = (lbound + ubound) / 2
      log.seek(mid)
      log.readline()  # skip to the end of the line, we will process the next one

      # some lines may not begin with a valid datetime (e.g exception messages that spans multiple lines)
      # hence, we loop until we find a line with a valid datetime
      is_valid_dt = False
      while not is_valid_dt:
        if log.tell() == ubound:
          # we have reached the end of the search block.
          # This should rarely happen unless there is a really long line in the log.
          # Do a linear search because we cannot make further progress
          return _linear_search_log_for_time(log_path, dt, word_count, lbound, ubound, reverse)
        line_start = log.tell()
        line = log.readline()
        timestr = ' '.join(line.split()[:word_count])
        try:
          log_dt = parser.parse(timestr)  # TODO(tlan) exception management
          # if the parse does not work the default time returned is dtime(0, 0, 0)
          # we ignore this time so it is not included in the calculation
          # if a test starts or ends with this time, this will return a superset of the relevant log lines of the tests
          # There may be a chance this affects validation; but the chance is low enough that it is acceptable
          if log_dt.time() != dtime(0, 0, 0):
            is_valid_dt = True
        except:
          is_valid_dt = False

      # the following conditional block updates the bounds. The line that was just process is kept within the bounds,
      # because it still may be the line that we are looking for.
      if log_dt > dt:
        ubound = log.tell()
      elif log_dt < dt:
        lbound = line_start
      else:
        # here we have found a matching time, but we must continue searching
        # because there may be multiple lines with matching times!
        if not reverse:
          ubound = log.tell()
        else:
          lbound = line_start

      #  perform linear search when further progress cannot be made.
      if ubound - lbound == search_area:
        return _linear_search_log_for_time(log_path, dt, word_count, lbound, ubound, reverse)
      search_area = ubound - lbound
dataset/ETHPy150Open linkedin/Zopkio/zopkio/test_utils.py/_search_log_for_datetime/swapped operands of `<`