Skip to content

RC: 2025-04 #494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 52 commits into from
May 16, 2025
Merged

RC: 2025-04 #494

merged 52 commits into from
May 16, 2025

Conversation

jhamon
Copy link
Collaborator

@jhamon jhamon commented May 16, 2025

We need to merge our RC branch so we can release.

jhamon and others added 30 commits March 14, 2025 10:30
## Problem

Need to prepare `release-candidate/2025-04` branch

## Solution

Regenerate core from 2025-04 api specification
## Problem

There were no info on assistant in the readme

## Solution

Now there is info on assistant in the readme

## Type of Change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Infrastructure change (CI configs, etc)
- [x] Non-code change (docs, etc)
- [ ] None of the above: (explain here)

## Test Plan

Describe specific steps for validating this change.
## Problem

- Currently we send urllib3 version in the user agent string
- Testing with importtime shows importing urllib3 just to get the
version extends the initial load time of the pinecone package by about
35 milliseconds.

## Solution

I confirmed we're not using this information in the header, so we should
remove it to improve initialization performance.

## Test Plan

- Analysis with showed Loading this urllib3 to get the version was
adding 35 milliseconds to the time needed to "from pinecone import
Pinecone"
- Updated unit tests
jhamon added 21 commits May 8, 2025 15:09
## Problem

In the upcoming release we want to take a dependency on
`pinecone-plugin-assitants`. But we don't want this dependency to come
at a cost of degraded performance for users who are not using the
features in the plugin. Adding it with no modifications to existing code
resulted in adding 93 milliseconds to the already sluggish time needed
to import the `Pinecone` class of 230 milliseconds.

With the changes in this PR, we are able to add the assistant
functionality and bring the time needed to load and do initial
instantiation of the `Pinecone` client down by about 65%.

## Solution

To accomplish these goals I wanted to do some significant refactoring
without breaking any existing functionality.

Some functional requirements of the refactor include:

- Existing integration tests able to pass without major modification. 
- Things should still be importable as before (e.g. `from pinecone
import Pinecone`). This includes many objects which are less-often
discussed but still needed by customers such as various data objects.
Anyone working heavily with types in python will need access to these
both before and after the refactoring, so we don't want to accidentally
remove items that used to be importable from the top-level.
- Existing client methods should continue to work as before
(`create_index`, etc)
- mypy type-checking still passing even with new lazy-loading approach
in the top-level `__init__.py`

With all that said, this refactor has implemented the following major
changes:

- **Define small resource-centric classes**. Move the implementation for
actions on a resource from `pinecone.py` into a class with a narrower
focus. Then only load and instantiate this class when the user is
attempting to call these methods.
- For example, actions are completed on the index resource with
`Pinecone` methods such as `create_index`, `list_indexes`,
`delete_index` that historically were defined inline in the `Pinecone`
class. After this refactoring, the behavior from those functions has
been moved into a new `IndexResource` class that exposes `create`,
`list`, etc methods. The parent `Pinecone` class now delegates to this
class which is lazily initialized only when needed. This speeds up the
time needed to import and instantiate `Pinecone` significantly.
- So far these resource classes have been implemented for both the sync
and asyncio versions of the `Index` and `Collections` classes under
`pinecone/db_control/resources`.
- **Remove unnecessary type imports with TYPE_CHECKING**. Use the
[`TYPE_CHECKING`](https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING)
boolean from the `typing` package to avoid importing code at runtime
that is only needed for type-checking (which does not occur at runtime.)
Type-checking with mypy is a static code inspection, and this
`TYPE_CHECKING` variable [will be treated as True when analyzing type
information](https://mypy.readthedocs.io/en/stable/runtime_troubles.html#typing-type-checking).
This allows mypy to understand what types are being used when type
checking without the runtime overhead (since during runtime
`TYPE_CHECKING` always evaluates to False). Without using this
technique, most of the benefits of refactoring into smaller lazy-loaded
classes would be undone by loading classes to use in type signatures.
- **Implemented a proxy module loader** in the top-level `__init__.py`
so that every importable item in the the entire package does not have to
be loaded in order to gain access to the `Pinecone` client object and
get started.
- **Modify PluginAware class to defer plugin loading.** The PluginAware
class is something that other classes can extend in order to become
pluggable and is currently used by the `Pinecone`, `Index`, and
`Inference` classes to implement plugins. In the past, on initialization
of a class extending `PluginAware`, the environment would be scanned for
the presence of plugins and if any are available they get installed.
This means we could not have a plugin in the environment without
incurring an initialization cost on every user. Since we want to ship
with the Assistant plugin in the upcoming release, but not every user is
using Assistant, a big startup penalty seems highly undesirable. So now
the PluginAware class has been reformulated. Now `PluginAware`
implements a `__getattr__` method that will install plugins only at the
moment a user tries to use them.
- **Removed urllib3 info from user-agent**. This seems like it should be
inconsequential, but importing the entire `urllib3` package just to get
the version during initialization of the Pinecone client was
contributing significant latency. Since we're not using that info for
anything anymore, we can nix it.
- **Added new integration tests**: To ensure the backwards compatibility
of these changes, most integration tests were left as they were. Some
new ones have been added to exercise new usage patterns such as
`pc.db.index.delete(name='foo')`, `pc.db.collection.list()`, etc. These
new tests now run in dedicated CI builds. I need to continue expanding
coverage on these, particularly for the async ones, but most of the
functionality is implicitly covered by the existing integration tests.
- **Reorganize some folders to align with API spec organization**. Along
the way to making these changes, it seemed appropriate to create some
new folder structures such as `pinecone/db_control` to mirror the
structure of our API definitions. Where things have been moved, I've
tried to add alias packages with warning messages so that anyone
reaching deeply into packages to import things should not be broken. A
warning message is now displayed, for example, if you attempt to import
from a legacy subpackage package: `The module at `pinecone.control` has
moved to `pinecone.db_control`. This warning will become an error in a
future version of the Pinecone Python SDK.` Very few people will ever
see these, I think, but they should help a few people. This is a
best-effort thing, but there's no way to ensure that I have covered
every possible way that somebody may have tried to import something from
our internals in the past.

New dependencies:
- `pinecone-plugin-assistant` to bring in assistant functions
- `tuna`: a dev dependency for visualizing load performance
- `python-dotenv`: dev dependency for managing environment variables
more easily in testing

## Initialization performance

To assess the load time for the pinecone package, I used a built-in
package called `importtime`.

```shell
poetry run python3 -X importtime -c "from pinecone import Pinecone; pc = Pinecone(api_key='foo')" 2> main.log
```

Then I visualized the results using a new dev-dependency called `tuna`

```shell
poetry run tuna main.log
```

These steps can be used to show that before any refactoring, the
initialization time was more than 300ms(!)

<img width="1485" alt="Screenshot 2025-05-08 at 3 20 27 PM"
src="https://github.com/user-attachments/assets/6593da21-1b37-44f5-a349-b7af4ec21ea0"
/>

After refactoring to make `PluginAware` lazy, and also restructure code
related to operations on indexes, collections, inference, etc to take
advantage of lazy loading we can improve the client initialization time
very significantly. This is a big improvement because it means users
will no longer need to wait to load a bunch of code for features they
are not using.

<img width="1482" alt="Screenshot 2025-05-08 at 3 18 16 PM"
src="https://github.com/user-attachments/assets/b31c1c2d-2b2f-443d-aaa4-347320367720"
/>


## Type of Change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Infrastructure change (CI configs, etc)
- [ ] Non-code change (docs, etc)
- [ ] None of the above: (explain here)

## Test Plan

Describe specific steps for validating this change.
## Problem

Implement backup & restore

## Solution

Added new methods to `Pinecone` and `PineconeAsyncio`:
- `create_index_from_backup`
- `create_backup`
- `list_backups`
- `describe_backup`
- `delete_backup`
- `list_restore_jobs`
- `describe_restore_job`

These can also be accessed with the new-style syntax, e.g.
`pc.db.index.create_from_backup`, `pc.db.backup.create`,
`pc.db.restore_job.list`.

More Details:

- Had to re-run codegen to pull in recent spec changes
- Organize implementation around resource-types
- Expose legacy-style names (`create_backup`,
`create_index_from_backups`) as well as new-style names
`pc.db.index.create_from_backup`. In the upcoming release, both styles
will be present. We still need to do some work to reorg methods for some
less-used parts of the client (bulk imports, etc) before transitioning
fully to the new style in examples and documentation.
- For new methods being added, begin enforcing keyword argument usage
with a new `@kwargs_required` decorator. I will probably follow up and
add this to all new methods added in the recent refactoring PR. Keyword
arguments are strongly preferred over positional arguments because the
keyword labels act as documentation and having the keyword labels makes
them order-independent. This gives a lot of flexibility to expand the
signature or change things from required to optional later without
creating breaking changes for callers.
- Wire up the code paths for new methods:
    - `Pinecone > DbControl > BackupResource`
    - `Pinecone > DbControl > IndexResource`
    - `Pinecone > DbControl > RestoreJobResource`
    - `PineconeAsyncio > DbControlAsyncio > AsyncioBackupResource`
    - `PineconeAsyncio > DbControlAsyncio > AsyncioIndexResource`
    - `PineconeAsyncio > DbControlAsyncio > AsyncioRestoreJobResource`
- Update interface classes so that docs will show information about the
new methods.

## Usage

### Initial setup

```python
from pinecone import Pinecone, ServerlessSpec

pc = Pinecone(api_key='key')

# First you need an index
pc.create_index(
    name='foo',
    dimension=2,
    metric='cosine',
    spec=ServerlessSpec(cloud='aws', region='us-east-1')
)

# Upsert some fake data just for demonstration purposes
import random

idx = pc.Index(name='foo')
idx.upsert(
    vectors=[
         (str(i), [random.random(), random.random()] for i in range(1000)
    ]
)
```

### Backups

```python
pc.create_backup(
    index_name='foo', 
    backup_name='bar', 
    description='an example backup'
)

# Describe a backup
pc.describe_backup(backup_id='7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1')
# {
#     "backup_id": "7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1",
#     "source_index_name": "foo",
#     "source_index_id": "4c292a8a-77cc-4a37-917d-51c6051a80bf",
#     "status": "Ready",
#     "cloud": "aws",
#     "region": "us-east-1",
#     "tags": {},
#     "name": "bar",
#     "description": "",
#     "dimension": 2,
#     "record_count": 1000,
#     "namespace_count": 1,
#     "size_bytes": 289392,
#     "created_at": "2025-05-13T14:15:16.908702Z"
# }


# List backups
pc.list_backups()
# [
#     {
#         "backup_id": "7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1",
#         "source_index_name": "foo",
#         "source_index_id": "4c292a8a-77cc-4a37-917d-51c6051a80bf",
#         "status": "Ready",
#         "cloud": "aws",
#         "region": "us-east-1",
#         "tags": {},
#         "name": "bar",
#         "description": "",
#         "dimension": 2,
#         "record_count": 1000,
#         "namespace_count": 1,
#         "size_bytes": 289392,
#         "created_at": "2025-05-13T14:15:16.908702Z"
#     }
# ]

# Delete backup
pc.delete_backup(backup_id='7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1')
```

### Creating an index from backup
```python
# Create index from backup
pc.create_index_from_backup(
  backup_id='7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1',
  name='foo2',
  deletion_protection='enabled',
  tags={'env': 'testing'}
)
# {
#     "name": "foo2",
#     "metric": "cosine",
#     "host": "foo2-dojoi3u.svc.aped-4627-b74a.pinecone.io",
#     "spec": {
#         "serverless": {
#             "cloud": "aws",
#             "region": "us-east-1"
#         }
#     },
#     "status": {
#         "ready": true,
#         "state": "Ready"
#     },
#     "vector_type": "dense",
#     "dimension": 2,
#     "deletion_protection": "enabled",
#     "tags": {
#         "env": "testing"
#     }
# }
```

### Restore job

```python
# List jobs
pc.list_restore_jobs()
# {'data': [{'backup_id': 'e5957dc2-a76e-4b72-9645-569fb7ec143f',
#            'completed_at': datetime.datetime(2025, 5, 13, 14, 56, 13, 939921, tzinfo=tzutc()),
#            'created_at': datetime.datetime(2025, 5, 13, 14, 56, 4, 534826, tzinfo=tzutc()),
#            'percent_complete': 100.0,
#            'restore_job_id': '744ea5bd-7ddc-44ce-81f5-cfb876572e59',
#            'status': 'Completed',
#            'target_index_id': '572130f9-cfdd-42bf-a280-4218cd112bf8',
#            'target_index_name': 'foo2'},
#           {'backup_id': '7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1',
#            'completed_at': datetime.datetime(2025, 5, 13, 16, 27, 10, 290234, tzinfo=tzutc()),
#            'created_at': datetime.datetime(2025, 5, 13, 16, 27, 6, 130522, tzinfo=tzutc()),
#            'percent_complete': 100.0,
#            'restore_job_id': '06aa5739-2785-4121-b71b-99b73c3e3247',
#            'status': 'Completed',
#            'target_index_id': 'd3f31cd1-b077-4bcf-8e7d-d091d408c82b',
#            'target_index_name': 'foo2'}],
#  'pagination': None}

# Describe jobs
pc.describe_restore_job(job_id='504dd1a9-e3cd-420f-8756-65d5411fcb10')
# {'backup_id': '7c8e6fcf-577b-4df5-9869-3c67f0f3d6e1',
#  'completed_at': datetime.datetime(2025, 5, 13, 15, 55, 10, 108584, tzinfo=tzutc()),
#  'created_at': datetime.datetime(2025, 5, 13, 15, 54, 49, 925105, tzinfo=tzutc()),
#  'percent_complete': 100.0,
#  'restore_job_id': '504dd1a9-e3cd-420f-8756-65d5411fcb10',
#  'status': 'Completed',
#  'target_index_id': 'b5607ee7-be78-4401-aaf5-ea20413f409d',
#  'target_index_name': 'foo4'}
```

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Test Plan

Describe specific steps for validating this change.
## Problem

The cleanup steps in the backup tests were deleting all backups in a
project, which creates a problem when multiple jobs in a test matrix are
running in parallel and backups may be suddenly deleted out from
underneath a running test.

## Solution

- Cleanup should only delete backups created with the current RUN_ID.
This information is stored in index tags and is visible on the backup
resource as well.
- Cleanup duplication in conftest setup. It's easier to make these
changes in one spot than in 6-8 spots.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)
…482)

## Problem

BYOC requires a new type of spec object, `ByocSpec`.

## Solution

- Update legacy-style methods to accept new `ByocSpec` type:
    - `Pinecone#create_index`
    - `PineconeAsyncio#create_index`
- Update resource classes (accessed from `pc.db.index.create`)
    - `IndexResource#create`
    - `AsyncioIndexResource#create`
- Update interfaces used for docgen

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Test Plan

- Added a new unit test to ensure the client can properly deserialize
API responses (e.g. from describe, list) that include the new byoc spec
type into the `IndexModel` object. This is important since I'm currently
not set up to do a full integration test of the feature.
## Problem

The Pinecone SDK does not currently have full coverage on mypy type
annotations, but we are adopting them in an incremental fashion.

## Solution

Add a `py.typed` file to the package. An empty `py.typed` file is used
as a
[marker](https://typing.python.org/en/latest/spec/distributing.html#packaging-typed-libraries)
to let mypy or other type checkers know there is type information in the
package.

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Test Plan

Describe specific steps for validating this change.
## Problem

Some test indexes are not being cleaned up properly because the created
indexes are not tagged with the test run id.

## Solution

Update tests that are missing tags.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)
## Problem

Want to isolate the impact of my test activities from prod

## Solution

Adjust CI test configuration to add an `x-environment` header to
requests using the `PINECONE_ADDITIONAL_HEADERS` environment variable,
which is picked up by the configuration parsing.

## Type of Change

- [x] Infrastructure change (CI configs, etc)

## Test Plan

Describe specific steps for validating this change.
## Problem

Python methods can be invoked with both positional and keyword
arguments, however the keyword argument form has a number of benefits
such as:
- The keyword argument label acts as a minor form of documentation
- Keyword arguments can be passed in any order, whereas positional
arguments must be passed in a specific fixed order. This order
flexibility works well when there are large numbers of optional
parameters
- If a function takes several parameters of the same type (e.g. str),
it's very easy to accidentally pass them in the wrong order since you
won't run into a type-related error letting you know you've done
something wrong. Keyword args don't have this problem.
- With positional arguments you must pass arguments with no default
value before those that have a default value; this means you can't add a
new default value without having to shuffle your argument order which
creates a breaking change out of what should be a benign UX improvement.
Keyword args do not have this limitation.

## Solution

I recently implemented a decorator called @kwargs_required that will
give an informative error if caller attempts to pass values as
positional arguments.

This PR is a follow-up to apply that decorator to all methods that are
newly added in the upcoming release. Adding this decorator would be a
breaking change for existing methods, so for now I will hold off on
doing that.

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Testing

```python
>>> pc.db.index.describe('foofoo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/utils/require_kwargs.py", line 10, in wrapper
    raise TypeError(
TypeError: describe() requires keyword arguments. Please use describe(name=value)
>>> pc.db.index.describe(name='foofoo')
{
    "name": "foofoo",
    "metric": "cosine",
    "host": "foofoo-dojoi3u.svc.aped-4627-b74a.pinecone.io",
    "spec": {
        "serverless": {
            "cloud": "aws",
            "region": "us-east-1"
        }
    },
    "status": {
        "ready": true,
        "state": "Ready"
    },
    "vector_type": "dense",
    "dimension": 2,
    "deletion_protection": "disabled",
    "tags": null
}
```
## Problem

We want to continue improving our import and initialization times.

## Solution

- Refactor the `@validate_and_convert_errors` decorator to use
lazy-loading of `urllib3`. We only need to load urllib3 in this
decorator at the moment an exception has occurred.
- Refactor `pinecone.config.openapi_configuration.py` to avoid loading
the `http` module unless enabling debug logging. The default http log
level is already 0 (disabled) so there's no need to set it in the
default case.

## Perf testing

```sh
poetry run python3 -X importtime -c "from pinecone import Pinecone; pc = Pinecone(api_key='foo')" 2> main.log
```

Comparing the importtime results before and after this change shows a
reduction from 101ms to 65ms, **a savings of 36ms which is about 36%.**

<img width="1492" alt="Screenshot 2025-05-14 at 4 00 38 AM"
src="https://github.com/user-attachments/assets/9ce9e582-c9d1-46da-a76d-c053e69991b1"
/>

<img width="1491" alt="Screenshot 2025-05-14 at 4 50 58 AM"
src="https://github.com/user-attachments/assets/b5db282f-6b2c-41aa-adbb-09591d21f255"
/>
… the future (#484)

## Problem

We need these classes to extend `PluginAware` in case we ever want to
add functions via plugin in the future.

## Solution

Adjust the constructor functions for each of these resource classes to
set the properties needed by `PluginAware`.

## Type of Change

- [x] New feature (non-breaking change which adds functionality)
## Problem

We need to verify the assistant plugin is able to be installed correctly

## Solution

- Add a simple test of one of the read-only functions within the plugin.
This verifies the plugin has been installed correctly.
- Add CI build for plugin tests

## Type of Change

- [x] Infrastructure change (CI configs, etc)
#488)

## Problem

We need to expose a new endpoint for discovering available inference
models

## Solution

- Regenerate code off the latest spec
- Wire the new method up in the sync and async implementations of
Inference
    - `pc.inference.get_model`
    - `pc.inference.list_models`
- Make some adjustments in model_utils to be less fragile if unexpected
values appear in enum fields
- Implement new tests for these list_models endpoints.

## Usage

```python
from pinecone import Pinecone

pc = Pinecone()

models = pc.inference.list_models()
models[0]
# {
#     "model": "llama-text-embed-v2",
#     "short_description": "A high performance dense embedding model optimized for multilingual and cross-lingual text question-answering retrieval with support for long documents (up to 2048 tokens) and dynamic embedding size (Matryoshka Embeddings).",
#     "type": "embed",
#     "supported_parameters": [
#         {
#             "parameter": "input_type",
#             "type": "one_of",
#             "value_type": "string",
#             "required": true,
#             "allowed_values": [
#                 "query",
#                 "passage"
#             ]
#         },
#         {
#             "parameter": "truncate",
#             "type": "one_of",
#             "value_type": "string",
#             "required": false,
#             "default": "END",
#             "allowed_values": [
#                 "END",
#                 "NONE",
#                 "START"
#             ]
#         },
#         {
#             "parameter": "dimension",
#             "type": "one_of",
#             "value_type": "integer",
#             "required": false,
#             "default": 1024,
#             "allowed_values": [
#                 384,
#                 512,
#                 768,
#                 1024,
#                 2048
#             ]
#         }
#     ],
#     "vector_type": "dense",
#     "default_dimension": 1024,
#     "modality": "text",
#     "max_sequence_length": 2048,
#     "max_batch_size": 96,
#     "provider_name": "NVIDIA",
#     "supported_metrics": [
#         "Cosine",
#         "DotProduct"
#     ],
#     "supported_dimensions": [
#         384,
#         512,
#         768,
#         1024,
#         2048
#     ]
# }
```

And async

```python
import asyncio
from pinecone import PineconeAsyncio

async def main():
  with PineconeAsyncio() as pc:
    await pc.inference.list_models()

asyncio.run(main())
```

## Type of Change

- [x] New feature (non-breaking change which adds functionality)
## Problem

We want to automatically retry when errors occur

## Solution

Implement `urllib3` retry configuration. We implemented the backup
calculation with jitter ourselves because this is not available for all
versions of `urllib3` that the SDK uses.

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Test Plan

I created a mock server in `scripts/text-server.py` that simulates a
high rate of failures (80% failure, only 1 in 5 requests succeed).

`poetry run python3 scripts/test-server.py`

Then I made some requests and observed logging to see what was going on.

```python
>>>  from pinecone import Pinecone
>>>  # Testing control plane with retries
>>> pc = Pinecone(host='http://localhost:8000')
>>> pc.list_indexes()
>>> 
>>> # Data plane
>>> idx = pc.Index(host='http://localhost:8000')
>>> # enable debug logging
>>> idx._vector_api.api_client.configuration.debug = True
>>> 
>>> idx.upsert(vectors=[('1', [0.1, 0.2])])
DEBUG    | pinecone.openapi_support.rest_urllib3:126 | Calling urllib3 request()
DEBUG    | urllib3.connectionpool:546 | http://localhost:8000 "POST /vectors/upsert HTTP/10" 500 None
DEBUG    | urllib3.util.retry:521 | Incremented Retry for (url='/vectors/upsert'): JitterRetry(total=4, connect=None, read=None, redirect=None, status=None)
DEBUG    | pinecone.openapi_support.retries:20 | Calculating retry backoff: 0.15197003184454544 (jitter: 0.15197003184454544)
DEBUG    | urllib3.connectionpool:943 | Retry: /vectors/upsert
DEBUG    | urllib3.connectionpool:546 | http://localhost:8000 "POST /vectors/upsert HTTP/10" 500 None
DEBUG    | urllib3.util.retry:521 | Incremented Retry for (url='/vectors/upsert'): JitterRetry(total=3, connect=None, read=None, redirect=None, status=None)
DEBUG    | pinecone.openapi_support.retries:20 | Calculating retry backoff: 0.7352149950424516 (jitter: 0.2352149950424516)
DEBUG    | urllib3.connectionpool:943 | Retry: /vectors/upsert
DEBUG    | urllib3.connectionpool:546 | http://localhost:8000 "POST /vectors/upsert HTTP/10" 500 None
DEBUG    | urllib3.util.retry:521 | Incremented Retry for (url='/vectors/upsert'): JitterRetry(total=2, connect=None, read=None, redirect=None, status=None)
DEBUG    | pinecone.openapi_support.retries:20 | Calculating retry backoff: 1.1307109027442626 (jitter: 0.13071090274426245)
DEBUG    | urllib3.connectionpool:943 | Retry: /vectors/upsert
DEBUG    | urllib3.connectionpool:546 | http://localhost:8000 "POST /vectors/upsert HTTP/10" 500 None
DEBUG    | urllib3.util.retry:521 | Incremented Retry for (url='/vectors/upsert'): JitterRetry(total=1, connect=None, read=None, redirect=None, status=None)
DEBUG    | pinecone.openapi_support.retries:20 | Calculating retry backoff: 2.142226695165083 (jitter: 0.14222669516508277)
DEBUG    | urllib3.connectionpool:943 | Retry: /vectors/upsert
DEBUG    | urllib3.connectionpool:546 | http://localhost:8000 "POST /vectors/upsert HTTP/10" 200 None
DEBUG    | pinecone.openapi_support.rest_urllib3:266 | response body: b'{"upsertedCount": 10}'
DEBUG    | pinecone.openapi_support.rest_utils:34 | response status: 200
{'upserted_count': 10}

```
## Problem

Sometimes unexpected values in API responses can cause unnecessary
errors due to validation logic being applied. Fields labeled in the
openapi as `enum` fields will error when unexpected values appear in the
response. In general, we want the client to just display what the API
returns without applying validation.

## Solution

Adjust the code generation to disable validation logic when
instantiating model objects from API response.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)

## Test Plan

I created a mock server script to do some manual testing of different
responses with odd values in them and saw this works without erroring.
For example, these responses no longer raise:
- New index status
- Index dimension > 20k
- Index name too long
## Problem

We want to use exponential backoff to retry failed requests made via
PineconeAsyncio

## Solution

- Add `aiohttp-retry` dependency without the `asyncio` extras group
- Implement a JitterRetry class to calculate backoff intervals
- The off-the-shelf JitteryRetry class has some odd behavior so i wanted
to implement my own. This helps keep the behavior close to what we're
doing for urllib3.
- Intervals are roughly 0.1, 0.2, 0.4, 0.8 seconds (plus small jitter
factor)
- Manual testing with test server in `scripts/test-server.py` and
`scripts/test-async-retry.py`

## Type of Change

- [x] New feature (non-breaking change which adds functionality)

## Test Plan

Added some scripts for manual testing
## Problem

Need to update docs for release

## Solution


![kermit-the-frog-kermit-typing](https://github.com/user-attachments/assets/00921776-3740-4b70-9fbd-b32b23fb38d0)

## Type of Change

- [x] Non-code change (docs, etc)
@jhamon jhamon changed the title Release candidate/2025 04 RC: 2025-04 May 16, 2025
@jhamon jhamon marked this pull request as ready for review May 16, 2025 23:31
@jhamon jhamon merged commit 1ae09e7 into main May 16, 2025
75 checks passed
@jhamon jhamon deleted the release-candidate/2025-04 branch May 16, 2025 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants