diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fe87cd91..cc51f6f8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.43.0" + ".": "0.44.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 94fe1cb4..94a0ae2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 42 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/profound/profound-4fb090ac5b0517a401c403e173daa5ca2315cb6a39c59dd301fce91e9ec4b7e8.yml -openapi_spec_hash: 7a2fa5d5d32944baa3cf81400251b900 -config_hash: fd78680283b85cba4aa8ddb88c757308 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/profound/profound-a4fb4c2b593d32e808cc7d918c9406a50f67b0c71eb509120b94379de5c3a8cc.yml +openapi_spec_hash: d8899b45e2fee59974c91a793814a9ec +config_hash: 511c02edba705a2d6e2b71bbd6051506 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0245f68b..47f612eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.44.0 (2026-05-04) + +Full Changelog: [v0.43.0...v0.44.0](https://github.com/cooper-square-technologies/profound-python-sdk/compare/v0.43.0...v0.44.0) + +### Features + +* **api:** api update ([70d45e3](https://github.com/cooper-square-technologies/profound-python-sdk/commit/70d45e37d2f49272ef71664ec2511a5de4a5612f)) +* **api:** api update ([1bf69d1](https://github.com/cooper-square-technologies/profound-python-sdk/commit/1bf69d1792cdd1963fd2baeb07ae5723767b9c77)) +* **api:** api update ([efcf127](https://github.com/cooper-square-technologies/profound-python-sdk/commit/efcf1277e29af8839fb53497a9a81bec409a06d6)) +* **api:** api update ([878aedf](https://github.com/cooper-square-technologies/profound-python-sdk/commit/878aedff119fe1068f2f7c1c8ff0230680b855e1)) +* **api:** configure `array_format` ([6d31755](https://github.com/cooper-square-technologies/profound-python-sdk/commit/6d3175599773bc6b99a220aa5caa8bb414644e48)) +* **api:** dual auth yml ([b9fbf14](https://github.com/cooper-square-technologies/profound-python-sdk/commit/b9fbf1498c2829ef5c7bf00d7c13b8aa20511c85)) +* **api:** update package name mcp - rollback package manager to yarn ([27b50ba](https://github.com/cooper-square-technologies/profound-python-sdk/commit/27b50ba580dba6b8d8ed86a0f7c96efe308d37ea)) + ## 0.43.0 (2026-05-01) Full Changelog: [v0.42.0...v0.43.0](https://github.com/cooper-square-technologies/profound-python-sdk/compare/v0.42.0...v0.43.0) diff --git a/README.md b/README.md index 2cd31667..3488c99e 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ and offers both synchronous and asynchronous clients powered by [httpx](https:// Use the Profound MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40profoundai%2Fmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBwcm9mb3VuZGFpL21jcCJdLCJlbnYiOnsiUFJPRk9VTkRfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40profoundai%2Fmcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40profoundai%2Fmcp%22%5D%2C%22env%22%3A%7B%22PROFOUND_API_KEY%22%3A%22My%20API%20Key%22%7D%7D) +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40profoundai%2Fmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBwcm9mb3VuZGFpL21jcCJdLCJlbnYiOnsiUFJPRk9VTkRfQUNDRVNTX1RPS0VOIjoiTXkgQWNjZXNzIFRva2VuIiwiUFJPRk9VTkRfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40profoundai%2Fmcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40profoundai%2Fmcp%22%5D%2C%22env%22%3A%7B%22PROFOUND_ACCESS_TOKEN%22%3A%22My%20Access%20Token%22%2C%22PROFOUND_API_KEY%22%3A%22My%20API%20Key%22%7D%7D) > Note: You may need to set environment variables in your MCP client. @@ -42,10 +42,10 @@ client = Profound( categories = client.organizations.categories.list() ``` -While you can provide an `api_key` keyword argument, +While you can provide a `access_token` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -to add `PROFOUND_API_KEY="My API Key"` to your `.env` file -so that your API Key is not stored in source control. +to add `PROFOUND_ACCESS_TOKEN="My Access Token"` to your `.env` file +so that your Access Token is not stored in source control. ## Async usage diff --git a/pyproject.toml b/pyproject.toml index c3604c5c..c3fbbbdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "profound" -version = "0.43.0" +version = "0.44.0" description = "The official Python library for the profound API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/profound/_client.py b/src/profound/_client.py index c9e78c6e..79875a3e 100644 --- a/src/profound/_client.py +++ b/src/profound/_client.py @@ -12,6 +12,7 @@ from ._qs import Querystring from ._types import ( Omit, + Headers, Timeout, NotGiven, Transport, @@ -27,7 +28,7 @@ from ._compat import cached_property from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import ProfoundError, APIStatusError +from ._exceptions import APIStatusError from ._base_client import ( DEFAULT_MAX_RETRIES, SyncAPIClient, @@ -58,11 +59,13 @@ class Profound(SyncAPIClient): # client options - api_key: str + access_token: str | None + api_key: str | None def __init__( self, *, + access_token: str | None = None, api_key: str | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, @@ -85,14 +88,16 @@ def __init__( ) -> None: """Construct a new synchronous Profound client instance. - This automatically infers the `api_key` argument from the `PROFOUND_API_KEY` environment variable if it is not provided. + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `access_token` from `PROFOUND_ACCESS_TOKEN` + - `api_key` from `PROFOUND_API_KEY` """ + if access_token is None: + access_token = os.environ.get("PROFOUND_ACCESS_TOKEN") + self.access_token = access_token + if api_key is None: api_key = os.environ.get("PROFOUND_API_KEY") - if api_key is None: - raise ProfoundError( - "The api_key client option must be set either by passing api_key to the client or by setting the PROFOUND_API_KEY environment variable" - ) self.api_key = api_key if base_url is None: @@ -173,12 +178,25 @@ def with_streaming_response(self) -> ProfoundWithStreamedResponse: @property @override def qs(self) -> Querystring: - return Querystring(array_format="comma") + return Querystring(array_format="repeat") @property @override def auth_headers(self) -> dict[str, str]: + return {**self._bearer_auth, **self._api_key_header} + + @property + def _bearer_auth(self) -> dict[str, str]: + access_token = self.access_token + if access_token is None: + return {} + return {"Authorization": f"Bearer {access_token}"} + + @property + def _api_key_header(self) -> dict[str, str]: api_key = self.api_key + if api_key is None: + return {} return {"X-API-Key": api_key} @property @@ -190,9 +208,22 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return + + if headers.get("X-API-Key") or isinstance(custom_headers.get("X-API-Key"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either access_token or api_key to be set. Or for one of the `Authorization` or `X-API-Key` headers to be explicitly omitted"' + ) + def copy( self, *, + access_token: str | None = None, api_key: str | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, @@ -227,6 +258,7 @@ def copy( http_client = http_client or self._client return self.__class__( + access_token=access_token or self.access_token, api_key=api_key or self.api_key, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, @@ -277,11 +309,13 @@ def _make_status_error( class AsyncProfound(AsyncAPIClient): # client options - api_key: str + access_token: str | None + api_key: str | None def __init__( self, *, + access_token: str | None = None, api_key: str | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, @@ -304,14 +338,16 @@ def __init__( ) -> None: """Construct a new async AsyncProfound client instance. - This automatically infers the `api_key` argument from the `PROFOUND_API_KEY` environment variable if it is not provided. + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `access_token` from `PROFOUND_ACCESS_TOKEN` + - `api_key` from `PROFOUND_API_KEY` """ + if access_token is None: + access_token = os.environ.get("PROFOUND_ACCESS_TOKEN") + self.access_token = access_token + if api_key is None: api_key = os.environ.get("PROFOUND_API_KEY") - if api_key is None: - raise ProfoundError( - "The api_key client option must be set either by passing api_key to the client or by setting the PROFOUND_API_KEY environment variable" - ) self.api_key = api_key if base_url is None: @@ -392,12 +428,25 @@ def with_streaming_response(self) -> AsyncProfoundWithStreamedResponse: @property @override def qs(self) -> Querystring: - return Querystring(array_format="comma") + return Querystring(array_format="repeat") @property @override def auth_headers(self) -> dict[str, str]: + return {**self._bearer_auth, **self._api_key_header} + + @property + def _bearer_auth(self) -> dict[str, str]: + access_token = self.access_token + if access_token is None: + return {} + return {"Authorization": f"Bearer {access_token}"} + + @property + def _api_key_header(self) -> dict[str, str]: api_key = self.api_key + if api_key is None: + return {} return {"X-API-Key": api_key} @property @@ -409,9 +458,22 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return + + if headers.get("X-API-Key") or isinstance(custom_headers.get("X-API-Key"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either access_token or api_key to be set. Or for one of the `Authorization` or `X-API-Key` headers to be explicitly omitted"' + ) + def copy( self, *, + access_token: str | None = None, api_key: str | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, @@ -446,6 +508,7 @@ def copy( http_client = http_client or self._client return self.__class__( + access_token=access_token or self.access_token, api_key=api_key or self.api_key, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, diff --git a/src/profound/_version.py b/src/profound/_version.py index c42131e6..2789b5ab 100644 --- a/src/profound/_version.py +++ b/src/profound/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "profound" -__version__ = "0.43.0" # x-release-please-version +__version__ = "0.44.0" # x-release-please-version diff --git a/src/profound/resources/organizations/categories.py b/src/profound/resources/organizations/categories.py index 7b773376..26866e7d 100644 --- a/src/profound/resources/organizations/categories.py +++ b/src/profound/resources/organizations/categories.py @@ -217,7 +217,7 @@ def prompts( self, category_id: str, *, - analysis_type: List[Literal["visibility", "sentiment", "accuracy"]] | Omit = omit, + analysis_type: List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]] | Omit = omit, cursor: Optional[str] | Omit = omit, limit: int | Omit = omit, order_dir: Literal["asc", "desc"] | Omit = omit, @@ -656,7 +656,7 @@ async def prompts( self, category_id: str, *, - analysis_type: List[Literal["visibility", "sentiment", "accuracy"]] | Omit = omit, + analysis_type: List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]] | Omit = omit, cursor: Optional[str] | Omit = omit, limit: int | Omit = omit, order_dir: Literal["asc", "desc"] | Omit = omit, diff --git a/src/profound/types/organizations/category_create_prompts_params.py b/src/profound/types/organizations/category_create_prompts_params.py index 8113a5e1..99ca9641 100644 --- a/src/profound/types/organizations/category_create_prompts_params.py +++ b/src/profound/types/organizations/category_create_prompts_params.py @@ -36,7 +36,7 @@ class Prompt(TypedDict, total=False): topic: Required[IDOrNameParam] """Topic to assign. A new topic is created if the name doesn't exist.""" - analysis_types: Optional[List[Literal["visibility", "sentiment", "accuracy"]]] + analysis_types: Optional[List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]]] """Analysis types: 'visibility', 'sentiment', 'accuracy'. Defaults to ['visibility']. diff --git a/src/profound/types/organizations/category_create_prompts_response.py b/src/profound/types/organizations/category_create_prompts_response.py index 55576855..ed7affb1 100644 --- a/src/profound/types/organizations/category_create_prompts_response.py +++ b/src/profound/types/organizations/category_create_prompts_response.py @@ -24,7 +24,7 @@ class Prompt(BaseModel): topic: NamedResource """Resolved topic.""" - analysis_types: Optional[List[Literal["visibility", "sentiment", "accuracy"]]] = None + analysis_types: Optional[List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]]] = None """Analysis types assigned to this prompt.""" asset: Optional[NamedResource] = None diff --git a/src/profound/types/organizations/category_prompts_params.py b/src/profound/types/organizations/category_prompts_params.py index 7e8ff00d..19cc5952 100644 --- a/src/profound/types/organizations/category_prompts_params.py +++ b/src/profound/types/organizations/category_prompts_params.py @@ -11,7 +11,7 @@ class CategoryPromptsParams(TypedDict, total=False): - analysis_type: List[Literal["visibility", "sentiment", "accuracy"]] + analysis_type: List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]] """Filter by analysis type (visibility, sentiment, accuracy).""" cursor: Optional[str] diff --git a/src/profound/types/organizations/category_prompts_response.py b/src/profound/types/organizations/category_prompts_response.py index 325f16ea..c2771119 100644 --- a/src/profound/types/organizations/category_prompts_response.py +++ b/src/profound/types/organizations/category_prompts_response.py @@ -30,7 +30,7 @@ class Data(BaseModel): updated_at: datetime - analysis_types: Optional[List[Literal["visibility", "sentiment", "accuracy"]]] = None + analysis_types: Optional[List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]]] = None personas: Optional[List[NamedResource]] = None diff --git a/src/profound/types/organizations/category_update_prompts_params.py b/src/profound/types/organizations/category_update_prompts_params.py index 1e4a7ba1..2db0745b 100644 --- a/src/profound/types/organizations/category_update_prompts_params.py +++ b/src/profound/types/organizations/category_update_prompts_params.py @@ -30,7 +30,7 @@ class Prompt(TypedDict, total=False): id: Required[str] """ID of the prompt to update.""" - analysis_types: Optional[List[Literal["visibility", "sentiment", "accuracy"]]] + analysis_types: Optional[List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]]] """New analysis types. Replaces all existing analysis types on the prompt.""" asset: Optional[IDOrNameParam] diff --git a/src/profound/types/shared/analysis_type_filter.py b/src/profound/types/shared/analysis_type_filter.py index 7870eb59..664d2f41 100644 --- a/src/profound/types/shared/analysis_type_filter.py +++ b/src/profound/types/shared/analysis_type_filter.py @@ -25,4 +25,7 @@ class AnalysisTypeFilter(BaseModel): "not_contains_case_insensitive", ] - value: Union[Literal["visibility", "sentiment", "accuracy"], List[Literal["visibility", "sentiment", "accuracy"]]] + value: Union[ + Literal["visibility", "sentiment", "sentiment_v2", "accuracy"], + List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]], + ] diff --git a/src/profound/types/shared/bot_name_filter.py b/src/profound/types/shared/bot_name_filter.py index af06354d..fc7d0923 100644 --- a/src/profound/types/shared/bot_name_filter.py +++ b/src/profound/types/shared/bot_name_filter.py @@ -56,6 +56,16 @@ class BotNameFilter(BaseModel): "Perplexity-User", "Grok-PageBrowser", "YouBot", + "OpenClaw", + "baiduspider", + "CCBot", + "ERNIEBot", + "Gemini-Fetch", + "YandexBot", + "PetalBot", + "MistralAI-User", + "Slurp", + "Gemini-Deep-Research", ], List[ Literal[ @@ -88,6 +98,16 @@ class BotNameFilter(BaseModel): "Perplexity-User", "Grok-PageBrowser", "YouBot", + "OpenClaw", + "baiduspider", + "CCBot", + "ERNIEBot", + "Gemini-Fetch", + "YandexBot", + "PetalBot", + "MistralAI-User", + "Slurp", + "Gemini-Deep-Research", ] ], ] diff --git a/src/profound/types/shared/bot_provider_filter.py b/src/profound/types/shared/bot_provider_filter.py index 828a2132..904ef62e 100644 --- a/src/profound/types/shared/bot_provider_filter.py +++ b/src/profound/types/shared/bot_provider_filter.py @@ -43,6 +43,13 @@ class BotProviderFilter(BaseModel): "xai", "grok", "gemini", + "mistral", + "huawei", + "yandex", + "baidu", + "yahoo", + "commoncrawl", + "openclaw", ], List[ Literal[ @@ -62,6 +69,13 @@ class BotProviderFilter(BaseModel): "xai", "grok", "gemini", + "mistral", + "huawei", + "yandex", + "baidu", + "yahoo", + "commoncrawl", + "openclaw", ] ], ] diff --git a/src/profound/types/shared_params/analysis_type_filter.py b/src/profound/types/shared_params/analysis_type_filter.py index 4a464ff3..fdc872ed 100644 --- a/src/profound/types/shared_params/analysis_type_filter.py +++ b/src/profound/types/shared_params/analysis_type_filter.py @@ -28,5 +28,8 @@ class AnalysisTypeFilter(TypedDict, total=False): ] value: Required[ - Union[Literal["visibility", "sentiment", "accuracy"], List[Literal["visibility", "sentiment", "accuracy"]]] + Union[ + Literal["visibility", "sentiment", "sentiment_v2", "accuracy"], + List[Literal["visibility", "sentiment", "sentiment_v2", "accuracy"]], + ] ] diff --git a/src/profound/types/shared_params/bot_name_filter.py b/src/profound/types/shared_params/bot_name_filter.py index 9c90654e..7db87388 100644 --- a/src/profound/types/shared_params/bot_name_filter.py +++ b/src/profound/types/shared_params/bot_name_filter.py @@ -59,6 +59,16 @@ class BotNameFilter(TypedDict, total=False): "Perplexity-User", "Grok-PageBrowser", "YouBot", + "OpenClaw", + "baiduspider", + "CCBot", + "ERNIEBot", + "Gemini-Fetch", + "YandexBot", + "PetalBot", + "MistralAI-User", + "Slurp", + "Gemini-Deep-Research", ], List[ Literal[ @@ -91,6 +101,16 @@ class BotNameFilter(TypedDict, total=False): "Perplexity-User", "Grok-PageBrowser", "YouBot", + "OpenClaw", + "baiduspider", + "CCBot", + "ERNIEBot", + "Gemini-Fetch", + "YandexBot", + "PetalBot", + "MistralAI-User", + "Slurp", + "Gemini-Deep-Research", ] ], ] diff --git a/src/profound/types/shared_params/bot_provider_filter.py b/src/profound/types/shared_params/bot_provider_filter.py index 95c2bf31..b97373a8 100644 --- a/src/profound/types/shared_params/bot_provider_filter.py +++ b/src/profound/types/shared_params/bot_provider_filter.py @@ -46,6 +46,13 @@ class BotProviderFilter(TypedDict, total=False): "xai", "grok", "gemini", + "mistral", + "huawei", + "yandex", + "baidu", + "yahoo", + "commoncrawl", + "openclaw", ], List[ Literal[ @@ -65,6 +72,13 @@ class BotProviderFilter(TypedDict, total=False): "xai", "grok", "gemini", + "mistral", + "huawei", + "yandex", + "baidu", + "yahoo", + "commoncrawl", + "openclaw", ] ], ] diff --git a/tests/api_resources/organizations/test_categories.py b/tests/api_resources/organizations/test_categories.py index b6c76030..ccafb7b6 100644 --- a/tests/api_resources/organizations/test_categories.py +++ b/tests/api_resources/organizations/test_categories.py @@ -37,7 +37,7 @@ def test_method_list(self, client: Profound) -> None: @parametrize def test_method_list_with_all_params(self, client: Profound) -> None: category = client.organizations.categories.list( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(CategoryListResponse, category, path=["response"]) @@ -592,7 +592,7 @@ async def test_method_list(self, async_client: AsyncProfound) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncProfound) -> None: category = await async_client.organizations.categories.list( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(CategoryListResponse, category, path=["response"]) diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py index 151ae021..3dafe0c6 100644 --- a/tests/api_resources/test_agents.py +++ b/tests/api_resources/test_agents.py @@ -80,7 +80,7 @@ def test_method_list_with_all_params(self, client: Profound) -> None: agent = client.agents.list( limit=1, next_cursor="next_cursor", - statuses=["published"], + statuses=["published", "draft"], ) assert_matches_type(AgentListResponse, agent, path=["response"]) @@ -175,7 +175,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncProfound) -> agent = await async_client.agents.list( limit=1, next_cursor="next_cursor", - statuses=["published"], + statuses=["published", "draft"], ) assert_matches_type(AgentListResponse, agent, path=["response"]) diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py index 355fb24e..5a8a8f09 100644 --- a/tests/api_resources/test_organizations.py +++ b/tests/api_resources/test_organizations.py @@ -62,7 +62,7 @@ def test_method_domains(self, client: Profound) -> None: @parametrize def test_method_domains_with_all_params(self, client: Profound) -> None: organization = client.organizations.domains( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationDomainsResponse, organization, path=["response"]) @@ -98,7 +98,7 @@ def test_method_get_personas(self, client: Profound) -> None: @parametrize def test_method_get_personas_with_all_params(self, client: Profound) -> None: organization = client.organizations.get_personas( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationGetPersonasResponse, organization, path=["response"]) @@ -134,7 +134,7 @@ def test_method_list_assets(self, client: Profound) -> None: @parametrize def test_method_list_assets_with_all_params(self, client: Profound) -> None: organization = client.organizations.list_assets( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationListAssetsResponse, organization, path=["response"]) @@ -198,7 +198,7 @@ def test_method_regions(self, client: Profound) -> None: @parametrize def test_method_regions_with_all_params(self, client: Profound) -> None: organization = client.organizations.regions( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationRegionsResponse, organization, path=["response"]) @@ -268,7 +268,7 @@ async def test_method_domains(self, async_client: AsyncProfound) -> None: @parametrize async def test_method_domains_with_all_params(self, async_client: AsyncProfound) -> None: organization = await async_client.organizations.domains( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationDomainsResponse, organization, path=["response"]) @@ -304,7 +304,7 @@ async def test_method_get_personas(self, async_client: AsyncProfound) -> None: @parametrize async def test_method_get_personas_with_all_params(self, async_client: AsyncProfound) -> None: organization = await async_client.organizations.get_personas( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationGetPersonasResponse, organization, path=["response"]) @@ -340,7 +340,7 @@ async def test_method_list_assets(self, async_client: AsyncProfound) -> None: @parametrize async def test_method_list_assets_with_all_params(self, async_client: AsyncProfound) -> None: organization = await async_client.organizations.list_assets( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationListAssetsResponse, organization, path=["response"]) @@ -404,7 +404,7 @@ async def test_method_regions(self, async_client: AsyncProfound) -> None: @parametrize async def test_method_regions_with_all_params(self, async_client: AsyncProfound) -> None: organization = await async_client.organizations.regions( - organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + organization_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(OrganizationRegionsResponse, organization, path=["response"]) diff --git a/tests/test_client.py b/tests/test_client.py index 0a965d98..f877ed5f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,7 +23,7 @@ from profound._types import Omit from profound._utils import asyncify from profound._models import BaseModel, FinalRequestOptions -from profound._exceptions import ProfoundError, APIStatusError, APITimeoutError, APIResponseValidationError +from profound._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from profound._base_client import ( DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, @@ -404,10 +404,17 @@ def test_validate_headers(self) -> None: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("X-API-Key") == api_key - with pytest.raises(ProfoundError): - with update_env(**{"PROFOUND_API_KEY": Omit()}): - client2 = Profound(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + with update_env(**{"PROFOUND_API_KEY": Omit()}): + client2 = Profound(base_url=base_url, api_key=None, _strict_response_validation=True) + + with pytest.raises( + TypeError, + match="Could not resolve authentication method. Expected either access_token or api_key to be set. Or for one of the `Authorization` or `X-API-Key` headers to be explicitly omitted", + ): + client2._build_request(FinalRequestOptions(method="get", url="/foo")) + + request2 = client2._build_request(FinalRequestOptions(method="get", url="/foo", headers={"X-API-Key": Omit()})) + assert request2.headers.get("X-API-Key") is None def test_default_query_option(self) -> None: client = Profound( @@ -1323,10 +1330,17 @@ def test_validate_headers(self) -> None: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("X-API-Key") == api_key - with pytest.raises(ProfoundError): - with update_env(**{"PROFOUND_API_KEY": Omit()}): - client2 = AsyncProfound(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + with update_env(**{"PROFOUND_API_KEY": Omit()}): + client2 = AsyncProfound(base_url=base_url, api_key=None, _strict_response_validation=True) + + with pytest.raises( + TypeError, + match="Could not resolve authentication method. Expected either access_token or api_key to be set. Or for one of the `Authorization` or `X-API-Key` headers to be explicitly omitted", + ): + client2._build_request(FinalRequestOptions(method="get", url="/foo")) + + request2 = client2._build_request(FinalRequestOptions(method="get", url="/foo", headers={"X-API-Key": Omit()})) + assert request2.headers.get("X-API-Key") is None async def test_default_query_option(self) -> None: client = AsyncProfound(