Skip to content

Commit

Permalink
[Feat] Helpful error when incorrectly instantiating Index client (#418)
Browse files Browse the repository at this point in the history
## Problem

Sometimes users incorrectly instantiate the Index client like this:

```python
import pinecone

# Initialize the Index with the host
index = pinecone.Index(index_name, host=index_host)
```

Then they will later get an authentication exception when using it,
since the `Index` class does not have the configuration values it needs
when attempting to perform vector operations.

```python
ForbiddenException: (403) Reason: Forbidden HTTP response headers: HTTPHeaderDict({'Date': 'Wed, 13 Nov 2024 02:06:45 GMT', 'Content-Type': 'text/plain', 'Content-Length': '9', 'Connection': 'keep-alive', 'x-pinecone-auth-rejected-reason': 'Wrong API key', 'www-authenticate': 'Wrong API key', 'server': 'envoy'}) HTTP response body: Forbidden
```

## Solution

- Rename the `Index` implementation to `_Index` so that people will not
accidentally interact with it.
- Add a new stub implementation for `Index` that throws an informative
message.

Bonus:
- Move the Index client docstrings off the implementation class and into
a related abstract base class. This wasn't strictly necessary, but I was
feeling a bit overwhelmed by the size of the `index.py` file. I copied
this approach from the grpc module. pdoc seems to still find and render
the docs okay when doing this.

## Usage

The error message incorporates the args/kwargs the user was attempting
to pass.

One positional arg
```python
>>> import pinecone
>>> i = pinecone.Index('my-index')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/data/index.py", line 113, in __init__
    raise IndexClientInstantiationError(args, kwargs)
pinecone.data.index.IndexClientInstantiationError: You are attempting to access the Index client directly from the pinecone module. The Index client must be instantiated through the parent Pinecone client instance so that it can inherit shared configurations such as API key.

    INCORRECT USAGE:
        ```
        import pinecone

        pc = pinecone.Pinecone(api_key='your-api-key')
        index = pinecone.Index('my-index')
        ```

    CORRECT USAGE:
        ```
        from pinecone import Pinecone

        pc = Pinecone(api_key='your-api-key')
        index = pc.Index('my-index')
        ```
```

Multiple positional args

```python
>>> i = pinecone.Index('my-index', 'https://my-index.blahblah.com')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/data/index.py", line 113, in __init__
    raise IndexClientInstantiationError(args, kwargs)
pinecone.data.index.IndexClientInstantiationError: You are attempting to access the Index client directly from the pinecone module. The Index client must be instantiated through the parent Pinecone client instance so that it can inherit shared configurations such as API key.

    INCORRECT USAGE:
        ```
        import pinecone

        pc = pinecone.Pinecone(api_key='your-api-key')
        index = pinecone.Index('my-index', 'https://my-index.blahblah.com')
        ```

    CORRECT USAGE:
        ```
        from pinecone import Pinecone

        pc = Pinecone(api_key='your-api-key')
        index = pc.Index('my-index', 'https://my-index.blahblah.com')
        ```

```


One keyword arg:

```python
>>> i = pinecone.Index(host='https://my-index.blahblah.com')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/data/index.py", line 113, in __init__
    raise IndexClientInstantiationError(args, kwargs)
pinecone.data.index.IndexClientInstantiationError: You are attempting to access the Index client directly from the pinecone module. The Index client must be instantiated through the parent Pinecone client instance so that it can inherit shared configurations such as API key.

    INCORRECT USAGE:
        ```
        import pinecone

        pc = pinecone.Pinecone(api_key='your-api-key')
        index = pinecone.Index(host='https://my-index.blahblah.com')
        ```

    CORRECT USAGE:
        ```
        from pinecone import Pinecone

        pc = Pinecone(api_key='your-api-key')
        index = pc.Index(host='https://my-index.blahblah.com')
        ```
```

Multiple kwargs

```python
>>> i = pinecone.Index(name='my-index', host='https://my-index.blahblah.com', pool_threads=20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/data/index.py", line 113, in __init__
    raise IndexClientInstantiationError(args, kwargs)
pinecone.data.index.IndexClientInstantiationError: You are attempting to access the Index client directly from the pinecone module. The Index client must be instantiated through the parent Pinecone client instance so that it can inherit shared configurations such as API key.

    INCORRECT USAGE:
        ```
        import pinecone

        pc = pinecone.Pinecone(api_key='your-api-key')
        index = pinecone.Index(name='my-index', host='https://my-index.blahblah.com', pool_threads=20)
        ```

    CORRECT USAGE:
        ```
        from pinecone import Pinecone

        pc = Pinecone(api_key='your-api-key')
        index = pc.Index(name='my-index', host='https://my-index.blahblah.com', pool_threads=20)
        ```
```

Mixed args/kwargs

```python
>>> i = pinecone.Index('my-index', host='https://my-index.blahblah.com', pool_threads=20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jhamon/workspace/pinecone-python-client/pinecone/data/index.py", line 113, in __init__
    raise IndexClientInstantiationError(args, kwargs)
pinecone.data.index.IndexClientInstantiationError: You are attempting to access the Index client directly from the pinecone module. The Index client must be instantiated through the parent Pinecone client instance so that it can inherit shared configurations such as API key.

    INCORRECT USAGE:
        ```
        import pinecone

        pc = pinecone.Pinecone(api_key='your-api-key')
        index = pinecone.Index('my-index', host='https://my-index.blahblah.com', pool_threads=20)
        ```

    CORRECT USAGE:
        ```
        from pinecone import Pinecone

        pc = Pinecone(api_key='your-api-key')
        index = pc.Index('my-index', host='https://my-index.blahblah.com', pool_threads=20)
```

## Type of Change

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

This change is a UX feature that could be considered breaking if someone
was importing `Index` directly and going out of their way to set it up
correctly. This was never documented usage, but somebody skilled at
reading code could have figured out how to do this.
  • Loading branch information
jhamon authored Nov 18, 2024
1 parent d6cb346 commit d9f365b
Show file tree
Hide file tree
Showing 5 changed files with 463 additions and 298 deletions.
4 changes: 2 additions & 2 deletions pinecone/control/pinecone.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from pinecone.models import ServerlessSpec, PodSpec, IndexModel, IndexList, CollectionList
from .langchain_import_warnings import _build_langchain_attribute_error_message

from pinecone.data import Index
from pinecone.data import _Index

from pinecone_plugin_interface import load_and_install as install_plugins

Expand Down Expand Up @@ -788,7 +788,7 @@ def Index(self, name: str = "", host: str = "", **kwargs):
# Otherwise, get host url from describe_index using the index name
index_host = self.index_host_store.get_host(self.index_api, self.config, name)

return Index(
return _Index(
host=index_host,
api_key=api_key,
pool_threads=pt,
Expand Down
Loading

0 comments on commit d9f365b

Please sign in to comment.