def gme_exc_handler(tries_remaining, exception, delay, args):
    """GME exception handler; retries 403 errors (access token expired) and prints a warning to stderr.

    tries_remaining: The number of tries remaining.
    exception: The exception instance which was raised.
    delay: The length of time we're sleeping for.
    args: A tuple of the arguments passed to the calling function.
    """

    # By convention Hodor always passes Context as the
    # first argument to anything that utilises retries.
    ctx = args[0]

    # Refresh expired access tokens
    if isinstance(exception, HttpError):
      if exception.resp.status == 401:
        print "Token Expired, Reauthenticating..."

        if not isinstance(ctx, Context):
          raise Exception("Error: Could not find Context object. Calling method must pass Context as the first argument.")

        ctx.refresh_services()

      # Files uploads return a 204 No Content "error" that needs to be handled farther up.
      elif exception.resp.status == 204:
        raise NoContent()

      # Allow these fatal errors to bubble up - there's nowt we can do about them here.
      elif exception.resp.status in [403, 500, 503, 410]:
        content = json.loads(exception.content)
        if content['error']['errors'][0]['reason'] == 'queryTooExpensive':
          raise QueryTooExpensive((content['error']['message']) % "Query too expensive '%s'")
        elif content['error']['errors'][0]['reason'] == 'backendError':
          # raise BackendError("GME backend error '%s'" % (content['error']['message']))

          # content['error']['message'] == "Service is unavailable. Retry."
          # HTTP 503 or 410

          # content['error']['message'] == "Deadline exceeded."
          # HTTP 410

          print content
          if content['error']['message'] == "Deadline exceeded.":
            raise BackendError("GME backend error '%s'" % (content['error']['message']))
          else:
            pass
        elif content['error']['errors'][0]['reason'] == 'tableTooLarge':
          raise TableTooLarge("Table too large '%s'" % (content['error']['message']))
        elif content['error']['errors'][0]['reason'] == 'internalError':
          raise InternalServerError("%s" % (content['error']['message']))
        elif content['error']['errors'][0]['reason'] == 'rateLimitExceeded':
          pass # Retry 403 Rate Limit Exceeded (for uploads only)

      # Retry non-fatal errors like "server didn't respond in time", GME's random "internal server error", or rate limit exceeded errors
      elif exception.resp.status not in [410, 429, 500]:
        raise exception

    if isinstance(ctx, Context):
      ctx.log("%s, %d tries remaining, sleeping for %s seconds" % (exception, tries_remaining, delay))
    else:
      if getattr(exception, 'content', None) is not None:
        content = json.loads(exception.content)
        message = content['error']['message'] + " " + content['error']['errors'][0]['reason']
        print >> sys.stderr, "Caught '%s' (%s), %d tries remaining, sleeping for %s seconds" % (message, exception.resp.status, tries_remaining, round(delay, 2))
      else:
        raise exception
dataset/ETHPy150Open keithmoss/Hodor/hodor/retries.py/gme_exc_handler/swapped operands of `%`