PY2 = sys.version_info[0] < 3
ENCODING = 'utf-8'
NONETYPE = type(None)
STRTYPE = basestring if PY2 else str
UNITYPE = unicode if PY2 else str
LONGTYPE = long if PY2 else int
UNICHR = unichr if PY2 else chr
    def iteritems_(adict):
    def next_(itr):
    def iteritems_(adict):
    def next_(itr):
def bytes_(astr):
def unicode_(astr): JSON_INDEX_TYPE = 'json' SEARCH_INDEX_ARGS = {
    'bookmark': STRTYPE,
    'counts': list,
    'drilldown': list,
    'group_field': STRTYPE,
    'group_limit': (int, NONETYPE),
    'group_sort': (STRTYPE, list),
    'include_docs': bool,
    'limit': (int, NONETYPE),
    'query': (STRTYPE, int, LONGTYPE),
    'q': (STRTYPE, int, LONGTYPE),
    'ranges': dict,
    'sort': (STRTYPE, list),
    'stale': STRTYPE,
    'highlight_fields': list,
    'highlight_pre_tag': STRTYPE,
    'highlight_post_tag': STRTYPE,
    'highlight_number': (int, LONGTYPE, NONETYPE),
    'highlight_size': (int, LONGTYPE, NONETYPE),
    'include_fields': list,
    'partition': STRTYPE
} SPECIAL_INDEX_TYPE = 'special' TEXT_INDEX_TYPE = 'text' TYPE_CONVERTERS = {
    STRTYPE: lambda x: json.dumps(x),
    str: lambda x: json.dumps(x),
    UNITYPE: lambda x: json.dumps(x),
    Sequence: lambda x: json.dumps(list(x)),
    list: lambda x: json.dumps(x),
    tuple: lambda x: json.dumps(list(x)),
    int: lambda x: x,
    LONGTYPE: lambda x: x,
    bool: lambda x: 'true' if x else 'false',
    NONETYPE: lambda x: x
} def get_docs(r_session, url, encoder=None, headers=None, **params):
    """
    Provides a helper for functions that require GET or POST requests
    with a JSON, text, or raw response containing documents.

    :param r_session: Authentication session from the client
    :param str url: URL containing the endpoint
    :param JSONEncoder encoder: Custom encoder from the client
    :param dict headers: Optional HTTP Headers to send with the request

    :returns: Raw response content from the specified endpoint
    """
    keys_list = params.pop('keys', None)
    keys = None
    if keys_list is not None:
        keys = json.dumps({'keys': keys_list}, cls=encoder)
    f_params = python_to_couch(params, encoder)
    resp = None
    if keys is not None:
        # If we're using POST we are sending JSON so add the header
        if headers is None:
            headers = {}
        headers['Content-Type'] = 'application/json'
        resp = r_session.post(url, headers=headers, params=f_params, data=keys)
    else:
        resp = r_session.get(url, headers=headers, params=f_params)
    resp.raise_for_status()
    return resp def response_to_json_dict(response, **kwargs):
    """
    Standard place to convert responses to JSON.

    :param response: requests response object
    :param **kwargs: arguments accepted by json.loads

    :returns: dict of JSON response
    """
    if response.encoding is None:
        response.encoding = 'utf-8'
    return json.loads(response.text, **kwargs) class Document(dict):
    """
    Encapsulates a JSON document.  A Document object is instantiated with a
    reference to a database and used to manipulate document content
    in a CouchDB or Cloudant database instance.

    In addition to basic CRUD style operations, a Document object also provides
    a convenient context manager.  This context manager removes having to
    explicitly :func:`~cloudant.document.Document.fetch` the document from the
    remote database before commencing work on it as well as explicitly having
    to :func:`~cloudant.document.Document.save` the document once work is
    complete.

    For example:

    .. code-block:: python

        # Upon entry into the document context, fetches the document from the
        # remote database, if it exists. Upon exit from the context, saves the
        # document to the remote database with changes made within the context.
        with Document(database, 'julia006') as document:
            # The document is fetched from the remote database
            # Changes are made locally
            document['name'] = 'Julia'
            document['age'] = 6
            # The document is saved to the remote database

    :param database: A database instance used by the Document.  Can be
        either a ``CouchDatabase`` or ``CloudantDatabase`` instance.
    :param str document_id: Optional document id used to identify the document.
    :param str encoder: Optional JSON encoder object (extending json.JSONEncoder).
    :param str decoder: Optional JSON decoder object (extending json.JSONDecoder).
    """
    def __init__(self, database, document_id=None, **kwargs):
        super(Document, self).__init__()
        self._client = database.client
        self._database = database
        self._database_host = self._client.server_url
        self._database_name = database.database_name
        if document_id:
            self['_id'] = document_id
        self.encoder = kwargs.get('encoder') or self._client.encoder
        self.decoder = kwargs.get('decoder') or json.JSONDecoder

    @property
    def r_session(self):
        """
        Returns the database instance ``r_session`` used by the document.

        :returns: Client ``r_session``
        """
        return self._client.r_session

    @property
    def document_url(self):
        """
        Constructs and returns the document URL.

        :returns: Document URL
        """
        if '_id' not in self or self['_id'] is None:
            return None

        # handle design document url
        if self['_id'].startswith('_design/'):
            return '/'.join((
                self._database_host,
                url_quote_plus(self._database_name),
                '_design',
                url_quote(self['_id'][8:], safe='')
            ))

        # handle _local document url
        if self['_id'].startswith('_local/'):
            return '/'.join((
                self._database_host,
                url_quote_plus(self._database_name),
                '_local',
                url_quote(self['_id'][7:], safe='')
            ))

        # handle document url
        return '/'.join((
            self._database_host,
            url_quote_plus(self._database_name),
            url_quote(self['_id'], safe='')
        ))

    def exists(self):
        """
        Retrieves whether the document exists in the remote database or not.

        :returns: True if the document exists in the remote database,
            otherwise False
        """
        if '_id' not in self or self['_id'] is None:
            return False

        assert_document_type_id(self['_id'])

        resp = self.r_session.head(self.document_url)
        if resp.status_code not in [200, 404]:
            resp.raise_for_status()

        return resp.status_code == 200

    def json(self):
        """
        Retrieves the JSON string representation of the current locally cached
        document object, encoded by the encoder specified in the associated
        client object.

        :returns: Encoded JSON string containing the document data
        """
        return json.dumps(dict(self), cls=self.encoder)

    def create(self):
        """
        Creates the current document in the remote database and if successful,
        updates the locally cached Document object with the ``_id``
        and ``_rev`` returned as part of the successful response.
        """

        # Ensure that an existing document will not be "updated"
        doc = dict(self)
        if doc.get('_rev') is not None:
            doc.__delitem__('_rev')

        headers = {'Content-Type': 'application/json'}
        resp = self.r_session.post(
            self._database.database_url,
            headers=headers,
            data=json.dumps(doc, cls=self.encoder)
        )
        resp.raise_for_status()
        data = response_to_json_dict(resp)
        super(Document, self).__setitem__('_id', data['id'])
        super(Document, self).__setitem__('_rev', data['rev'])

    def fetch(self):
        """
        Retrieves the content of the current document from the remote database
        and populates the locally cached Document object with that content.
        A call to fetch will overwrite any dictionary content currently in
        the locally cached Document object.
        """
        if self.document_url is None:
            raise CloudantDocumentException(101)
        if '_id' in self:
            assert_document_type_id(self['_id'])
        resp = self.r_session.get(self.document_url)
        resp.raise_for_status()
        self.clear()
        self.update(response_to_json_dict(resp, cls=self.decoder))

    def save(self):
        """
        Saves changes made to the locally cached Document object's data
        structures to the remote database.  If the document does not exist
        remotely then it is created in the remote database.  If the object
        does exist remotely then the document is updated remotely.  In either
        case the locally cached Document object is also updated accordingly
        based on the successful response of the operation.
        """
        headers = {}
        headers.setdefault('Content-Type', 'application/json')
        if not self.exists():
            self.create()
            return
        put_resp = self.r_session.put(
            self.document_url,
            data=self.json(),
            headers=headers
        )
        put_resp.raise_for_status()
        data = response_to_json_dict(put_resp)
        super(Document, self).__setitem__('_rev', data['rev'])
        return

    # Update Actions
    # These are handy functions to use with update_field below.
    @staticmethod
    def list_field_append(doc, field, value):
        """
        Appends a value to a list field in a locally cached Document object.
        If a field does not exist it will be created first.

        :param Document doc: Locally cached Document object that can be a
            Document, DesignDocument or dict.
        :param str field: Name of the field list to append to.
        :param value: Value to append to the field list.
        """
        if doc.get(field) is None:
            doc[field] = []
        if not isinstance(doc[field], list):
            raise CloudantDocumentException(102, field)
        if value is not None:
            doc[field].append(value)

    @staticmethod
    def list_field_remove(doc, field, value):
        """
        Removes a value from a list field in a locally cached Document object.

        :param Document doc: Locally cached Document object that can be a
            Document, DesignDocument or dict.
        :param str field: Name of the field list to remove from.
        :param value: Value to remove from the field list.
        """
        if not isinstance(doc[field], list):
            raise CloudantDocumentException(102, field)
        doc[field].remove(value)

    @staticmethod
    def field_set(doc, field, value):
        """
        Sets or replaces a value for a field in a locally cached Document
        object.  To remove the field set the ``value`` to None.

        :param Document doc: Locally cached Document object that can be a
            Document, DesignDocument or dict.
        :param str field: Name of the field to set.
        :param value: Value to set the field to.
        """
        if value is None:
            doc.__delitem__(field)
        else:
            doc[field] = value

    def _update_field(self, action, field, value, max_tries, tries=0):
        """
        Private update_field method. Wrapped by Document.update_field.
        Tracks a "tries" var to help limit recursion.
        """
        # Refresh our view of the document.
        self.fetch()

        # Update the field.
        action(self, field, value)

        # Attempt to save, retrying conflicts up to max_tries.
        try:
            self.save()
        except requests.HTTPError as ex:
            if tries < max_tries and ex.response.status_code == 409:
                self._update_field(
                    action, field, value, max_tries, tries=tries+1)
            else:
                raise

    def update_field(self, action, field, value, max_tries=10):
        """
        Updates a field in the remote document. If a conflict exists,
        the document is re-fetched from the remote database and the update
        is retried.  This is performed up to ``max_tries`` number of times.

        Use this method when you want to update a single field in a document,
        and don't want to risk clobbering other people's changes to
        the document in other fields, but also don't want the caller
        to implement logic to deal with conflicts.

        For example:

        .. code-block:: python

            # Append the string 'foo' to the 'words' list of Document doc.
            doc.update_field(
                action=doc.list_field_append,
                field='words',
                value='foo'
            )

        :param callable action: A routine that takes a Document object,
            a field name, and a value. The routine should attempt to
            update a field in the locally cached Document object with the
            given value, using whatever logic is appropriate.
            Valid actions are
            :func:`~cloudant.document.Document.list_field_append`,
            :func:`~cloudant.document.Document.list_field_remove`,
            :func:`~cloudant.document.Document.field_set`
        :param str field: Name of the field to update
        :param value: Value to update the field with
        :param int max_tries: In the case of a conflict, the number of retries
            to attempt
        """
        self._update_field(action, field, value, max_tries)

    def delete(self):
        """
        Removes the document from the remote database and clears the content of
        the locally cached Document object with the exception of the ``_id``
        field.  In order to successfully remove a document from the remote
        database, a ``_rev`` value must exist in the locally cached Document
        object.
        """
        if not self.get("_rev"):
            raise CloudantDocumentException(103)

        assert_document_type_id(self['_id'])

        del_resp = self.r_session.delete(
            self.document_url,
            params={"rev": self["_rev"]},
        )
        del_resp.raise_for_status()
        _id = self['_id']
        self.clear()
        self['_id'] = _id

    def __enter__(self):
        """
        Supports context like editing of document fields.  Handles context
        entry logic.  Executes a Document.fetch() upon entry.
        """

        # We don't want to raise an exception if the document is not found
        # because upon __exit__ the save() call will create the document
        # if necessary.
        try:
            self.fetch()
        except HTTPError as error:
            if error.response.status_code != 404:
                raise
        except CloudantDocumentException as error:
            if error.status_code != 101:
                raise

        return self

    def __exit__(self, exc_type, exc_value, traceback):
        """
        Support context like editing of document fields. Handles context exit
        logic. Executes a `Document.save()` upon exit if no exception occurred.
        """
        if exc_type is None:
            self.save()

    def get_attachment(
            self,
            attachment,
            headers=None,
            write_to=None,
            attachment_type=None):
        """
        Retrieves a document's attachment and optionally writes it to a file.
        If the content_type of the attachment is 'application/json' then the
        data returned will be in JSON format otherwise the response content will
        be returned as text or binary.

        :param str attachment: Attachment file name used to identify the
            attachment.
        :param dict headers: Optional, additional headers to be sent
            with request.
        :param file write_to: Optional file handler to write the attachment to.
            The write_to file must be opened for writing prior to including it
            as an argument for this method.
        :param str attachment_type: Optional setting to define how to handle the
            attachment when returning its contents from this method.  Valid
            values are ``'text'``, ``'json'``, and ``'binary'``  If
            omitted then the returned content will be based on the
            response Content-Type.

        :returns: The attachment content
        """
        # need latest rev
        self.fetch()
        assert_attachment_name(attachment)
        attachment_url = '/'.join((self.document_url, url_quote(attachment, safe='')))
        if headers is None:
            headers = {'If-Match': self['_rev']}
        else:
            headers['If-Match'] = self['_rev']

        resp = self.r_session.get(attachment_url, headers=headers)
        resp.raise_for_status()

        if attachment_type is None:
            if resp.headers['Content-Type'].startswith('text/'):
                attachment_type = 'text'
            elif resp.headers['Content-Type'] == 'application/json':
                attachment_type = 'json'
            else:
                attachment_type = 'binary'

        if write_to is not None:
            if attachment_type in ('text', 'json'):
                write_to.write(resp.text)
            else:
                write_to.write(resp.content)
        if attachment_type == 'text':
            return resp.text
        if attachment_type == 'json':
            return response_to_json_dict(resp)

        return resp.content

    def delete_attachment(self, attachment, headers=None):
        """
        Removes an attachment from a remote document and refreshes the locally
        cached document object.

        :param str attachment: Attachment file name used to identify the
            attachment.
        :param dict headers: Optional, additional headers to be sent
            with request.

        :returns: Attachment deletion status in JSON format
        """
        # need latest rev
        self.fetch()
        assert_attachment_name(attachment)
        attachment_url = '/'.join((self.document_url, attachment))
        if headers is None:
            headers = {'If-Match': self['_rev']}
        else:
            headers['If-Match'] = self['_rev']

        resp = self.r_session.delete(
            attachment_url,
            headers=headers
        )
        resp.raise_for_status()
        super(Document, self).__setitem__('_rev', response_to_json_dict(resp)['rev'])
        # Execute logic only if attachment metadata exists locally
        if self.get('_attachments'):
            # Remove the attachment metadata for the specified attachment
            if self['_attachments'].get(attachment):
                self['_attachments'].__delitem__(attachment)
            # Remove empty attachment metadata from the local dictionary
            if not self['_attachments']:
                super(Document, self).__delitem__('_attachments')

        return response_to_json_dict(resp)

    def put_attachment(self, attachment, content_type, data, headers=None):
        """
        Adds a new attachment, or updates an existing attachment, to
        the remote document and refreshes the locally cached
        Document object accordingly.

        :param attachment: Attachment file name used to identify the
            attachment.
        :param content_type: The http ``Content-Type`` of the attachment used
            as an additional header.
        :param data: Attachment data defining the attachment content.
        :param headers: Optional, additional headers to be sent
            with request.

        :returns: Attachment addition/update status in JSON format
        """
        # need latest rev
        self.fetch()
        assert_attachment_name(attachment)
        attachment_url = '/'.join((self.document_url, attachment))
        if headers is None:
            headers = {
                'If-Match': self['_rev'],
                'Content-Type': content_type
            }
        else:
            headers['If-Match'] = self['_rev']
            headers['Content-Type'] = content_type

        resp = self.r_session.put(
            attachment_url,
            data=data,
            headers=headers
        )
        resp.raise_for_status()
        self.fetch()
        return response_to_json_dict(resp) class DesignDocument(Document):
    """
    Encapsulates a specialized version of a
    :class:`~cloudant.document.Document`.  A DesignDocument object is
    instantiated with a reference to a database and
    provides an API to view management, index management, list and show
    functions, etc.  When instantiating a DesignDocument or
    when setting the document id (``_id``) field, the value must start with
    ``_design/``.  If it does not, then ``_design/`` will be prepended to
    the provided document id value.

    Note:  Currently only the view management and search index management API
    exists.  Remaining design document functionality will be added later.

    :param database: A database instance used by the DesignDocument.  Can be
        either a ``CouchDatabase`` or ``CloudantDatabase`` instance.
    :param str document_id: Optional document id.  If provided and does not
        start with ``_design/``, it will be prepended with ``_design/``.
    :param bool partitioned: Optional. Create as a partitioned design document.
        Defaults to ``False`` for both partitioned and non-partitioned
        databases.
    """
    def __init__(self, database, document_id=None, partitioned=False):
        if document_id:
            assert_document_type_id(document_id)
        if document_id and not document_id.startswith(DESIGN_PREFIX):
            document_id = '{0}{1}'.format(DESIGN_PREFIX, document_id)
        super(DesignDocument, self).__init__(database, document_id)

        if partitioned:
            self.setdefault('options', {'partitioned': True})
        else:
            self.setdefault('options', {'partitioned': False})

        self._nested_object_names = frozenset(['views', 'indexes', 'lists', 'shows'])
        for prop in self._nested_object_names:
            self.setdefault(prop, dict())

    @property
    def validate_doc_update(self):
        """
        Provides an accessor property to the update validators dictionary in
        the locally cached DesignDocument.  Update validators evaluate whether a
        document should be written to disk when insertions and updates are attempted.

        Update validator example:

        .. code-block:: python

            # Add the update validator to ``validate_doc_update`` and save the design document
            ddoc = DesignDocument(self.db, '_design/ddoc001')
            ddoc['validate_doc_update'] = (
                'function(newDoc, oldDoc, userCtx, secObj) { '
                'if (newDoc.address === undefined) { '
                'throw({forbidden: \'Document must have an address.\'}); }}')
            ddoc.save()

        For more details, see the `Update Validators documentation
        <https://console.bluemix.net/docs/services/Cloudant/api/design_documents.html#update-validators>`_.

        :returns: Dictionary containing update validator functions
        """
        return self.get('validate_doc_update')

    @property
    def filters(self):
        """
        Provides an accessor property to the filters dictionary in the locally cached
        DesignDocument.  Filter functions enable you to add tests for filtering each
        of the objects included in the changes feed.  If any of the function tests
        fail, the object is filtered from the feed.  If the function returns a true
        result when applied to a change, the change remains in the feed.

        Filter functions require two arguments: ``doc`` and ``req``.  The ``doc`` argument
        represents the document being tested for filtering.  The ``req`` argument contains
        additional information about the HTTP request.

        Filter function example:

        .. code-block:: python

            # Add the filter function to ``filters`` and save the design document
            ddoc = DesignDocument(self.db, '_design/ddoc001')
            # Filter and remove documents that are not of ``type`` mail
            ddoc['filters'] = {
                'filter001': 'function(doc, req){if (doc.type != \'mail\'){return false;} '
                             'return true;} '
            }
            ddoc.save()

        To execute filter functions on a changes feed, see the database API
        :func:`~cloudant.database.CouchDatabase.changes`

        For more details, see the `Filter functions documentation
        <https://console.bluemix.net/docs/services/Cloudant/api/design_documents.html#filter-functions>`_.

        :returns: Dictionary containing filter function names and functions
            as key/value
        """
        return self.get('filters')

    @property
    def updates(self):
        """
        Provides an accessor property to the updates dictionary in the locally
        cached DesignDocument. Update handlers are custom functions stored on
        Cloudant's server that will create or update a document.
        To execute the update handler function, see
        :func:`~cloudant.database.CouchDatabase.update_handler_result`.

        Update handlers receive two arguments: ``doc`` and ``req``. If a document ID is
        provided in the request to the update handler, then ``doc`` will be the
        document corresponding with that ID.
        If no ID was provided, ``doc`` will be null.

        Update handler example:

        .. code-block:: python

            # Add the update handler to ``updates`` and save the design document
            ddoc = DesignDocument(self.db, '_design/ddoc001')
            ddoc001['updates'] = {
                'update001': 'function(doc, req) { if (!doc) '
                             '{ if ('id' in req && req.id){ return [{_id: req.id}, '
                             '\"New World\"] } return [null, \"Empty World\"] } '
                             'doc.world = \'hello\'; '
                             'return [doc, \"Added world.hello!\"]} '
            }
            ddoc.save()

        Note: Update handler functions must return an array of two elements,
        the first being the document to save (or null, if you don't want to
        save anything), and the second being the response body.

        :returns: Dictionary containing update handler names and objects
            as key/value
        """
        return self.get('updates')

    @property
    def st_indexes(self):
        """
        Provides an accessor property to the Cloudant Geospatial
        (a.k.a. Cloudant Geo) indexes dictionary in the locally cached
        DesignDocument.  Each Cloudant Geo index is a JSON object within the
        ``st_indexes`` containing an index name and a javascript function.

        Note: To make it easier to work with Cloudant Geo documents, it is best
        practice to create a separate design document specifically for
        Cloudant Geo indexes.

        Geospatial index example:

        .. code-block:: python

            # Add the Cloudant Geo index to ``st_indexes`` and save the design document
            ddoc = DesignDocument(self.db, '_design/ddoc001')
            ddoc['st_indexes'] = {
                'geoidx': {
                    'index': 'function(doc) { '
                             'if (doc.geometry && doc.geometry.coordinates) { '
                             'st_index(doc.geometry);}} '
                }
            }
            ddoc.save()

        Once the Cloudant Geo index is saved to the remote database, you can
        query the index with a GET request.  To issue a request against the
        ``_geo`` endpoint, see the steps outlined in the `endpoint access
        <getting_started.html#endpoint-access>`_ section.

        For more details, see the `Cloudant Geospatial
        documentation <https://console.bluemix.net/docs/services/Cloudant/api/cloudant-geo.html>`_.

        :return: Dictionary containing Cloudant Geo names and index objects
            as key/value
        """
        return self.get('st_indexes')

    @property
    def lists(self):
        """
        Provides an accessor property to the lists dictionary in the locally
        cached DesignDocument.

        :returns: Dictionary containing list names and objects as key/value
        """
        return self.get('lists')

    @property
    def shows(self):
        """
        Provides an accessor property to the shows dictionary in the
        locally cached DesignDocument.

        :returns: Dictionary containing show names and functions
            as key/value
        """
        return self.get('shows')

    @property
    def rewrites(self):
        """
        Provides an accessor property to a list of dictionaries with rewrite
        rules in the locally cached DesignDocument.  Each rule for URL rewriting
        is a JSON object with four fields: ``from``, ``to``, ``method``,
        and ``query``.

        Note: Requests that match the rewrite rules must have a URL path that
        starts with ``/$DATABASE/_design/doc/_rewrite``.

        Rewrite rule example:

        .. code-block:: python

            # Add the rule to ``rewrites`` and save the design document
            ddoc = DesignDocument(self.db, '_design/ddoc001')
            ddoc['rewrites'] = [
                {"from": "/old/topic",
                 "to": "/new/",
                 "method": "GET",
                 "query": {}
                 }
            ]
            ddoc.save()

        Once the rewrite rule is saved to the remote database, the GET
        request URL ``/$DATABASE/_design/doc/_rewrite/old/topic?k=v`` would be
        rewritten as ``/$DATABASE/_design/doc/_rewrite/new?k=v``.

        For more details on URL rewriting, see the `rewrite rules
        documentation <https://console.bluemix.net/docs/services/Cloudant/api/design_documents.html
        #rewrite-rules>`_.

        :returns: List of dictionaries containing rewrite rules as key/value
        """
        return self.get('rewrites')

    @property
    def views(self):
        """
        Provides an accessor property to the View dictionary in the locally
        cached DesignDocument.

        :returns: Dictionary containing view names and View objects as key/value
        """
        return self.get('views')

    @property
    def indexes(self):
        """
        Provides an accessor property to the indexes dictionary in the
        locally cached DesignDocument.

        :returns: Dictionary containing index names and index objects
            as key/value
        """
        return self.get('indexes')

    def document_partition_url(self, partition_key):
        """
        Retrieve the design document partition URL.

        :param str partition_key: Partition key.
        :return: Design document partition URL.
        :rtype: str
        """
        return '/'.join((
            self._database.database_partition_url(partition_key),
            '_design',
            url_quote_plus(self['_id'][8:], safe='')
        ))

    def add_view(self, view_name, map_func, reduce_func=None, **kwargs):
        """
        Appends a MapReduce view to the locally cached DesignDocument View
        dictionary.  To create a JSON query index use
        :func:`~cloudant.database.CloudantDatabase.create_query_index` instead.
        A CloudantException is raised if an attempt to add a QueryIndexView
        (JSON query index) using this method is made.

        :param str view_name: Name used to identify the View.
        :param str map_func: Javascript map function.
        :param str reduce_func: Optional Javascript reduce function.
        """
        if self.get_view(view_name) is not None:
            raise CloudantArgumentError(107, view_name)
        if self.get('language', None) == QUERY_LANGUAGE:
            raise CloudantDesignDocumentException(101)

        view = View(self, view_name, map_func, reduce_func, **kwargs)
        self.views.__setitem__(view_name, view)

    def add_search_index(self, index_name, search_func, analyzer=None):
        """
        Appends a Cloudant search index to the locally cached DesignDocument
        indexes dictionary.

        :param str index_name: Name used to identify the search index.
        :param str search_func: Javascript search index function.
        :param analyzer: Optional analyzer for this search index.
        """
        if self.get_index(index_name) is not None:
            raise CloudantArgumentError(108, index_name)
        if analyzer is not None:
            search = {'index': codify(search_func), 'analyzer': analyzer}
        else:
            search = {'index': codify(search_func)}

        self.indexes.__setitem__(index_name, search)

    def add_list_function(self, list_name, list_func):
        """
        Appends a list function to the locally cached DesignDocument
        indexes dictionary.

        :param str list_name: Name used to identify the list function.
        :param str list_func: Javascript list function.
        """
        if self.get_list_function(list_name) is not None:
            raise CloudantArgumentError(109, list_name)

        self.lists.__setitem__(list_name, codify(list_func))

    def add_show_function(self, show_name, show_func):
        """
        Appends a show function to the locally cached DesignDocument
        shows dictionary.

        :param show_name: Name used to identify the show function.
        :param show_func: Javascript show function.
        """
        if self.get_show_function(show_name) is not None:
            raise CloudantArgumentError(110, show_name)

        self.shows.__setitem__(show_name, show_func)

    def update_view(self, view_name, map_func, reduce_func=None, **kwargs):
        """
        Modifies/overwrites an existing MapReduce view definition in the
        locally cached DesignDocument View dictionary.  To update a JSON
        query index use
        :func:`~cloudant.database.CloudantDatabase.delete_query_index` followed
        by :func:`~cloudant.database.CloudantDatabase.create_query_index`
        instead.  A CloudantException is raised if an attempt to update a
        QueryIndexView (JSON query index) using this method is made.

        :param str view_name: Name used to identify the View.
        :param str map_func: Javascript map function.
        :param str reduce_func: Optional Javascript reduce function.
        """
        view = self.get_view(view_name)
        if view is None:
            raise CloudantArgumentError(111, view_name)
        if isinstance(view, QueryIndexView):
            raise CloudantDesignDocumentException(102)

        view = View(self, view_name, map_func, reduce_func, **kwargs)
        self.views.__setitem__(view_name, view)

    def update_search_index(self, index_name, search_func, analyzer=None):
        """
        Modifies/overwrites an existing Cloudant search index in the
        locally cached DesignDocument indexes dictionary.

        :param str index_name: Name used to identify the search index.
        :param str search_func: Javascript search index function.
        :param analyzer: Optional analyzer for this search index.
        """
        search = self.get_index(index_name)
        if search is None:
            raise CloudantArgumentError(112, index_name)
        if analyzer is not None:
            search = {'index': codify(search_func), 'analyzer': analyzer}
        else:
            search = {'index': codify(search_func)}

        self.indexes.__setitem__(index_name, search)

    def update_list_function(self, list_name, list_func):
        """
        Modifies/overwrites an existing list function in the
        locally cached DesignDocument indexes dictionary.

        :param str list_name: Name used to identify the list function.
        :param str list_func: Javascript list function.
        """
        if self.get_list_function(list_name) is None:
            raise CloudantArgumentError(113, list_name)

        self.lists.__setitem__(list_name, codify(list_func))

    def update_show_function(self, show_name, show_func):
        """
        Modifies/overwrites an existing show function in the
        locally cached DesignDocument shows dictionary.

        :param show_name: Name used to identify the show function.
        :param show_func: Javascript show function.
        """
        if self.get_show_function(show_name) is None:
            raise CloudantArgumentError(114, show_name)

        self.shows.__setitem__(show_name, show_func)

    def delete_view(self, view_name):
        """
        Removes an existing MapReduce view definition from the locally cached
        DesignDocument View dictionary.  To delete a JSON query index
        use :func:`~cloudant.database.CloudantDatabase.delete_query_index`
        instead.  A CloudantException is raised if an attempt to delete a
        QueryIndexView (JSON query index) using this method is made.

        :param str view_name: Name used to identify the View.
        """
        view = self.get_view(view_name)
        if view is None:
            return
        if isinstance(view, QueryIndexView):
            raise CloudantDesignDocumentException(103)

        self.views.__delitem__(view_name)

    def delete_index(self, index_name):
        """
        Removes an existing index in the locally cached DesignDocument
        indexes dictionary.

        :param str index_name: Name used to identify the index.
        """
        index = self.get_index(index_name)
        if index is None:
            return

        self.indexes.__delitem__(index_name)

    def delete_list_function(self, list_name):
        """
        Removes an existing list function in the locally cached DesignDocument
        lists dictionary.

        :param str list_name: Name used to identify the list.
        """
        self.lists.__delitem__(list_name)

    def delete_show_function(self, show_name):
        """
        Removes an existing show function in the locally cached DesignDocument
        shows dictionary.

        :param show_name: Name used to identify the list.
        """
        if self.get_show_function(show_name) is None:
            return

        self.shows.__delitem__(show_name)

    def fetch(self):
        """
        Retrieves the remote design document content and populates the locally
        cached DesignDocument dictionary.  View content is stored either as
        View or QueryIndexView objects which are extensions of the ``dict``
        type.  All other design document data are stored directly as
        ``dict`` types.
        """
        super(DesignDocument, self).fetch()
        if self.views:
            for view_name, view_def in iteritems_(self.get('views', dict())):
                if self.get('language', None) != QUERY_LANGUAGE:
                    self['views'][view_name] = View(
                        self,
                        view_name,
                        view_def.pop('map', None),
                        view_def.pop('reduce', None),
                        **view_def
                    )
                else:
                    self['views'][view_name] = QueryIndexView(
                        self,
                        view_name,
                        view_def.pop('map', None),
                        view_def.pop('reduce', None),
                        **view_def
                    )

        for prop in self._nested_object_names:
            # Ensure dict for each sub-object exists in locally cached DesignDocument.
            getattr(self, prop, self.setdefault(prop, dict()))

    # pylint: disable=too-many-branches
    def save(self):
        """
        Saves changes made to the locally cached DesignDocument object's data
        structures to the remote database.  If the design document does not
        exist remotely then it is created in the remote database.  If the object
        does exist remotely then the design document is updated remotely.  In
        either case the locally cached DesignDocument object is also updated
        accordingly based on the successful response of the operation.
        """
        if self.views:
            if self.get('language', None) != QUERY_LANGUAGE:
                for view_name, view in self.iterviews():
                    if isinstance(view, QueryIndexView):
                        raise CloudantDesignDocumentException(104, view_name)
            else:
                for view_name, view in self.iterviews():
                    if not isinstance(view, QueryIndexView):
                        raise CloudantDesignDocumentException(105, view_name)

        if self.indexes:
            if self.get('language', None) != QUERY_LANGUAGE:
                for index_name, search in self.iterindexes():
                    # Check the instance of the javascript search function
                    if not isinstance(search['index'], STRTYPE):
                        raise CloudantDesignDocumentException(106, index_name)
            else:
                for index_name, index in self.iterindexes():
                    if not isinstance(index['index'], dict):
                        raise CloudantDesignDocumentException(107, index_name)

        for prop in self._nested_object_names:
            if not getattr(self, prop):
                # Ensure empty dict for each sub-object is not saved remotely.
                self.__delitem__(prop)

        super(DesignDocument, self).save()

        for prop in self._nested_object_names:
            # Ensure views, indexes, and lists dict exist in locally cached DesignDocument.
            getattr(self, prop, self.setdefault(prop, dict()))

    def __setitem__(self, key, value):
        """
        Ensures that when setting the document id for a DesignDocument it is
        always prefaced with '_design'.
        """
        if (
                key == '_id' and
                value is not None and
                not value.startswith('_design/')
        ):
            value = '_design/{0}'.format(value)
        super(DesignDocument, self).__setitem__(key, value)

    def iterviews(self):
        """
        Provides a way to iterate over the locally cached DesignDocument View
        dictionary.

        For example:

        .. code-block:: python

            for view_name, view in ddoc.iterviews():
                # Perform view processing

        :returns: Iterable containing view name and associated View object
        """
        for view_name, view in iteritems_(self.views):
            yield view_name, view

    def iterindexes(self):
        """
        Provides a way to iterate over the locally cached DesignDocument
        indexes dictionary.

        For example:

        .. code-block:: python

            for index_name, search_func in ddoc.iterindexes():
                # Perform search index processing

        :returns: Iterable containing index name and associated
            index object
        """
        for index_name, search_func in iteritems_(self.indexes):
            yield index_name, search_func

    def iterlists(self):
        """
        Provides a way to iterate over the locally cached DesignDocument
        lists dictionary.

        :returns: Iterable containing list function name and associated
            list function
        """
        for list_name, list_func in iteritems_(self.lists):
            yield list_name, list_func

    def itershows(self):
        """
        Provides a way to iterate over the locally cached DesignDocument
        shows dictionary.

        :returns: Iterable containing show function name and associated
            show function
        """
        for show_name, show_func in iteritems_(self.shows):
            yield show_name, show_func

    def list_views(self):
        """
        Retrieves a list of available View objects in the locally cached
        DesignDocument.

        :returns: List of view names
        """
        return list(self.views.keys())

    def list_indexes(self):
        """
        Retrieves a list of available indexes in the locally cached
        DesignDocument.

        :returns: List of index names
        """
        return list(self.indexes.keys())

    def list_list_functions(self):
        """
        Retrieves a list of available list functions in the locally cached
        DesignDocument lists dictionary.

        :returns: List of list function names
        """
        return list(self.lists.keys())

    def list_show_functions(self):
        """
        Retrieves a list of available show functions in the locally cached
        DesignDocument shows dictionary.

        :returns: List of show function names
        """
        return list(self.shows.keys())

    def get_view(self, view_name):
        """
        Retrieves a specific View from the locally cached DesignDocument by
        name.

        :param str view_name: Name used to identify the View.

        :returns: View object for the specified view_name
        """
        return self.views.get(view_name)

    def get_index(self, index_name):
        """
        Retrieves a specific index from the locally cached DesignDocument
        indexes dictionary by name.

        :param str index_name: Name used to identify the index.

        :returns: Index dictionary for the specified index name
        """
        return self.indexes.get(index_name)

    def get_list_function(self, list_name):
        """
        Retrieves a specific list function from the locally cached DesignDocument
        lists dictionary by name.

        :param str list_name: Name used to identify the list function.

        :returns: String form of the specified list function
        """
        return self.lists.get(list_name)

    def get_show_function(self, show_name):
        """
        Retrieves a specific show function from the locally cached DesignDocument
        shows dictionary by name.

        :param str show_name: Name used to identify the show function.

        :returns: String form of the specified show function
        """
        return self.shows.get(show_name)

    def info(self):
        """
        Retrieves the design document view information data, returns dictionary

        GET databasename/_design/{ddoc}/_info
        """
        ddoc_info = self.r_session.get(
            '/'.join([self.document_url, '_info']))
        ddoc_info.raise_for_status()
        return response_to_json_dict(ddoc_info)

    def search_info(self, search_index):
        """
        Retrieves information about a specified search index within the design
        document, returns dictionary

        GET databasename/_design/{ddoc}/_search_info/{search_index}
        """
        ddoc_search_info = self.r_session.get(
            '/'.join([self.document_url, '_search_info', search_index]))
        ddoc_search_info.raise_for_status()
        return response_to_json_dict(ddoc_search_info)

    def search_disk_size(self, search_index):
        """
        Retrieves disk size information about a specified search index within
        the design document, returns dictionary

        GET databasename/_design/{ddoc}/_search_disk_size/{search_index}
        """
        ddoc_search_disk_size = self.r_session.get(
            '/'.join([self.document_url, '_search_disk_size', search_index]))
        ddoc_search_disk_size.raise_for_status()
        return response_to_json_dict(ddoc_search_disk_size) class SecurityDocument(dict):
    """
    Encapsulates a JSON security document.  A SecurityDocument object is
    instantiated with a reference to a database and used to manipulate security
    document content in a CouchDB or Cloudant database instance.

    In addition to basic read/write operations, a SecurityDocument object also
    provides a convenient context manager.  This context manager removes having
    to explicitly :func:`~cloudant.security_document.SecurityDocument.fetch`
    the security document from the remote database before commencing work on it
    as well as explicitly having to
    :func:`~cloudant.security_document.SecurityDocument.save` the security
    document once work is complete.

    For example:

    .. code-block:: python

        # Upon entry into the security document context, fetches the security
        # document from the remote database, if it exists. Upon exit from the
        # context, saves the security document to the remote database with
        # changes made within the context.
        with SecurityDocument(database) as security_document:
            # The security document is fetched from the remote database
            # Changes are made locally
            security_document['Cloudant']['julia'] = ['_reader', '_writer']
            security_document['Cloudant']['ruby'] = ['_admin', '_replicator']
            # The security document is saved to the remote database

    :param database: A database instance used by the SecurityDocument.  Can be
        either a ``CouchDatabase`` or ``CloudantDatabase`` instance.
    """
    def __init__(self, database):
        super(SecurityDocument, self).__init__()
        self._client = database.client
        self._database = database
        self._database_host = self._client.server_url
        self._database_name = database.database_name
        self.encoder = self._client.encoder

    @property
    def document_url(self):
        """
        Constructs and returns the security document URL.

        :returns: Security document URL
        """
        return '/'.join([
            self._database_host,
            url_quote_plus(self._database_name),
            '_security'
        ])

    @property
    def r_session(self):
        """
        Returns the Python requests session used by the security document.

        :returns: The Python requests session
        """
        return self._client.r_session

    def json(self):
        """
        Retrieves the JSON string representation of the current locally cached
        security document object, encoded by the encoder specified in the
        associated client object.

        :returns: Encoded JSON string containing the security document data
        """
        return json.dumps(dict(self), cls=self.encoder)

    def fetch(self):
        """
        Retrieves the content of the current security document from the remote
        database and populates the locally cached SecurityDocument object with
        that content.  A call to fetch will overwrite any dictionary content
        currently in the locally cached SecurityDocument object.
        """
        resp = self.r_session.get(self.document_url)
        resp.raise_for_status()
        self.clear()
        self.update(response_to_json_dict(resp))

    def save(self):
        """
        Saves changes made to the locally cached SecurityDocument object's data
        structures to the remote database.
        """
        resp = self.r_session.put(
            self.document_url,
            data=self.json(),
            headers={'Content-Type': 'application/json'}
        )
        resp.raise_for_status()

    def __enter__(self):
        """
        Supports context like editing of security document fields.
        Handles context entry logic.  Executes a
        :func:`~cloudant.security_document.SecurityDocument.fetch` upon entry.
        """
        self.fetch()
        return self

    def __exit__(self, *args):
        """
        Support context like editing of security document fields.
        Handles context exit logic.  Executes a
        :func:`~cloudant.security_document.SecurityDocument.save` upon exit.
        """
        self.save() class View(dict):
    """
    Encapsulates a view as a dictionary based object, exposing the map and
    reduce functions as attributes and supporting query/data access through
    the view.  A View object is instantiated with a reference to a
    DesignDocument and is typically used as part of the
    :class:`~cloudant.design_document.DesignDocument` view management API.

    A View object provides a key accessible, sliceable, and iterable default
    result collection that can be used to query the view data through the
    ``result`` attribute.

    For example:

    .. code-block:: python

        # Access result collection through individual keys
        view.result[100]
        view.result['foo']

        # Access result collection through index slicing:
        view.result[100: 200]
        view.result[: 200]
        view.result[100: ]
        view.result[: ]

        # Access result collection through key slicing:
        view.result['bar': 'foo']
        view.result['bar': ]
        view.result[: 'foo']

        # Iterate over the result collection:
        for doc in view.result:
            print doc

    The default result collection provides basic functionality,
    which can be customized with other arguments using the
    :func:`~cloudant.view.View.custom_result` context manager.

    For example:

    .. code-block:: python

        # Including documents as part of a custom result
        with view.custom_result(include_docs=True) as rslt:
            rslt[100: 200]                       # slice by result
            rslt[['2013', '10']: ['2013', '11']] # slice by startkey/endkey

            # Iteration
            for doc in rslt:
                print doc

        # Iteration over a view within startkey/endkey range:
        with view.custom_result(startkey='2013', endkey='2014') as rslt:
            for doc in rslt:
                print doc

    Note:  A view must exist as part of a design document remotely in order to
    access result content as depicted in the above examples.

    :param DesignDocument ddoc: DesignDocument instance used in part to
        identify the view.
    :param str view_name: Name used in part to identify the view.
    :param str map_func: Optional Javascript map function.
    :param str reduce_func: Optional Javascript reduce function.
    :param str partition_key: Optional. Specify a view partition key. Defaults
        to ``None`` resulting in global queries.
    """
    def __init__(
            self,
            ddoc,
            view_name,
            map_func=None,
            reduce_func=None,
            partition_key=None,
            **kwargs
    ):
        super(View, self).__init__()
        self.design_doc = ddoc
        self._r_session = self.design_doc.r_session
        self.view_name = view_name
        if map_func is not None:
            self['map'] = codify(map_func)
        if reduce_func is not None:
            self['reduce'] = codify(reduce_func)
        self._partition_key = partition_key
        self.update(kwargs)
        self.result = Result(self)

    @property
    def map(self):
        """
        Provides an map property accessor and setter.

        For example:

        .. code-block:: python

            # Set the View map property
            view.map = 'function (doc) {\\n  emit(doc._id, 1);\\n}'
            print view.map

        :param str js_func: Javascript function.

        :returns: Codified map function
        """
        return self.get('map')

    @map.setter
    def map(self, js_func):
        """
        Provides a map property setter.
        """
        self['map'] = codify(js_func)

    @property
    def reduce(self):
        """
        Provides an reduce property accessor and setter.

        For example:

        .. code-block:: python

            # Set the View reduce property
            view.reduce = '_count'
            # Get and print the View reduce property
            print view.reduce

        :param str js_func: Javascript function.

        :returns: Codified reduce function
        """
        return self.get('reduce')

    @reduce.setter
    def reduce(self, js_func):
        """
        Provides a reduce property setter.
        """
        self['reduce'] = codify(js_func)

    @property
    def url(self):
        """
        Constructs and returns the View URL.

        :returns: View URL
        """
        if self._partition_key:
            base_url = self.design_doc.document_partition_url(
                self._partition_key)
        else:
            base_url = self.design_doc.document_url

        return '/'.join((
            base_url,
            '_view',
            self.view_name
        ))

    def __call__(self, **kwargs):
        """
        Makes the View object callable and retrieves the raw JSON content
        from the remote database based on the View definition on the server,
        using the kwargs provided as query parameters.

        For example:

        .. code-block:: python

            # Construct a View
            view = View(ddoc, 'view001')
            # Assuming that 'view001' exists as part of the
            # design document ddoc in the remote database...
            # Use view as a callable
            for row in view(include_docs=True, limit=100, skip=100)['rows']:
                # Process view data (in JSON format).

        Note:  Rather than using the View callable directly, if you wish to
        retrieve view results in raw JSON format use ``raw_result=True`` with
        the provided database API of
        :func:`~cloudant.database.CouchDatabase.get_view_result` instead.

        :param bool descending: Return documents in descending key order.
        :param endkey: Stop returning records at this specified key.
        :param str endkey_docid: Stop returning records when the specified
            document id is reached.
        :param bool group: Using the reduce function, group the results to a
            group or single row.
        :param group_level: Only applicable if the view uses complex keys: keys
            that are JSON arrays. Groups reduce results for the specified number
            of array fields.
        :param bool include_docs: Include the full content of the documents.
        :param bool inclusive_end: Include rows with the specified endkey.
        :param str key: Return only documents that match the specified key.
        :param list keys: Return only documents that match the specified keys.
        :param int limit: Limit the number of returned documents to the
            specified count.
        :param bool reduce: True to use the reduce function, false otherwise.
        :param int skip: Skip this number of rows from the start.
        :param str stale: Allow the results from a stale view to be used. This
            makes the request return immediately, even if the view has not been
            completely built yet. If this parameter is not given, a response is
            returned only after the view has been built.
        :param startkey: Return records starting with the specified key.
        :param str startkey_docid: Return records starting with the specified
            document ID.

        :returns: View result data in JSON format
        """
        resp = get_docs(self._r_session,
                        self.url,
                        self.design_doc.encoder,
                        **kwargs)
        return response_to_json_dict(resp)

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        Customizes the :class:`~cloudant.result.Result` behavior and provides
        a convenient context manager for the Result.  Result customizations
        can be made by providing extra options to the result call using this
        context manager.  Depending on how you are accessing, slicing or
        iterating through your result collection certain query parameters are
        not permitted.  See :class:`~cloudant.result.Result` for additional
        details.

        For example:

        .. code-block:: python

            with view.custom_result(include_docs=True, reduce=False) as rslt:
                data = rslt[100: 200]

        :param bool descending: Return documents in descending key order.
        :param endkey: Stop returning records at this specified key.
            Not valid when used with :class:`~cloudant.result.Result` key
            access and key slicing.
        :param str endkey_docid: Stop returning records when the specified
            document id is reached.
        :param bool group: Using the reduce function, group the results to a
            group or single row.
        :param group_level: Only applicable if the view uses complex keys: keys
            that are JSON arrays. Groups reduce results for the specified number
            of array fields.
        :param bool include_docs: Include the full content of the documents.
        :param bool inclusive_end: Include rows with the specified endkey.
        :param key: Return only documents that match the specified key.
            Not valid when used with :class:`~cloudant.result.Result` key
            access and key slicing.
        :param list keys: Return only documents that match the specified keys.
            Not valid when used with :class:`~cloudant.result.Result` key
            access and key slicing.
        :param int limit: Limit the number of returned documents to the
            specified count.  Not valid when used with
            :class:`~cloudant.result.Result` iteration.
        :param int page_size: Sets the page size for result iteration.
        :param bool reduce: True to use the reduce function, false otherwise.
        :param int skip: Skip this number of rows from the start.
            Not valid when used with :class:`~cloudant.result.Result` iteration.
        :param str stale: Allow the results from a stale view to be used. This
            makes the request return immediately, even if the view has not been
            completely built yet. If this parameter is not given, a response is
            returned only after the view has been built.
        :param startkey: Return records starting with the specified key.
            Not valid when used with :class:`~cloudant.result.Result` key
            access and key slicing.
        :param str startkey_docid: Return records starting with the specified
            document ID.

        :returns: View result data wrapped in a Result instance
        """
        rslt = Result(self, **options)
        yield rslt
        del rslt class Index(object):
    """
    Provides an interface for managing a JSON query index.  Primarily
    meant to be used by the database convenience methods
    :func:`~cloudant.database.CloudantDatabase.create_query_index`,
    :func:`~cloudant.database.CloudantDatabase.delete_query_index`, and
    :func:`~cloudant.database.CloudantDatabase.get_query_indexes`.  It is
    recommended that you use those methods to manage an index rather than
    directly interfacing with Index objects.

    :param CloudantDatabase database: A Cloudant database instance used by the
        Index.
    :param str design_document_id: Optional identifier of the design document.
    :param str name: Optional name of the index.
    :param bool partitioned: Optional. Create as a partitioned index. Defaults
        to ``False`` for both partitioned and non-partitioned databases.
    :param kwargs: Options used to construct the index definition for the
        purposes of index creation.  For more details on valid options See
        :func:`~cloudant.database.CloudantDatabase.create_query_index`.
    """

    def __init__(self, database, design_document_id=None, name=None, partitioned=None, **kwargs):
        self._database = database
        self._r_session = self._database.r_session
        self._ddoc_id = design_document_id
        self._name = name
        self._type = JSON_INDEX_TYPE
        self._def = kwargs
        self._partitioned = partitioned

    @property
    def index_url(self):
        """
        Constructs and returns the index URL.

        :returns: Index URL
        """
        return '/'.join((self._database.database_url, '_index'))

    @property
    def design_document_id(self):
        """
        Displays the design document id.

        :returns: Design document that this index belongs to
        """
        return self._ddoc_id

    @property
    def name(self):
        """
        Displays the index name.

        :returns: Name for this index
        """
        return self._name

    @property
    def type(self):
        """
        Displays the index type.

        :returns: Type of this index
        """
        return self._type

    @property
    def definition(self):
        """
        Displays the index definition.  This could be either the definiton to
        be used to construct the index or the definition as it is returned by
        a GET request to the *_index* endpoint.

        :returns: Index definition as a dictionary
        """
        return self._def

    @property
    def partitioned(self):
        """
        Check if this index is partitioned.

        :return: ``True`` if index is partitioned, else ``False``.
        :rtype: bool
        """

        return self._partitioned

    def as_a_dict(self):
        """
        Displays the index as a dictionary.  This includes the design document
        id, index name, index type, and index definition.

        :returns: Dictionary representation of the index as a dictionary
        """
        index_dict = {
            'ddoc': self._ddoc_id,
            'name': self._name,
            'type': self._type,
            'def': self._def
        }

        if self._partitioned:
            index_dict['partitioned'] = True

        return index_dict

    def create(self):
        """
        Creates the current index in the remote database.
        """
        payload = {'type': self._type}
        if self._ddoc_id and self._ddoc_id != '':
            if isinstance(self._ddoc_id, STRTYPE):
                if self._ddoc_id.startswith('_design/'):
                    payload['ddoc'] = self._ddoc_id[8:]
                else:
                    payload['ddoc'] = self._ddoc_id
            else:
                raise CloudantArgumentError(122, self._ddoc_id)
        if self._name and self._name != '':
            if isinstance(self._name, STRTYPE):
                payload['name'] = self._name
            else:
                raise CloudantArgumentError(123, self._name)
        self._def_check()
        payload['index'] = self._def

        if self._partitioned is not None:
            payload['partitioned'] = bool(self._partitioned)

        headers = {'Content-Type': 'application/json'}
        resp = self._r_session.post(
            self.index_url,
            data=json.dumps(payload, cls=self._database.client.encoder),
            headers=headers
        )
        resp.raise_for_status()
        self._ddoc_id = response_to_json_dict(resp)['id']
        self._name = response_to_json_dict(resp)['name']

    def _def_check(self):
        """
        Checks that the only definition provided is a "fields" definition.
        """
        if list(self._def.keys()) != ['fields']:
            raise CloudantArgumentError(124, self._def)

    def delete(self):
        """
        Removes the current index from the remote database.
        """
        if not self._ddoc_id:
            raise CloudantArgumentError(125)
        if not self._name:
            raise CloudantArgumentError(126)
        ddoc_id = self._ddoc_id
        if ddoc_id.startswith('_design/'):
            ddoc_id = ddoc_id[8:]
        url = '/'.join((self.index_url, ddoc_id, self._type, self._name))
        resp = self._r_session.delete(url)
        resp.raise_for_status() class TextIndex(Index):
    """
    Provides an interface for managing a text query index.  Primarily
    meant to be used by the database convenience methods
    :func:`~cloudant.database.CloudantDatabase.create_query_index`,
    :func:`~cloudant.database.CloudantDatabase.delete_query_index`, and
    :func:`~cloudant.database.CloudantDatabase.get_query_indexes`.  It is
    recommended that you use those methods to manage an index rather than
    directly interfacing with TextIndex objects.

    :param CloudantDatabase database: A Cloudant database instance used by the
        TextIndex.
    :param str design_document_id: Optional identifier of the design document.
    :param str name: Optional name of the index.
    :param kwargs: Options used to construct the index definition for the
        purposes of index creation.  For more details on valid options See
        :func:`~cloudant.database.CloudantDatabase.create_query_index`.
    """
    def __init__(self, database, design_document_id=None, name=None, **kwargs):
        super(TextIndex, self).__init__(
            database,
            design_document_id,
            name,
            **kwargs
        )
        self._type = TEXT_INDEX_TYPE

    def _def_check(self):
        """
        Checks that the definition provided contains only valid arguments for a
        text index.
        """
        if self._def != dict():
            for key, val in iteritems_(self._def):
                if key not in list(TEXT_INDEX_ARGS.keys()):
                    raise CloudantArgumentError(127, key)
                if not isinstance(val, TEXT_INDEX_ARGS[key]):
                    raise CloudantArgumentError(128, key, TEXT_INDEX_ARGS[key]) class SpecialIndex(Index):
    """
    Provides an interface for viewing the "special" primary index of a database.
    Primarily meant to be used by the database convenience method
    :func:`~cloudant.database.CloudantDatabase.get_query_indexes`.  It is
    recommended that you use that method to view the "special" index rather than
    directly interfacing with the SpecialIndex object.
    """
    def __init__(
            self,
            database,
            design_document_id=None,
            name='_all_docs',
            **kwargs
    ):
        super(SpecialIndex, self).__init__(
            database,
            design_document_id,
            name,
            **kwargs
        )
        self._type = SPECIAL_INDEX_TYPE

    def create(self):
        """
        A "special" index cannot be created.  This method is disabled for a
        SpecialIndex object.
        """
        raise CloudantIndexException(101)

    def delete(self):
        """
        A "special" index cannot be deleted.  This method is disabled for a
        SpecialIndex object.
        """
        raise CloudantIndexException(102) class Query(dict):
    """
    Encapsulates a query as a dictionary based object, providing a sliceable
    and iterable query result collection that can be used to process query
    output data through the ``result`` attribute.

    For example:

    .. code-block:: python

        # Slicing to skip/limit:
        query.result[100:200]
        query.result[:200]
        query.result[100:]
        query.result[:]

        # Iteration is supported via the result attribute:
        for doc in query.result:
            print doc

    The query ``result`` collection provides basic functionality,
    which can be customized with other arguments using the
    :func:`~cloudant.query.Query.custom_result` context.

    For example:

    .. code-block:: python

        # Setting the read quorum as part of a custom result
        with query.custom_result(r=3) as rslt:
            rslt[100:200] # slice the result

            # Iteration
            for doc in rslt:
                print doc

        # Iteration over a query result sorted by the "name" field:
        with query.custom_result(sort=[{'name': 'asc'}]) as rslt:
            for doc in rslt:
                print doc

    :param CloudantDatabase database: A Cloudant database instance used by the
        Query.
    :param str bookmark: A string that enables you to specify which page of
        results you require.
    :param list fields: A list of fields to be returned by the query.
    :param int limit: Maximum number of results returned.
    :param int r: Read quorum needed for the result.  Each document is read from
        at least 'r' number of replicas before it is returned in the results.
    :param dict selector: Dictionary object describing criteria used to select
        documents.
    :param int skip: Skip the first 'n' results, where 'n' is the value
        specified.
    :param list sort: A list of fields to sort by.  Optionally the list can
        contain elements that are single member dictionary structures that
        specify sort direction.  For example ``sort=['name', {'age': 'desc'}]``
        means to sort the query results by the "name" field in ascending order
        and the "age" field in descending order.
    :param str use_index: Identifies a specific index for the query to run
        against, rather than using the Cloudant Query algorithm which finds
        what it believes to be the best index.
    :param str partition_key: Optional. Specify a query partition key. Defaults
        to ``None`` resulting in global queries.
    """

    def __init__(self, database, **kwargs):
        super(Query, self).__init__()
        self._database = database
        self._partition_key = kwargs.pop('partition_key', None)
        self._r_session = self._database.r_session
        self._encoder = self._database.client.encoder
        if kwargs.get('fields', True) is None:
            del kwargs['fields']  # delete `None` fields kwarg
        if kwargs:
            super(Query, self).update(kwargs)
        self.result = QueryResult(self)

    @property
    def url(self):
        """
        Constructs and returns the Query URL.

        :returns: Query URL
        """
        if self._partition_key:
            base_url = self._database.database_partition_url(
                self._partition_key)
        else:
            base_url = self._database.database_url

        return base_url + '/_find'

    def __call__(self, **kwargs):
        """
        Makes the Query object callable and retrieves the raw JSON content
        from the remote database based on the current Query definition,
        and any additional kwargs provided as query parameters.

        For example:

        .. code-block:: python

            # Construct a Query
            query = Query(database, selector={'_id': {'$gt': 0}})
            # Use query as a callable limiting results to 100,
            # skipping the first 100.
            for doc in query(limit=100, skip=100)['docs']:
                # Process query data (in JSON format).

        Note:  Rather than using the Query callable directly, if you wish to
        retrieve query results in raw JSON format use the provided database API
        of :func:`~cloudant.database.CouchDatabase.get_query_result`
        and set ``raw_result=True`` instead.

        :param str bookmark: A string that enables you to specify which page of
            results you require.
        :param list fields: A list of fields to be returned by the query.
        :param int limit: Maximum number of results returned.
        :param int r: Read quorum needed for the result.  Each document is read
            from at least 'r' number of replicas before it is returned in the
            results.
        :param dict selector: Dictionary object describing criteria used to
            select documents.
        :param int skip: Skip the first 'n' results, where 'n' is the value
            specified.
        :param list sort: A list of fields to sort by.  Optionally the list can
            contain elements that are single member dictionary structures that
            specify sort direction.  For example
            ``sort=['name', {'age': 'desc'}]`` means to sort the query results
            by the "name" field in ascending order and the "age" field in
            descending order.
        :param str use_index: Identifies a specific index for the query to run
            against, rather than using the Cloudant Query algorithm which finds
            what it believes to be the best index.

        :returns: Query result data in JSON format
        """
        data = dict(self)
        data.update(kwargs)

        # Validate query arguments and values
        for key, val in iteritems_(data):
            if key not in list(QUERY_ARG_TYPES.keys()):
                raise CloudantArgumentError(129, key)
            if not isinstance(val, QUERY_ARG_TYPES[key]):
                raise CloudantArgumentError(130, key, QUERY_ARG_TYPES[key])
        if data.get('selector', None) is None or data.get('selector') == {}:
            raise CloudantArgumentError(131)

        # Execute query find
        headers = {'Content-Type': 'application/json'}
        resp = self._r_session.post(
            self.url,
            headers=headers,
            data=json.dumps(data, cls=self._encoder)
        )
        resp.raise_for_status()
        return response_to_json_dict(resp)

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        Customizes the :class:`~cloudant.result.QueryResult` behavior and
        provides a convenient context manager for the QueryResult.  QueryResult
        customizations can be made by providing extra options to the query
        result call using this context manager.  The use of ``skip`` and
        ``limit`` as options are not valid when using a QueryResult since the
        ``skip`` and ``limit`` functionality is handled in the QueryResult.

        For example:

        .. code-block:: python

            with query.custom_result(sort=[{'name': 'asc'}]) as rslt:
                data = rslt[100:200]

        :param str bookmark: A string that enables you to specify which page of
            results you require.
        :param list fields: A list of fields to be returned by the query.
        :param int page_size: Sets the page size for result iteration.  Default
            is 100.
        :param int r: Read quorum needed for the result.  Each document is read
            from at least 'r' number of replicas before it is returned in the
            results.
        :param dict selector: Dictionary object describing criteria used to
            select documents.
        :param list sort: A list of fields to sort by.  Optionally the list can
            contain elements that are single member dictionary structures that
            specify sort direction.  For example
            ``sort=['name', {'age': 'desc'}]`` means to sort the query results
            by the "name" field in ascending order and the "age" field in
            descending order.
        :param str use_index: Identifies a specific index for the query to run
            against, rather than using the Cloudant Query algorithm which finds
            what it believes to be the best index.

        :returns: Query result data wrapped in a QueryResult instance
        """
        rslt = QueryResult(self, **options)
        yield rslt
        del rslt class CloudantArgumentError(CloudantException):
    """
    Provides a way to issue Cloudant Python client library specific exceptions
    that pertain to invalid argument errors.

    Note:  The intended use for this class is internal to the Cloudant Python
    client library.

    :param int code: An optional code value used to identify the exception.
        Defaults to 100.
    :param args: A list of arguments used to format the exception message.
    """
    def __init__(self, code=100, *args):
        try:
            msg = ARGUMENT_ERROR[code].format(*args)
        except (KeyError, IndexError):
            code = 100
            msg = ARGUMENT_ERROR[code]
        super(CloudantArgumentError, self).__init__(msg, code) class CloudantDatabaseException(CloudantException):
    """
    Provides a way to issue Cloudant library database specific exceptions.

    :param int code: A code value used to identify the database exception.
    :param args: A list of arguments used to format the exception message.
    """
    def __init__(self, code=100, *args):
        try:
            if code in DATABASE:
                msg = DATABASE[code].format(*args)
            elif isinstance(code, int):
                msg = ' '.join(args)
            else:
                code = 100
                msg = DATABASE[code]
        except (KeyError, IndexError):
            code = 100
            msg = DATABASE[code]
        super(CloudantDatabaseException, self).__init__(msg, code) class Result(object):
    """
    Provides a key accessible, sliceable, and iterable interface to result
    collections.  A Result object is constructed with a raw data callable
    reference such as the database API convenience method
    :func:`~cloudant.database.CouchDatabase.all_docs` or the View
    :func:`~cloudant.view.View.__call__` callable, used to retrieve data.
    A Result object can also use optional extra arguments for result
    customization and supports efficient, paged iteration over the result
    collection to avoid large result data from adversely affecting memory.

    In Python, slicing returns by value, whereas iteration will yield
    elements of the sequence.  This means that individual key access and slicing
    will perform better for smaller data collections, whereas iteration will
    be more efficient for larger data collections.

    For example:

    .. code-block:: python

        # Key access:

        # Access by index value:
        result = Result(callable)
        result[9]                 # skip first 9 records and get 10th

        # Access by key value:
        result = Result(callable)
        result['foo']             # get records matching 'foo'
        result[ResultByKey(9)]    # get records matching 9

        # Slice access:

        # Access by index slices:
        result = Result(callable)
        result[100: 200]          # get records after the 100th and up to and including the 200th
        result[: 200]             # get records up to and including the 200th
        result[100: ]             # get all records after the 100th
        result[: ]                # get all records

        # Access by key slices:
        result = Result(callable)
        result['bar':'foo']       # get records between and including 'bar' and 'foo'
        result['foo':]            # get records after and including 'foo'
        result[:'foo']            # get records up to and including 'foo'

        result[['foo', 10]:
               ['foo', 11]]       # Complex key access and slicing works the same as simple keys

        result[ResultByKey(5):
               ResultByKey(10)]   # key slice access of integer keys

        # Iteration:

        # Iterate over the entire result collection
        result = Result(callable)
        for i in result:
            print i

        # Iterate over the result collection between startkey and endkey
        result = Result(callable, startkey='2013', endkey='2014')
        for i in result:
            print i

        # Iterate over the entire result collection in batches of 1000, including documents.
        result = Result(callable, include_docs=True, page_size=1000)
        for i in result:
            print i

    Note: Since Result object key access, slicing, and iteration use query
    parameters behind the scenes to handle their processing, some query
    parameters are not permitted as part of a Result customization,
    depending on whether key access, slicing, or iteration is being performed.

    Such as:

    +-------------------------------+-----------------------------------------------------------+
    | Access/Slicing by index value | No restrictions                                           |
    +-------------------------------+-----------------------------------------------------------+
    | Access/Slicing by key value   | ``key``, ``keys``, ``startkey``, ``endkey`` not permitted |
    +-------------------------------+-----------------------------------------------------------+
    | Iteration                     | ``limit``, ``skip`` not permitted                         |
    +-------------------------------+-----------------------------------------------------------+

    :param str method_ref: A reference to the method or callable that returns
        the JSON content result to be wrapped as a Result.
    :param bool descending: Return documents in descending key order.
    :param endkey: Stop returning records at this specified key.
        Not valid when used with key access and key slicing.
    :param str endkey_docid: Stop returning records when the specified
        document id is reached.
    :param bool group: Using the reduce function, group the results to a
        group or single row.
    :param group_level: Only applicable if the view uses complex keys: keys
        that are JSON arrays. Groups reduce results for the specified number
        of array fields.
    :param bool include_docs: Include the full content of the documents.
    :param bool inclusive_end: Include rows with the specified endkey.
    :param key: Return only documents that match the specified key.
        Not valid when used with key access and key slicing.
    :param list keys: Return only documents that match the specified keys.
        Not valid when used with key access and key slicing.
    :param int limit: Limit the number of returned documents to the
        specified count.  Not valid when used with key iteration.
    :param int page_size: Sets the page size for result iteration.
    :param bool reduce: True to use the reduce function, false otherwise.
    :param int skip: Skip this number of rows from the start.
        Not valid when used with key iteration.
    :param bool stable: Whether or not the view results should be returned from
        a "stable" set of shards.
    :param str stale: Allow the results from a stale view to be used. This makes
        the request return immediately, even if the view has not been completely
        built yet. If this parameter is not given, a response is returned only
        after the view has been built. Note that this parameter is deprecated
        and the appropriate combination of `stable` and `update` should be used
        instead.
    :param startkey: Return records starting with the specified key.
        Not valid when used with key access and key slicing.
    :param str startkey_docid: Return records starting with the specified
        document ID.
    :param str update: Determine whether the view in question should be
        updated prior to or after responding to the user. Valid values are:
        false: return results before updating the view; true: Return results
        after updating the view; lazy: Return the view results without
        waiting for an update, but update them immediately after the request.

    """
    def __init__(self, method_ref, **options):
        self.options = options
        self._ref = method_ref
        self._page_size = options.pop('page_size', 100)

    def __getitem__(self, arg):
        """
        Provides Result key access and slicing support.

        An ``int`` argument will be interpreted as a ``skip`` and then a get of
        the next record.  For example ``[100]`` means skip the first 100 records
        and then get the next record.

        A ``str``, ``list`` or :class:`~cloudant.result.ResultByKey` argument
        will be interpreted as a ``key`` and then get all records that match the
        given key.  For example ``['foo']`` will get all records that match
        the key 'foo'.

        An ``int`` slice argument will be interpreted as a ``skip:limit-skip``
        style pair.  For example ``[100: 200]`` means skip the first 100 records
        then get up to and including the 200th record so that you get the range
        between the supplied slice values.

        A slice argument that contains ``str``, ``list``, or
        :class:`~cloudant.result.ResultByKey` will be interpreted as a
        ``startkey: endkey`` style pair.  For example ``['bar': 'foo']`` means
        get the range of records where the keys are between and including
        'bar' and 'foo'.

        See :class:`~cloudant.result.Result` for more detailed key access and
        slicing examples.

        :param arg:  A single value representing a key or a pair of values
            representing a slice.  The argument value(s) can be ``int``,
            ``str``, ``list`` (in the case of complex keys), or
            :class:`~cloudant.result.ResultByKey`.

        :returns: Rows data as a list in JSON format
        """
        data = None
        if isinstance(arg, int):
            data = self._handle_result_by_index(arg)
        elif isinstance(arg, (STRTYPE, list)):
            data = self._handle_result_by_key(arg)
        elif isinstance(arg, ResultByKey):
            data = self._handle_result_by_key(arg())
        elif isinstance(arg, slice):
            # slice is entire result set - no additional processing required
            if arg.start is None and arg.stop is None:
                data = self._ref(**self.options)
            # key slice identified
            elif (type_or_none((STRTYPE, list, ResultByKey), arg.start) and
                  type_or_none((STRTYPE, list, ResultByKey), arg.stop)):
                data = self._handle_result_by_key_slice(arg)
            # index slice identified
            elif (type_or_none(int, arg.start) and
                  type_or_none(int, arg.stop)):
                data = self._handle_result_by_idx_slice(arg)
        if data is None:
            raise ResultException(101, arg)
        return self._parse_data(data)

    def _handle_result_by_index(self, idx):
        """
        Handle processing when the result argument provided is an integer.
        """
        if idx < 0:
            return None
        opts = dict(self.options)
        skip = opts.pop('skip', 0)
        limit = opts.pop('limit', None)
        py_to_couch_validate('skip', skip)
        py_to_couch_validate('limit', limit)
        if limit is not None and idx >= limit:
            # Result is out of range
            return dict()
        return self._ref(skip=skip+idx, limit=1, **opts)

    def _handle_result_by_key(self, key):
        """
        Handle processing when the result argument provided is a document key.
        """
        invalid_options = ('key', 'keys', 'startkey', 'endkey')
        if any(x in invalid_options for x in self.options):
            raise ResultException(102, invalid_options, self.options)
        return self._ref(key=key, **self.options)

    def _handle_result_by_idx_slice(self, idx_slice):
        """
        Handle processing when the result argument provided is an index slice.
        """
        opts = dict(self.options)
        skip = opts.pop('skip', 0)
        limit = opts.pop('limit', None)
        py_to_couch_validate('skip', skip)
        py_to_couch_validate('limit', limit)
        start = idx_slice.start
        stop = idx_slice.stop
        data = None
        # start and stop cannot be None and both must be greater than 0
        if all(i is not None and i >= 0 for i in [start, stop]) and start < stop:
            if limit is not None:
                if start >= limit:
                    # Result is out of range
                    return dict()
                if stop > limit:
                    # Ensure that slice does not extend past original limit
                    return self._ref(skip=skip+start, limit=limit-start, **opts)
            data = self._ref(skip=skip+start, limit=stop-start, **opts)
        elif start is not None and stop is None and start >= 0:
            if limit is not None:
                if start >= limit:
                    # Result is out of range
                    return dict()
                # Ensure that slice does not extend past original limit
                data = self._ref(skip=skip+start, limit=limit-start, **opts)
            else:
                data = self._ref(skip=skip+start, **opts)
        elif start is None and stop is not None and stop >= 0:
            if limit is not None and stop > limit:
                # Ensure that slice does not extend past original limit
                data = self._ref(skip=skip, limit=limit, **opts)
            else:
                data = self._ref(skip=skip, limit=stop, **opts)
        return data

    def _handle_result_by_key_slice(self, key_slice):
        """
        Handle processing when the result argument provided is a key slice.
        """
        invalid_options = ('key', 'keys', 'startkey', 'endkey')
        if any(x in invalid_options for x in self.options):
            raise ResultException(102, invalid_options, self.options)

        if isinstance(key_slice.start, ResultByKey):
            start = key_slice.start()
        else:
            start = key_slice.start

        if isinstance(key_slice.stop, ResultByKey):
            stop = key_slice.stop()
        else:
            stop = key_slice.stop

        if (start is not None and stop is not None and
                isinstance(start, type(stop))):
            data = self._ref(startkey=start, endkey=stop, **self.options)
        elif start is not None and stop is None:
            data = self._ref(startkey=start, **self.options)
        elif start is None and stop is not None:
            data = self._ref(endkey=stop, **self.options)
        else:
            data = None
        return data

    def __iter__(self):
        """
        Provides iteration support, primarily for large data collections.
        The iterator uses the ``startkey``, ``startkey_docid``, and ``limit``
        options to consume data in chunks controlled by the ``page_size``
        option. It retrieves a batch of data from the result collection
        and then yields each element.

        See :class:`~cloudant.result.Result` for Result iteration examples.

        :returns: Iterable data sequence
        """
        invalid_options = ('limit', )
        if any(x in invalid_options for x in self.options):
            raise ResultException(103, invalid_options, self.options)

        try:
            self._page_size = int(self._page_size)
            if self._page_size <= 0:
                raise ResultException(104, self._page_size)
        except ValueError:
            raise ResultException(104, self._page_size)

        init_opts = {
            'skip': self.options.pop('skip', None),
            'startkey': self.options.pop('startkey', None)
        }

        self._call = partial(self._ref,  #pylint: disable=attribute-defined-outside-init
                             limit=self._real_page_size,
                             **self.options)

        response = self._call(**{k: v
                                 for k, v
                                 in init_opts.items()
                                 if v is not None})

        return self._iterator(response)

    @property
    def _real_page_size(self):
        '''
        In views we paginate with N+1 items per page.
        https://docs.couchdb.org/en/stable/ddocs/views/pagination.html#paging-alternate-method
        '''
        return self._page_size + 1

    def _iterator(self, response):
        '''
        Iterate through view data.
        '''

        while True:
            result = deque(self._parse_data(response))
            del response
            if result:
                doc_count = len(result)
                last = result.pop()
                while result:
                    yield result.popleft()

                # We expect doc_count = self._page_size + 1 results, if
                # we have self._page_size or less it means we are on the
                # last page and need to return the last result.
                if doc_count < self._real_page_size:
                    yield last
                    break
                del result

                # if we are in a view, keys could be duplicate so we
                # need to start from the right docid
                last_doc_id = last.get('id')
                if last_doc_id is not None:
                    response = self._call(startkey=last['key'],
                                          startkey_docid=last_doc_id)
                # reduce result keys are unique by definition
                else:
                    response = self._call(startkey=last['key'])

            else:
                break

    # pylint: disable=no-self-use
    def _parse_data(self, data):
        """
        Used to extract the rows content from the JSON result content
        """
        return data.get('rows', [])

    def all(self):
        """
        Retrieve all results.

        Specifying a ``limit`` parameter in the ``Result`` constructor will
        limit the number of documents returned. Be aware that the ``page_size``
        parameter is not honoured.

        :return: results data as list in JSON format.
        """
        return self[:] class QueryResult(Result):
    """
    Provides a index key accessible, sliceable and iterable interface to query
    result collections by extending the :class:`~cloudant.result.Result` class.
    A QueryResult object is constructed with a raw data callable reference to
    the Query :func:`~cloudant.query.Query.__call__` callable, which is used to
    retrieve data.  A QueryResult object can also use optional extra arguments
    for result customization and supports efficient, paged iteration over the
    result collection to avoid large result data from adversely affecting
    memory.

    In Python, slicing returns by value, whereas iteration will yield
    elements of the sequence.  This means that index key access and slicing will
    perform better for smaller data collections, whereas iteration will be more
    efficient for larger data collections.

    For example:

    .. code-block:: python

        # Key access:

        # Access by index value:
        query_result = QueryResult(query)
        query_result[9]        # skip first 9 documents and get 10th

        # Slice access:

        # Access by index slices:
        query_result = QueryResult(query)
        query_result[100: 200] # get documents after the 100th and up to and including the 200th
        query_result[ :200]    # get documents up to and including the 200th
        query_result[100: ]    # get all documents after the 100th
        query_result[: ]       # get all documents

        # Iteration:

        # Iterate over the entire result collection
        query_result = QueryResult(query)
        for doc in query_result:
            print doc

        # Iterate over the result collection, with an overriding query sort
        query_result = QueryResult(query, sort=[{'name': 'desc'}])
        for doc in query_result:
            print doc

        # Iterate over the entire result collection,
        # explicitly setting the index and in batches of 1000.
        query_result = QueryResult(query, use_index='my_index', page_size=1000)
        for doc in query_result:
            print doc

    Note: Only access by index value, slicing by index values and iteration are
    supported by QueryResult.  Also, since QueryResult object iteration uses the
    ``skip`` and ``limit`` query parameters to handle its processing, ``skip``
    and ``limit`` are not permitted to be part of the query callable or be
    included as part of the QueryResult customized parameters.

    :param query: A reference to the query callable that returns
        the JSON content result to be wrapped.
    :param str bookmark: A string that enables you to specify which page of
        results you require.
    :param list fields: A list of fields to be returned by the query.
    :param int page_size: Sets the page size for result iteration.  Default
        is 100.
    :param int r: Read quorum needed for the result.  Each document is read
        from at least 'r' number of replicas before it is returned in the
        results.
    :param dict selector: Dictionary object describing criteria used to
        select documents.
    :param list sort: A list of fields to sort by.  Optionally the list can
        contain elements that are single member dictionary structures that
        specify sort direction.  For example
        ``sort=['name', {'age': 'desc'}]`` means to sort the query results
        by the "name" field in ascending order and the "age" field in
        descending order.
    :param str use_index: Identifies a specific index for the query to run
        against, rather than using the Cloudant Query algorithm which finds
        what it believes to be the best index.
    """
    def __init__(self, query, **options):
        # Move skip/limit to options so super class Result can handle as needed.
        if 'skip' in query and 'skip' not in options:
            options['skip'] = query['skip']
        if 'limit' in query and 'limit' not in options:
            options['limit'] = query['limit']
        super(QueryResult, self).__init__(query, **options)

    def __getitem__(self, arg):
        """
        Provides QueryResult index access and index slicing support.

        An ``int`` argument will be interpreted as a ``skip`` and then a get of
        the next document.  For example ``[100]`` means skip the first 100
        documents and then get the next document.

        An ``int`` slice argument will be interpreted as a ``skip:limit-skip``
        style pair.  For example ``[100: 200]`` means skip the first 100
        documents then get up to and including the 200th document so that you
        get the range between the supplied slice values.

        See :class:`~cloudant.result.QueryResult` for more detailed index access
        and index slicing examples.

        :param arg:  A single value representing a key or a pair of values
            representing a slice.  The argument value(s) must be ``int``.

        :returns: Document data as a list in JSON format
        """
        # Argument can only be an integer or an integer slice.
        if ((isinstance(arg, int)) or
                (isinstance(arg, slice) and
                 type_or_none(int, arg.start) and
                 type_or_none(int, arg.stop))):
            return super(QueryResult, self).__getitem__(arg)

        raise ResultException(101, arg)

    def _parse_data(self, data):
        """
        Overrides Result._parse_data to extract the docs content from the
        query result JSON response content
        """
        return data.get('docs', [])

    @property
    def _real_page_size(self):
        '''
        During queries iteration page size is user-specified
        '''
        return self._page_size

    def _iterator(self, response):
        '''
        Iterate through query data.
        '''

        while True:
            result = self._parse_data(response)
            bookmark = response.get('bookmark')
            if result:
                for row in result:
                    yield row

                del result

                if not bookmark:
                    break

                response = self._call(bookmark=bookmark)

            else:
                break class Feed(object):
    """
    Provides an iterator for consuming client and database feeds such as
    ``_db_updates`` and ``_changes``.  A Feed object is constructed with a
    :mod:`~cloudant.client` or a :mod:`~cloudant.database` which it uses to
    issue HTTP requests to the appropriate feed endpoint. Instead of using this
    class directly, it is recommended to use the client APIs
    :func:`~cloudant.client.CouchDB.db_updates`,
    :func:`~cloudant.client.Cloudant.db_updates`, or the database API
    :func:`~cloudant.database.CouchDatabase.changes`.  Reference those methods
    for a list of valid feed options.

    :param source: Either a :mod:`~cloudant.client` object or a
        :mod:`~cloudant.database` object.
    :param bool raw_data: If set to True then the raw response data will be
        streamed otherwise if set to False then JSON formatted data will be
        streamed.  Default is False.
    """
    def __init__(self, source, raw_data=False, **options):
        self._r_session = source.r_session
        self._raw_data = raw_data
        self._options = options
        self._source = source.__class__.__name__
        if self._source == 'CouchDB':
            self._url = '/'.join([source.server_url, '_db_updates'])
            # Set CouchDB _db_updates option defaults as they differ from
            # the _changes and Cloudant _db_updates option defaults
            self._options['feed'] = self._options.get('feed', 'longpoll')
            self._options['heartbeat'] = self._options.get('heartbeat', True)
        elif self._source == 'Cloudant':
            self._url = '/'.join([source.server_url, '_db_updates'])
        else:
            self._url = '/'.join([source.database_url, '_changes'])
        self._chunk_size = self._options.pop('chunk_size', 512)

        self._resp = None
        self._lines = None
        self._last_seq = None
        self._stop = False

    @property
    def last_seq(self):
        """
        Returns the last sequence identifier for the feed.  Only available after
        the feed has iterated through to completion.

        :returns: A string representing the last sequence number of a feed.
        """
        return self._last_seq

    def stop(self):
        """
        Stops a feed iteration.
        """
        self._stop = True

    def _start(self):
        """
        Starts streaming the feed using the provided session and feed options.
        """
        params = self._translate(self._options)
        self._resp = self._r_session.get(self._url, params=params, stream=True)
        self._resp.raise_for_status()
        self._lines = self._resp.iter_lines(self._chunk_size)

    def _translate(self, options):
        """
        Perform translation of feed options passed in as keyword
        arguments to CouchDB/Cloudant equivalent.
        """
        translation = dict()
        for key, val in iteritems_(options):
            self._validate(key, val, feed_arg_types(self._source))
            try:
                if isinstance(val, STRTYPE):
                    translation[key] = val
                elif not isinstance(val, NONETYPE):
                    arg_converter = TYPE_CONVERTERS.get(type(val), json.dumps)
                    translation[key] = arg_converter(val)
            except Exception as ex:
                raise CloudantArgumentError(115, key, ex)
        return translation

    def _validate(self, key, val, arg_types):
        """
        Ensures that the key and the value are valid arguments to be used with
        the feed.
        """
        if key in arg_types:
            arg_type = arg_types[key]
        else:
            if ANY_ARG not in arg_types:
                raise CloudantArgumentError(116, key)
            arg_type = arg_types[ANY_ARG]

        if arg_type == ANY_TYPE:
            return
        if (not isinstance(val, arg_type) or
                (isinstance(val, bool) and int in arg_type)):
            raise CloudantArgumentError(117, key, arg_type)
        if isinstance(val, int) and val < 0 and not isinstance(val, bool):
            raise CloudantArgumentError(118, key, val)
        if key == 'feed':
            valid_vals = ('continuous', 'normal', 'longpoll')
            if self._source == 'CouchDB':
                valid_vals = ('continuous', 'longpoll')
            if val not in valid_vals:
                raise CloudantArgumentError(119, val, valid_vals)
        if key == 'style' and val not in ('main_only', 'all_docs'):
            raise CloudantArgumentError(120, val)

    def __iter__(self):
        """
        Makes this object an iterator.
        """
        return self

    def __next__(self):
        """
        Provides Python3 compatibility.
        """
        return self.next()  # pylint: disable=not-callable

    def next(self):
        """
        Handles the iteration by pulling the next line out of the stream,
        attempting to convert the response to JSON if necessary.

        :returns: Data representing what was seen in the feed
        """
        while True:
            if not self._resp:
                self._start()
            if self._stop:
                raise StopIteration
            skip, data = self._process_data(next_(self._lines))
            if not skip:
                break
        return data

    def _process_data(self, line):
        """
        Validates and processes the line passed in and converts it to a
        Python object if necessary.
        """
        skip = False
        if self._raw_data:
            return skip, line
        line = unicode_(line)
        if not line:
            if (self._options.get('heartbeat', False) and
                    self._options.get('feed') in ('continuous', 'longpoll') and
                    not self._last_seq):
                line = None
            else:
                skip = True
        elif line in ('{"results":[', '],'):
            skip = True
        elif line[-1] == ',':
            line = line[:-1]
        elif line[:10] == ('"last_seq"'):
            line = '{' + line
        try:
            if line:
                data = json.loads(line)
                if data.get('last_seq'):
                    self._last_seq = data['last_seq']
                    skip = True
            else:
                data = None
        except ValueError:
            data = {"error": "Bad JSON line", "line": line}
        return skip, data class InfiniteFeed(Feed):
    """
    Provides an infinite iterator for consuming client and database feeds such
    as ``_db_updates`` and ``_changes``.  An InfiniteFeed object is constructed
    with a :class:`~cloudant.client.Cloudant` object or a
    :mod:`~cloudant.database` object which it uses to issue HTTP requests to the
    appropriate feed endpoint.  An infinite feed is NOT supported for use with a
    :class:`~cloudant.client.CouchDB` object and unlike a
    :class:`~cloudant.feed.Feed` which can be a ``normal``, ``longpoll``,
    or ``continuous`` feed, an InfiniteFeed can only be ``continuous`` and the
    iterator will only stream formatted JSON objects.  Instead of using this
    class directly, it is recommended to use the client
    API :func:`~cloudant.client.Cloudant.infinite_db_updates` or the database
    API :func:`~cloudant.database.CouchDatabase._infinite_changes`.  Reference
    those methods for a valid list of feed options.

    Note: The infinite iterator is not exception resilient so if an
    unexpected exception occurs, the iterator will terminate.  Any unexpected
    exceptions should be handled in code outside of this library.  If you wish
    to restart the infinite iterator from where it left off that can be done by
    constructing a new InfiniteFeed object with the ``since`` option set to the
    sequence number of the last row of data prior to termination.

    :param source: Either a :class:`~cloudant.client.Cloudant` object or a
        :mod:`~cloudant.database` object.
    """
    def __init__(self, source, **options):
        super(InfiniteFeed, self).__init__(source, False, **options)
        # Default feed to continuous if not explicitly set
        self._options['feed'] = self._options.get('feed', 'continuous')

    def _validate(self, key, val, arg_types):
        """
        Ensures that the key and the value are valid arguments to be used with
        the feed.
        """
        if key == 'feed' and val != 'continuous':
            raise CloudantArgumentError(121, val)
        super(InfiniteFeed, self)._validate(key, val, arg_types)

    def next(self):
        """
        Handles the iteration by pulling the next line out of the stream and
        converting the response to JSON.

        :returns: Data representing what was seen in the feed
        """
        while True:
            if self._source == 'CouchDB':
                raise CloudantFeedException(101)
            if self._last_seq:
                self._options.update({'since': self._last_seq})
                self._resp = None
                self._last_seq = None
            if not self._resp:
                self._start()
            if self._stop:
                raise StopIteration
            skip, data = self._process_data(next_(self._lines))
            if not skip:
                break
        return data
import json
import contextlib
from requests.exceptions import HTTPError
from ._2to3 import url_quote_plus, iteritems_
from ._common_util import (
    JSON_INDEX_TYPE,
    SEARCH_INDEX_ARGS,
    SPECIAL_INDEX_TYPE,
    TEXT_INDEX_TYPE,
    TYPE_CONVERTERS,
    get_docs,
    response_to_json_dict)
from .document import Document
from .design_document import DesignDocument
from .security_document import SecurityDocument
from .view import View
from .index import Index, TextIndex, SpecialIndex
from .query import Query
from .error import CloudantArgumentError, CloudantDatabaseException
from .result import Result, QueryResult
from .feed import Feed, InfiniteFeed
        :returns: Metadata dictionary for the database partition.
        :rtype: dict
        """
        resp = self.r_session.get(self.database_partition_url(partition_key))
        resp.raise_for_status()
        return response_to_json_dict(resp)

    def doc_count(self):
        """
        Retrieves the number of documents in the remote database

        :returns: Database document count
        """
        return self.metadata().get('doc_count')

    def create_document(self, data, throw_on_exists=False):
        """
        Creates a new document in the remote and locally cached database, using
        the data provided.  If an _id is included in the data then depending on
        that _id either a :class:`~cloudant.document.Document` or a
        :class:`~cloudant.design_document.DesignDocument`
        object will be added to the locally cached database and returned by this
        method.

        :param dict data: Dictionary of document JSON data, containing _id.
        :param bool throw_on_exists: Optional flag dictating whether to raise
            an exception if the document already exists in the database.

        :returns: A :class:`~cloudant.document.Document` or
            :class:`~cloudant.design_document.DesignDocument` instance
            corresponding to the new document in the database.
        """
        docid = data.get('_id', None)
        doc = None
        if docid and docid.startswith('_design/'):
            doc = DesignDocument(self, docid)
        else:
            doc = Document(self, docid)
        doc.update(data)
        try:
            doc.create()
        except HTTPError as error:
            if error.response.status_code == 409:
                if throw_on_exists:
                    raise CloudantDatabaseException(409, docid)
            else:
                raise
        super(CouchDatabase, self).__setitem__(doc['_id'], doc)
        return doc

    def new_document(self):
        """
        Creates a new, empty document in the remote and locally cached database,
        auto-generating the _id.

        :returns: Document instance corresponding to the new document in the
            database
        """
        doc = Document(self, None)
        doc.create()
        super(CouchDatabase, self).__setitem__(doc['_id'], doc)
        return doc

    def design_documents(self):
        """
        Retrieve the JSON content for all design documents in this database.
        Performs a remote call to retrieve the content.

        :returns: All design documents found in this database in JSON format
        """
        url = '/'.join((self.database_url, '_all_docs'))
        query = "startkey=\"_design\"&endkey=\"_design0\"&include_docs=true"
        resp = self.r_session.get(url, params=query)
        resp.raise_for_status()
        data = response_to_json_dict(resp)
        return data['rows']

    def list_design_documents(self):
        """
        Retrieves a list of design document names in this database.
        Performs a remote call to retrieve the content.

        :returns: List of names for all design documents in this database
        """
        url = '/'.join((self.database_url, '_all_docs'))
        query = "startkey=\"_design\"&endkey=\"_design0\""
        resp = self.r_session.get(url, params=query)
        resp.raise_for_status()
        data = response_to_json_dict(resp)
        return [x.get('key') for x in data.get('rows', [])]

    def get_design_document(self, ddoc_id):
        """
        Retrieves a design document.  If a design document exists remotely
        then that content is wrapped in a DesignDocument object and returned
        to the caller.  Otherwise a "shell" DesignDocument object is returned.

        :param str ddoc_id: Design document id

        :returns: A DesignDocument instance, if exists remotely then it will
            be populated accordingly
        """
        ddoc = DesignDocument(self, ddoc_id)
        try:
            ddoc.fetch()
        except HTTPError as error:
            if error.response.status_code != 404:
                raise

        return ddoc

    def get_security_document(self):
        """
        Retrieves the database security document as a SecurityDocument object.
        The returned object is useful for viewing as well as updating the
        the database's security document.

        :returns: A SecurityDocument instance representing the database
            security document
        """

        sdoc = SecurityDocument(self)