[](https://github.com/IBM/cloudant-python-sdk/actions/workflows/test.yml)
[](https://github.com/IBM/cloudant-python-sdk/releases/latest)
[](https://ibm.github.io/cloudant-python-sdk/)
# IBM Cloudant Python SDK Version 0.10.5
IBM Cloudant Python SDK is a client library that interacts with the
[IBM Cloudant APIs](https://cloud.ibm.com/apidocs/cloudant?code=python).
Disclaimer: This library is still a 0.x release. We do consider this
library production-ready and capable, but there are still some
limitations we’re working to resolve, and refinements we want to
deliver. We are working really hard to minimise the disruption from
now until the 1.0 release, but there may still be some changes that
impact applications using this SDK. For now, be sure to pin versions
to avoid surprises.
<details>
<summary>Table of Contents</summary>
<!-- toc -->
- [Overview](#overview)
- [Features](#features)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Using the SDK](#using-the-sdk)
* [Authentication](#authentication)
+ [Authentication with environment variables](#authentication-with-environment-variables)
- [IAM API key authentication](#iam-api-key-authentication)
- [IAM Trusted profile (container) authentication](#iam-trusted-profile-container-authentication)
- [IAM Trusted profile (VPC) authentication](#iam-trusted-profile-vpc-authentication)
- [IAM Trusted profile (assume identity) authentication](#iam-trusted-profile-assume-identity-authentication)
- [Session cookie authentication](#session-cookie-authentication)
+ [Authentication with external configuration](#authentication-with-external-configuration)
+ [Programmatic authentication](#programmatic-authentication)
* [Automatic retries](#automatic-retries)
* [Request timeout configuration](#request-timeout-configuration)
* [Code examples](#code-examples)
+ [1. Create a database and add a document](#1-create-a-database-and-add-a-document)
+ [2. Retrieve information from an existing database](#2-retrieve-information-from-an-existing-database)
+ [3. Update your previously created document](#3-update-your-previously-created-document)
+ [4. Delete your previously created document](#4-delete-your-previously-created-document)
+ [Further code examples](#further-code-examples)
* [Error handling](#error-handling)
* [Raw IO](#raw-io)
* [Model classes vs dictionaries](#model-classes-vs-dictionaries)
* [Further resources](#further-resources)
* [Changes feed follower](#changes-feed-follower)
+ [Introduction](#introduction)
+ [Modes of operation](#modes-of-operation)
+ [Configuring the changes follower](#configuring-the-changes-follower)
+ [Error suppression](#error-suppression)
+ [Follower operation](#follower-operation)
+ [Checkpoints](#checkpoints)
+ [Code examples](#code-examples-1)
- [Initializing a changes follower](#initializing-a-changes-follower)
- [Starting the changes follower](#starting-the-changes-follower)
* [Start mode for continuous listening](#start-mode-for-continuous-listening)
* [Start mode for one-off fetching](#start-mode-for-one-off-fetching)
- [Processing changes](#processing-changes)
* [Process continuous changes](#process-continuous-changes)
* [Process one-off changes](#process-one-off-changes)
- [Stopping the changes follower](#stopping-the-changes-follower)
* [Pagination (beta)](#pagination-beta)
+ [Introduction](#introduction-1)
+ [Limitations](#limitations)
+ [Capacity considerations](#capacity-considerations)
+ [Available operations](#available-operations)
+ [Creating a pagination](#creating-a-pagination)
- [Initialize the service](#initialize-the-service)
- [Set the options](#set-the-options)
- [Create the pagination](#create-the-pagination)
+ [Using pagination](#using-pagination)
- [Iterate pages](#iterate-pages)
- [Iterate rows](#iterate-rows)
- [Pager](#pager)
* [Get each page from a pager](#get-each-page-from-a-pager)
* [Get all results from a pager](#get-all-results-from-a-pager)
- [Questions](#questions)
- [Issues](#issues)
- [Versioning and LTS support](#versioning-and-lts-support)
- [Open source at IBM](#open-source-at-ibm)
- [Contributing](#contributing)
- [License](#license)
</details>
## Overview
The IBM Cloudant Python SDK allows developers to programmatically
interact with [IBM Cloudant](https://cloud.ibm.com/apidocs/cloudant)
with the help of the `ibmcloudant` package.
## Features
The purpose of this Python SDK is to wrap most of the HTTP request APIs
provided by Cloudant and supply other functions to ease the usage of Cloudant.
This SDK should make life easier for programmers to do what’s really important
to them: developing software.
Reasons why you should consider using Cloudant Python SDK in your
project:
- Supported by IBM Cloudant.
- Server compatibility with:
- IBM Cloudant.
- [Apache CouchDB 3.x](https://docs.couchdb.org/en/stable/) for data operations.
- Includes all the most popular and latest supported endpoints for
applications.
- Handles the authentication.
- Familiar user experience with IBM Cloud SDKs.
- Flexibility to use either built-in models or byte-based requests and responses for documents.
- Built-in [Changes feed follower](#changes-feed-follower)
- Built-in [Pagination](#pagination-beta) (beta)
- Instances of the client are unconditionally thread-safe.
## Prerequisites
- A
[Cloudant](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-getting-started-with-cloudant)
service instance or a
[CouchDB](https://docs.couchdb.org/en/latest/install/index.html)
server.
- Python 3.9 or above.
## Installation
To install, use `pip` or `easy_install`:
```bash
pip install --upgrade "ibmcloudant>=0.10.5"
```
or
```bash
easy_install --upgrade "ibmcloudant>=0.10.5"
```
## Using the SDK
For fundamental SDK usage information and config options, please see the common [IBM Cloud SDK](https://github.com/IBM/ibm-cloud-sdk-common/blob/main/README.md) documentation.
This library requires configuration with a service URL and
[Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) to authenticate with your
account.
There are several ways to **set** these authentication properties:
1. As [environment variables](#authentication-with-environment-variables)
2. The [programmatic approach](#programmatic-authentication)
3. With an [external credentials file](#authentication-with-external-configuration)
The following section describes the different authentication types and provides environment variable examples.
Examples for other configuration methods are available by following the provided links.
### Authentication
This library requires credentials to authenticate with IBM Cloudant. These credentials may be:
* IBM Cloud IAM credentials (with authentication types `CONTAINER`, `VPC`, `IAMASSUME` and `IAM`)
* [IBM Cloud account](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-managing-access-for-cloudant#introduction-iam-ai) user, service ID or trusted profile credentials
that have access granted to the IBM Cloud Cloudant resource instance.
* [IBM Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) generated by the IBM Cloud Cloudant resource instance.
* Username and password credentials (with authentication types `COUCHDB_SESSION` and `BASIC`)
* [IBM Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) generated for an IBM Cloud Cloudant resource instance not configured as `IAM only`.
* IBM Cloudant [legacy credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#basic-authentication) (username and password) for instances not in IBM Cloud.
* IBM Cloudant [legacy API keys](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#api-keys).
| Authentication type | Recommended for | `AUTH_TYPE` | Description |
| --- | --- | --- | --- |
| IAM Trusted Profiles (compute resource [container](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#container-authentication)) | Cloudant<BR>(SDK running in IBM Cloud IKS) | `CONTAINER` | Obtains a compute resource (CR) token from the container.<BR>Exchanges the CR token for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |
| IAM Trusted Profiles (compute resource [VPC](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#vpc-instance-authentication)) | Cloudant<BR>(SDK running in IBM Cloud VPC) | `VPC` | Obtains an identity token from the VPC instance metadata.<BR>Exchanges the identity token for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |
| IAM Trusted Profiles ([assume identity](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#identity-and-access-management-iam-authentication-grant-type-assume)) | Cloudant | `IAMASSUME` | Exchanges an IAM API key for an IAM `access_token` (same as `IAM` auth type).<BR>Uses that initial token to obtain a second `access_token` from IAM with the assumed identity information.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |
| [IAM API key](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#identity-and-access-management-iam-authentication-grant-type-apikey) | Cloudant | `IAM` | Exchanges an IAM API key for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |
| [Session cookie](#session-cookie-authentication) | [Cloudant](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#cookie-authentication)<BR>(legacy credentials & instances without IAM)<BR><BR>[Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#cookie-authentication) | `COUCHDB_SESSION` | Exchanges credentials with `/_session` endpoint to retrieve a cookie.<BR>Adds `Cookie` header and content to each HTTP request.<BR>Automatically renews session when needed. |
| [Bearer token](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#bearer-token-authentication) | [Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#jwt-authentication)<BR>(using JWT authentication) | `BEARERTOKEN` | Adds an `Authorization: Bearer <token>` to each HTTP request.<BR>No token management or renewal.<BR>Also compatible with IAM access tokens managed independently of the SDK. |
| [Basic](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#basic-authentication) | [Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#basic-authentication)<BR>(if cookies are not enabled) | `BASIC` | Adds an `Authorization: Basic <encoded username and password>` header to each HTTP request. |
| [None](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#no-auth-authentication) | - | `NOAUTH` | Note that this authentication type only works for operations against a database allowing access for unauthenticated users. |
The default authentication type for the SDK is `CONTAINER` unless supplying `APIKEY` configuration, which changes the default authentication type to `IAM`.
#### Authentication with environment variables
The default service name is `CLOUDANT` so these examples use `CLOUDANT_` prefixed names.
Any custom service name prefix is valid, provided it matches the name used to instantiate the SDK client
and applied to all configuration options.
##### IAM API key authentication
For Cloudant *IAM API key authentication*, set the following environmental variables by
replacing the `<url>` and `<apikey>` with your proper
[service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials). There is no need to set
`CLOUDANT_AUTH_TYPE` to `IAM` because it is the default when supplying an `APIKEY`.
```bash
CLOUDANT_URL=<url>
CLOUDANT_APIKEY=<apikey>
```
##### IAM Trusted profile (container) authentication
For Cloudant *IAM Trusted profile compute resource container authentication*, set the following environmental variables by
replacing the `<url>` and `<id>` with your values. There is no need to set
`CLOUDANT_AUTH_TYPE` to `CONTAINER` because it is the default.
```bash
CLOUDANT_URL=<url>
CLOUDANT_IAM_PROFILE_ID=<id>
```
Alternatives to `CLOUDANT_IAM_PROFILE_ID`:
* `CLOUDANT_IAM_PROFILE_NAME`
##### IAM Trusted profile (VPC) authentication
For Cloudant *IAM Trusted profile compute resource vpc authentication*, set the following environmental variables by
replacing the `<url>` and `<id>` with your values.
```bash
CLOUDANT_AUTH_TYPE=VPC
CLOUDANT_URL=<url>
CLOUDANT_IAM_PROFILE_ID=<id>
```
Alternatives to `CLOUDANT_IAM_PROFILE_ID`:
* `CLOUDANT_IAM_PROFILE_CRN`
* No profile information (uses the default trusted profile linked to the compute resource)
##### IAM Trusted profile (assume identity) authentication
For Cloudant *IAM Trusted profile assume authentication*, set the following environmental variables by
replacing the `<url>` and `<id>` with your values.
```bash
CLOUDANT_AUTH_TYPE=IAMASSUME
CLOUDANT_URL=<url>
CLOUDANT_IAM_PROFILE_ID=<id>
```
Alternatives to `CLOUDANT_IAM_PROFILE_ID`:
* `CLOUDANT_IAM_PROFILE_CRN`
* `CLOUDANT_IAM_PROFILE_NAME` *and* `CLOUDANT_IAM_ACCOUNT_ID` (ID of the account that contains the named trusted profile)
##### Session cookie authentication
For `COUCHDB_SESSION` authentication, set the following environmental variables
by replacing the `<url>`, `<username>` and `<password>` with your proper
[service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials).
```bash
CLOUDANT_AUTH_TYPE=COUCHDB_SESSION
CLOUDANT_URL=<url>
CLOUDANT_USERNAME=<username>
CLOUDANT_PASSWORD=<password>
```
#### Authentication with external configuration
For more information about using an external configuration file, see the related documentation in
[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#authentication-with-external-configuration),
or the
[general SDK usage information](https://github.com/IBM/ibm-cloud-sdk-common#using-external-configuration).
#### Programmatic authentication
To learn more about how to use programmatic authentication, see the related
documentation in the
[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#programmatic-authentication)
or in the
[Python SDK Core document](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md) about authentication.
### Automatic retries
The SDK supports a generalized retry feature that can automatically retry on common errors.
The [automatic retries](https://github.com/IBM/ibm-cloud-sdk-common#automatic-retries) section has details on how to enable the retries with default values and customize the retries programmatically or with external configuration.
### Request timeout configuration
No request timeout is defined, but a 2.5m read and a 60s connect timeout are set by default. Be sure to set a request timeout appropriate to your application usage and environment.
The [request timeout](https://github.com/IBM/ibm-cloud-sdk-common#configuring-request-timeouts) section contains details on how to change the value.
**Note:** System settings may take precedence over configured timeout values.
### Code examples
The following code examples
[authenticate with the environment variables](#authentication-with-environment-variables).
#### 1. Create a database and add a document
**Note:** This example code assumes that `orders` database does not exist in your account.
This example code creates `orders` database and adds a new document "example"
into it. To connect, you must set your environment variables with
the *service url*, *authentication type* and *authentication credentials*
of your Cloudant service.
Cloudant environment variable naming starts with a *service name* prefix that identifies your service.
By default, this is `CLOUDANT`, see the settings in the
[authentication with environment variables section](#authentication-with-environment-variables).
If you would like to rename your Cloudant service from `CLOUDANT`,
you must use your defined service name as the prefix for all Cloudant related environment variables.
Once the environment variables are set, you can try out the code examples.
```py
from ibm_cloud_sdk_core import ApiException
from ibmcloudant.cloudant_v1 import CloudantV1, Document
# 1. Create a client with `CLOUDANT` default service name =============
client = CloudantV1.new_instance()
# 2. Create a database ================================================
example_db_name = "orders"
# Try to create database if it doesn't exist
try:
put_database_result = client.put_database(
db=example_db_name
).get_result()
if put_database_result["ok"]:
print(f'"{example_db_name}" database created.')
except ApiException as ae:
if ae.status_code == 412:
print(f'Cannot create "{example_db_name}" database, ' +
'it already exists.')
# 3. Create a document ================================================
# Create a document object with "example" id
example_doc_id = "example"
# Setting `id` for the document is optional when "post_document"
# function is used for CREATE. When `id` is not provided the server
# will generate one for your document.
example_document: Document = Document(id=example_doc_id)
# Add "name" and "joined" fields to the document
example_document.name = "Bob Smith"
example_document.joined = "2019-01-24T10:42:59.000Z"
# Save the document in the database with "post_document" function
create_document_response = client.post_document(
db=example_db_name,
document=example_document
).get_result()
# =====================================================================
# Note: saving the document can also be done with the "put_document"
# function. In this case `doc_id` is required for a CREATE operation:
"""
create_document_response = client.put_document(
db=example_db_name,
doc_id=example_doc_id,
document=example_document
).get_result()
"""
# =====================================================================
# Keeping track of the revision number of the document object
# is necessary for further UPDATE/DELETE operations:
example_document.rev = create_document_response["rev"]
print(f'You have created the document:\n{example_document}')
```
When you run the code, you see a result similar to the following output.
```text
"orders" database created.
You have created the document:
{
"_id": "example",
"_rev": "1-1b403633540686aa32d013fda9041a5d",
"name": "Bob Smith",
"joined": "2019-01-24T10:42:99.000Z"
}
```
#### 2. Retrieve information from an existing database
**Note**: This example code assumes that you have created both the `orders`
database and the `example` document by
[running the previous example code](#1-create-a-database-and-add-a-document)
successfully. Otherwise, the following error message occurs, "Cannot delete document because either 'orders'
database or 'example' document was not found."
<details>
<summary>Gather database information example</summary>
```py
import json
from ibmcloudant.cloudant_v1 import CloudantV1
# 1. Create a client with `CLOUDANT` default service name ============
client = CloudantV1.new_instance()
# 2. Get server information ===========================================
server_information = client.get_server_information(
).get_result()
print(f'Server Version: {server_information["version"]}')
# 3. Get database information for "orders" ==========================
db_name = "orders"
db_information = client.get_database_information(
db=db_name
).get_result()
# 4. Show document count in database ==================================
document_count = db_information["doc_count"]
print(f'Document count in \"{db_information["db_name"]}\" '
f'database is {document_count}.')
# 5. Get "example" document out of the database by document id ============
document_example = client.get_document(
db=db_name,
doc_id="example"
).get_result()
print(f'Document retrieved from database:\n'
f'{json.dumps(document_example, indent=2)}')
```
</details>
When you run the code, you see a result similar to the following output.
```text
Server Version: 2.1.1
Document count in "orders" database is 1.
Document retrieved from database:
{
"_id": "example",
"_rev": "1-1b403633540686aa32d013fda9041a5d",
"name": "Bob Smith",
"joined": "2019-01-24T10:42:99.000Z"
}
```
#### 3. Update your previously created document
**Note**: This example code assumes that you have created both the `orders`
database and the `example` document by
[running the previous example code](#1-create-a-database-and-add-a-document)
successfully. Otherwise, the following error message occurs, "Cannot update document because either 'orders'
database or 'example' document was not found."
<details>
<summary>Update code example</summary>
```py
import json
from ibm_cloud_sdk_core import ApiException
from ibmcloudant.cloudant_v1 import CloudantV1
# 1. Create a client with `CLOUDANT` default service name =============
client = CloudantV1.new_instance()
# 2. Update the document ==============================================
example_db_name = "orders"
example_doc_id = "example"
# Try to get the document if it previously existed in the database
try:
document = client.get_document(
db=example_db_name,
doc_id=example_doc_id
).get_result()
# =================================================================
# Note: for response byte stream use:
"""
document_as_byte_stream = client.get_document_as_stream(
db=example_db_name,
doc_id=example_doc_id
).get_result()
"""
# =================================================================
# Add Bob Smith's address to the document
document["address"] = "19 Front Street, Darlington, DL5 1TY"
# Remove the joined property from document object
if "joined" in document:
document.pop("joined")
# Update the document in the database
update_document_response = client.post_document(
db=example_db_name,
document=document
).get_result()
# =================================================================
# Note 1: for request byte stream use:
"""
update_document_response = client.post_document(
db=example_db_name,
document=document_as_byte_stream
).get_result()
"""
# =================================================================
# =================================================================
# Note 2: updating the document can also be done with the
# "put_document" function. `doc_id` and `rev` are required for an
# UPDATE operation, but `rev` can be provided in the document
# object as `_rev` too:
"""
update_document_response = client.put_document(
db=example_db_name,
doc_id=example_doc_id, # doc_id is a required parameter
rev=document["_rev"],
document=document # _rev in the document object CAN replace above `rev` parameter
).get_result()
"""
# =================================================================
# Keeping track of the latest revision number of the document
# object is necessary for further UPDATE/DELETE operations:
document["_rev"] = update_document_response["rev"]
print(f'You have updated the document:\n' +
json.dumps(document, indent=2))
except ApiException as ae:
if ae.status_code == 404:
print('Cannot delete document because either ' +
f'"{example_db_name}" database or "{example_doc_id}" ' +
'document was not found.')
```
</details>
When you run the code, you see a result similar to the following output.
```text
{
"_id": "example",
"_rev": "2-4e2178e85cffb32d38ba4e451f6ca376",
"name": "Bob Smith",
"address": "19 Front Street, Darlington, DL5 1TY"
}
```
#### 4. Delete your previously created document
**Note**: This example code assumes that you have created both the `orders`
database and the `example` document by
[running the previous example code](#1-create-a-database-and-add-a-document)
successfully. Otherwise, the following error message occurs, "Cannot delete document because either 'orders'
database or 'example' document was not found."
<details>
<summary>Delete code example</summary>
```py
from ibm_cloud_sdk_core import ApiException
from ibmcloudant.cloudant_v1 import CloudantV1
# 1. Create a client with `CLOUDANT` default service name =============
client = CloudantV1.new_instance()
# 2. Delete the document ==============================================
example_db_name = "orders"
example_doc_id = "example"
# Try to get the document if it previously existed in the database
try:
document = client.get_document(
db=example_db_name,
doc_id=example_doc_id
).get_result()
delete_document_response = client.delete_document(
db=example_db_name,
doc_id=example_doc_id, # `doc_id` is required for DELETE
rev=document["_rev"] # `rev` is required for DELETE
).get_result()
if delete_document_response["ok"]:
print('You have deleted the document.')
except ApiException as ae:
if ae.status_code == 404:
print('Cannot delete document because either ' +
f'"{example_db_name}" database or "{example_doc_id}"' +
'document was not found.')
```
</details>
When you run the code, you see the following output.
```text
You have deleted the document.
```
#### Further code examples
For a complete list of code examples, see the [examples directory](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#examples-for-python).
### Error handling
For sample code on handling errors, see
[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#error-handling).
### Raw IO
For endpoints that read or write document content it is possible to bypass
usage of the built-in object with byte streams.
Depending on the specific SDK operation it may be possible to:
* accept a user-provided byte stream to send to the server as a request body
* return a byte stream of the server response body to the user
Request byte stream can be supplied for arguments that accept the `BinaryIO` type.
For these cases you can pass this byte stream directly to the HTTP request body.
Response byte stream is supported in functions with the suffix of `_as_stream`.
The returned byte stream allows the response body to be consumed
without triggering JSON unmarshalling that is typically performed by the SDK.
The [update document](#3-update-your-previously-created-document) section
contains examples for both request and response byte stream cases.
The API reference contains further examples of using byte streams.
They are titled "Example request as stream" and are initially collapsed.
Expand them to see examples of:
- Byte requests:
- [Bulk modify multiple documents in a database](https://cloud.ibm.com/apidocs/cloudant?code=python#postbulkdocs)
- Byte responses:
- [Query a list of all documents in a database](https://cloud.ibm.com/apidocs/cloudant?code=python#postalldocs)
- [Query the database document changes feed](https://cloud.ibm.com/apidocs/cloudant?code=python#postchanges)
### Model classes vs dictionaries
This SDK supports two possible formats to define an HTTP request. One approach uses only model classes and the other only dictionaries.
<details>
<summary>Example using model class structure</summary>
```py
from ibmcloudant.cloudant_v1 import DesignDocument, CloudantV1, DesignDocumentOptions, SearchIndexDefinition
client = CloudantV1.new_instance()
price_index = SearchIndexDefinition(
index='function (doc) { index("price", doc.price); }'
)
design_document_options = DesignDocumentOptions(
partitioned=True
)
partitioned_design_doc = DesignDocument(
indexes={'findByPrice': price_index},
options=design_document_options
)
response = client.put_design_document(
db='products',
design_document=partitioned_design_doc,
ddoc='appliances'
).get_result()
print(response)
```
</details>
<details>
<summary>Same example using dictionary structure</summary>
```py
from ibmcloudant.cloudant_v1 import CloudantV1
client = CloudantV1.new_instance()
price_index = {
'index': 'function (doc) { index("price", doc.price); }'
}
partitioned_design_doc = {
'indexes': {'findByPrice': price_index},
'options': {'partitioned': True},
}
response = client.put_design_document(
db='products',
design_document=partitioned_design_doc,
ddoc='appliances'
).get_result()
print(response)
```
</details>
Since model classes and dicts are different data structures, they cannot be combined.
<details>
<summary>This solution will be invalid</summary>
```py
from ibmcloudant.cloudant_v1 import CloudantV1, DesignDocument
client = CloudantV1.new_instance()
price_index = {
'index': 'function (doc) { index("price", doc.price); }'
}
partitioned_design_doc = DesignDocument(
indexes={'findByPrice': price_index},
options={'partitioned': True}
)
response = client.put_design_document(
db='products',
design_document=partitioned_design_doc,
ddoc='appliances'
).get_result()
print(response)
```
</details>
### Further resources
- [Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python):
API reference including usage examples for Cloudant Python SDK API.
- [Pydoc](https://ibm.github.io/cloudant-python-sdk/):
Cloudant Python SDK API Documentation.
- [Cloudant docs](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-getting-started-with-cloudant):
The official documentation page for Cloudant.
- [Cloudant blog](https://blog.cloudant.com/):
Many useful articles about how to optimize Cloudant for common problems.
### Changes feed follower
#### Introduction
The SDK provides a changes feed follower utility.
This helper utility connects to the `_changes` endpoint and returns the individual change items.
It removes some complexity of using the `_changes` endpoint by setting some options automatically
and providing error suppression and retries.
*Tip: the changes feed often does not meet user expectations or assumptions.*
Consult the [Cloudant changes feed FAQ](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-faq-using-changes-feed)
to get a better understanding of the limitations and suitable use-cases before using the changes feed in your application.
#### Modes of operation
There are two modes of operation:
* Start mode
* Fetches the changes from the supplied `since` sequence (in this mode follower defaults to reading the feed from `now`).
* Fetches all available changes and then continues listening for new changes indefinitely unless encountering an end condition.
* An example use case for this mode is event driven workloads.
* Start one-off mode
* Fetches the changes from the supplied `since` sequence (in this mode follower defaults to reading the feed from the beginning).
* Fetches all available changes and then stops when either there are no further changes pending or encountering an end condition.
* An example use case for this mode is ETL style workloads.
#### Configuring the changes follower
The SDK's model of changes feed options is also used to configure the follower.
However, a subset of the options used internally by the follower implementation are invalid.
Supplying these options when instantiating the follower causes an error.
The invalid options are:
* `descending`
* `feed`
* `heartbeat`
* `lastEventId` - use `since` instead
* `timeout`
* Follower permits only the value `_selector` for the `filter` option. This restriction is because selector
based filters perform better than JavaScript backed filters. Configuring a non-selector based filter
causes the follower to error.
Note that the `limit` parameter terminates the follower at the given number of changes in either
operating mode.
The changes follower requires the client to have HTTP timeouts of at least 1 minute and errors during
instantiation if it is insufficient. The default client configuration has sufficiently long timeouts.
For use-cases where these configuration limitations are too restrictive then write code to use the SDK's
[POST `_changes` API](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#postchanges) instead of the follower.
#### Error suppression
By default, the changes follower suppresses transient errors indefinitely and attempts to run to completion or listen forever as
dictated by the operating mode.
For applications where that is not desirable configure the optional error tolerance duration. This controls the time since
the last successful response that the follower suppresses transient errors. An example usage is an application grace period
before reporting an error and requiring intervention.
There are some additional points to consider for error suppression:
* Errors considered terminal, for example, the database not existing or invalid credentials are never suppressed and error immediately.
* The error suppression duration is not guaranteed to fire immediately after lapsing and is a minimum suppression time.
* The changes follower backs-off between retries and as such may remain paused for a short while after the transient errors have resolved.
* If the underlying SDK client used to initialize the follower also has retries configured then suppression of errors may last
significantly longer than the follower's configured error tolerance duration depending on the specific options.
#### Follower operation
For both modes:
* The end conditions are:
* A terminal error (HTTP codes `400`, `401`, `403` `404`).
* Transient errors occur for longer than the error tolerance duration. Transient errors are all other HTTP status codes and connection errors.
* The number of changes received reaches the configured `limit`.
* The application calls stop to terminate the feed early.
As is true for the `_changes` endpoint change items have *at least once* delivery and callers may receive
an individual item multiple times. When using the follower change items may repeat even within a limited
number of changes (that is using the `limit` option) this is a minor difference from using `limit` on the HTTP native API.
The follower is not optimized for some use cases and it is not recommended to use it in cases where:
* Setting `include_docs` and larger document sizes (for example > 10 kiB).
* The volume of changes is very high (if the rate of changes in the database exceeds the follower's rate of pulling them it can never catch-up).
In these use-cases use the SDK's [POST `_changes` API](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#postchanges)
for specific control over the number of change requests made and the content size of the responses.
#### Checkpoints
The changes follower does not checkpoint since it has no information about whether the consuming application
has processed a change item after delivery. It is the application developer's responsibility
to store the sequence IDs to have appropriate checkpoints and to re-initialize the follower with the required
`since` value after, for example, the application restarts.
The frequency and conditions for checkpoints are application specific and some applications may be tolerant
of dropped changes. This section provides only general guidance on how to avoid missing changes.
To guarantee processing of all changes do not persist the sequence ID from a change item until *after*
the processing of the change item by the application has completed. As indicated previously change item
delivery is *at least once* so application code must be able to handle repeated changes already. It is
preferable to restart from an older `since` value and receive changes again than risk missing them.
The sequence IDs are available on each change item by default. However, the server omits sequence IDs from
some change items when using the `seq_interval` configuration option.
Infrequent sequence IDs may improve performance by reducing the amount of data transfer and server load,
but the tradeoff is repeating more changes if it is necessary to resume the changes follower.
Take extreme care persisting sequences if choosing to process change items in parallel as there
is a considerable risk of missing changes on a restart if the recorded sequence is out of order.
#### Code examples
##### Initializing a changes follower
```py
import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1
client = CloudantV1.new_instance()
cf_params = {
'db': 'example', # Required: the database name.
'limit': 100, # Optional: return only 100 changes (including duplicates).
'since': '3-g1AG3...' # Optional: start from this sequence ID (e.g. with a value read from persistent storage).
}
changes_follower = ChangesFollower(
service=client, # Required: the Cloudant service client instance.
error_tolerance=10000, # Optional: suppress transient errors for at least 10 seconds before terminating.
**cf_params # Required: changes feed configuration options dict.
)
```
##### Starting the changes follower
###### Start mode for continuous listening
```py
import Iterable
from ibmcloudant import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1, ChangesResultItem
client = CloudantV1.new_instance()
changes_follower = ChangesFollower(
service=client,
**{'db': 'example'})
changes_items: Iterable[ChangesResultItem] = changes_follower.start()
# Note: iterable will not do anything until it is iterated
# Create a for loop to iterate over the flow of changes
# for changes_item in changes_items: ...
```
###### Start mode for one-off fetching
```py
import Iterable
from ibmcloudant import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1, ChangesResultItem
client = CloudantV1.new_instance()
changes_follower = ChangesFollower(
service=client,
**{'db': 'example'})
changes_items: Iterable[ChangesResultItem] = changes_follower.start_one_off()
# Note: iterable will not do anything until it is iterated
# Create a for loop to iterate over the flow of changes
# for changes_item in changes_items: ...
```
##### Processing changes
###### Process continuous changes
```py
import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1
client = CloudantV1.new_instance()
# Start from a previously persisted seq
# Normally this would be read by the app from persistent storage
# e.g. previously_persisted_seq = your_app_persistence_read_func()
previously_persisted_seq = '3-g1AG3...'
changes_follower = ChangesFollower(
service=client,
**{'db': 'example', 'since': previously_persisted_seq})
changes_items = changes_follower.start()
for changes_item in changes_items:
# do something with changes
print(changes_item.id)
for change in changes_item.changes:
print(change.rev)
# when change item processing is complete app can store seq
seq = changes_item.seq
# write seq to persistent storage for use as since if required to resume later
# e.g. your_app_persistence_write_func(seq)
# keep processing changes until the application is terminated or some other stop condition is reached
# Note: iterator above is blocking, code here will be unreachable
# until the iteration is stopped or another stop condition is reached.
# For long running followers careful consideration should be made of where to call stop on the iterator.
```
###### Process one-off changes
```py
import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1
client = CloudantV1.new_instance()
# Start from a previously persisted seq
# Normally this would be read by the app from persistent storage
# e.g. previously_persisted_seq = your_app_persistence_read_func()
previously_persisted_seq = '3-g1AG3...'
changes_follower = ChangesFollower(
service=client,
**{'db': 'example', 'since': previously_persisted_seq})
changes_items = changes_follower.start_one_off()
for changes_item in changes_items:
# do something with changes
print(changes_item.id)
for change in changes_item.changes:
print(change.rev)
# when change item processing is complete app can store seq
seq = changes_item.seq
# write seq to persistent storage for use as since if required to resume later
# e.g. your_app_persistence_write_func(seq)
# Note: iterator above is blocking, code here will be unreachable
# until all changes are processed (or another stop condition is reached).
```
##### Stopping the changes follower
```py
import ChangesFollower
from ibmcloudant.cloudant_v1 import CloudantV1
client = CloudantV1.new_instance()
changes_follower = ChangesFollower(
service=client,
**{'db': 'example'})
changes_items = changes_follower.start()
for changes_item in changes_items:
# Option 1: call stop after some condition
# Note that since the iterator is blocking at least one item
# must be returned from it to reach to this point.
# Additional changes may be processed before the iterator stops.
changes_follower.stop()
# Option 2: call stop method when you want to end the continuous loop from
# outside the iterator. For example, you've put the changes follower in a
# separate thread and need to call stop on the main thread.
# Note: in this context the call must be made from a different thread because
# code immediately following the iterator is unreachable until the iterator
# has stopped.
changes_follower.stop()
```
### Pagination (beta)
#### Introduction
The pagination feature (currently beta) accepts options for a single operation and automatically
creates the multiple requests to the server necessary to page through the results a fixed number at a time.
Pagination is a best-practice to break apart large queries into multiple server requests.
This has a number of advantages:
* Keeping requests within server imposed limits, for example
* `200` max results for text search
* `2000` max results for partitioned queries
* Fetching only the necessary data, for example
* User finds required result on first page, no need to continue fetching results
* Reducing the duration of any individual query
* Reduce risk of query timing out on the server
* Reduce risk of network request timeouts
#### Limitations
Limitations of pagination:
* Forward only, no backwards paging
* Limitations on `_all_docs` and `_design_docs` operations
* No pagination for `key` option.
There is no need to paginate as IDs are unique and this returns only a single row.
This is better achieved with a single document get request.
* No pagination for `keys` option.
* Limitations on `_view` operations
* No pagination for `key` option. Pass the same `key` as a start and end key instead.
* No pagination for `keys` option.
* Views that emit multiple identical keys (with the same or different values)
from the same document cannot paginate if those key rows with the same ID
span a page boundary.
The pagination feature detects this condition and an error occurs.
It may be possible to workaround using a different page size.
* Limitations on `_search` operations
* No pagination of grouped results.
* No pagination of faceted `counts` or `ranges` results.
#### Capacity considerations
Pagination can make many requests rapidly from a single program call.
For IBM Cloudant take care to ensure you have appropriate plan capacity
in place to avoid consuming all the permitted requests.
If there is no remaining plan allowance and retries are not enabled or insufficient
then a `429 Too Many Requests` error occurs.
#### Available operations
Pagination is available for these operations:
* Query all documents [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postalldocs)
and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionalldocs)
* [Global all documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/AllDocsPagination.py)
* [Partitioned all documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_all_docs_pagination.py)
* Query all [design documents](https://cloud.ibm.com/apidocs/cloudant?code=python#postdesigndocs)
* [Design documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/design_docs_pagination.py)
* Query with selector syntax [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postfind)
and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionfind)
* [Global find selector query examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/find_pagination.py)
* [Partitioned find selector query examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_find_pagination.py)
* Query a search index [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postsearch)
and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionsearch)
* [Global search examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/search_pagination.py)
* [Partitioned search examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_search_pagination.py)
* Query a MapReduce view [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postview)
and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionview)
* [Global view examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/view_pagination.py)
* [Partitioned view examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_view_pagination.py)
The examples presented in this `README` are for all documents in a partition.
The links in the list are to equivalent examples for each of the other available operations.
#### Creating a pagination
Make a new pagination from a client, `PagerType` for the operation
and the options for the chosen operation.
Use the `limit` option to configure the page size (default and maximum `200`).
Imports required for these examples:
<details open>
<summary>Python:</summary>
```py
from ibmcloudant import Pager, Pagination, PagerType
from ibmcloudant.cloudant_v1 import CloudantV1
```
</details>
##### Initialize the service
<details open>
<summary>Python:</summary>
```py
# Initialize service
service = CloudantV1.new_instance()
```
</details>
##### Set the options
<details open>
<summary>Python:</summary>
```py
# Setup options
opts = {
'db': 'events', # example database name
'limit': 50, # limit option sets the page size
'partition_key': 'ns1HJS13AMkK', # query only this partition
}
```
</details>
##### Create the pagination
<details open>
<summary>Python:</summary>
```py
# Create pagination
pagination = Pagination.new_pagination(
service, PagerType.POST_PARTITION_ALL_DOCS, **opts)
# pagination can be reused without side-effects as a factory for iterables or pagers
# options are fixed at pagination creation time
```
</details>
#### Using pagination
Once you have a pagination factory there are multiple options available.
* Iterate pages
* Iterate rows
* Get each page from a pager
* Get all results from a pager
All the paging styles produce equivalent results and make identical page requests.
The style of paging to choose depends on the use case requirements
in particular whether to process a page at a time or a row at a time.
The pagination factory is reusable and can repeatedly produce new instances
of the same or different pagination styles for the same operation options.
Here are examples for each paging style.
##### Iterate pages
Iterating pages is ideal for using an iterable for loop to process a page at a time.
<details open>
<summary>Python:</summary>
```py
# Option: iterate pages
# Ideal for using a for loop with each page.
# Each call to pages() returns a fresh iterator that can be traversed once.
for page in pagination.pages():
# Do something with page
pass
```
</details>
##### Iterate rows
Iterating rows is ideal for using an iterable for loop to process a result row at a time.
<details open>
<summary>Python:</summary>
```py
# Option: iterate rows
# Ideal for using a for loop with each row.
# Each call to rows() returns a fresh iterator that can be traversed once.
for row in pagination.rows():
# Do something with row
pass
```
</details>
##### Pager
The pager style is similar to other [IBM Cloud SDKs](https://github.com/IBM/ibm-cloud-sdk-common?tab=readme-ov-file#pagination).
Users familiar with that style of pagination may find using them preferable
to the native language style iterators.
In the Cloudant SDKs these pagers are single use and traverse the complete set of pages once and only once.
After exhaustion they cannot be re-used, simply create a new one from the pagination factory if needed.
Pagers are only valid for one of either page at a time or getting all results.
For example, calling for the next page then calling for all results causes an error.
###### Get each page from a pager
This is useful for calling to retrieve one page at a time, for example,
in a user interface with a "next page" interaction.
If calling for the next page errors, it is valid to call for the next page again
to continue paging.
<details open>
<summary>Python:</summary>
```py
# Option: use pager next page
# For retrieving one page at a time with a method call.
pager: Pager = pagination.pager()
if pager.has_next():
page = pager.get_next()
# Do something with page
```
</details>
###### Get all results from a pager
This is useful to retrieve all results in a single call.
However, this approach requires sufficient memory for the entire collection of results.
So although it may be convenient for small result sets generally prefer iterating pages
or rows with the other paging styles, especially for large result sets.
If calling for all the results errors, then calling for all the results again restarts the pagination.
<details open>
<summary>Python:</summary>
```py
# Option: use pager all results
# For retrieving all result rows in a single list
# Note: all result rows may be very large!
# Preferably use iterables instead of get_all for memory efficiency with large result sets.
all_pager: Pager = pagination.pager()
all_rows = all_pager.get_all()
for page in all_rows:
# Do something with row
pass
```
</details>
## Questions
If you are having difficulties using this SDK or have a question about the
IBM Cloud services, ask a question on
[Stack Overflow](http://stackoverflow.com/questions/ask?tags=ibm-cloud).
## Issues
If you encounter an issue with the project, you are welcome to submit a
[bug report](https://github.com/IBM/cloudant-python-sdk/issues).
Before you submit a bug report, search for
[similar issues](https://github.com/IBM/cloudant-python-sdk/issues?q=is%3Aissue) and review the
[KNOWN_ISSUES file](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/KNOWN_ISSUES.md) to verify that your issue hasn't been reported yet.
Please consult the [security policy](https://github.com/IBM/cloudant-python-sdk/security/policy) before opening security related issues.
## Versioning and LTS support
This SDK follows semantic versioning with respect to the definition of user facing APIs.
This means under some circumstances breaking changes may occur within a major or minor version
of the SDK related to changes in supported language platforms.
The SDK is supported on the available LTS releases of the language platform.
The LTS language versions are listed in the prerequisites:
* [LTS versions currently supported by the SDK](https://github.com/IBM/cloudant-python-sdk/#prerequisites)
* [LTS versions for this release of the SDK](#prerequisites)
Incompatible changes from new language versions are not added to the SDK
until they are available in the minimum supported language version.
When language LTS versions move out of support the following will happen:
* Existing SDK releases will continue to run on obsolete language versions, but will no longer be supported.
* The minimum language version supported by the SDK will be updated to the next available LTS.
* New language features may be added in subsequent SDK releases that will cause breaking changes
if the new releases of the SDK are used with older, now unsupported, language levels.
## Open source at IBM
Find more open source projects on the [IBM GitHub](http://ibm.github.io/) page.
## Contributing
For more information, see [CONTRIBUTING](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/CONTRIBUTING.md).
## License
This SDK is released under the Apache 2.0 license. To read the full text of the license, see [LICENSE](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/LICENSE).
Raw data
{
"_id": null,
"home_page": null,
"name": "ibmcloudant",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "ibmcloudant, Cloudant, IBM, database, client, SDK, official",
"author": null,
"author_email": "IBM <cldtsdks@us.ibm.com>",
"download_url": "https://files.pythonhosted.org/packages/5f/bf/147e8d15de8c038b4a64f57bb5bbfe64782b0e54c25f1f79bb8678caa395/ibmcloudant-0.10.5.tar.gz",
"platform": null,
"description": "[](https://github.com/IBM/cloudant-python-sdk/actions/workflows/test.yml)\n[](https://github.com/IBM/cloudant-python-sdk/releases/latest)\n[](https://ibm.github.io/cloudant-python-sdk/)\n\n# IBM Cloudant Python SDK Version 0.10.5\n\nIBM Cloudant Python SDK is a client library that interacts with the\n[IBM Cloudant APIs](https://cloud.ibm.com/apidocs/cloudant?code=python).\n\nDisclaimer: This library is still a 0.x release. We do consider this\nlibrary production-ready and capable, but there are still some\nlimitations we\u2019re working to resolve, and refinements we want to\ndeliver. We are working really hard to minimise the disruption from\nnow until the 1.0 release, but there may still be some changes that\nimpact applications using this SDK. For now, be sure to pin versions\nto avoid surprises.\n\n<details>\n<summary>Table of Contents</summary>\n\n<!-- toc -->\n- [Overview](#overview)\n- [Features](#features)\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n- [Using the SDK](#using-the-sdk)\n * [Authentication](#authentication)\n + [Authentication with environment variables](#authentication-with-environment-variables)\n - [IAM API key authentication](#iam-api-key-authentication)\n - [IAM Trusted profile (container) authentication](#iam-trusted-profile-container-authentication)\n - [IAM Trusted profile (VPC) authentication](#iam-trusted-profile-vpc-authentication)\n - [IAM Trusted profile (assume identity) authentication](#iam-trusted-profile-assume-identity-authentication)\n - [Session cookie authentication](#session-cookie-authentication)\n + [Authentication with external configuration](#authentication-with-external-configuration)\n + [Programmatic authentication](#programmatic-authentication)\n * [Automatic retries](#automatic-retries)\n * [Request timeout configuration](#request-timeout-configuration)\n * [Code examples](#code-examples)\n + [1. Create a database and add a document](#1-create-a-database-and-add-a-document)\n + [2. Retrieve information from an existing database](#2-retrieve-information-from-an-existing-database)\n + [3. Update your previously created document](#3-update-your-previously-created-document)\n + [4. Delete your previously created document](#4-delete-your-previously-created-document)\n + [Further code examples](#further-code-examples)\n * [Error handling](#error-handling)\n * [Raw IO](#raw-io)\n * [Model classes vs dictionaries](#model-classes-vs-dictionaries)\n * [Further resources](#further-resources)\n * [Changes feed follower](#changes-feed-follower)\n + [Introduction](#introduction)\n + [Modes of operation](#modes-of-operation)\n + [Configuring the changes follower](#configuring-the-changes-follower)\n + [Error suppression](#error-suppression)\n + [Follower operation](#follower-operation)\n + [Checkpoints](#checkpoints)\n + [Code examples](#code-examples-1)\n - [Initializing a changes follower](#initializing-a-changes-follower)\n - [Starting the changes follower](#starting-the-changes-follower)\n * [Start mode for continuous listening](#start-mode-for-continuous-listening)\n * [Start mode for one-off fetching](#start-mode-for-one-off-fetching)\n - [Processing changes](#processing-changes)\n * [Process continuous changes](#process-continuous-changes)\n * [Process one-off changes](#process-one-off-changes)\n - [Stopping the changes follower](#stopping-the-changes-follower)\n * [Pagination (beta)](#pagination-beta)\n + [Introduction](#introduction-1)\n + [Limitations](#limitations)\n + [Capacity considerations](#capacity-considerations)\n + [Available operations](#available-operations)\n + [Creating a pagination](#creating-a-pagination)\n - [Initialize the service](#initialize-the-service)\n - [Set the options](#set-the-options)\n - [Create the pagination](#create-the-pagination)\n + [Using pagination](#using-pagination)\n - [Iterate pages](#iterate-pages)\n - [Iterate rows](#iterate-rows)\n - [Pager](#pager)\n * [Get each page from a pager](#get-each-page-from-a-pager)\n * [Get all results from a pager](#get-all-results-from-a-pager)\n- [Questions](#questions)\n- [Issues](#issues)\n- [Versioning and LTS support](#versioning-and-lts-support)\n- [Open source at IBM](#open-source-at-ibm)\n- [Contributing](#contributing)\n- [License](#license)\n\n</details>\n\n## Overview\n\nThe IBM Cloudant Python SDK allows developers to programmatically\ninteract with [IBM Cloudant](https://cloud.ibm.com/apidocs/cloudant)\nwith the help of the `ibmcloudant` package.\n\n## Features\n\nThe purpose of this Python SDK is to wrap most of the HTTP request APIs\nprovided by Cloudant and supply other functions to ease the usage of Cloudant.\nThis SDK should make life easier for programmers to do what\u2019s really important\nto them: developing software.\n\nReasons why you should consider using Cloudant Python SDK in your\nproject:\n\n- Supported by IBM Cloudant.\n- Server compatibility with:\n - IBM Cloudant.\n - [Apache CouchDB 3.x](https://docs.couchdb.org/en/stable/) for data operations.\n- Includes all the most popular and latest supported endpoints for\n applications.\n- Handles the authentication.\n- Familiar user experience with IBM Cloud SDKs.\n- Flexibility to use either built-in models or byte-based requests and responses for documents.\n- Built-in [Changes feed follower](#changes-feed-follower)\n- Built-in [Pagination](#pagination-beta) (beta)\n- Instances of the client are unconditionally thread-safe.\n\n## Prerequisites\n\n- A\n [Cloudant](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-getting-started-with-cloudant)\n service instance or a\n [CouchDB](https://docs.couchdb.org/en/latest/install/index.html)\n server.\n- Python 3.9 or above.\n\n## Installation\n\nTo install, use `pip` or `easy_install`:\n\n```bash\npip install --upgrade \"ibmcloudant>=0.10.5\"\n```\n\nor\n\n```bash\neasy_install --upgrade \"ibmcloudant>=0.10.5\"\n```\n\n## Using the SDK\n\nFor fundamental SDK usage information and config options, please see the common [IBM Cloud SDK](https://github.com/IBM/ibm-cloud-sdk-common/blob/main/README.md) documentation.\n\nThis library requires configuration with a service URL and\n[Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) to authenticate with your\naccount.\n\nThere are several ways to **set** these authentication properties:\n\n1. As [environment variables](#authentication-with-environment-variables)\n2. The [programmatic approach](#programmatic-authentication)\n3. With an [external credentials file](#authentication-with-external-configuration)\n\nThe following section describes the different authentication types and provides environment variable examples.\nExamples for other configuration methods are available by following the provided links.\n\n### Authentication\n\n\nThis library requires credentials to authenticate with IBM Cloudant. These credentials may be:\n* IBM Cloud IAM credentials (with authentication types `CONTAINER`, `VPC`, `IAMASSUME` and `IAM`)\n * [IBM Cloud account](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-managing-access-for-cloudant#introduction-iam-ai) user, service ID or trusted profile credentials\n that have access granted to the IBM Cloud Cloudant resource instance.\n * [IBM Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) generated by the IBM Cloud Cloudant resource instance.\n* Username and password credentials (with authentication types `COUCHDB_SESSION` and `BASIC`)\n * [IBM Cloudant service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials) generated for an IBM Cloud Cloudant resource instance not configured as `IAM only`.\n * IBM Cloudant [legacy credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#basic-authentication) (username and password) for instances not in IBM Cloud.\n * IBM Cloudant [legacy API keys](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#api-keys).\n\n| Authentication type | Recommended for | `AUTH_TYPE` | Description |\n| --- | --- | --- | --- |\n| IAM Trusted Profiles (compute resource [container](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#container-authentication)) | Cloudant<BR>(SDK running in IBM Cloud IKS) | `CONTAINER` | Obtains a compute resource (CR) token from the container.<BR>Exchanges the CR token for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |\n| IAM Trusted Profiles (compute resource [VPC](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#vpc-instance-authentication)) | Cloudant<BR>(SDK running in IBM Cloud VPC) | `VPC` | Obtains an identity token from the VPC instance metadata.<BR>Exchanges the identity token for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |\n| IAM Trusted Profiles ([assume identity](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#identity-and-access-management-iam-authentication-grant-type-assume)) | Cloudant | `IAMASSUME` | Exchanges an IAM API key for an IAM `access_token` (same as `IAM` auth type).<BR>Uses that initial token to obtain a second `access_token` from IAM with the assumed identity information.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |\n| [IAM API key](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#identity-and-access-management-iam-authentication-grant-type-apikey) | Cloudant | `IAM` | Exchanges an IAM API key for an IAM `access_token`.<BR>Adds an `Authorization: Bearer <access_token>` header to each HTTP request.<BR>Automatically renews the access token when needed. |\n| [Session cookie](#session-cookie-authentication) | [Cloudant](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-work-with-your-account#cookie-authentication)<BR>(legacy credentials & instances without IAM)<BR><BR>[Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#cookie-authentication) | `COUCHDB_SESSION` | Exchanges credentials with `/_session` endpoint to retrieve a cookie.<BR>Adds `Cookie` header and content to each HTTP request.<BR>Automatically renews session when needed. |\n| [Bearer token](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#bearer-token-authentication) | [Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#jwt-authentication)<BR>(using JWT authentication) | `BEARERTOKEN` | Adds an `Authorization: Bearer <token>` to each HTTP request.<BR>No token management or renewal.<BR>Also compatible with IAM access tokens managed independently of the SDK. |\n| [Basic](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#basic-authentication) | [Apache CouchDB](https://docs.couchdb.org/en/stable/api/server/authn.html#basic-authentication)<BR>(if cookies are not enabled) | `BASIC` | Adds an `Authorization: Basic <encoded username and password>` header to each HTTP request. |\n| [None](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md#no-auth-authentication) | - | `NOAUTH` | Note that this authentication type only works for operations against a database allowing access for unauthenticated users. |\n\nThe default authentication type for the SDK is `CONTAINER` unless supplying `APIKEY` configuration, which changes the default authentication type to `IAM`.\n\n#### Authentication with environment variables\n\nThe default service name is `CLOUDANT` so these examples use `CLOUDANT_` prefixed names.\n\nAny custom service name prefix is valid, provided it matches the name used to instantiate the SDK client\nand applied to all configuration options.\n\n##### IAM API key authentication\n\nFor Cloudant *IAM API key authentication*, set the following environmental variables by\nreplacing the `<url>` and `<apikey>` with your proper\n[service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials). There is no need to set\n`CLOUDANT_AUTH_TYPE` to `IAM` because it is the default when supplying an `APIKEY`.\n\n```bash\nCLOUDANT_URL=<url>\nCLOUDANT_APIKEY=<apikey>\n```\n\n##### IAM Trusted profile (container) authentication\n\nFor Cloudant *IAM Trusted profile compute resource container authentication*, set the following environmental variables by\nreplacing the `<url>` and `<id>` with your values. There is no need to set\n`CLOUDANT_AUTH_TYPE` to `CONTAINER` because it is the default.\n\n```bash\nCLOUDANT_URL=<url>\nCLOUDANT_IAM_PROFILE_ID=<id>\n```\n\nAlternatives to `CLOUDANT_IAM_PROFILE_ID`:\n* `CLOUDANT_IAM_PROFILE_NAME`\n\n##### IAM Trusted profile (VPC) authentication\n\nFor Cloudant *IAM Trusted profile compute resource vpc authentication*, set the following environmental variables by\nreplacing the `<url>` and `<id>` with your values.\n\n```bash\nCLOUDANT_AUTH_TYPE=VPC\nCLOUDANT_URL=<url>\nCLOUDANT_IAM_PROFILE_ID=<id>\n```\n\nAlternatives to `CLOUDANT_IAM_PROFILE_ID`:\n* `CLOUDANT_IAM_PROFILE_CRN`\n* No profile information (uses the default trusted profile linked to the compute resource)\n\n##### IAM Trusted profile (assume identity) authentication\n\nFor Cloudant *IAM Trusted profile assume authentication*, set the following environmental variables by\nreplacing the `<url>` and `<id>` with your values.\n\n```bash\nCLOUDANT_AUTH_TYPE=IAMASSUME\nCLOUDANT_URL=<url>\nCLOUDANT_IAM_PROFILE_ID=<id>\n```\n\nAlternatives to `CLOUDANT_IAM_PROFILE_ID`:\n* `CLOUDANT_IAM_PROFILE_CRN`\n* `CLOUDANT_IAM_PROFILE_NAME` *and* `CLOUDANT_IAM_ACCOUNT_ID` (ID of the account that contains the named trusted profile)\n\n##### Session cookie authentication\n\nFor `COUCHDB_SESSION` authentication, set the following environmental variables\nby replacing the `<url>`, `<username>` and `<password>` with your proper\n[service credentials](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-locating-your-service-credentials).\n\n```bash\nCLOUDANT_AUTH_TYPE=COUCHDB_SESSION\nCLOUDANT_URL=<url>\nCLOUDANT_USERNAME=<username>\nCLOUDANT_PASSWORD=<password>\n```\n\n#### Authentication with external configuration\n\nFor more information about using an external configuration file, see the related documentation in\n[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#authentication-with-external-configuration),\nor the\n[general SDK usage information](https://github.com/IBM/ibm-cloud-sdk-common#using-external-configuration).\n\n#### Programmatic authentication\n\nTo learn more about how to use programmatic authentication, see the related\ndocumentation in the\n[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#programmatic-authentication)\nor in the\n[Python SDK Core document](https://github.com/IBM/python-sdk-core/blob/main/Authentication.md) about authentication.\n\n### Automatic retries\n\nThe SDK supports a generalized retry feature that can automatically retry on common errors.\n\nThe [automatic retries](https://github.com/IBM/ibm-cloud-sdk-common#automatic-retries) section has details on how to enable the retries with default values and customize the retries programmatically or with external configuration.\n\n### Request timeout configuration\n\nNo request timeout is defined, but a 2.5m read and a 60s connect timeout are set by default. Be sure to set a request timeout appropriate to your application usage and environment.\nThe [request timeout](https://github.com/IBM/ibm-cloud-sdk-common#configuring-request-timeouts) section contains details on how to change the value.\n\n**Note:** System settings may take precedence over configured timeout values.\n\n### Code examples\n\nThe following code examples\n[authenticate with the environment variables](#authentication-with-environment-variables).\n\n#### 1. Create a database and add a document\n\n**Note:** This example code assumes that `orders` database does not exist in your account.\n\nThis example code creates `orders` database and adds a new document \"example\"\ninto it. To connect, you must set your environment variables with\nthe *service url*, *authentication type* and *authentication credentials*\nof your Cloudant service.\n\nCloudant environment variable naming starts with a *service name* prefix that identifies your service.\nBy default, this is `CLOUDANT`, see the settings in the\n[authentication with environment variables section](#authentication-with-environment-variables).\n\nIf you would like to rename your Cloudant service from `CLOUDANT`,\nyou must use your defined service name as the prefix for all Cloudant related environment variables.\n\nOnce the environment variables are set, you can try out the code examples.\n\n```py\nfrom ibm_cloud_sdk_core import ApiException\nfrom ibmcloudant.cloudant_v1 import CloudantV1, Document\n\n# 1. Create a client with `CLOUDANT` default service name =============\nclient = CloudantV1.new_instance()\n\n# 2. Create a database ================================================\nexample_db_name = \"orders\"\n\n# Try to create database if it doesn't exist\ntry:\n put_database_result = client.put_database(\n db=example_db_name\n ).get_result()\n if put_database_result[\"ok\"]:\n print(f'\"{example_db_name}\" database created.')\nexcept ApiException as ae:\n if ae.status_code == 412:\n print(f'Cannot create \"{example_db_name}\" database, ' +\n 'it already exists.')\n\n# 3. Create a document ================================================\n# Create a document object with \"example\" id\nexample_doc_id = \"example\"\n# Setting `id` for the document is optional when \"post_document\"\n# function is used for CREATE. When `id` is not provided the server\n# will generate one for your document.\nexample_document: Document = Document(id=example_doc_id)\n\n# Add \"name\" and \"joined\" fields to the document\nexample_document.name = \"Bob Smith\"\nexample_document.joined = \"2019-01-24T10:42:59.000Z\"\n\n# Save the document in the database with \"post_document\" function\ncreate_document_response = client.post_document(\n db=example_db_name,\n document=example_document\n).get_result()\n\n# =====================================================================\n# Note: saving the document can also be done with the \"put_document\"\n# function. In this case `doc_id` is required for a CREATE operation:\n\"\"\"\ncreate_document_response = client.put_document(\n db=example_db_name,\n doc_id=example_doc_id,\n document=example_document\n).get_result()\n\"\"\"\n# =====================================================================\n\n# Keeping track of the revision number of the document object\n# is necessary for further UPDATE/DELETE operations:\nexample_document.rev = create_document_response[\"rev\"]\nprint(f'You have created the document:\\n{example_document}')\n```\n\nWhen you run the code, you see a result similar to the following output.\n\n```text\n\"orders\" database created.\nYou have created the document:\n{\n \"_id\": \"example\",\n \"_rev\": \"1-1b403633540686aa32d013fda9041a5d\",\n \"name\": \"Bob Smith\",\n \"joined\": \"2019-01-24T10:42:99.000Z\"\n}\n```\n\n#### 2. Retrieve information from an existing database\n\n**Note**: This example code assumes that you have created both the `orders`\ndatabase and the `example` document by\n[running the previous example code](#1-create-a-database-and-add-a-document)\nsuccessfully. Otherwise, the following error message occurs, \"Cannot delete document because either 'orders'\ndatabase or 'example' document was not found.\"\n\n<details>\n<summary>Gather database information example</summary>\n\n```py\nimport json\n\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\n# 1. Create a client with `CLOUDANT` default service name ============\nclient = CloudantV1.new_instance()\n\n# 2. Get server information ===========================================\nserver_information = client.get_server_information(\n).get_result()\n\nprint(f'Server Version: {server_information[\"version\"]}')\n\n# 3. Get database information for \"orders\" ==========================\ndb_name = \"orders\"\n\ndb_information = client.get_database_information(\n db=db_name\n).get_result()\n\n# 4. Show document count in database ==================================\ndocument_count = db_information[\"doc_count\"]\n\nprint(f'Document count in \\\"{db_information[\"db_name\"]}\\\" '\n f'database is {document_count}.')\n\n# 5. Get \"example\" document out of the database by document id ============\ndocument_example = client.get_document(\n db=db_name,\n doc_id=\"example\"\n).get_result()\n\nprint(f'Document retrieved from database:\\n'\n f'{json.dumps(document_example, indent=2)}')\n```\n\n</details>\nWhen you run the code, you see a result similar to the following output.\n\n```text\nServer Version: 2.1.1\nDocument count in \"orders\" database is 1.\nDocument retrieved from database:\n{\n \"_id\": \"example\",\n \"_rev\": \"1-1b403633540686aa32d013fda9041a5d\",\n \"name\": \"Bob Smith\",\n \"joined\": \"2019-01-24T10:42:99.000Z\"\n}\n```\n\n#### 3. Update your previously created document\n\n**Note**: This example code assumes that you have created both the `orders`\ndatabase and the `example` document by\n[running the previous example code](#1-create-a-database-and-add-a-document)\nsuccessfully. Otherwise, the following error message occurs, \"Cannot update document because either 'orders'\ndatabase or 'example' document was not found.\"\n\n<details>\n<summary>Update code example</summary>\n\n```py\nimport json\n\nfrom ibm_cloud_sdk_core import ApiException\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\n# 1. Create a client with `CLOUDANT` default service name =============\nclient = CloudantV1.new_instance()\n\n# 2. Update the document ==============================================\nexample_db_name = \"orders\"\nexample_doc_id = \"example\"\n\n# Try to get the document if it previously existed in the database\ntry:\n document = client.get_document(\n db=example_db_name,\n doc_id=example_doc_id\n ).get_result()\n\n # =================================================================\n # Note: for response byte stream use:\n \"\"\"\n document_as_byte_stream = client.get_document_as_stream(\n db=example_db_name,\n doc_id=example_doc_id\n ).get_result()\n \"\"\"\n # =================================================================\n\n # Add Bob Smith's address to the document\n document[\"address\"] = \"19 Front Street, Darlington, DL5 1TY\"\n\n # Remove the joined property from document object\n if \"joined\" in document:\n document.pop(\"joined\")\n\n # Update the document in the database\n update_document_response = client.post_document(\n db=example_db_name,\n document=document\n ).get_result()\n\n # =================================================================\n # Note 1: for request byte stream use:\n \"\"\"\n update_document_response = client.post_document(\n db=example_db_name,\n document=document_as_byte_stream\n ).get_result()\n \"\"\"\n # =================================================================\n\n # =================================================================\n # Note 2: updating the document can also be done with the\n # \"put_document\" function. `doc_id` and `rev` are required for an\n # UPDATE operation, but `rev` can be provided in the document\n # object as `_rev` too:\n \"\"\"\n update_document_response = client.put_document(\n db=example_db_name,\n doc_id=example_doc_id, # doc_id is a required parameter\n rev=document[\"_rev\"],\n document=document # _rev in the document object CAN replace above `rev` parameter\n ).get_result()\n \"\"\"\n # =================================================================\n\n # Keeping track of the latest revision number of the document\n # object is necessary for further UPDATE/DELETE operations:\n document[\"_rev\"] = update_document_response[\"rev\"]\n print(f'You have updated the document:\\n' +\n json.dumps(document, indent=2))\n\nexcept ApiException as ae:\n if ae.status_code == 404:\n print('Cannot delete document because either ' +\n f'\"{example_db_name}\" database or \"{example_doc_id}\" ' +\n 'document was not found.')\n```\n\n</details>\nWhen you run the code, you see a result similar to the following output.\n\n```text\n{\n \"_id\": \"example\",\n \"_rev\": \"2-4e2178e85cffb32d38ba4e451f6ca376\",\n \"name\": \"Bob Smith\",\n \"address\": \"19 Front Street, Darlington, DL5 1TY\"\n}\n```\n\n#### 4. Delete your previously created document\n\n**Note**: This example code assumes that you have created both the `orders`\ndatabase and the `example` document by\n[running the previous example code](#1-create-a-database-and-add-a-document)\nsuccessfully. Otherwise, the following error message occurs, \"Cannot delete document because either 'orders'\ndatabase or 'example' document was not found.\"\n\n<details>\n<summary>Delete code example</summary>\n\n```py\nfrom ibm_cloud_sdk_core import ApiException\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\n# 1. Create a client with `CLOUDANT` default service name =============\nclient = CloudantV1.new_instance()\n\n# 2. Delete the document ==============================================\nexample_db_name = \"orders\"\nexample_doc_id = \"example\"\n\n# Try to get the document if it previously existed in the database\ntry:\n document = client.get_document(\n db=example_db_name,\n doc_id=example_doc_id\n ).get_result()\n\n delete_document_response = client.delete_document(\n db=example_db_name,\n doc_id=example_doc_id, # `doc_id` is required for DELETE\n rev=document[\"_rev\"] # `rev` is required for DELETE\n ).get_result()\n\n if delete_document_response[\"ok\"]:\n print('You have deleted the document.')\n\nexcept ApiException as ae:\n if ae.status_code == 404:\n print('Cannot delete document because either ' +\n f'\"{example_db_name}\" database or \"{example_doc_id}\"' +\n 'document was not found.')\n```\n\n</details>\nWhen you run the code, you see the following output.\n\n```text\nYou have deleted the document.\n```\n\n#### Further code examples\n\nFor a complete list of code examples, see the [examples directory](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#examples-for-python).\n\n### Error handling\n\nFor sample code on handling errors, see\n[Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python#error-handling).\n\n### Raw IO\n\nFor endpoints that read or write document content it is possible to bypass\nusage of the built-in object with byte streams.\n\nDepending on the specific SDK operation it may be possible to:\n* accept a user-provided byte stream to send to the server as a request body\n* return a byte stream of the server response body to the user\n\nRequest byte stream can be supplied for arguments that accept the `BinaryIO` type.\nFor these cases you can pass this byte stream directly to the HTTP request body.\n\nResponse byte stream is supported in functions with the suffix of `_as_stream`.\nThe returned byte stream allows the response body to be consumed\nwithout triggering JSON unmarshalling that is typically performed by the SDK.\n\nThe [update document](#3-update-your-previously-created-document) section\ncontains examples for both request and response byte stream cases.\n\nThe API reference contains further examples of using byte streams.\nThey are titled \"Example request as stream\" and are initially collapsed.\nExpand them to see examples of:\n\n- Byte requests:\n - [Bulk modify multiple documents in a database](https://cloud.ibm.com/apidocs/cloudant?code=python#postbulkdocs)\n\n- Byte responses:\n - [Query a list of all documents in a database](https://cloud.ibm.com/apidocs/cloudant?code=python#postalldocs)\n - [Query the database document changes feed](https://cloud.ibm.com/apidocs/cloudant?code=python#postchanges)\n\n### Model classes vs dictionaries\n\nThis SDK supports two possible formats to define an HTTP request. One approach uses only model classes and the other only dictionaries.\n\n<details>\n<summary>Example using model class structure</summary>\n\n```py\nfrom ibmcloudant.cloudant_v1 import DesignDocument, CloudantV1, DesignDocumentOptions, SearchIndexDefinition\n\nclient = CloudantV1.new_instance()\n\nprice_index = SearchIndexDefinition(\n index='function (doc) { index(\"price\", doc.price); }'\n)\n\ndesign_document_options = DesignDocumentOptions(\n partitioned=True\n)\n\npartitioned_design_doc = DesignDocument(\n indexes={'findByPrice': price_index},\n options=design_document_options\n)\n\nresponse = client.put_design_document(\n db='products',\n design_document=partitioned_design_doc,\n ddoc='appliances'\n).get_result()\n\nprint(response)\n```\n\n</details>\n\n<details>\n<summary>Same example using dictionary structure</summary>\n\n```py\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\nclient = CloudantV1.new_instance()\n\nprice_index = {\n 'index': 'function (doc) { index(\"price\", doc.price); }'\n}\n\npartitioned_design_doc = {\n 'indexes': {'findByPrice': price_index},\n 'options': {'partitioned': True},\n}\n\nresponse = client.put_design_document(\n db='products',\n design_document=partitioned_design_doc,\n ddoc='appliances'\n).get_result()\n\nprint(response)\n```\n\n</details>\n\nSince model classes and dicts are different data structures, they cannot be combined.\n\n<details>\n<summary>This solution will be invalid</summary>\n\n```py\nfrom ibmcloudant.cloudant_v1 import CloudantV1, DesignDocument\n\nclient = CloudantV1.new_instance()\n\nprice_index = {\n 'index': 'function (doc) { index(\"price\", doc.price); }'\n}\n\npartitioned_design_doc = DesignDocument(\n indexes={'findByPrice': price_index},\n options={'partitioned': True}\n)\n\nresponse = client.put_design_document(\n db='products',\n design_document=partitioned_design_doc,\n ddoc='appliances'\n).get_result()\n\nprint(response)\n```\n\n</details>\n\n### Further resources\n\n- [Cloudant API docs](https://cloud.ibm.com/apidocs/cloudant?code=python):\n API reference including usage examples for Cloudant Python SDK API.\n- [Pydoc](https://ibm.github.io/cloudant-python-sdk/):\n Cloudant Python SDK API Documentation.\n- [Cloudant docs](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-getting-started-with-cloudant):\n The official documentation page for Cloudant.\n- [Cloudant blog](https://blog.cloudant.com/):\n Many useful articles about how to optimize Cloudant for common problems.\n\n### Changes feed follower\n\n#### Introduction\n\nThe SDK provides a changes feed follower utility.\nThis helper utility connects to the `_changes` endpoint and returns the individual change items.\nIt removes some complexity of using the `_changes` endpoint by setting some options automatically\nand providing error suppression and retries.\n\n*Tip: the changes feed often does not meet user expectations or assumptions.*\n\nConsult the [Cloudant changes feed FAQ](https://cloud.ibm.com/docs/Cloudant?topic=Cloudant-faq-using-changes-feed)\nto get a better understanding of the limitations and suitable use-cases before using the changes feed in your application.\n\n#### Modes of operation\n\nThere are two modes of operation:\n* Start mode\n * Fetches the changes from the supplied `since` sequence (in this mode follower defaults to reading the feed from `now`).\n * Fetches all available changes and then continues listening for new changes indefinitely unless encountering an end condition.\n * An example use case for this mode is event driven workloads.\n* Start one-off mode\n * Fetches the changes from the supplied `since` sequence (in this mode follower defaults to reading the feed from the beginning).\n * Fetches all available changes and then stops when either there are no further changes pending or encountering an end condition.\n * An example use case for this mode is ETL style workloads.\n\n#### Configuring the changes follower\n\nThe SDK's model of changes feed options is also used to configure the follower.\nHowever, a subset of the options used internally by the follower implementation are invalid.\nSupplying these options when instantiating the follower causes an error.\nThe invalid options are:\n* `descending`\n* `feed`\n* `heartbeat`\n* `lastEventId` - use `since` instead\n* `timeout`\n* Follower permits only the value `_selector` for the `filter` option. This restriction is because selector\n based filters perform better than JavaScript backed filters. Configuring a non-selector based filter\n causes the follower to error.\n\nNote that the `limit` parameter terminates the follower at the given number of changes in either\noperating mode.\n\nThe changes follower requires the client to have HTTP timeouts of at least 1 minute and errors during\ninstantiation if it is insufficient. The default client configuration has sufficiently long timeouts.\n\nFor use-cases where these configuration limitations are too restrictive then write code to use the SDK's\n[POST `_changes` API](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#postchanges) instead of the follower.\n\n#### Error suppression\n\nBy default, the changes follower suppresses transient errors indefinitely and attempts to run to completion or listen forever as\ndictated by the operating mode.\nFor applications where that is not desirable configure the optional error tolerance duration. This controls the time since\nthe last successful response that the follower suppresses transient errors. An example usage is an application grace period\nbefore reporting an error and requiring intervention.\n\nThere are some additional points to consider for error suppression:\n* Errors considered terminal, for example, the database not existing or invalid credentials are never suppressed and error immediately.\n* The error suppression duration is not guaranteed to fire immediately after lapsing and is a minimum suppression time.\n* The changes follower backs-off between retries and as such may remain paused for a short while after the transient errors have resolved.\n* If the underlying SDK client used to initialize the follower also has retries configured then suppression of errors may last\n significantly longer than the follower's configured error tolerance duration depending on the specific options.\n\n#### Follower operation\n\nFor both modes:\n* The end conditions are:\n * A terminal error (HTTP codes `400`, `401`, `403` `404`).\n * Transient errors occur for longer than the error tolerance duration. Transient errors are all other HTTP status codes and connection errors.\n * The number of changes received reaches the configured `limit`.\n * The application calls stop to terminate the feed early.\n\nAs is true for the `_changes` endpoint change items have *at least once* delivery and callers may receive\nan individual item multiple times. When using the follower change items may repeat even within a limited\nnumber of changes (that is using the `limit` option) this is a minor difference from using `limit` on the HTTP native API.\n\nThe follower is not optimized for some use cases and it is not recommended to use it in cases where:\n* Setting `include_docs` and larger document sizes (for example > 10 kiB).\n* The volume of changes is very high (if the rate of changes in the database exceeds the follower's rate of pulling them it can never catch-up).\n\nIn these use-cases use the SDK's [POST `_changes` API](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/examples#postchanges)\nfor specific control over the number of change requests made and the content size of the responses.\n\n#### Checkpoints\n\nThe changes follower does not checkpoint since it has no information about whether the consuming application\nhas processed a change item after delivery. It is the application developer's responsibility\nto store the sequence IDs to have appropriate checkpoints and to re-initialize the follower with the required\n`since` value after, for example, the application restarts.\n\nThe frequency and conditions for checkpoints are application specific and some applications may be tolerant\nof dropped changes. This section provides only general guidance on how to avoid missing changes.\n\nTo guarantee processing of all changes do not persist the sequence ID from a change item until *after*\nthe processing of the change item by the application has completed. As indicated previously change item\ndelivery is *at least once* so application code must be able to handle repeated changes already. It is\npreferable to restart from an older `since` value and receive changes again than risk missing them.\n\nThe sequence IDs are available on each change item by default. However, the server omits sequence IDs from\nsome change items when using the `seq_interval` configuration option.\nInfrequent sequence IDs may improve performance by reducing the amount of data transfer and server load,\nbut the tradeoff is repeating more changes if it is necessary to resume the changes follower.\n\nTake extreme care persisting sequences if choosing to process change items in parallel as there\nis a considerable risk of missing changes on a restart if the recorded sequence is out of order.\n\n#### Code examples\n\n##### Initializing a changes follower\n```py\nimport ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\nclient = CloudantV1.new_instance()\n\ncf_params = {\n 'db': 'example', # Required: the database name.\n 'limit': 100, # Optional: return only 100 changes (including duplicates).\n 'since': '3-g1AG3...' # Optional: start from this sequence ID (e.g. with a value read from persistent storage).\n}\n\nchanges_follower = ChangesFollower(\n service=client, # Required: the Cloudant service client instance.\n error_tolerance=10000, # Optional: suppress transient errors for at least 10 seconds before terminating.\n **cf_params # Required: changes feed configuration options dict.\n)\n```\n\n##### Starting the changes follower\n\n###### Start mode for continuous listening\n```py\nimport Iterable\n\nfrom ibmcloudant import ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1, ChangesResultItem\n\nclient = CloudantV1.new_instance()\n\nchanges_follower = ChangesFollower(\n service=client,\n **{'db': 'example'})\n\nchanges_items: Iterable[ChangesResultItem] = changes_follower.start()\n# Note: iterable will not do anything until it is iterated\n# Create a for loop to iterate over the flow of changes\n# for changes_item in changes_items: ...\n```\n\n###### Start mode for one-off fetching\n```py\nimport Iterable\n\nfrom ibmcloudant import ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1, ChangesResultItem\n\nclient = CloudantV1.new_instance()\n\nchanges_follower = ChangesFollower(\n service=client,\n **{'db': 'example'})\n\nchanges_items: Iterable[ChangesResultItem] = changes_follower.start_one_off()\n# Note: iterable will not do anything until it is iterated\n# Create a for loop to iterate over the flow of changes\n# for changes_item in changes_items: ...\n```\n\n##### Processing changes\n\n###### Process continuous changes\n```py\nimport ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\nclient = CloudantV1.new_instance()\n\n# Start from a previously persisted seq\n# Normally this would be read by the app from persistent storage\n# e.g. previously_persisted_seq = your_app_persistence_read_func()\npreviously_persisted_seq = '3-g1AG3...'\nchanges_follower = ChangesFollower(\n service=client,\n **{'db': 'example', 'since': previously_persisted_seq})\n\nchanges_items = changes_follower.start()\nfor changes_item in changes_items:\n # do something with changes\n print(changes_item.id)\n for change in changes_item.changes:\n print(change.rev)\n # when change item processing is complete app can store seq\n seq = changes_item.seq\n # write seq to persistent storage for use as since if required to resume later\n # e.g. your_app_persistence_write_func(seq)\n # keep processing changes until the application is terminated or some other stop condition is reached\n\n# Note: iterator above is blocking, code here will be unreachable\n# until the iteration is stopped or another stop condition is reached.\n# For long running followers careful consideration should be made of where to call stop on the iterator.\n```\n\n###### Process one-off changes\n```py\nimport ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\nclient = CloudantV1.new_instance()\n\n# Start from a previously persisted seq\n# Normally this would be read by the app from persistent storage\n# e.g. previously_persisted_seq = your_app_persistence_read_func()\npreviously_persisted_seq = '3-g1AG3...'\nchanges_follower = ChangesFollower(\n service=client,\n **{'db': 'example', 'since': previously_persisted_seq})\n\nchanges_items = changes_follower.start_one_off()\nfor changes_item in changes_items:\n # do something with changes\n print(changes_item.id)\n for change in changes_item.changes:\n print(change.rev)\n # when change item processing is complete app can store seq\n seq = changes_item.seq\n # write seq to persistent storage for use as since if required to resume later\n # e.g. your_app_persistence_write_func(seq)\n\n# Note: iterator above is blocking, code here will be unreachable\n# until all changes are processed (or another stop condition is reached).\n```\n\n##### Stopping the changes follower\n```py\nimport ChangesFollower\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n\nclient = CloudantV1.new_instance()\nchanges_follower = ChangesFollower(\n service=client,\n **{'db': 'example'})\nchanges_items = changes_follower.start()\n\nfor changes_item in changes_items:\n # Option 1: call stop after some condition\n # Note that since the iterator is blocking at least one item\n # must be returned from it to reach to this point.\n # Additional changes may be processed before the iterator stops.\n changes_follower.stop()\n\n# Option 2: call stop method when you want to end the continuous loop from\n# outside the iterator. For example, you've put the changes follower in a\n# separate thread and need to call stop on the main thread.\n# Note: in this context the call must be made from a different thread because\n# code immediately following the iterator is unreachable until the iterator\n# has stopped.\nchanges_follower.stop()\n```\n\n### Pagination (beta)\n\n#### Introduction\n\nThe pagination feature (currently beta) accepts options for a single operation and automatically\ncreates the multiple requests to the server necessary to page through the results a fixed number at a time.\n\nPagination is a best-practice to break apart large queries into multiple server requests.\nThis has a number of advantages:\n* Keeping requests within server imposed limits, for example\n * `200` max results for text search\n * `2000` max results for partitioned queries\n* Fetching only the necessary data, for example\n * User finds required result on first page, no need to continue fetching results\n* Reducing the duration of any individual query\n * Reduce risk of query timing out on the server\n * Reduce risk of network request timeouts\n\n#### Limitations\n\nLimitations of pagination:\n* Forward only, no backwards paging\n* Limitations on `_all_docs` and `_design_docs` operations\n * No pagination for `key` option.\n There is no need to paginate as IDs are unique and this returns only a single row.\n This is better achieved with a single document get request.\n * No pagination for `keys` option.\n* Limitations on `_view` operations\n * No pagination for `key` option. Pass the same `key` as a start and end key instead.\n * No pagination for `keys` option.\n * Views that emit multiple identical keys (with the same or different values)\n from the same document cannot paginate if those key rows with the same ID\n span a page boundary.\n The pagination feature detects this condition and an error occurs.\n It may be possible to workaround using a different page size.\n* Limitations on `_search` operations\n * No pagination of grouped results.\n * No pagination of faceted `counts` or `ranges` results.\n\n#### Capacity considerations\n\nPagination can make many requests rapidly from a single program call.\n\nFor IBM Cloudant take care to ensure you have appropriate plan capacity\nin place to avoid consuming all the permitted requests.\nIf there is no remaining plan allowance and retries are not enabled or insufficient\nthen a `429 Too Many Requests` error occurs.\n\n#### Available operations\n\nPagination is available for these operations:\n* Query all documents [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postalldocs)\n and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionalldocs)\n * [Global all documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/AllDocsPagination.py)\n * [Partitioned all documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_all_docs_pagination.py)\n* Query all [design documents](https://cloud.ibm.com/apidocs/cloudant?code=python#postdesigndocs)\n * [Design documents examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/design_docs_pagination.py)\n* Query with selector syntax [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postfind)\n and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionfind)\n * [Global find selector query examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/find_pagination.py)\n * [Partitioned find selector query examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_find_pagination.py)\n* Query a search index [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postsearch)\n and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionsearch)\n * [Global search examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/search_pagination.py)\n * [Partitioned search examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_search_pagination.py)\n* Query a MapReduce view [global](https://cloud.ibm.com/apidocs/cloudant?code=python#postview)\n and [partitioned](https://cloud.ibm.com/apidocs/cloudant?code=python#postpartitionview)\n * [Global view examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/view_pagination.py)\n * [Partitioned view examples](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/test/examples/src/features/pagination/partition_view_pagination.py)\n\nThe examples presented in this `README` are for all documents in a partition.\nThe links in the list are to equivalent examples for each of the other available operations.\n\n#### Creating a pagination\n\nMake a new pagination from a client, `PagerType` for the operation\nand the options for the chosen operation.\nUse the `limit` option to configure the page size (default and maximum `200`).\n\nImports required for these examples:\n\n<details open>\n<summary>Python:</summary>\n\n```py\nfrom ibmcloudant import Pager, Pagination, PagerType\nfrom ibmcloudant.cloudant_v1 import CloudantV1\n```\n\n</details>\n\n##### Initialize the service\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Initialize service\nservice = CloudantV1.new_instance()\n```\n\n</details>\n\n##### Set the options\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Setup options\nopts = {\n 'db': 'events', # example database name\n 'limit': 50, # limit option sets the page size\n 'partition_key': 'ns1HJS13AMkK', # query only this partition\n}\n```\n\n</details>\n\n##### Create the pagination\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Create pagination\npagination = Pagination.new_pagination(\n service, PagerType.POST_PARTITION_ALL_DOCS, **opts)\n# pagination can be reused without side-effects as a factory for iterables or pagers\n# options are fixed at pagination creation time\n```\n\n</details>\n\n#### Using pagination\n\nOnce you have a pagination factory there are multiple options available.\n\n* Iterate pages\n* Iterate rows\n* Get each page from a pager\n* Get all results from a pager\n\nAll the paging styles produce equivalent results and make identical page requests.\nThe style of paging to choose depends on the use case requirements\nin particular whether to process a page at a time or a row at a time.\n\nThe pagination factory is reusable and can repeatedly produce new instances\nof the same or different pagination styles for the same operation options.\n\nHere are examples for each paging style.\n\n##### Iterate pages\n\nIterating pages is ideal for using an iterable for loop to process a page at a time.\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Option: iterate pages\n# Ideal for using a for loop with each page.\n# Each call to pages() returns a fresh iterator that can be traversed once.\nfor page in pagination.pages():\n # Do something with page\n pass\n```\n\n</details>\n\n##### Iterate rows\n\nIterating rows is ideal for using an iterable for loop to process a result row at a time.\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Option: iterate rows\n# Ideal for using a for loop with each row.\n# Each call to rows() returns a fresh iterator that can be traversed once.\nfor row in pagination.rows():\n # Do something with row\n pass\n```\n\n</details>\n\n##### Pager\n\nThe pager style is similar to other [IBM Cloud SDKs](https://github.com/IBM/ibm-cloud-sdk-common?tab=readme-ov-file#pagination).\nUsers familiar with that style of pagination may find using them preferable\nto the native language style iterators.\n\nIn the Cloudant SDKs these pagers are single use and traverse the complete set of pages once and only once.\nAfter exhaustion they cannot be re-used, simply create a new one from the pagination factory if needed.\n\nPagers are only valid for one of either page at a time or getting all results.\nFor example, calling for the next page then calling for all results causes an error.\n\n###### Get each page from a pager\n\nThis is useful for calling to retrieve one page at a time, for example,\nin a user interface with a \"next page\" interaction.\n\nIf calling for the next page errors, it is valid to call for the next page again\nto continue paging.\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Option: use pager next page\n# For retrieving one page at a time with a method call.\npager: Pager = pagination.pager()\nif pager.has_next():\n page = pager.get_next()\n # Do something with page\n```\n\n</details>\n\n###### Get all results from a pager\n\nThis is useful to retrieve all results in a single call.\nHowever, this approach requires sufficient memory for the entire collection of results.\nSo although it may be convenient for small result sets generally prefer iterating pages\nor rows with the other paging styles, especially for large result sets.\n\nIf calling for all the results errors, then calling for all the results again restarts the pagination.\n\n<details open>\n<summary>Python:</summary>\n\n```py\n# Option: use pager all results\n# For retrieving all result rows in a single list\n# Note: all result rows may be very large!\n# Preferably use iterables instead of get_all for memory efficiency with large result sets.\nall_pager: Pager = pagination.pager()\nall_rows = all_pager.get_all()\nfor page in all_rows:\n # Do something with row\n pass\n```\n\n</details>\n\n## Questions\n\nIf you are having difficulties using this SDK or have a question about the\nIBM Cloud services, ask a question on\n[Stack Overflow](http://stackoverflow.com/questions/ask?tags=ibm-cloud).\n\n## Issues\n\nIf you encounter an issue with the project, you are welcome to submit a\n[bug report](https://github.com/IBM/cloudant-python-sdk/issues).\n\nBefore you submit a bug report, search for\n[similar issues](https://github.com/IBM/cloudant-python-sdk/issues?q=is%3Aissue) and review the\n[KNOWN_ISSUES file](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/KNOWN_ISSUES.md) to verify that your issue hasn't been reported yet.\n\nPlease consult the [security policy](https://github.com/IBM/cloudant-python-sdk/security/policy) before opening security related issues.\n\n## Versioning and LTS support\n\nThis SDK follows semantic versioning with respect to the definition of user facing APIs.\nThis means under some circumstances breaking changes may occur within a major or minor version\nof the SDK related to changes in supported language platforms.\n\nThe SDK is supported on the available LTS releases of the language platform.\nThe LTS language versions are listed in the prerequisites:\n* [LTS versions currently supported by the SDK](https://github.com/IBM/cloudant-python-sdk/#prerequisites)\n* [LTS versions for this release of the SDK](#prerequisites)\n\nIncompatible changes from new language versions are not added to the SDK\nuntil they are available in the minimum supported language version.\n\nWhen language LTS versions move out of support the following will happen:\n* Existing SDK releases will continue to run on obsolete language versions, but will no longer be supported.\n* The minimum language version supported by the SDK will be updated to the next available LTS.\n* New language features may be added in subsequent SDK releases that will cause breaking changes\n if the new releases of the SDK are used with older, now unsupported, language levels.\n\n## Open source at IBM\n\nFind more open source projects on the [IBM GitHub](http://ibm.github.io/) page.\n\n## Contributing\n\nFor more information, see [CONTRIBUTING](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/CONTRIBUTING.md).\n\n## License\n\nThis SDK is released under the Apache 2.0 license. To read the full text of the license, see [LICENSE](https://github.com/IBM/cloudant-python-sdk/tree/v0.10.5/LICENSE).\n",
"bugtrack_url": null,
"license": null,
"summary": "Python client library for IBM Cloudant",
"version": "0.10.5",
"project_urls": {
"Bug Tracker": "https://github.com/IBM/cloudant-python-sdk/issues",
"Homepage": "https://github.com/IBM/cloudant-python-sdk"
},
"split_keywords": [
"ibmcloudant",
" cloudant",
" ibm",
" database",
" client",
" sdk",
" official"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d5815f7789e87c796bd43384661b02dbb690007eb39ed2abab67234035dd9cd0",
"md5": "8cc26960806ded2c2df2701c51e8e7d2",
"sha256": "1c4f71c6246145c035304772683769a37fc91148796503d0ab3bab66bfa04004"
},
"downloads": -1,
"filename": "ibmcloudant-0.10.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8cc26960806ded2c2df2701c51e8e7d2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 128415,
"upload_time": "2025-07-18T09:46:57",
"upload_time_iso_8601": "2025-07-18T09:46:57.921535Z",
"url": "https://files.pythonhosted.org/packages/d5/81/5f7789e87c796bd43384661b02dbb690007eb39ed2abab67234035dd9cd0/ibmcloudant-0.10.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5fbf147e8d15de8c038b4a64f57bb5bbfe64782b0e54c25f1f79bb8678caa395",
"md5": "c2692cd339fa2902b26c42e58d2f0f82",
"sha256": "ba6b13ddb342aa63820ac51199eeadaa5e32fea17c573701291456f1a79bb666"
},
"downloads": -1,
"filename": "ibmcloudant-0.10.5.tar.gz",
"has_sig": false,
"md5_digest": "c2692cd339fa2902b26c42e58d2f0f82",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 133577,
"upload_time": "2025-07-18T09:46:59",
"upload_time_iso_8601": "2025-07-18T09:46:59.512392Z",
"url": "https://files.pythonhosted.org/packages/5f/bf/147e8d15de8c038b4a64f57bb5bbfe64782b0e54c25f1f79bb8678caa395/ibmcloudant-0.10.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-18 09:46:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "IBM",
"github_project": "cloudant-python-sdk",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ibmcloudant"
}