|
| 1 | +import pytest |
1 | 2 | import re
|
2 | 3 | from pinecone.config import ConfigBuilder
|
3 | 4 | from pinecone.core.client.api.manage_indexes_api import ManageIndexesApi
|
4 |
| -from pinecone.utils.setup_openapi_client import setup_openapi_client |
| 5 | +from pinecone.core.client.api_client import ApiClient |
| 6 | +from pinecone.utils.setup_openapi_client import setup_openapi_client, build_plugin_setup_client |
5 | 7 |
|
6 | 8 | class TestSetupOpenAPIClient():
|
7 | 9 | def test_setup_openapi_client(self):
|
8 |
| - "" |
9 |
| - # config = ConfigBuilder.build(api_key="my-api-key", host="https://my-controller-host") |
10 |
| - # api_client = setup_openapi_client(ManageIndexesApi, config=config, pool_threads=2) |
11 |
| - # # assert api_client.user_agent == "pinecone-python-client/0.0.1" |
| 10 | + config = ConfigBuilder.build( |
| 11 | + api_key="my-api-key", |
| 12 | + host="https://my-controller-host" |
| 13 | + ) |
| 14 | + openapi_config = ConfigBuilder.build_openapi_config(config) |
| 15 | + assert openapi_config.host == "https://my-controller-host" |
| 16 | + |
| 17 | + control_plane_client = setup_openapi_client(ApiClient, ManageIndexesApi, config=config, openapi_config=openapi_config, pool_threads=2) |
| 18 | + user_agent_regex = re.compile(r"python-client-\d+\.\d+\.\d+ \(urllib3\:\d+\.\d+\.\d+\)") |
| 19 | + assert re.match(user_agent_regex, control_plane_client.api_client.user_agent) |
| 20 | + assert re.match(user_agent_regex, control_plane_client.api_client.default_headers['User-Agent']) |
| 21 | + |
| 22 | + def test_setup_openapi_client_with_api_version(self): |
| 23 | + config = ConfigBuilder.build( |
| 24 | + api_key="my-api-key", |
| 25 | + host="https://my-controller-host", |
| 26 | + ) |
| 27 | + openapi_config = ConfigBuilder.build_openapi_config(config) |
| 28 | + assert openapi_config.host == "https://my-controller-host" |
| 29 | + |
| 30 | + control_plane_client = setup_openapi_client(ApiClient, ManageIndexesApi, config=config, openapi_config=openapi_config, pool_threads=2, api_version="2024-04") |
| 31 | + user_agent_regex = re.compile(r"python-client-\d+\.\d+\.\d+ \(urllib3\:\d+\.\d+\.\d+\)") |
| 32 | + assert re.match(user_agent_regex, control_plane_client.api_client.user_agent) |
| 33 | + assert re.match(user_agent_regex, control_plane_client.api_client.default_headers['User-Agent']) |
| 34 | + assert control_plane_client.api_client.default_headers['X-Pinecone-API-Version'] == "2024-04" |
| 35 | + |
| 36 | + |
| 37 | +class TestBuildPluginSetupClient(): |
| 38 | + @pytest.mark.parametrize("plugin_api_version,plugin_host", [ |
| 39 | + (None, None), |
| 40 | + ("2024-07", "https://my-plugin-host") |
| 41 | + ]) |
| 42 | + def test_setup_openapi_client_with_host_override(self, plugin_api_version, plugin_host): |
| 43 | + # These configurations represent the configurations that the core sdk |
| 44 | + # (e.g. Pinecone class) will have built prior to invoking the plugin setup. |
| 45 | + # In real usage, this takes place during the Pinecone class initialization |
| 46 | + # and pulls together configuration from all sources (kwargs and env vars). |
| 47 | + # It reflects a merging of the user's configuration and the defaults set |
| 48 | + # by the sdk. |
| 49 | + config = ConfigBuilder.build( |
| 50 | + api_key="my-api-key", |
| 51 | + host="https://api.pinecone.io", |
| 52 | + source_tag="my_source_tag", |
| 53 | + proxy_url="http://my-proxy.com", |
| 54 | + ssl_ca_certs="path/to/bundle.pem" |
| 55 | + ) |
| 56 | + openapi_config = ConfigBuilder.build_openapi_config(config) |
| 57 | + |
| 58 | + # The core sdk (e.g. Pinecone class) will be responsible for invoking the |
| 59 | + # build_plugin_setup_client method before passing the result to the plugin |
| 60 | + # install method. This is |
| 61 | + # somewhat like currying the openapi setup function, because we want some |
| 62 | + # information to be controled by the core sdk (e.g. the user-agent string, |
| 63 | + # proxy settings, etc) while allowing the plugin to pass the parts of the |
| 64 | + # configuration that are relevant to it such as api version, base url if |
| 65 | + # served from somewhere besides api.pinecone.io, etc. |
| 66 | + client_builder = build_plugin_setup_client(config=config, openapi_config=openapi_config, pool_threads=2) |
| 67 | + |
| 68 | + # The plugin machinery in pinecone_plugin_interface will be the one to call |
| 69 | + # this client_builder function using classes and other config it discovers inside the |
| 70 | + # pinecone_plugin namespace package. Putting plugin configuration and references |
| 71 | + # to the implementation classes into a spot where the pinecone_plugin_interface |
| 72 | + # can find them is the responsibility of the plugin developer. |
| 73 | + # |
| 74 | + # Passing ManagedIndexesApi and ApiClient here are just a standin for testing |
| 75 | + # purposes; in a real plugin, the class would be something else related |
| 76 | + # to a new feature, but to test that this setup works I just need a FooApi |
| 77 | + # class generated off the openapi spec. |
| 78 | + plugin_api=ManageIndexesApi |
| 79 | + plugin_client = client_builder( |
| 80 | + api_client_klass=ApiClient, |
| 81 | + api_klass=plugin_api, |
| 82 | + api_version=plugin_api_version, |
| 83 | + host=plugin_host |
| 84 | + ) |
| 85 | + |
| 86 | + # Returned client is an instance of the input class |
| 87 | + assert isinstance(plugin_client, plugin_api) |
| 88 | + |
| 89 | + # We want requests from plugins to have a user-agent matching the host SDK. |
| 90 | + user_agent_regex = re.compile(r"python-client-\d+\.\d+\.\d+ \(urllib3\:\d+\.\d+\.\d+\)") |
| 91 | + assert re.match(user_agent_regex, plugin_client.api_client.user_agent) |
| 92 | + assert re.match(user_agent_regex, plugin_client.api_client.default_headers['User-Agent']) |
| 93 | + |
| 94 | + # User agent still contains the source tag that was set in the sdk config |
| 95 | + assert 'my_source_tag' in plugin_client.api_client.default_headers['User-Agent'] |
| 96 | + |
| 97 | + # Proxy settings should be passed from the core sdk to the plugin client |
| 98 | + assert plugin_client.api_client.configuration.proxy == "http://my-proxy.com" |
| 99 | + assert plugin_client.api_client.configuration.ssl_ca_cert == "path/to/bundle.pem" |
| 100 | + |
| 101 | + # Plugins need to be able to pass their own API version (optionally) |
| 102 | + assert plugin_client.api_client.default_headers.get('X-Pinecone-API-Version') == plugin_api_version |
| 103 | + |
| 104 | + # Plugins need to be able to override the host (optionally) |
| 105 | + if plugin_host: |
| 106 | + assert plugin_client.api_client.configuration._base_path == plugin_host |
| 107 | + else: |
| 108 | + # When plugin does not set a host, it should default to the host set in the core sdk |
| 109 | + assert plugin_client.api_client.configuration._base_path == "https://api.pinecone.io" |
0 commit comments