diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cb9d254..3f63a67 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.22.0" + ".": "0.22.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df3d7d..b665547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.22.1 (2025-12-16) + +Full Changelog: [v0.22.0...v0.22.1](https://github.com/perplexityai/perplexity-py/compare/v0.22.0...v0.22.1) + +### Bug Fixes + +* **types:** allow pyright to infer TypedDict types within SequenceNotStr ([1dae6e5](https://github.com/perplexityai/perplexity-py/commit/1dae6e56a918d3ac6cbc38accd3058c169199515)) + + +### Chores + +* add missing docstrings ([be56ae3](https://github.com/perplexityai/perplexity-py/commit/be56ae34c5342b345e53b706c006f6a873e1db74)) +* **internal:** add missing files argument to base client ([a2599a9](https://github.com/perplexityai/perplexity-py/commit/a2599a9261bf65ee59f611918b05eee8b7c55ead)) +* speedup initial import ([2e54d11](https://github.com/perplexityai/perplexity-py/commit/2e54d1119537403fe72903a25cba1ef75fcb274f)) + ## 0.22.0 (2025-12-05) Full Changelog: [v0.21.0...v0.22.0](https://github.com/perplexityai/perplexity-py/compare/v0.21.0...v0.22.0) diff --git a/pyproject.toml b/pyproject.toml index bef3a3d..8a6f075 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "perplexityai" -version = "0.22.0" +version = "0.22.1" description = "The official Python library for the perplexity API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/perplexity/_base_client.py b/src/perplexity/_base_client.py index c4f1449..94e3a65 100644 --- a/src/perplexity/_base_client.py +++ b/src/perplexity/_base_client.py @@ -1247,9 +1247,12 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1767,9 +1770,12 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return await self.request(cast_to, opts) async def put( diff --git a/src/perplexity/_client.py b/src/perplexity/_client.py index f151ece..2ae7397 100644 --- a/src/perplexity/_client.py +++ b/src/perplexity/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Mapping +from typing import TYPE_CHECKING, Any, Mapping from typing_extensions import Self, override import httpx @@ -20,8 +20,8 @@ not_given, ) from ._utils import is_given, get_async_library +from ._compat import cached_property from ._version import __version__ -from .resources import search from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError, PerplexityError from ._base_client import ( @@ -29,8 +29,12 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.chat import chat -from .resources.async_ import async_ + +if TYPE_CHECKING: + from .resources import chat, async_, search + from .resources.search import SearchResource, AsyncSearchResource + from .resources.chat.chat import ChatResource, AsyncChatResource + from .resources.async_.async_ import AsyncResource, AsyncAsyncResource __all__ = [ "Timeout", @@ -45,12 +49,6 @@ class Perplexity(SyncAPIClient): - chat: chat.ChatResource - search: search.SearchResource - async_: async_.AsyncResource - with_raw_response: PerplexityWithRawResponse - with_streaming_response: PerplexityWithStreamedResponse - # client options api_key: str @@ -107,11 +105,31 @@ def __init__( self._default_stream_cls = Stream - self.chat = chat.ChatResource(self) - self.search = search.SearchResource(self) - self.async_ = async_.AsyncResource(self) - self.with_raw_response = PerplexityWithRawResponse(self) - self.with_streaming_response = PerplexityWithStreamedResponse(self) + @cached_property + def chat(self) -> ChatResource: + from .resources.chat import ChatResource + + return ChatResource(self) + + @cached_property + def search(self) -> SearchResource: + from .resources.search import SearchResource + + return SearchResource(self) + + @cached_property + def async_(self) -> AsyncResource: + from .resources.async_ import AsyncResource + + return AsyncResource(self) + + @cached_property + def with_raw_response(self) -> PerplexityWithRawResponse: + return PerplexityWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PerplexityWithStreamedResponse: + return PerplexityWithStreamedResponse(self) @property @override @@ -219,12 +237,6 @@ def _make_status_error( class AsyncPerplexity(AsyncAPIClient): - chat: chat.AsyncChatResource - search: search.AsyncSearchResource - async_: async_.AsyncAsyncResource - with_raw_response: AsyncPerplexityWithRawResponse - with_streaming_response: AsyncPerplexityWithStreamedResponse - # client options api_key: str @@ -281,11 +293,31 @@ def __init__( self._default_stream_cls = AsyncStream - self.chat = chat.AsyncChatResource(self) - self.search = search.AsyncSearchResource(self) - self.async_ = async_.AsyncAsyncResource(self) - self.with_raw_response = AsyncPerplexityWithRawResponse(self) - self.with_streaming_response = AsyncPerplexityWithStreamedResponse(self) + @cached_property + def chat(self) -> AsyncChatResource: + from .resources.chat import AsyncChatResource + + return AsyncChatResource(self) + + @cached_property + def search(self) -> AsyncSearchResource: + from .resources.search import AsyncSearchResource + + return AsyncSearchResource(self) + + @cached_property + def async_(self) -> AsyncAsyncResource: + from .resources.async_ import AsyncAsyncResource + + return AsyncAsyncResource(self) + + @cached_property + def with_raw_response(self) -> AsyncPerplexityWithRawResponse: + return AsyncPerplexityWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPerplexityWithStreamedResponse: + return AsyncPerplexityWithStreamedResponse(self) @property @override @@ -393,31 +425,103 @@ def _make_status_error( class PerplexityWithRawResponse: + _client: Perplexity + def __init__(self, client: Perplexity) -> None: - self.chat = chat.ChatResourceWithRawResponse(client.chat) - self.search = search.SearchResourceWithRawResponse(client.search) - self.async_ = async_.AsyncResourceWithRawResponse(client.async_) + self._client = client + + @cached_property + def chat(self) -> chat.ChatResourceWithRawResponse: + from .resources.chat import ChatResourceWithRawResponse + + return ChatResourceWithRawResponse(self._client.chat) + + @cached_property + def search(self) -> search.SearchResourceWithRawResponse: + from .resources.search import SearchResourceWithRawResponse + + return SearchResourceWithRawResponse(self._client.search) + + @cached_property + def async_(self) -> async_.AsyncResourceWithRawResponse: + from .resources.async_ import AsyncResourceWithRawResponse + + return AsyncResourceWithRawResponse(self._client.async_) class AsyncPerplexityWithRawResponse: + _client: AsyncPerplexity + def __init__(self, client: AsyncPerplexity) -> None: - self.chat = chat.AsyncChatResourceWithRawResponse(client.chat) - self.search = search.AsyncSearchResourceWithRawResponse(client.search) - self.async_ = async_.AsyncAsyncResourceWithRawResponse(client.async_) + self._client = client + + @cached_property + def chat(self) -> chat.AsyncChatResourceWithRawResponse: + from .resources.chat import AsyncChatResourceWithRawResponse + + return AsyncChatResourceWithRawResponse(self._client.chat) + + @cached_property + def search(self) -> search.AsyncSearchResourceWithRawResponse: + from .resources.search import AsyncSearchResourceWithRawResponse + + return AsyncSearchResourceWithRawResponse(self._client.search) + + @cached_property + def async_(self) -> async_.AsyncAsyncResourceWithRawResponse: + from .resources.async_ import AsyncAsyncResourceWithRawResponse + + return AsyncAsyncResourceWithRawResponse(self._client.async_) class PerplexityWithStreamedResponse: + _client: Perplexity + def __init__(self, client: Perplexity) -> None: - self.chat = chat.ChatResourceWithStreamingResponse(client.chat) - self.search = search.SearchResourceWithStreamingResponse(client.search) - self.async_ = async_.AsyncResourceWithStreamingResponse(client.async_) + self._client = client + + @cached_property + def chat(self) -> chat.ChatResourceWithStreamingResponse: + from .resources.chat import ChatResourceWithStreamingResponse + + return ChatResourceWithStreamingResponse(self._client.chat) + + @cached_property + def search(self) -> search.SearchResourceWithStreamingResponse: + from .resources.search import SearchResourceWithStreamingResponse + + return SearchResourceWithStreamingResponse(self._client.search) + + @cached_property + def async_(self) -> async_.AsyncResourceWithStreamingResponse: + from .resources.async_ import AsyncResourceWithStreamingResponse + + return AsyncResourceWithStreamingResponse(self._client.async_) class AsyncPerplexityWithStreamedResponse: + _client: AsyncPerplexity + def __init__(self, client: AsyncPerplexity) -> None: - self.chat = chat.AsyncChatResourceWithStreamingResponse(client.chat) - self.search = search.AsyncSearchResourceWithStreamingResponse(client.search) - self.async_ = async_.AsyncAsyncResourceWithStreamingResponse(client.async_) + self._client = client + + @cached_property + def chat(self) -> chat.AsyncChatResourceWithStreamingResponse: + from .resources.chat import AsyncChatResourceWithStreamingResponse + + return AsyncChatResourceWithStreamingResponse(self._client.chat) + + @cached_property + def search(self) -> search.AsyncSearchResourceWithStreamingResponse: + from .resources.search import AsyncSearchResourceWithStreamingResponse + + return AsyncSearchResourceWithStreamingResponse(self._client.search) + + @cached_property + def async_(self) -> async_.AsyncAsyncResourceWithStreamingResponse: + from .resources.async_ import AsyncAsyncResourceWithStreamingResponse + + return AsyncAsyncResourceWithStreamingResponse(self._client.async_) Client = Perplexity diff --git a/src/perplexity/_types.py b/src/perplexity/_types.py index c55fb01..2907540 100644 --- a/src/perplexity/_types.py +++ b/src/perplexity/_types.py @@ -243,6 +243,9 @@ class HttpxSendArgs(TypedDict, total=False): if TYPE_CHECKING: # This works because str.__contains__ does not accept object (either in typeshed or at runtime) # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. class SequenceNotStr(Protocol[_T_co]): @overload def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... @@ -251,8 +254,6 @@ def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... def __contains__(self, value: object, /) -> bool: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T_co]: ... - def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... - def count(self, value: Any, /) -> int: ... def __reversed__(self) -> Iterator[_T_co]: ... else: # just point this to a normal `Sequence` at runtime to avoid having to special case diff --git a/src/perplexity/_version.py b/src/perplexity/_version.py index f9098f7..16c4414 100644 --- a/src/perplexity/_version.py +++ b/src/perplexity/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "perplexity" -__version__ = "0.22.0" # x-release-please-version +__version__ = "0.22.1" # x-release-please-version diff --git a/src/perplexity/types/shared/chat_message_input.py b/src/perplexity/types/shared/chat_message_input.py index 6fa7c37..36ca9c3 100644 --- a/src/perplexity/types/shared/chat_message_input.py +++ b/src/perplexity/types/shared/chat_message_input.py @@ -111,22 +111,30 @@ class ContentStructuredContentChatMessageContentVideoChunk(BaseModel): class ReasoningStepExecutePython(BaseModel): + """Code generation step details wrapper class""" + code: str result: str class ReasoningStepFetchURLContent(BaseModel): + """Fetch url content step details wrapper class""" + contents: List[APIPublicSearchResult] class ReasoningStepWebSearch(BaseModel): + """Web search step details wrapper class""" + search_keywords: List[str] search_results: List[APIPublicSearchResult] class ReasoningStep(BaseModel): + """Reasoning step wrapper class""" + thought: str execute_python: Optional[ReasoningStepExecutePython] = None diff --git a/src/perplexity/types/shared/chat_message_output.py b/src/perplexity/types/shared/chat_message_output.py index c646c8f..84052c6 100644 --- a/src/perplexity/types/shared/chat_message_output.py +++ b/src/perplexity/types/shared/chat_message_output.py @@ -111,22 +111,30 @@ class ContentStructuredContentChatMessageContentVideoChunk(BaseModel): class ReasoningStepExecutePython(BaseModel): + """Code generation step details wrapper class""" + code: str result: str class ReasoningStepFetchURLContent(BaseModel): + """Fetch url content step details wrapper class""" + contents: List[APIPublicSearchResult] class ReasoningStepWebSearch(BaseModel): + """Web search step details wrapper class""" + search_keywords: List[str] search_results: List[APIPublicSearchResult] class ReasoningStep(BaseModel): + """Reasoning step wrapper class""" + thought: str execute_python: Optional[ReasoningStepExecutePython] = None diff --git a/src/perplexity/types/shared_params/chat_message_input.py b/src/perplexity/types/shared_params/chat_message_input.py index cfd114e..5ea15b6 100644 --- a/src/perplexity/types/shared_params/chat_message_input.py +++ b/src/perplexity/types/shared_params/chat_message_input.py @@ -113,22 +113,30 @@ class ContentStructuredContentChatMessageContentVideoChunk(TypedDict, total=Fals class ReasoningStepExecutePython(TypedDict, total=False): + """Code generation step details wrapper class""" + code: Required[str] result: Required[str] class ReasoningStepFetchURLContent(TypedDict, total=False): + """Fetch url content step details wrapper class""" + contents: Required[Iterable[APIPublicSearchResult]] class ReasoningStepWebSearch(TypedDict, total=False): + """Web search step details wrapper class""" + search_keywords: Required[SequenceNotStr[str]] search_results: Required[Iterable[APIPublicSearchResult]] class ReasoningStep(TypedDict, total=False): + """Reasoning step wrapper class""" + thought: Required[str] execute_python: Optional[ReasoningStepExecutePython]