Skip to content

Commit e73726d

Browse files
authored
Move all grpc stuff into pinecone.grpc subpackage (pinecone-io#238)
## Problem In the past this package attempted to import extra grpc deps in the root `__init__.py` inside a try/catch that caught `ImportError` when deps were missing. This is error prone because people may be attempting to use the `pinecone` module alongside other packages that depend on incompatible versions of these dependencies, so we shouldn't interpret successful import as a sign that a user has installed the `pinecone-client[grpc]` extras (with the versions we expect). When these incompatible versions are present, the `ImportError` doesn't happen but other runtime errors can occur even when the person is not attempting to use `GRPCIndex`. ## Solution The gist of this PR is to better isolate everything GRPC-related into a subpackage to minimize the changes of a grpc-related dependency clash getting in the way of using Pinecone. By doing this, issues with grpc dependencies should never impact people using the non-grpc client. Summary of changes: - Moving files - Contents of `pinecone/data/grpc` moved up and over to `pinecone/grpc` - Tests moved from `tests/unit/test_index_grpc.py` into `tests/unit_grpc/test_index_grpc.py`. This is to make it easier to split grpc and non-grpc test runs. - Delete remaining cruft in `pinecone/deprecated/legacy_utils.py` because they were unused and loading grpc deps. - Making `from pinecone import Pinecone` independent of GRPC - References to all GRPC deps removed from `pinecone/__init__.py` - Adjusting `pinecone/pinecone.py` to remove `IndexGRPC()` method. - Setting up for `from pinecone.grpc import Pinecone` - Add `pinecone/grpc/pinecone.yaml` that extends the other Pinecone class, modifying only the `Index()` method to use `GRPCIndex`. - Add `pinecone/grpc/__init__.py` with entries for grpc-flavored `Pinecone` and `IndexGRPC` exports. - CI updates - `pyproject.toml` adjusted to properly indicate grpc deps as `optional = true`; I discovered in testing that grpc dependencies were always being installed in CI. - Add an input var to the `setup-poetry` action so that we can toggle on grpc dependencies when needed. - `.github/workflows/testing.yaml` refactored to break GRPC and non-GRPC into separate jobs, since they have different install requirements. #### Usage evolution ##### Legacy implementation ```python import pinecone pinecone.init(api_key='foo', environment='bar') index = pinecone.Index('index-name') index_grpc = pinecone.GRPCIndex('index-name') ``` ##### Unreleased spruce branch (before this PR) This was an improvement over the legacy approach because we no longer relied on global state for configuration. Instead, we wrap configuration state into a class instance. However, the `Pinecone` class had a dependency on GRPC stuff to implement the `GRPCIndex()` method. The imports of these extra deps was intended to noop when they were not installed, but as I described above there are situations where you could still have runtime errors if other dependencies in your notebook / app have installed incompatible GRPC dependencies that prevent you from using the REST version of the client. ```python from pinecone import Pinecone p = Pinecone(api_key='foo') index = p.Index('index-name') index_grpc = p.GRPCIndex('index-name') ``` ##### After this PR, import from different subpackage when GRPC desired Now the usage is exactly the same for REST vs GRPC except for the import coming from `pinecone.grpc` instead of `pinecone` when you want data operations to use grpc. GRPC deps are not loaded at all unless you specifically import from `pinecone.grpc`. To use REST, import from `pinecone` ```python from pinecone import Pinecone p = Pinecone(api_key='foo') index = p.Index('index-name') ``` To use GRPC, import from `pinecone.grpc` subpackage ```python from pinecone.grpc import Pinecone p = Pinecone(api_key='foo') index = p.Index('index-name') ``` If you ever wanted to use these side by side for some reason (no real reason to ever do this unless you are writing tests for this package) you would have to alias one of the imports to avoid a name collision. ```python from pinecone import Pinecone from pinecone.grpc import Pinecone as PineconeGRPC ... ``` ## Type of Change - [x] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] This change requires a documentation update - [x] Infrastructure change (CI configs, etc) ## Test Plan Describe specific steps for validating this change.
1 parent 85fce4f commit e73726d

File tree

21 files changed

+88
-62
lines changed

21 files changed

+88
-62
lines changed

.github/actions/build-docs/action.yml

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ runs:
1515

1616
- name: Setup Poetry
1717
uses: ./.github/actions/setup-poetry
18+
with:
19+
include_grpc: 'true'
1820

1921
- name: Build html documentation
2022
shell: bash

.github/actions/setup-poetry/action.yml

+7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
name: 'Setup Poetry'
22
description: 'Installs Poetry and dependencies'
3+
inputs:
4+
include_grpc:
5+
description: 'Install gRPC dependencies'
6+
required: true
7+
default: 'false'
38
runs:
49
using: 'composite'
510
steps:
611
- name: Install Poetry
712
uses: snok/install-poetry@v1
813

914
- name: Install dependencies
15+
if: ${{ inputs.include_grpc == 'false' }}
1016
shell: bash
1117
run: |
1218
poetry install
@@ -16,6 +22,7 @@ runs:
1622
# The dependencies that are specific to gRPC are defined in pyproject.toml
1723
# under tool.poetry.extras
1824
- name: Install gRPC dependencies
25+
if: ${{ inputs.include_grpc == 'true' }}
1926
shell: bash
2027
run: |
2128
poetry install --extras "grpc"

.github/workflows/testing.yaml

+46-8
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ on:
44
workflow_call: {}
55

66
jobs:
7-
run-tests:
8-
name: Run tests
7+
units-no-grpc:
8+
name: Run tests (REST)
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
@@ -22,11 +22,49 @@ jobs:
2222
- name: Setup Poetry
2323
uses: ./.github/actions/setup-poetry
2424

25-
- name: Run tests
26-
run: make tests
25+
- name: Run unit tests
26+
run: poetry run pytest --cov=pinecone --timeout=120 tests/unit
2727

28-
- name: Build Python client
29-
run: make package
28+
units-grpc:
29+
name: Run tests (GRPC)
30+
runs-on: ubuntu-latest
31+
strategy:
32+
matrix:
33+
python-version: [3.8, 3.9, '3.10', 3.11]
34+
35+
steps:
36+
- uses: actions/checkout@v3
37+
38+
- name: Set up Python ${{ matrix.python-version }}
39+
uses: actions/setup-python@v4
40+
with:
41+
python-version: ${{ matrix.python-version }}
42+
43+
- name: Setup Poetry
44+
uses: ./.github/actions/setup-poetry
45+
with:
46+
include_grpc: true
47+
48+
- name: Run unit tests (GRPC)
49+
run: poetry run pytest --cov=pinecone --timeout=120 tests/unit_grpc
50+
51+
package:
52+
name: Check packaging
53+
runs-on: ubuntu-latest
54+
strategy:
55+
matrix:
56+
python-version: [3.8, 3.9, '3.10', 3.11]
57+
58+
steps:
59+
- uses: actions/checkout@v3
60+
61+
- name: Set up Python ${{ matrix.python-version }}
62+
uses: actions/setup-python@v4
63+
with:
64+
python-version: ${{ matrix.python-version }}
65+
66+
- name: Setup Poetry
67+
uses: ./.github/actions/setup-poetry
3068

31-
- name: Build docs
32-
run: make docs
69+
- name: Package
70+
run: poetry build

Makefile

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ image:
99
develop:
1010
poetry install -E grpc
1111

12-
tests:
13-
@echo "Installing dependencies..."
14-
poetry install
12+
test-unit:
1513
@echo "Running tests..."
1614
poetry run pytest --cov=pinecone --timeout=120 tests/unit
1715

16+
test-grpc-unit:
17+
@echo "Running tests..."
18+
poetry run pytest --cov=pinecone --timeout=120 tests/unit_grpc
19+
1820
version:
1921
poetry version
2022

pinecone/__init__.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,4 @@
44
from .config import *
55
from .exceptions import *
66
from .control.pinecone import Pinecone
7-
from .data.index import *
8-
9-
try:
10-
from .data.grpc.index_grpc import *
11-
except ImportError:
12-
pass # ignore for non-[grpc] installations
7+
from .data.index import *

pinecone/control/pinecone.py

-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
from pinecone.utils import get_user_agent
1515

1616
from pinecone.data import Index
17-
from pinecone.data import GRPCIndex
18-
1917

2018
class Pinecone:
2119
def __init__(
@@ -270,6 +268,3 @@ def _get_status(self, name: str):
270268
def Index(self, name: str):
271269
index_host = self.index_host_store.get_host(self.index_api, self.config, name)
272270
return Index(api_key=self.config.API_KEY, host=index_host)
273-
274-
def GRPCIndex(self, name: str):
275-
return GRPCIndex(self.config, name)

pinecone/data/__init__.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
from .index import Index
2-
from .grpc.index_grpc import GRPCIndex
1+
from .index import Index

pinecone/data/grpc/__init__.py

Whitespace-only changes.

pinecone/deprecated/__init__.py

-1
This file was deleted.

pinecone/deprecated/legacy_utils.py

-21
This file was deleted.

pinecone/grpc/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .index_grpc import GRPCIndex
2+
from .pinecone import Pinecone

pinecone/data/grpc/base.py renamed to pinecone/grpc/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from abc import ABC, abstractmethod
33
from functools import wraps
4-
from typing import NamedTuple, Optional, Dict
4+
from typing import Dict
55

66
import certifi
77
import grpc
File renamed without changes.
File renamed without changes.

pinecone/data/grpc/index_grpc.py renamed to pinecone/grpc/index_grpc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
REQUIRED_VECTOR_FIELDS,
3535
OPTIONAL_VECTOR_FIELDS,
3636
)
37-
from pinecone.data.grpc.base import GRPCIndexBase
38-
from pinecone.data.grpc.future import PineconeGrpcFuture
37+
from .base import GRPCIndexBase
38+
from .future import PineconeGrpcFuture
3939

4040
__all__ = ["GRPCIndex", "GRPCVector", "GRPCQueryVector", "GRPCSparseValues"]
4141

pinecone/grpc/pinecone.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from ..control.pinecone import Pinecone
2+
from .index_grpc import GRPCIndex
3+
4+
class Pinecone(Pinecone):
5+
def Index(self, name: str):
6+
index_host = self.index_host_store.get_host(self.index_api, self.config, name)
7+
return GRPCIndex(api_key=self.config.API_KEY, host=index_host)
File renamed without changes.
File renamed without changes.

poetry.lock

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ dnspython = ">=2.0.0"
6363
python-dateutil = ">=2.5.3"
6464
urllib3 = "1.25.3"
6565
tqdm = ">=4.64.1"
66-
grpcio = ">=1.44.0"
67-
grpc-gateway-protoc-gen-openapiv2 = "0.1.0"
68-
googleapis-common-protos = ">=1.53.0"
69-
lz4 = ">=3.1.3"
70-
protobuf = "~=3.20.0"
66+
grpcio = { version = ">=1.44.0", optional = true }
67+
grpc-gateway-protoc-gen-openapiv2 = { version = "0.1.0", optional = true }
68+
googleapis-common-protos = { version = ">=1.53.0", optional = true }
69+
lz4 = { version = ">=3.1.3", optional = true }
70+
protobuf = { version = "~=3.20.0", optional = true }
7171

7272
[tool.poetry.group.dev.dependencies]
7373
numpy = ">=1.22"

tests/unit/test_grpc_index.py renamed to tests/unit_grpc/test_grpc_index.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import pandas as pd
55
import pytest
66

7-
from pinecone import Config, GRPCIndex
7+
from pinecone import Config
8+
from pinecone.grpc import GRPCIndex
89
from pinecone import DescribeIndexStatsRequest
910
from pinecone.core.grpc.protos.vector_service_pb2 import (
1011
Vector,
@@ -18,7 +19,7 @@
1819
UpsertResponse,
1920
SparseValues,
2021
)
21-
from pinecone.data.grpc.utils import dict_to_proto_struct
22+
from pinecone.grpc.utils import dict_to_proto_struct
2223

2324
class TestGrpcIndex:
2425
def setup_method(self):

0 commit comments

Comments
 (0)