text: from __future__ import unicode_literals, division, absolute_import
  from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
  
  import logging
  from math import ceil
  
  from flask import jsonify, request
  from sqlalchemy.orm.exc import NoResultFound
  
  from flexget.api import api, APIResource
  from flexget.api.app import base_message_schema, success_response, NotFoundError, etag, pagination_headers
  from flexget.plugins.filter.retry_failed import FailedEntry, get_failures
  
  log = logging.getLogger('failed_api')
  
  retry_failed_api = api.namespace('failed', description='View and manage failed entries')
  
  
  class ObjectsContainer(object):
      retry_failed_entry_object = {
          'type': 'object',
          'properties': {
              'id': {'type': 'integer'},
              'title': {'type': 'string'},
              'url': {'type': 'string'},
              'added_at': {'type': 'string', 'format': 'date-time'},
              'reason': {'type': 'string'},
              'count': {'type': 'integer'},
              'retry_time': {'type': ['string', 'null'], 'format': 'date-time'}
          },
          'required': ['id', 'title', 'url', 'added_at', 'reason', 'count', 'retry_time'],
          'additionalProperties': False
      }
      retry_entries_list_object = {'type': 'array', 'items': retry_failed_entry_object}
  
  
  retry_failed_entry_schema = api.schema('retry_failed_entry_schema', ObjectsContainer.retry_failed_entry_object)
  retry_entries_list_schema = api.schema('retry_entries_list_schema', ObjectsContainer.retry_entries_list_object)
  
  sort_choices = ('failure_time', 'id', 'title', 'url', 'reason', 'count', 'retry_time')
  failed_parser = api.pagination_parser(sort_choices=sort_choices)
  
  
  @retry_failed_api.route('/')
  class RetryFailed(APIResource):
      @etag
      @api.response(NotFoundError)
      @api.response(200, model=retry_entries_list_schema)
      @api.doc(parser=failed_parser)
      def get(self, session=None):
          """ List all failed entries """
          args = failed_parser.parse_args()
  
          # Pagination and sorting params
          page = args['page']
          per_page = args['per_page']
          sort_by = args['sort_by']
          sort_order = args['order']
  
          if sort_by == 'failure_time':
              sort_by = 'tof'
  
          # Handle max size limit
          if per_page > 100:
              per_page = 100
  
          descending = sort_order == 'desc'
  
          # Handle max size limit
          if per_page > 100:
              per_page = 100
  
          start = per_page * (page - 1)
          stop = start + per_page
  
          kwargs = {
              'start': start,
              'stop': stop,
              'descending': descending,
              'sort_by': sort_by,
              'session': session
          }
  
          total_items = get_failures(session, count=True)
  
          if not total_items:
              return jsonify([])
  
          failed_entries = [failed.to_dict() for failed in get_failures(**kwargs)]
  
          total_pages = int(ceil(total_items / float(per_page)))
  
          if page > total_pages:
              raise NotFoundError('page %s does not exist' % page)
  
          # Actual results in page
          actual_size = min(per_page, len(failed_entries))
  
          # Get pagination headers
          pagination = pagination_headers(total_pages, total_items, actual_size, request)
  
          # Created response
          rsp = jsonify(failed_entries)
  
          # Add link header to response
          rsp.headers.extend(pagination)
  
          return rsp
  
      @api.response(200, 'successfully deleted failed entry', model=base_message_schema)
      def delete(self, session=None):
          """ Clear all failed entries """
          log.debug('deleting all failed entries')
          deleted = session.query(FailedEntry).delete()
          return success_response('successfully deleted %d failed entries' % deleted)
  
  
  @retry_failed_api.route('/<int:failed_entry_id>/')
  @api.response(NotFoundError)
  class RetryFailedID(APIResource):
      @etag
      @api.doc(params={'failed_entry_id': 'ID of the failed entry'})
      @api.response(200, model=retry_failed_entry_schema)
      def get(self, failed_entry_id, session=None):
          """ Get failed entry by ID """
          try:
              failed_entry = session.query(FailedEntry).filter(FailedEntry.id == failed_entry_id).one()
          except NoResultFound:
              raise NotFoundError('could not find entry with ID %i' % failed_entry_id)
          return jsonify(failed_entry.to_dict())
  
      @api.response(200, 'successfully delete failed entry', model=base_message_schema)
      def delete(self, failed_entry_id, session=None):
          """ Delete failed entry by ID """
          try:
              failed_entry = session.query(FailedEntry).filter(FailedEntry.id == failed_entry_id).one()
          except NoResultFound:
              raise NotFoundError('could not find entry with ID %i' % failed_entry_id)
          log.debug('deleting failed entry: "%s"' % failed_entry.title)
          session.delete(failed_entry)
          return success_response('successfully delete failed entry %d' % failed_entry_id)
  