> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrade the Python API client to version 3

> Keep your Python API client up to date to benefit from improvements and bug fixes.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Upgrade" href="/doc/libraries/sdk/upgrade/python" />

The Python API client follows [semantic versioning](http://semver.org).

## Upgrade to version 3

### From version 2

This document lists every known breaking change:

* Remove support for Python 2
* Add support for Python 3.9 and later
* Remove deprecated `RecommendationClient`,

Update your `algoliasearch` dependency to `>=3.0,<4.0` using pip:

```sh Command line icon=square-terminal theme={"system"}
python -m pip install --upgrade 'algoliasearch>=3.0,<4.0'
```

Then, update your requirements in your `setup.py` or `requirements.txt` to: `algoliasearch>=3.0,<4.0`.

### From version 1

Update to version 2 first, then update from version 2 to 3.

## Upgrade from version 1.20 to version 2

This document lists every known breaking change.
Not all these changes may affect your application,
since some of these breaking changes happen in obscure parts of the client.

Update your `algoliasearch` dependency to `>=2.0,<3.0` using pip:

```sh Command line icon=square-terminal theme={"system"}
python -m pip install --upgrade 'algoliasearch>=2.0,<3.0'
```

Then, update your requirements in your `setup.py` or `requirements.txt` to: `algoliasearch>=2.0,<3.0`.

## `SearchClient`

You can initialize the `SearchClient` as follows:

```diff icon=code theme={"system"}
- from algoliasearch.client import Client
- client = Client('app_id', 'api_key')

+ from algoliasearch.search_client import SearchClient
+ client = SearchClient.create('app_id', 'api_key')
```

### List of method signature changes

| Version 1.20                                                                                                                                 | Breaking change                                     | Version 2                                                          |
| -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------ |
| `addUserKey(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0, indexes=None)`                                             | Removed, use `add_api_key` instead                  | `add_api_key(acl, request_options=None)`                           |
| `add_api_key(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0, indexes=None, request_options=None)`                      | Changed                                             | `add_api_key(acl, request_options=None)`                           |
| `add_user_key(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0, indexes=None)`                                           | Removed, use `add_api_key` instead                  | `add_api_key(acl, request_options=None)`                           |
| `batch(requests, request_options=None)`                                                                                                      | Removed, use `multiple_batch` instead               | `multiple_batch(operations, request_options=None)`                 |
| `copyIndex(src_index_name, dst_index_name)`                                                                                                  | Removed, use `copy_index` instead                   | `copy_index(src_index_name, dst_index_name, request_options=None)` |
| `copy_index(src_index_name, dst_index_name, request_options=None, scope=None)`                                                               | Changed                                             | `copy_index(src_index_name, dst_index_name, request_options=None)` |
| `deleteIndex(index_name)`                                                                                                                    | Removed, use `init_index('name').delete()` instead  | `delete(request_options=None)`                                     |
| `deleteUserKey(api_key)`                                                                                                                     | Removed, use `delete_api_key` instead               | `delete_api_key(key, request_options=None)`                        |
| `delete_api_key(api_key, request_options=None)`                                                                                              | Changed                                             | `delete_api_key(key, request_options=None)`                        |
| `delete_index(index_name, request_options=None)`                                                                                             | Removed, use `init_index('name').delete()` instead  | `delete(request_options=None)`                                     |
| `delete_user_key(api_key)`                                                                                                                   | Removed, use `delete_api_key` instead               | `delete_api_key(key, request_options=None)`                        |
| `disableRateLimitForward()`                                                                                                                  | Removed, use `RequestOptions` instead               |                                                                    |
| `disable_rate_limit_forward()`                                                                                                               | Removed, use `RequestOptions` instead               |                                                                    |
| `enableRateLimitForward(admin_api_key, end_user_ip, rate_limit_api_key)`                                                                     | Removed, use `RequestOptions` instead               |                                                                    |
| `enable_rate_limit_forward(end_user_ip, rate_limit_api_key)`                                                                                 | Removed, use `RequestOptions` instead               |                                                                    |
| `generateSecuredApiKey(private_api_key, tag_filters, user_token='')`                                                                         | Removed, use `generate_secured_api_key` instead     | `generate_secured_api_key(parent_api_key, restrictions)`           |
| `generate_secured_api_key(private_api_key, queryParameters, user_token='')`                                                                  | Changed                                             | `generate_secured_api_key(parent_api_key, restrictions)`           |
| `getLogs(offset=0, length=10, type='all')`                                                                                                   | Removed, use `get_logs` instead                     | `get_logs(request_options=None)`                                   |
| `getUserKeyACL(api_key)`                                                                                                                     | Removed, use `get_api_key` instead                  | `get_api_key(key, request_options=None)`                           |
| `get_api_key(api_key, request_options=None)`                                                                                                 | Changed                                             | `get_api_key(key, request_options=None)`                           |
| `get_api_key_acl(api_key, request_options=None)`                                                                                             | Removed, use `get_api_key` instead                  | `get_api_key(key, request_options=None)`                           |
| `get_logs(offset=0, length=10, type='all', request_options=None)`                                                                            | Changed                                             | `get_logs(request_options=None)`                                   |
| `get_task(index_name, task_id, request_options=None)`                                                                                        | Removed, use `init_index('name').get_task` instead  | `get_task(task_id, request_options=None)`                          |
| `get_top_user_id(request_options=None)`                                                                                                      | Removed, use `get_top_user_ids` instead             | `get_top_user_ids(request_options=None)`                           |
| `get_user_key_acl(api_key)`                                                                                                                  | Removed, use `get_api_key` instead                  | `get_api_key(key, request_options=None)`                           |
| `initIndex(index_name)`                                                                                                                      | Removed, use `init_index` instead                   | `init_index(name)`                                                 |
| `init_analytics()`                                                                                                                           | Removed, use `AnalyticsClient.create` instead       | `create(app_id=None, api_key=None, region=None)`                   |
| `init_index(index_name)`                                                                                                                     | Changed                                             | `init_index(name)`                                                 |
| `init_insights_client(region='us')`                                                                                                          | Removed, use `InsightsClient.create` instead        | `create(app_id=None, api_key=None, region=None)`                   |
| `is_alive(request_options=None)`                                                                                                             | Removed                                             |                                                                    |
| `is_task_published(index_name, task_id, request_options=None)`                                                                               | Removed                                             |                                                                    |
| `listIndexes()`                                                                                                                              | Removed, use `list_indices` instead                 | `list_indices(request_options=None)`                               |
| `listUserKeys()`                                                                                                                             | Removed, use `list_api_keys` instead                | `list_api_keys(request_options=None)`                              |
| `list_indexes(request_options=None)`                                                                                                         | Removed, use `list_indices` instead                 | `list_indices(request_options=None)`                               |
| `list_user_ids(page=0, hits_per_page=20, request_options=None)`                                                                              | Changed                                             | `list_user_ids(request_options=None)`                              |
| `list_user_keys()`                                                                                                                           | Removed, use `list_api_keys` instead                | `list_api_keys(request_options=None)`                              |
| `moveIndex(src_index_name, dst_index_name)`                                                                                                  | Removed, use `move_index` instead                   | `move_index(src_index_name, dst_index_name, request_options=None)` |
| `multipleQueries(queries, index_name_key='indexName')`                                                                                       | Removed, use `multiple_queries` instead             | `multiple_queries(queries, request_options=None)`                  |
| `multiple_queries(queries, index_name_key='indexName', strategy='none', request_options=None)`                                               | Changed                                             | `multiple_queries(queries, request_options=None)`                  |
| `restore_api_key(api_key, request_options=None)`                                                                                             | Changed                                             | `restore_api_key(key, request_options=None)`                       |
| `search_user_ids(query, cluster=None, page=None, hits_per_page=None, request_options=None)`                                                  | Changed                                             | `search_user_ids(query, request_options=None)`                     |
| `set_end_user_ip(end_user_ip)`                                                                                                               | Removed, use `RequestOptions` instead               |                                                                    |
| `set_extra_header(key, value)`                                                                                                               | Removed, use `RequestOptions` instead               |                                                                    |
| `set_extra_headers(**kwargs)`                                                                                                                | Removed, use `RequestOptions` instead               |                                                                    |
| `set_timeout(connect_timeout, read_timeout, search_timeout=5)`                                                                               | Removed, use `RequestOptions` instead               |                                                                    |
| `update_api_key(api_key, obj, validity=None, max_queries_per_ip_per_hour=None, max_hits_per_query=None, indexes=None, request_options=None)` | Changed                                             | `update_api_key(key, request_options=None)`                        |
| `update_user_key(api_key, obj, validity=None, max_queries_per_ip_per_hour=None, max_hits_per_query=None, indexes=None)`                      | Removed, use `update_api_key` instead               | `update_api_key(key, request_options=None)`                        |
| `wait_task(index_name, task_id, time_before_retry=100, request_options=None)`                                                                | Removed, use `init_index('name').wait_task` instead | `wait_task(task_id, request_options=None)`                         |

## `SearchIndex`

You can initialize the `SearchIndex` as follows:

```diff icon=code theme={"system"}
- from algoliasearch.client import Client
- index = Client('app_id', 'api_key').init_index('name')

+ from algoliasearch.search_client import SearchClient
+ index = SearchClient.create('app_id', 'api_key').init_index('name')
```

### List of method signature changes

| Version 1.20                                                                                                                          | Breaking change                                    | Version 2                                                                |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ |
| `addObject(content, object_id=None)`                                                                                                  | Removed, use `save_object` instead                 | `save_object(obj, request_options=None)`                                 |
| `addObjects(objects)`                                                                                                                 | Removed, use `save_objects` instead                | `save_objects(objects, request_options=None)`                            |
| `addUserKey(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0)`                                                    | Removed, use `SearchClient.add_api_key` instead    | `add_api_key(acl, request_options=None)`                                 |
| `add_api_key(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0, request_options=None)`                             | Removed, use `SearchClient.add_api_key` instead    | `add_api_key(acl, request_options=None)`                                 |
| `add_object(content, object_id=None, request_options=None)`                                                                           | Removed, use `save_object` instead                 | `save_object(obj, request_options=None)`                                 |
| `add_objects(objects, request_options=None)`                                                                                          | Removed, use `save_objects` instead                | `save_objects(objects, request_options=None)`                            |
| `add_user_key(obj, validity=0, max_queries_per_ip_per_hour=0, max_hits_per_query=0)`                                                  | Removed, use `SearchClient.add_api_key` instead    | `add_api_key(acl, request_options=None)`                                 |
| `batch(requests, no_create=False, request_options=None)`                                                                              | Changed                                            | `batch(requests, request_options=None)`                                  |
| `batch_rules(rules, forward_to_replicas=False, clear_existing_rules=False, request_options=None)`                                     | Removed, use `save_rules` instead                  | `save_rules(rules, request_options=None)`                                |
| `batch_synonyms(synonyms, forward_to_slaves=False, replace_existing_synonyms=False, forward_to_replicas=False, request_options=None)` | Removed, use `save_synonyms` instead               | `save_synonyms(synonyms, request_options=None)`                          |
| `browse(page=0, hits_per_page=1000)`                                                                                                  | Removed, use `browse_objects` instead              | `browse_objects(request_options=None)`                                   |
| `browse_all(params=None, request_options=None)`                                                                                       | Removed, use `browse_objects` instead              | `browse_objects(request_options=None)`                                   |
| `browse_from(params=None, cursor=None, request_options=None)`                                                                         | Removed, use `browse_objects` instead              | `browse_objects(request_options=None)`                                   |
| `clearIndex()`                                                                                                                        | Removed, use `clear_objects` instead               | `clear_objects(request_options=None)`                                    |
| `clear_index(request_options=None)`                                                                                                   | Removed, use `clear_objects` instead               | `clear_objects(request_options=None)`                                    |
| `clear_rules(forward_to_replicas=False, request_options=None)`                                                                        | Changed                                            | `clear_rules(request_options=None)`                                      |
| `clear_synonyms(forward_to_slaves=False, forward_to_replicas=False, request_options=None)`                                            | Changed                                            | `clear_synonyms(request_options=None)`                                   |
| `deleteByQuery(query, params=None)`                                                                                                   | Removed, use `delete_by` instead                   | `delete_by(filters, request_options=None)`                               |
| `deleteObject(object_id)`                                                                                                             | Removed, use `delete_object` instead               | `delete_object(object_id, request_options=None)`                         |
| `deleteObjects(objects)`                                                                                                              | Removed, use `delete_objects` instead              | `delete_objects(object_ids, request_options=None)`                       |
| `deleteUserKey(key)`                                                                                                                  | Removed, use `SearchClient.delete_api_key` instead | `delete_api_key(key, request_options=None)`                              |
| `delete_api_key(key, request_options=None)`                                                                                           | Removed, use `SearchClient.delete_api_key` instead | `delete_api_key(key, request_options=None)`                              |
| `delete_by(params, request_options=None)`                                                                                             | Changed                                            | `delete_by(filters, request_options=None)`                               |
| `delete_by_query(query, params=None, request_options=None)`                                                                           | Removed, use `delete_by` instead                   | `delete_by(filters, request_options=None)`                               |
| `delete_objects(objects, request_options=None)`                                                                                       | Changed                                            | `delete_objects(object_ids, request_options=None)`                       |
| `delete_rule(objectID, forward_to_replicas=False, request_options=None)`                                                              | Changed                                            | `delete_rule(object_id, request_options=None)`                           |
| `delete_synonym(object_id, forward_to_slaves=False, forward_to_replicas=False, request_options=None)`                                 | Changed                                            | `delete_synonym(object_id, request_options=None)`                        |
| `delete_user_key(key)`                                                                                                                | Removed, use `SearchClient.delete_api_key` instead | `delete_api_key(key, request_options=None)`                              |
| `getObject(object_id, attributes_to_retrieve=None)`                                                                                   | Removed, use `get_object` instead                  | `get_object(object_id, request_options=None)`                            |
| `getObjects(object_ids)`                                                                                                              | Removed, use `get_objects` instead                 | `get_objects(object_ids, request_options=None)`                          |
| `getSettings()`                                                                                                                       | Removed, use `get_settings` instead                | `get_settings(request_options=None)`                                     |
| `getUserKeyACL(key)`                                                                                                                  | Removed, use `SearchClient.get_api_key` instead    | `get_api_key(key, request_options=None)`                                 |
| `get_api_key_acl(key, request_options=None)`                                                                                          | Removed, use `SearchClient.get_api_key` instead    | `get_api_key(key, request_options=None)`                                 |
| `get_object(object_id, attributes_to_retrieve=None, request_options=None)`                                                            | Changed                                            | `get_object(object_id, request_options=None)`                            |
| `get_objects(object_ids, attributes_to_retrieve=None, request_options=None)`                                                          | Changed                                            | `get_objects(object_ids, request_options=None)`                          |
| `get_user_key_acl(key)`                                                                                                               | Removed, use `SearchClient.get_api_key` instead    | `get_api_key(key, request_options=None)`                                 |
| `is_task_published(task_id, request_options=None)`                                                                                    | Removed                                            |                                                                          |
| `iter_rules(hits_per_page=1000, request_options=None)`                                                                                | Removed, use `browse_rules` instead                | `browse_rules(request_options=None)`                                     |
| `iter_synonyms(hits_per_page=1000, request_options=None)`                                                                             | Removed, use `browse_synonyms` instead             | `browse_synonyms(request_options=None)`                                  |
| `listUserKeys()`                                                                                                                      | Removed, use `SearchClient.list_api_keys` instead  | `list_api_keys(self, request_options=None)`                              |
| `list_api_keys(request_options=None)`                                                                                                 | Removed, use `SearchClient.list_api_keys` instead  | `list_api_keys(self, request_options=None)`                              |
| `list_user_keys()`                                                                                                                    | Removed, use `SearchClient.list_api_keys` instead  | `list_api_keys(self, request_options=None)`                              |
| `partialUpdateObject(partial_object)`                                                                                                 | Removed, use `partial_update_object` instead       | `partial_update_object(obj, request_options=None)`                       |
| `partialUpdateObjects(objects)`                                                                                                       | Removed, use `partial_update_objects` instead      | `partial_update_objects(objects, request_options=None)`                  |
| `partial_update_object(partial_object, no_create=False, request_options=None)`                                                        | Changed                                            | `partial_update_object(obj, request_options=None)`                       |
| `partial_update_objects(objects, no_create=False, request_options=None)`                                                              | Changed                                            | `partial_update_objects(objects, request_options=None)`                  |
| `read_rule(objectID, request_options=None)`                                                                                           | Removed, use `get_rule` instead                    | `get_rule(object_id, request_options=None)`                              |
| `saveObject(obj)`                                                                                                                     | Removed, use `save_object` instead                 | `save_object(obj, request_options=None)`                                 |
| `saveObjects(objects)`                                                                                                                | Removed, use `save_objects` instead                | `save_objects(objects, request_options=None)`                            |
| `save_rule(rule, forward_to_replicas=False, request_options=None)`                                                                    | Changed                                            | `save_rule(rule, request_options=None)`                                  |
| `save_synonym(content, object_id, forward_to_slaves=False, forward_to_replicas=False, request_options=None)`                          | Changed                                            | `save_synonym(synonym, request_options=None)`                            |
| `search(query, args=None, request_options=None)`                                                                                      | Changed                                            | `search(query, request_options=None)`                                    |
| `searchDisjunctiveFaceting(query, disjunctive_facets, params=None, refinements=None)`                                                 | Removed                                            |                                                                          |
| `search_disjunctive_faceting(query, disjunctive_facets, params=None, refinements=None, request_options=None)`                         | Removed                                            |                                                                          |
| `search_facet(facet_name, facet_query, query=None, request_options=None)`                                                             | Removed, use `search_for_facet_values` instead     | `search_for_facet_values(facet_name, facet_query, request_options=None)` |
| `search_for_facet_values(facet_name, facet_query, query=None, request_options=None)`                                                  | Removed, use `search_for_facet_values` instead     | `search_for_facet_values(facet_name, facet_query, request_options=None)` |
| `search_rules(query=None, anchoring=None, context=None, page=None, hitsPerPage=None, request_options=None)`                           | Changed                                            | `search_rules(query, request_options=None)`                              |
| `search_synonyms(query, types=[], page=0, hits_per_page=100, request_options=None)`                                                   | Changed                                            | `search_synonyms(query, request_options=None)`                           |
| `setSettings(settings)`                                                                                                               | Removed, use `set_settings` instead                | `set_settings(settings, request_options=None)`                           |
| `set_settings(settings, forward_to_slaves=True, forward_to_replicas=True, request_options=None)`                                      | Changed                                            | `set_settings(settings, request_options=None)`                           |
| `update_api_key(key, obj, validity=None, max_queries_per_ip_per_hour=None, max_hits_per_query=None, request_options=None)`            | Removed, use `SearchClient.update_api_key` instead | `update_api_key(key, request_options=None)`                              |
| `update_user_key(key, obj, validity=None, max_queries_per_ip_per_hour=None, max_hits_per_query=None)`                                 | Removed, use `SearchClient.update_api_key` instead | `update_api_key(key, request_options=None)`                              |
| `waitTask(task_id, time_before_retry=100)`                                                                                            | Removed, use `wait_task` instead                   | `wait_task(task_id, request_options=None)`                               |
| `wait_task(task_id, time_before_retry=100, request_options=None)`                                                                     | Changed                                            | `wait_task(task_id, request_options=None)`                               |

## `AnalyticsClient`

You can initialize the `AnalyticsClient` as follows:

```diff icon=code theme={"system"}
- from algoliasearch.client import Client
- analytics = Client('app_id', 'api_key').init_analytics()

+ from algoliasearch.analytics_client import AnalyticsClient
+ analytics = AnalyticsClient.create('app_id', 'api_key')
```

### List of method signature changes

| Version 1.20                                                                  | Breaking change | Version 2                                          |
| ----------------------------------------------------------------------------- | --------------- | -------------------------------------------------- |
| `add_ab_test(ab_test)`                                                        | Changed         | `add_ab_test(ab_test, request_options=None)`       |
| `delete_ab_test(ab_test_id)`                                                  | Changed         | `delete_ab_test(ab_test_id, request_options=None)` |
| `get_ab_test(ab_test_id)`                                                     | Changed         | `get_ab_test(ab_test_id, request_options=None)`    |
| `get_ab_tests(args=None)`                                                     | Changed         | `get_ab_tests(request_options=None)`               |
| `stop_ab_test(ab_test_id)`                                                    | Changed         | `stop_ab_test(ab_test_id, request_options=None)`   |
| `wait_task(index_name, task_id, time_before_retry=100, request_options=None)` | Removed         |                                                    |

## `InsightsClient`

You can initialize the `InsightsClient` as follows:

```diff icon=code theme={"system"}
- from algoliasearch.client import Client
- insights = Client('app_id', 'api_key').init_insights()

+ from algoliasearch.insights_client import InsightsClient
+ insights = InsightsClient.create('app_id', 'api_key')
```

### List of method signature changes

| Version 1.20                       | Breaking change | Version 2 |
| ---------------------------------- | --------------- | --------- |
| `post(data, request_options=None)` | Removed         |           |

## Use configuration

You can instantiate all clients with configuration objects. This is useful to change the way a client behaves.

All setters have been removed. If, for instance, you rely on `set_extra_headers` or `set_timeout`, you need to change your code to use a configuration object:

```diff icon=code theme={"system"}
- client.timeout = (1, 30)
+ from algoliasearch.configs import SearchConfig

+ config = SearchConfig()
+ config.read_timeout = 1
+ config.write_timeout = 30

+ client = SearchClient.create_with_config(config)
```

## Optional methods parameters and `requestOptions`

To have the most consistent, predictable, and future-proof method signature, the API client follows three rules:

* All required parameters have a single argument each
* All optional arguments are passed in a [`request_options`](/doc/libraries/sdk/v1/request-options) dictionary, as the last argument
* The client never sets any default values

Here are some examples:

```diff icon=code theme={"system"}
- client.get_logs(0, 100, 'all')
+ client.get_logs({'offset': 0, 'length': 100, 'type': 'all'})
```

```diff icon=code theme={"system"}
forward_to_replicas = True
synonym = {
  'objectID': 'a-unique-identifier',
  'type': 'altCorrection1',
  # ...
}

- index.save_synonym(synonym, 'a-unique-identifier', forward_to_replicas)
+ index.save_synonym(synonym, {'forwardToReplicas': forward_to_replicas})
```

```diff icon=code theme={"system"}
object = {'foo': 'bar'}

- index.add_object(object)
+ index.save_object(object, {'autoGenerateObjectIDIfNotExist': True})
```

```diff icon=code theme={"system"}
settings = {"searchableAttributes": ["name", "address"]}

- index.set_settings(settings, True)
+ index.set_settings(settings, {'forwardToReplicas': True})
```

## Exceptions

The import of the base `AlgoliaException` exception has changed:

```diff icon=code theme={"system"}
- from algoliasearch.helpers import AlgoliaException
+ from algoliasearch.exceptions import AlgoliaException
```
