diff --git a/README.md b/README.md index 2e258279..a4e29fb6 100644 --- a/README.md +++ b/README.md @@ -295,7 +295,7 @@ if response.my_field is None: ### Accessing raw response data (e.g. headers) -The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call. +The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., ```py from finch import Finch @@ -308,7 +308,32 @@ directory = response.parse() # get the object that `hris.directory.list()` woul print(directory.id) ``` -These methods return an [`APIResponse`](https://github.com/Finch-API/finch-api-python/tree/main/src/finch/_response.py) object. +These methods return an [`LegacyAPIResponse`](https://github.com/Finch-API/finch-api-python/tree/main/src/finch/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. + +For the sync client this will mostly be the same with the exception +of `content` & `text` will be methods instead of properties. In the +async client, all methods will be async. + +A migration script will be provided & the migration in general should +be smooth. + +#### `.with_streaming_response` + +The above interface eagerly reads the full response body when you make the request, which may not always be what you want. + +To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. + +As such, `.with_streaming_response` methods return a different [`APIResponse`](https://github.com/Finch-API/finch-api-python/tree/main/src/finch/_response.py) object, and the async client returns an [`AsyncAPIResponse`](https://github.com/Finch-API/finch-api-python/tree/main/src/finch/_response.py) object. + +```python +with client.hris.directory.with_streaming_response.list() as response: + print(response.headers.get("X-My-Header")) + + for line in response.iter_lines(): + print(line) +``` + +The context manager is required so that the response will reliably be closed. ### Configuring the HTTP client diff --git a/src/finch/__init__.py b/src/finch/__init__.py index 4fb56959..25aca495 100644 --- a/src/finch/__init__.py +++ b/src/finch/__init__.py @@ -5,6 +5,7 @@ from ._utils import file_from_path from ._client import Finch, Client, Stream, Timeout, Transport, AsyncFinch, AsyncClient, AsyncStream, RequestOptions from ._version import __title__, __version__ +from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse from ._exceptions import ( APIError, FinchError, diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py index c2c2db5f..1dfbd7df 100644 --- a/src/finch/_base_client.py +++ b/src/finch/_base_client.py @@ -1,6 +1,5 @@ from __future__ import annotations -import os import json import time import uuid @@ -31,7 +30,7 @@ overload, ) from functools import lru_cache -from typing_extensions import Literal, override +from typing_extensions import Literal, override, get_origin import anyio import httpx @@ -61,18 +60,22 @@ AsyncTransport, RequestOptions, ModelBuilderProtocol, - BinaryResponseContent, ) from ._utils import is_dict, is_given, is_mapping from ._compat import model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type -from ._response import APIResponse +from ._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + extract_response_type, +) from ._constants import ( DEFAULT_LIMITS, DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, RAW_RESPONSE_HEADER, - STREAMED_RAW_RESPONSE_HEADER, + OVERRIDE_CAST_TO_HEADER, ) from ._streaming import Stream, AsyncStream from ._exceptions import ( @@ -81,6 +84,7 @@ APIConnectionError, APIResponseValidationError, ) +from ._legacy_response import LegacyAPIResponse log: logging.Logger = logging.getLogger(__name__) @@ -493,28 +497,25 @@ def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, o serialized[key] = value return serialized - def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - ) -> ResponseT: - api_response = APIResponse( - raw=response, - client=self, - cast_to=cast_to, - stream=stream, - stream_cls=stream_cls, - options=options, - ) + def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: + if not is_given(options.headers): + return cast_to - if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": - return cast(ResponseT, api_response) + # make a copy of the headers so we don't mutate user-input + headers = dict(options.headers) - return api_response.parse() + # we internally support defining a temporary header to override the + # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` + # see _response.py for implementation details + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + if is_given(override_cast_to): + options.headers = headers + return cast(Type[ResponseT], override_cast_to) + + return cast_to + + def _should_stream_response_body(self, request: httpx.Request) -> bool: + return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] def _process_response_data( self, @@ -540,12 +541,6 @@ def _process_response_data( except pydantic.ValidationError as err: raise APIResponseValidationError(response=response, body=data) from err - def _should_stream_response_body(self, *, request: httpx.Request) -> bool: - if request.headers.get(STREAMED_RAW_RESPONSE_HEADER) == "true": - return True - - return False - @property def qs(self) -> Querystring: return Querystring() @@ -610,6 +605,8 @@ def _calculate_retry_timeout( if response_headers is not None: retry_header = response_headers.get("retry-after") try: + # note: the spec indicates that this should only ever be an integer + # but if someone sends a float there's no reason for us to not respect it retry_after = float(retry_header) except Exception: retry_date_tuple = email.utils.parsedate_tz(retry_header) @@ -873,6 +870,7 @@ def _request( stream: bool, stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: + cast_to = self._maybe_override_cast_to(cast_to, options) self._prepare_options(options) retries = self._remaining_retries(remaining_retries, options) @@ -987,6 +985,63 @@ def _retry_request( stream_cls=stream_cls, ) + def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + ) -> ResponseT: + if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": + return cast( + ResponseT, + LegacyAPIResponse( + raw=response, + client=self, + cast_to=cast_to, + stream=stream, + stream_cls=stream_cls, + options=options, + ), + ) + + origin = get_origin(cast_to) or cast_to + + if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if not issubclass(origin, APIResponse): + raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + ResponseT, + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = APIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return api_response.parse() + def _request_api_list( self, model: Type[object], @@ -1353,6 +1408,7 @@ async def _request( stream_cls: type[_AsyncStreamT] | None, remaining_retries: int | None, ) -> ResponseT | _AsyncStreamT: + cast_to = self._maybe_override_cast_to(cast_to, options) await self._prepare_options(options) retries = self._remaining_retries(remaining_retries, options) @@ -1428,7 +1484,7 @@ async def _request( log.debug("Re-raising status error") raise self._make_status_error_from_response(err.response) from None - return self._process_response( + return await self._process_response( cast_to=cast_to, options=options, response=response, @@ -1465,6 +1521,63 @@ async def _retry_request( stream_cls=stream_cls, ) + async def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + ) -> ResponseT: + if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": + return cast( + ResponseT, + LegacyAPIResponse( + raw=response, + client=self, + cast_to=cast_to, + stream=stream, + stream_cls=stream_cls, + options=options, + ), + ) + + origin = get_origin(cast_to) or cast_to + + if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if not issubclass(origin, AsyncAPIResponse): + raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + "ResponseT", + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = AsyncAPIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return await api_response.parse() + def _request_api_list( self, model: Type[_T], @@ -1783,105 +1896,3 @@ def _merge_mappings( """ merged = {**obj1, **obj2} return {key: value for key, value in merged.items() if not isinstance(value, Omit)} - - -class HttpxBinaryResponseContent(BinaryResponseContent): - response: httpx.Response - - def __init__(self, response: httpx.Response) -> None: - self.response = response - - @property - @override - def content(self) -> bytes: - return self.response.content - - @property - @override - def text(self) -> str: - return self.response.text - - @property - @override - def encoding(self) -> Optional[str]: - return self.response.encoding - - @property - @override - def charset_encoding(self) -> Optional[str]: - return self.response.charset_encoding - - @override - def json(self, **kwargs: Any) -> Any: - return self.response.json(**kwargs) - - @override - def read(self) -> bytes: - return self.response.read() - - @override - def iter_bytes(self, chunk_size: Optional[int] = None) -> Iterator[bytes]: - return self.response.iter_bytes(chunk_size) - - @override - def iter_text(self, chunk_size: Optional[int] = None) -> Iterator[str]: - return self.response.iter_text(chunk_size) - - @override - def iter_lines(self) -> Iterator[str]: - return self.response.iter_lines() - - @override - def iter_raw(self, chunk_size: Optional[int] = None) -> Iterator[bytes]: - return self.response.iter_raw(chunk_size) - - @override - def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - with open(file, mode="wb") as f: - for data in self.response.iter_bytes(chunk_size): - f.write(data) - - @override - def close(self) -> None: - return self.response.close() - - @override - async def aread(self) -> bytes: - return await self.response.aread() - - @override - async def aiter_bytes(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]: - return self.response.aiter_bytes(chunk_size) - - @override - async def aiter_text(self, chunk_size: Optional[int] = None) -> AsyncIterator[str]: - return self.response.aiter_text(chunk_size) - - @override - async def aiter_lines(self) -> AsyncIterator[str]: - return self.response.aiter_lines() - - @override - async def aiter_raw(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]: - return self.response.aiter_raw(chunk_size) - - @override - async def astream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.response.aiter_bytes(chunk_size): - await f.write(data) - - @override - async def aclose(self) -> None: - return await self.response.aclose() diff --git a/src/finch/_client.py b/src/finch/_client.py index a2235b30..f49ef73e 100644 --- a/src/finch/_client.py +++ b/src/finch/_client.py @@ -61,6 +61,7 @@ class Finch(SyncAPIClient): jobs: resources.Jobs sandbox: resources.Sandbox with_raw_response: FinchWithRawResponse + with_streaming_response: FinchWithStreamedResponse # client options access_token: str | None @@ -161,6 +162,7 @@ def __init__( self.jobs = resources.Jobs(self) self.sandbox = resources.Sandbox(self) self.with_raw_response = FinchWithRawResponse(self) + self.with_streaming_response = FinchWithStreamedResponse(self) @property @override @@ -411,6 +413,7 @@ class AsyncFinch(AsyncAPIClient): jobs: resources.AsyncJobs sandbox: resources.AsyncSandbox with_raw_response: AsyncFinchWithRawResponse + with_streaming_response: AsyncFinchWithStreamedResponse # client options access_token: str | None @@ -511,6 +514,7 @@ def __init__( self.jobs = resources.AsyncJobs(self) self.sandbox = resources.AsyncSandbox(self) self.with_raw_response = AsyncFinchWithRawResponse(self) + self.with_streaming_response = AsyncFinchWithStreamedResponse(self) @property @override @@ -773,6 +777,28 @@ def __init__(self, client: AsyncFinch) -> None: self.sandbox = resources.AsyncSandboxWithRawResponse(client.sandbox) +class FinchWithStreamedResponse: + def __init__(self, client: Finch) -> None: + self.access_tokens = resources.AccessTokensWithStreamingResponse(client.access_tokens) + self.hris = resources.HRISWithStreamingResponse(client.hris) + self.providers = resources.ProvidersWithStreamingResponse(client.providers) + self.account = resources.AccountWithStreamingResponse(client.account) + self.request_forwarding = resources.RequestForwardingWithStreamingResponse(client.request_forwarding) + self.jobs = resources.JobsWithStreamingResponse(client.jobs) + self.sandbox = resources.SandboxWithStreamingResponse(client.sandbox) + + +class AsyncFinchWithStreamedResponse: + def __init__(self, client: AsyncFinch) -> None: + self.access_tokens = resources.AsyncAccessTokensWithStreamingResponse(client.access_tokens) + self.hris = resources.AsyncHRISWithStreamingResponse(client.hris) + self.providers = resources.AsyncProvidersWithStreamingResponse(client.providers) + self.account = resources.AsyncAccountWithStreamingResponse(client.account) + self.request_forwarding = resources.AsyncRequestForwardingWithStreamingResponse(client.request_forwarding) + self.jobs = resources.AsyncJobsWithStreamingResponse(client.jobs) + self.sandbox = resources.AsyncSandboxWithStreamingResponse(client.sandbox) + + Client = Finch AsyncClient = AsyncFinch diff --git a/src/finch/_constants.py b/src/finch/_constants.py index 39b46eb0..76b21f0c 100644 --- a/src/finch/_constants.py +++ b/src/finch/_constants.py @@ -3,7 +3,7 @@ import httpx RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" -STREAMED_RAW_RESPONSE_HEADER = "X-Stainless-Streamed-Raw-Response" +OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" # default timeout is 1 minute DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0) diff --git a/src/finch/_legacy_response.py b/src/finch/_legacy_response.py new file mode 100644 index 00000000..a350fbdb --- /dev/null +++ b/src/finch/_legacy_response.py @@ -0,0 +1,385 @@ +from __future__ import annotations + +import os +import inspect +import logging +import datetime +import functools +from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, Iterator, AsyncIterator, cast +from typing_extensions import Awaitable, ParamSpec, get_args, override, deprecated, get_origin + +import anyio +import httpx + +from ._types import NoneType +from ._utils import is_given +from ._models import BaseModel, is_basemodel +from ._constants import RAW_RESPONSE_HEADER +from ._exceptions import APIResponseValidationError + +if TYPE_CHECKING: + from ._models import FinalRequestOptions + from ._base_client import Stream, BaseClient, AsyncStream + + +P = ParamSpec("P") +R = TypeVar("R") + +log: logging.Logger = logging.getLogger(__name__) + + +class LegacyAPIResponse(Generic[R]): + """This is a legacy class as it will be replaced by `APIResponse` + and `AsyncAPIResponse` in the `_response.py` file in the next major + release. + + For the sync client this will mostly be the same with the exception + of `content` & `text` will be methods instead of properties. In the + async client, all methods will be async. + + A migration script will be provided & the migration in general should + be smooth. + """ + + _cast_to: type[R] + _client: BaseClient[Any, Any] + _parsed: R | None + _stream: bool + _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None + _options: FinalRequestOptions + + http_response: httpx.Response + + def __init__( + self, + *, + raw: httpx.Response, + cast_to: type[R], + client: BaseClient[Any, Any], + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + options: FinalRequestOptions, + ) -> None: + self._cast_to = cast_to + self._client = client + self._parsed = None + self._stream = stream + self._stream_cls = stream_cls + self._options = options + self.http_response = raw + + def parse(self) -> R: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + NOTE: For the async client: this will become a coroutine in the next major version. + """ + if self._parsed is not None: + return self._parsed + + parsed = self._parse() + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed = parsed + return parsed + + @property + def headers(self) -> httpx.Headers: + return self.http_response.headers + + @property + def http_request(self) -> httpx.Request: + return self.http_response.request + + @property + def status_code(self) -> int: + return self.http_response.status_code + + @property + def url(self) -> httpx.URL: + return self.http_response.url + + @property + def method(self) -> str: + return self.http_request.method + + @property + def content(self) -> bytes: + """Return the binary response content. + + NOTE: this will be removed in favour of `.read()` in the + next major version. + """ + return self.http_response.content + + @property + def text(self) -> str: + """Return the decoded response content. + + NOTE: this will be turned into a method in the next major version. + """ + return self.http_response.text + + @property + def http_version(self) -> str: + return self.http_response.http_version + + @property + def is_closed(self) -> bool: + return self.http_response.is_closed + + @property + def elapsed(self) -> datetime.timedelta: + """The time taken for the complete request/response cycle to complete.""" + return self.http_response.elapsed + + def _parse(self) -> R: + if self._stream: + if self._stream_cls: + return cast( + R, + self._stream_cls( + cast_to=_extract_stream_chunk_type(self._stream_cls), + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) + if stream_cls is None: + raise MissingStreamClassError() + + return cast( + R, + stream_cls( + cast_to=self._cast_to, + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + cast_to = self._cast_to + if cast_to is NoneType: + return cast(R, None) + + response = self.http_response + if cast_to == str: + return cast(R, response.text) + + origin = get_origin(cast_to) or cast_to + + if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): + return cast(R, cast_to(response)) # type: ignore + + if origin == LegacyAPIResponse: + raise RuntimeError("Unexpected state - cast_to is `APIResponse`") + + if inspect.isclass(origin) and issubclass(origin, httpx.Response): + # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response + # and pass that class to our request functions. We cannot change the variance to be either + # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct + # the response class ourselves but that is something that should be supported directly in httpx + # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. + if cast_to != httpx.Response: + raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") + return cast(R, response) + + # The check here is necessary as we are subverting the the type system + # with casts as the relationship between TypeVars and Types are very strict + # which means we must return *exactly* what was input or transform it in a + # way that retains the TypeVar state. As we cannot do that in this function + # then we have to resort to using `cast`. At the time of writing, we know this + # to be safe as we have handled all the types that could be bound to the + # `ResponseT` TypeVar, however if that TypeVar is ever updated in the future, then + # this function would become unsafe but a type checker would not report an error. + if ( + cast_to is not object + and not origin is list + and not origin is dict + and not origin is Union + and not issubclass(origin, BaseModel) + ): + raise RuntimeError( + f"Invalid state, expected {cast_to} to be a subclass type of {BaseModel}, {dict}, {list} or {Union}." + ) + + # split is required to handle cases where additional information is included + # in the response, e.g. application/json; charset=utf-8 + content_type, *_ = response.headers.get("content-type").split(";") + if content_type != "application/json": + if is_basemodel(cast_to): + try: + data = response.json() + except Exception as exc: + log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) + else: + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + if self._client._strict_response_validation: + raise APIResponseValidationError( + response=response, + message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", + body=response.text, + ) + + # If the API responds with content that isn't JSON then we just return + # the (decoded) text without performing any parsing so that you can still + # handle the response however you need to. + return response.text # type: ignore + + data = response.json() + + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + @override + def __repr__(self) -> str: + return f"" + + +class MissingStreamClassError(TypeError): + def __init__(self) -> None: + super().__init__( + "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `finch._streaming` for reference", + ) + + +def _extract_stream_chunk_type(stream_cls: type) -> type: + args = get_args(stream_cls) + if not args: + raise TypeError( + f"Expected stream_cls to have been given a generic type argument, e.g. Stream[Foo] but received {stream_cls}", + ) + return cast(type, args[0]) + + +def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, LegacyAPIResponse[R]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "true" + + kwargs["extra_headers"] = extra_headers + + return cast(LegacyAPIResponse[R], func(*args, **kwargs)) + + return wrapped + + +def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[LegacyAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "true" + + kwargs["extra_headers"] = extra_headers + + return cast(LegacyAPIResponse[R], await func(*args, **kwargs)) + + return wrapped + + +class HttpxBinaryResponseContent: + response: httpx.Response + + def __init__(self, response: httpx.Response) -> None: + self.response = response + + @property + def content(self) -> bytes: + return self.response.content + + @property + def text(self) -> str: + return self.response.text + + @property + def encoding(self) -> str | None: + return self.response.encoding + + @property + def charset_encoding(self) -> str | None: + return self.response.charset_encoding + + def json(self, **kwargs: Any) -> Any: + return self.response.json(**kwargs) + + def read(self) -> bytes: + return self.response.read() + + def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: + return self.response.iter_bytes(chunk_size) + + def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: + return self.response.iter_text(chunk_size) + + def iter_lines(self) -> Iterator[str]: + return self.response.iter_lines() + + def iter_raw(self, chunk_size: int | None = None) -> Iterator[bytes]: + return self.response.iter_raw(chunk_size) + + @deprecated( + "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead" + ) + def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + with open(file, mode="wb") as f: + for data in self.response.iter_bytes(chunk_size): + f.write(data) + + def close(self) -> None: + return self.response.close() + + async def aread(self) -> bytes: + return await self.response.aread() + + async def aiter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + return self.response.aiter_bytes(chunk_size) + + async def aiter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: + return self.response.aiter_text(chunk_size) + + async def aiter_lines(self) -> AsyncIterator[str]: + return self.response.aiter_lines() + + async def aiter_raw(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + return self.response.aiter_raw(chunk_size) + + @deprecated( + "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead" + ) + async def astream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.response.aiter_bytes(chunk_size): + await f.write(data) + + async def aclose(self) -> None: + return await self.response.aclose() diff --git a/src/finch/_response.py b/src/finch/_response.py index 36af2199..936c0cb5 100644 --- a/src/finch/_response.py +++ b/src/finch/_response.py @@ -1,19 +1,32 @@ from __future__ import annotations +import os import inspect import logging import datetime import functools -from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Union, + Generic, + TypeVar, + Callable, + Iterator, + AsyncIterator, + cast, +) from typing_extensions import Awaitable, ParamSpec, override, get_origin +import anyio import httpx -from ._types import NoneType, BinaryResponseContent +from ._types import NoneType from ._utils import is_given, extract_type_var_from_base from ._models import BaseModel, is_basemodel -from ._constants import RAW_RESPONSE_HEADER -from ._exceptions import APIResponseValidationError +from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER +from ._exceptions import FinchError, APIResponseValidationError if TYPE_CHECKING: from ._models import FinalRequestOptions @@ -22,15 +35,17 @@ P = ParamSpec("P") R = TypeVar("R") +_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") +_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") log: logging.Logger = logging.getLogger(__name__) -class APIResponse(Generic[R]): +class BaseAPIResponse(Generic[R]): _cast_to: type[R] _client: BaseClient[Any, Any] _parsed: R | None - _stream: bool + _is_sse_stream: bool _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None _options: FinalRequestOptions @@ -49,28 +64,18 @@ def __init__( self._cast_to = cast_to self._client = client self._parsed = None - self._stream = stream + self._is_sse_stream = stream self._stream_cls = stream_cls self._options = options self.http_response = raw - def parse(self) -> R: - if self._parsed is not None: - return self._parsed - - parsed = self._parse() - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - self._parsed = parsed - return parsed - @property def headers(self) -> httpx.Headers: return self.http_response.headers @property def http_request(self) -> httpx.Request: + """Returns the httpx Request instance associated with the current response.""" return self.http_response.request @property @@ -79,20 +84,13 @@ def status_code(self) -> int: @property def url(self) -> httpx.URL: + """Returns the URL for which the request was made.""" return self.http_response.url @property def method(self) -> str: return self.http_request.method - @property - def content(self) -> bytes: - return self.http_response.content - - @property - def text(self) -> str: - return self.http_response.text - @property def http_version(self) -> str: return self.http_response.http_version @@ -102,13 +100,29 @@ def elapsed(self) -> datetime.timedelta: """The time taken for the complete request/response cycle to complete.""" return self.http_response.elapsed + @property + def is_closed(self) -> bool: + """Whether or not the response body has been closed. + + If this is False then there is response data that has not been read yet. + You must either fully consume the response body or call `.close()` + before discarding the response to prevent resource leaks. + """ + return self.http_response.is_closed + + @override + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" + ) + def _parse(self) -> R: - if self._stream: + if self._is_sse_stream: if self._stream_cls: return cast( R, self._stream_cls( - cast_to=_extract_stream_chunk_type(self._stream_cls), + cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), ), @@ -135,9 +149,13 @@ def _parse(self) -> R: if cast_to == str: return cast(R, response.text) + if cast_to == bytes: + return cast(R, response.content) + origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BinaryResponseContent): + # handle the legacy binary response case + if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": return cast(R, cast_to(response)) # type: ignore if origin == APIResponse: @@ -208,9 +226,227 @@ def _parse(self) -> R: response=response, ) - @override - def __repr__(self) -> str: - return f"" + +class APIResponse(BaseAPIResponse[R]): + def parse(self) -> R: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + """ + if self._parsed is not None: + return self._parsed + + if not self._is_sse_stream: + self.read() + + parsed = self._parse() + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed = parsed + return parsed + + def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return self.http_response.read() + except httpx.StreamConsumed as exc: + # The default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message. + raise StreamAlreadyConsumed() from exc + + def text(self) -> str: + """Read and decode the response content into a string.""" + self.read() + return self.http_response.text + + def json(self) -> object: + """Read and decode the JSON response content.""" + self.read() + return self.http_response.json() + + def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.http_response.close() + + def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + for chunk in self.http_response.iter_bytes(chunk_size): + yield chunk + + def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + for chunk in self.http_response.iter_text(chunk_size): + yield chunk + + def iter_lines(self) -> Iterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + for chunk in self.http_response.iter_lines(): + yield chunk + + +class AsyncAPIResponse(BaseAPIResponse[R]): + async def parse(self) -> R: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + """ + if self._parsed is not None: + return self._parsed + + if not self._is_sse_stream: + await self.read() + + parsed = self._parse() + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed = parsed + return parsed + + async def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return await self.http_response.aread() + except httpx.StreamConsumed as exc: + # the default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message + raise StreamAlreadyConsumed() from exc + + async def text(self) -> str: + """Read and decode the response content into a string.""" + await self.read() + return self.http_response.text + + async def json(self) -> object: + """Read and decode the JSON response content.""" + await self.read() + return self.http_response.json() + + async def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.http_response.aclose() + + async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + async for chunk in self.http_response.aiter_bytes(chunk_size): + yield chunk + + async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + async for chunk in self.http_response.aiter_text(chunk_size): + yield chunk + + async def iter_lines(self) -> AsyncIterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + async for chunk in self.http_response.aiter_lines(): + yield chunk + + +class BinaryAPIResponse(APIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(): + f.write(data) + + +class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + async def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(): + await f.write(data) + + +class StreamedBinaryAPIResponse(APIResponse[bytes]): + def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(chunk_size): + f.write(data) + + +class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): + async def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(chunk_size): + await f.write(data) class MissingStreamClassError(TypeError): @@ -220,14 +456,176 @@ def __init__(self) -> None: ) -def _extract_stream_chunk_type(stream_cls: type) -> type: - from ._base_client import Stream, AsyncStream +class StreamAlreadyConsumed(FinchError): + """ + Attempted to read or stream content, but the content has already + been streamed. - return extract_type_var_from_base( - stream_cls, - index=0, - generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), - ) + This can happen if you use a method like `.iter_lines()` and then attempt + to read th entire response body afterwards, e.g. + + ```py + response = await client.post(...) + async for line in response.iter_lines(): + ... # do something with `line` + + content = await response.read() + # ^ error + ``` + + If you want this behaviour you'll need to either manually accumulate the response + content or call `await response.read()` before iterating over the stream. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream some content, but the content has " + "already been streamed. " + "This could be due to attempting to stream the response " + "content more than once." + "\n\n" + "You can fix this by manually accumulating the response content while streaming " + "or by calling `.read()` before starting to stream." + ) + super().__init__(message) + + +class ResponseContextManager(Generic[_APIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: + self._request_func = request_func + self.__response: _APIResponseT | None = None + + def __enter__(self) -> _APIResponseT: + self.__response = self._request_func() + return self.__response + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + self.__response.close() + + +class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: + self._api_request = api_request + self.__response: _AsyncAPIResponseT | None = None + + async def __aenter__(self) -> _AsyncAPIResponseT: + self.__response = await self._api_request + return self.__response + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + await self.__response.close() + + +def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) + + return wrapped + + +def async_to_streamed_response_wrapper( + func: Callable[P, Awaitable[R]], +) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) + + return wrapped + + +def to_custom_streamed_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, ResponseContextManager[_APIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) + + return wrapped + + +def async_to_custom_streamed_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) + + return wrapped def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: @@ -238,7 +636,7 @@ def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]] @functools.wraps(func) def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "true" + extra_headers[RAW_RESPONSE_HEADER] = "raw" kwargs["extra_headers"] = extra_headers @@ -247,18 +645,102 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: return wrapped -def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[APIResponse[R]]]: +def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: """Higher order function that takes one of our bound API methods and wraps it to support returning the raw `APIResponse` object directly. """ @functools.wraps(func) - async def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "true" + extra_headers[RAW_RESPONSE_HEADER] = "raw" kwargs["extra_headers"] = extra_headers - return cast(APIResponse[R], await func(*args, **kwargs)) + return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) return wrapped + + +def to_custom_raw_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, _APIResponseT]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(_APIResponseT, func(*args, **kwargs)) + + return wrapped + + +def async_to_custom_raw_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: + extra_headers = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) + + return wrapped + + +def extract_stream_chunk_type(stream_cls: type) -> type: + """Given a type like `Stream[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyStream(Stream[bytes]): + ... + + extract_stream_chunk_type(MyStream) -> bytes + ``` + """ + from ._base_client import Stream, AsyncStream + + return extract_type_var_from_base( + stream_cls, + index=0, + generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), + ) + + +def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: + """Given a type like `APIResponse[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(APIResponse[bytes]): + ... + + extract_response_type(MyResponse) -> bytes + ``` + """ + return extract_type_var_from_base( + typ, + generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), + index=0, + ) diff --git a/src/finch/_types.py b/src/finch/_types.py index 04fa5bf8..1ccf4a5e 100644 --- a/src/finch/_types.py +++ b/src/finch/_types.py @@ -1,7 +1,6 @@ from __future__ import annotations from os import PathLike -from abc import ABC, abstractmethod from typing import ( IO, TYPE_CHECKING, @@ -14,10 +13,8 @@ Mapping, TypeVar, Callable, - Iterator, Optional, Sequence, - AsyncIterator, ) from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable @@ -27,6 +24,8 @@ if TYPE_CHECKING: from ._models import BaseModel + from ._response import APIResponse, AsyncAPIResponse + from ._legacy_response import HttpxBinaryResponseContent Transport = BaseTransport AsyncTransport = AsyncBaseTransport @@ -37,162 +36,6 @@ _T = TypeVar("_T") -class BinaryResponseContent(ABC): - @abstractmethod - def __init__( - self, - response: Any, - ) -> None: - ... - - @property - @abstractmethod - def content(self) -> bytes: - pass - - @property - @abstractmethod - def text(self) -> str: - pass - - @property - @abstractmethod - def encoding(self) -> Optional[str]: - """ - Return an encoding to use for decoding the byte content into text. - The priority for determining this is given by... - - * `.encoding = <>` has been set explicitly. - * The encoding as specified by the charset parameter in the Content-Type header. - * The encoding as determined by `default_encoding`, which may either be - a string like "utf-8" indicating the encoding to use, or may be a callable - which enables charset autodetection. - """ - pass - - @property - @abstractmethod - def charset_encoding(self) -> Optional[str]: - """ - Return the encoding, as specified by the Content-Type header. - """ - pass - - @abstractmethod - def json(self, **kwargs: Any) -> Any: - pass - - @abstractmethod - def read(self) -> bytes: - """ - Read and return the response content. - """ - pass - - @abstractmethod - def iter_bytes(self, chunk_size: Optional[int] = None) -> Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, and brotli encoded responses. - """ - pass - - @abstractmethod - def iter_text(self, chunk_size: Optional[int] = None) -> Iterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - pass - - @abstractmethod - def iter_lines(self) -> Iterator[str]: - pass - - @abstractmethod - def iter_raw(self, chunk_size: Optional[int] = None) -> Iterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - pass - - @abstractmethod - def stream_to_file( - self, - file: str | PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """ - Stream the output to the given file. - """ - pass - - @abstractmethod - def close(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - pass - - @abstractmethod - async def aread(self) -> bytes: - """ - Read and return the response content. - """ - pass - - @abstractmethod - async def aiter_bytes(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, and brotli encoded responses. - """ - pass - - @abstractmethod - async def aiter_text(self, chunk_size: Optional[int] = None) -> AsyncIterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - pass - - @abstractmethod - async def aiter_lines(self) -> AsyncIterator[str]: - pass - - @abstractmethod - async def aiter_raw(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - pass - - @abstractmethod - async def astream_to_file( - self, - file: str | PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """ - Stream the output to the given file. - """ - pass - - @abstractmethod - async def aclose(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - pass - - # Approximates httpx internal ProxiesTypes and RequestFiles types # while adding support for `PathLike` instances ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] @@ -343,7 +186,9 @@ def get(self, __key: str) -> str | None: Dict[str, Any], Response, ModelBuilderProtocol, - BinaryResponseContent, + "APIResponse[Any]", + "AsyncAPIResponse[Any]", + "HttpxBinaryResponseContent", ], ) @@ -359,6 +204,7 @@ def get(self, __key: str) -> str | None: @runtime_checkable class InheritsGeneric(Protocol): """Represents a type that has inherited from `Generic` + The `__orig_bases__` property can be used to determine the resolved type variable for a given base class. """ diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py index b3c215be..13ad3da5 100644 --- a/src/finch/resources/__init__.py +++ b/src/finch/resources/__init__.py @@ -1,22 +1,61 @@ # File generated from our OpenAPI spec by Stainless. -from .hris import HRIS, AsyncHRIS, HRISWithRawResponse, AsyncHRISWithRawResponse -from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse -from .account import Account, AsyncAccount, AccountWithRawResponse, AsyncAccountWithRawResponse -from .sandbox import Sandbox, AsyncSandbox, SandboxWithRawResponse, AsyncSandboxWithRawResponse +from .hris import ( + HRIS, + AsyncHRIS, + HRISWithRawResponse, + AsyncHRISWithRawResponse, + HRISWithStreamingResponse, + AsyncHRISWithStreamingResponse, +) +from .jobs import ( + Jobs, + AsyncJobs, + JobsWithRawResponse, + AsyncJobsWithRawResponse, + JobsWithStreamingResponse, + AsyncJobsWithStreamingResponse, +) +from .account import ( + Account, + AsyncAccount, + AccountWithRawResponse, + AsyncAccountWithRawResponse, + AccountWithStreamingResponse, + AsyncAccountWithStreamingResponse, +) +from .sandbox import ( + Sandbox, + AsyncSandbox, + SandboxWithRawResponse, + AsyncSandboxWithRawResponse, + SandboxWithStreamingResponse, + AsyncSandboxWithStreamingResponse, +) from .webhooks import Webhooks, AsyncWebhooks -from .providers import Providers, AsyncProviders, ProvidersWithRawResponse, AsyncProvidersWithRawResponse +from .providers import ( + Providers, + AsyncProviders, + ProvidersWithRawResponse, + AsyncProvidersWithRawResponse, + ProvidersWithStreamingResponse, + AsyncProvidersWithStreamingResponse, +) from .access_tokens import ( AccessTokens, AsyncAccessTokens, AccessTokensWithRawResponse, AsyncAccessTokensWithRawResponse, + AccessTokensWithStreamingResponse, + AsyncAccessTokensWithStreamingResponse, ) from .request_forwarding import ( RequestForwarding, AsyncRequestForwarding, RequestForwardingWithRawResponse, AsyncRequestForwardingWithRawResponse, + RequestForwardingWithStreamingResponse, + AsyncRequestForwardingWithStreamingResponse, ) __all__ = [ @@ -24,30 +63,44 @@ "AsyncAccessTokens", "AccessTokensWithRawResponse", "AsyncAccessTokensWithRawResponse", + "AccessTokensWithStreamingResponse", + "AsyncAccessTokensWithStreamingResponse", "HRIS", "AsyncHRIS", "HRISWithRawResponse", "AsyncHRISWithRawResponse", + "HRISWithStreamingResponse", + "AsyncHRISWithStreamingResponse", "Providers", "AsyncProviders", "ProvidersWithRawResponse", "AsyncProvidersWithRawResponse", + "ProvidersWithStreamingResponse", + "AsyncProvidersWithStreamingResponse", "Account", "AsyncAccount", "AccountWithRawResponse", "AsyncAccountWithRawResponse", + "AccountWithStreamingResponse", + "AsyncAccountWithStreamingResponse", "Webhooks", "AsyncWebhooks", "RequestForwarding", "AsyncRequestForwarding", "RequestForwardingWithRawResponse", "AsyncRequestForwardingWithRawResponse", + "RequestForwardingWithStreamingResponse", + "AsyncRequestForwardingWithStreamingResponse", "Jobs", "AsyncJobs", "JobsWithRawResponse", "AsyncJobsWithRawResponse", + "JobsWithStreamingResponse", + "AsyncJobsWithStreamingResponse", "Sandbox", "AsyncSandbox", "SandboxWithRawResponse", "AsyncSandboxWithRawResponse", + "SandboxWithStreamingResponse", + "AsyncSandboxWithStreamingResponse", ] diff --git a/src/finch/resources/access_tokens.py b/src/finch/resources/access_tokens.py index 161da255..0256050b 100644 --- a/src/finch/resources/access_tokens.py +++ b/src/finch/resources/access_tokens.py @@ -4,12 +4,13 @@ import httpx +from .. import _legacy_response from ..types import CreateAccessTokenResponse, access_token_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .._base_client import ( make_request_options, ) @@ -22,6 +23,10 @@ class AccessTokens(SyncAPIResource): def with_raw_response(self) -> AccessTokensWithRawResponse: return AccessTokensWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AccessTokensWithStreamingResponse: + return AccessTokensWithStreamingResponse(self) + def create( self, *, @@ -71,6 +76,10 @@ class AsyncAccessTokens(AsyncAPIResource): def with_raw_response(self) -> AsyncAccessTokensWithRawResponse: return AsyncAccessTokensWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncAccessTokensWithStreamingResponse: + return AsyncAccessTokensWithStreamingResponse(self) + async def create( self, *, @@ -117,13 +126,27 @@ async def create( class AccessTokensWithRawResponse: def __init__(self, access_tokens: AccessTokens) -> None: - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( access_tokens.create, ) class AsyncAccessTokensWithRawResponse: def __init__(self, access_tokens: AsyncAccessTokens) -> None: - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + access_tokens.create, + ) + + +class AccessTokensWithStreamingResponse: + def __init__(self, access_tokens: AccessTokens) -> None: + self.create = to_streamed_response_wrapper( + access_tokens.create, + ) + + +class AsyncAccessTokensWithStreamingResponse: + def __init__(self, access_tokens: AsyncAccessTokens) -> None: + self.create = async_to_streamed_response_wrapper( access_tokens.create, ) diff --git a/src/finch/resources/account.py b/src/finch/resources/account.py index 04f8eb14..1906b838 100644 --- a/src/finch/resources/account.py +++ b/src/finch/resources/account.py @@ -4,11 +4,12 @@ import httpx +from .. import _legacy_response from ..types import Introspection, DisconnectResponse from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .._base_client import ( make_request_options, ) @@ -21,6 +22,10 @@ class Account(SyncAPIResource): def with_raw_response(self) -> AccountWithRawResponse: return AccountWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AccountWithStreamingResponse: + return AccountWithStreamingResponse(self) + def disconnect( self, *, @@ -69,6 +74,10 @@ class AsyncAccount(AsyncAPIResource): def with_raw_response(self) -> AsyncAccountWithRawResponse: return AsyncAccountWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncAccountWithStreamingResponse: + return AsyncAccountWithStreamingResponse(self) + async def disconnect( self, *, @@ -114,19 +123,39 @@ async def introspect( class AccountWithRawResponse: def __init__(self, account: Account) -> None: - self.disconnect = to_raw_response_wrapper( + self.disconnect = _legacy_response.to_raw_response_wrapper( account.disconnect, ) - self.introspect = to_raw_response_wrapper( + self.introspect = _legacy_response.to_raw_response_wrapper( account.introspect, ) class AsyncAccountWithRawResponse: def __init__(self, account: AsyncAccount) -> None: - self.disconnect = async_to_raw_response_wrapper( + self.disconnect = _legacy_response.async_to_raw_response_wrapper( + account.disconnect, + ) + self.introspect = _legacy_response.async_to_raw_response_wrapper( + account.introspect, + ) + + +class AccountWithStreamingResponse: + def __init__(self, account: Account) -> None: + self.disconnect = to_streamed_response_wrapper( + account.disconnect, + ) + self.introspect = to_streamed_response_wrapper( + account.introspect, + ) + + +class AsyncAccountWithStreamingResponse: + def __init__(self, account: AsyncAccount) -> None: + self.disconnect = async_to_streamed_response_wrapper( account.disconnect, ) - self.introspect = async_to_raw_response_wrapper( + self.introspect = async_to_streamed_response_wrapper( account.introspect, ) diff --git a/src/finch/resources/hris/__init__.py b/src/finch/resources/hris/__init__.py index 8f292e8f..3eea83c6 100644 --- a/src/finch/resources/hris/__init__.py +++ b/src/finch/resources/hris/__init__.py @@ -1,22 +1,68 @@ # File generated from our OpenAPI spec by Stainless. -from .hris import HRIS, AsyncHRIS, HRISWithRawResponse, AsyncHRISWithRawResponse +from .hris import ( + HRIS, + AsyncHRIS, + HRISWithRawResponse, + AsyncHRISWithRawResponse, + HRISWithStreamingResponse, + AsyncHRISWithStreamingResponse, +) from .company import ( CompanyResource, AsyncCompanyResource, CompanyResourceWithRawResponse, AsyncCompanyResourceWithRawResponse, + CompanyResourceWithStreamingResponse, + AsyncCompanyResourceWithStreamingResponse, +) +from .benefits import ( + Benefits, + AsyncBenefits, + BenefitsWithRawResponse, + AsyncBenefitsWithRawResponse, + BenefitsWithStreamingResponse, + AsyncBenefitsWithStreamingResponse, +) +from .payments import ( + Payments, + AsyncPayments, + PaymentsWithRawResponse, + AsyncPaymentsWithRawResponse, + PaymentsWithStreamingResponse, + AsyncPaymentsWithStreamingResponse, +) +from .directory import ( + Directory, + AsyncDirectory, + DirectoryWithRawResponse, + AsyncDirectoryWithRawResponse, + DirectoryWithStreamingResponse, + AsyncDirectoryWithStreamingResponse, +) +from .employments import ( + Employments, + AsyncEmployments, + EmploymentsWithRawResponse, + AsyncEmploymentsWithRawResponse, + EmploymentsWithStreamingResponse, + AsyncEmploymentsWithStreamingResponse, +) +from .individuals import ( + Individuals, + AsyncIndividuals, + IndividualsWithRawResponse, + AsyncIndividualsWithRawResponse, + IndividualsWithStreamingResponse, + AsyncIndividualsWithStreamingResponse, ) -from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse -from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse -from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse -from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse -from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse from .pay_statements import ( PayStatements, AsyncPayStatements, PayStatementsWithRawResponse, AsyncPayStatementsWithRawResponse, + PayStatementsWithStreamingResponse, + AsyncPayStatementsWithStreamingResponse, ) __all__ = [ @@ -24,32 +70,48 @@ "AsyncCompanyResource", "CompanyResourceWithRawResponse", "AsyncCompanyResourceWithRawResponse", + "CompanyResourceWithStreamingResponse", + "AsyncCompanyResourceWithStreamingResponse", "Directory", "AsyncDirectory", "DirectoryWithRawResponse", "AsyncDirectoryWithRawResponse", + "DirectoryWithStreamingResponse", + "AsyncDirectoryWithStreamingResponse", "Individuals", "AsyncIndividuals", "IndividualsWithRawResponse", "AsyncIndividualsWithRawResponse", + "IndividualsWithStreamingResponse", + "AsyncIndividualsWithStreamingResponse", "Employments", "AsyncEmployments", "EmploymentsWithRawResponse", "AsyncEmploymentsWithRawResponse", + "EmploymentsWithStreamingResponse", + "AsyncEmploymentsWithStreamingResponse", "Payments", "AsyncPayments", "PaymentsWithRawResponse", "AsyncPaymentsWithRawResponse", + "PaymentsWithStreamingResponse", + "AsyncPaymentsWithStreamingResponse", "PayStatements", "AsyncPayStatements", "PayStatementsWithRawResponse", "AsyncPayStatementsWithRawResponse", + "PayStatementsWithStreamingResponse", + "AsyncPayStatementsWithStreamingResponse", "Benefits", "AsyncBenefits", "BenefitsWithRawResponse", "AsyncBenefitsWithRawResponse", + "BenefitsWithStreamingResponse", + "AsyncBenefitsWithStreamingResponse", "HRIS", "AsyncHRIS", "HRISWithRawResponse", "AsyncHRISWithRawResponse", + "HRISWithStreamingResponse", + "AsyncHRISWithStreamingResponse", ] diff --git a/src/finch/resources/hris/benefits/__init__.py b/src/finch/resources/hris/benefits/__init__.py index 9a5b9063..07a79df6 100644 --- a/src/finch/resources/hris/benefits/__init__.py +++ b/src/finch/resources/hris/benefits/__init__.py @@ -1,15 +1,33 @@ # File generated from our OpenAPI spec by Stainless. -from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse -from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse +from .benefits import ( + Benefits, + AsyncBenefits, + BenefitsWithRawResponse, + AsyncBenefitsWithRawResponse, + BenefitsWithStreamingResponse, + AsyncBenefitsWithStreamingResponse, +) +from .individuals import ( + Individuals, + AsyncIndividuals, + IndividualsWithRawResponse, + AsyncIndividualsWithRawResponse, + IndividualsWithStreamingResponse, + AsyncIndividualsWithStreamingResponse, +) __all__ = [ "Individuals", "AsyncIndividuals", "IndividualsWithRawResponse", "AsyncIndividualsWithRawResponse", + "IndividualsWithStreamingResponse", + "AsyncIndividualsWithStreamingResponse", "Benefits", "AsyncBenefits", "BenefitsWithRawResponse", "AsyncBenefitsWithRawResponse", + "BenefitsWithStreamingResponse", + "AsyncBenefitsWithStreamingResponse", ] diff --git a/src/finch/resources/hris/benefits/benefits.py b/src/finch/resources/hris/benefits/benefits.py index 9d5f1555..9177f389 100644 --- a/src/finch/resources/hris/benefits/benefits.py +++ b/src/finch/resources/hris/benefits/benefits.py @@ -6,12 +6,20 @@ import httpx +from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._utils import maybe_transform from ...._compat import cached_property -from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse +from .individuals import ( + Individuals, + AsyncIndividuals, + IndividualsWithRawResponse, + AsyncIndividualsWithRawResponse, + IndividualsWithStreamingResponse, + AsyncIndividualsWithStreamingResponse, +) from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ....pagination import SyncSinglePage, AsyncSinglePage from ....types.hris import ( BenefitType, @@ -40,6 +48,10 @@ def individuals(self) -> Individuals: def with_raw_response(self) -> BenefitsWithRawResponse: return BenefitsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> BenefitsWithStreamingResponse: + return BenefitsWithStreamingResponse(self) + def create( self, *, @@ -215,6 +227,10 @@ def individuals(self) -> AsyncIndividuals: def with_raw_response(self) -> AsyncBenefitsWithRawResponse: return AsyncBenefitsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncBenefitsWithStreamingResponse: + return AsyncBenefitsWithStreamingResponse(self) + async def create( self, *, @@ -385,19 +401,19 @@ class BenefitsWithRawResponse: def __init__(self, benefits: Benefits) -> None: self.individuals = IndividualsWithRawResponse(benefits.individuals) - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( benefits.create, ) - self.retrieve = to_raw_response_wrapper( + self.retrieve = _legacy_response.to_raw_response_wrapper( benefits.retrieve, ) - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( benefits.update, ) - self.list = to_raw_response_wrapper( + self.list = _legacy_response.to_raw_response_wrapper( benefits.list, ) - self.list_supported_benefits = to_raw_response_wrapper( + self.list_supported_benefits = _legacy_response.to_raw_response_wrapper( benefits.list_supported_benefits, ) @@ -406,18 +422,60 @@ class AsyncBenefitsWithRawResponse: def __init__(self, benefits: AsyncBenefits) -> None: self.individuals = AsyncIndividualsWithRawResponse(benefits.individuals) - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + benefits.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + benefits.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + benefits.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + benefits.list, + ) + self.list_supported_benefits = _legacy_response.async_to_raw_response_wrapper( + benefits.list_supported_benefits, + ) + + +class BenefitsWithStreamingResponse: + def __init__(self, benefits: Benefits) -> None: + self.individuals = IndividualsWithStreamingResponse(benefits.individuals) + + self.create = to_streamed_response_wrapper( + benefits.create, + ) + self.retrieve = to_streamed_response_wrapper( + benefits.retrieve, + ) + self.update = to_streamed_response_wrapper( + benefits.update, + ) + self.list = to_streamed_response_wrapper( + benefits.list, + ) + self.list_supported_benefits = to_streamed_response_wrapper( + benefits.list_supported_benefits, + ) + + +class AsyncBenefitsWithStreamingResponse: + def __init__(self, benefits: AsyncBenefits) -> None: + self.individuals = AsyncIndividualsWithStreamingResponse(benefits.individuals) + + self.create = async_to_streamed_response_wrapper( benefits.create, ) - self.retrieve = async_to_raw_response_wrapper( + self.retrieve = async_to_streamed_response_wrapper( benefits.retrieve, ) - self.update = async_to_raw_response_wrapper( + self.update = async_to_streamed_response_wrapper( benefits.update, ) - self.list = async_to_raw_response_wrapper( + self.list = async_to_streamed_response_wrapper( benefits.list, ) - self.list_supported_benefits = async_to_raw_response_wrapper( + self.list_supported_benefits = async_to_streamed_response_wrapper( benefits.list_supported_benefits, ) diff --git a/src/finch/resources/hris/benefits/individuals.py b/src/finch/resources/hris/benefits/individuals.py index 4b6a83bb..fe020367 100644 --- a/src/finch/resources/hris/benefits/individuals.py +++ b/src/finch/resources/hris/benefits/individuals.py @@ -6,11 +6,12 @@ import httpx +from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ....pagination import SyncSinglePage, AsyncSinglePage from ...._base_client import ( AsyncPaginator, @@ -34,6 +35,10 @@ class Individuals(SyncAPIResource): def with_raw_response(self) -> IndividualsWithRawResponse: return IndividualsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> IndividualsWithStreamingResponse: + return IndividualsWithStreamingResponse(self) + def enroll_many( self, benefit_id: str, @@ -205,6 +210,10 @@ class AsyncIndividuals(AsyncAPIResource): def with_raw_response(self) -> AsyncIndividualsWithRawResponse: return AsyncIndividualsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncIndividualsWithStreamingResponse: + return AsyncIndividualsWithStreamingResponse(self) + def enroll_many( self, benefit_id: str, @@ -373,31 +382,63 @@ def unenroll_many( class IndividualsWithRawResponse: def __init__(self, individuals: Individuals) -> None: - self.enroll_many = to_raw_response_wrapper( + self.enroll_many = _legacy_response.to_raw_response_wrapper( individuals.enroll_many, ) - self.enrolled_ids = to_raw_response_wrapper( + self.enrolled_ids = _legacy_response.to_raw_response_wrapper( individuals.enrolled_ids, ) - self.retrieve_many_benefits = to_raw_response_wrapper( + self.retrieve_many_benefits = _legacy_response.to_raw_response_wrapper( individuals.retrieve_many_benefits, ) - self.unenroll_many = to_raw_response_wrapper( + self.unenroll_many = _legacy_response.to_raw_response_wrapper( individuals.unenroll_many, ) class AsyncIndividualsWithRawResponse: def __init__(self, individuals: AsyncIndividuals) -> None: - self.enroll_many = async_to_raw_response_wrapper( + self.enroll_many = _legacy_response.async_to_raw_response_wrapper( + individuals.enroll_many, + ) + self.enrolled_ids = _legacy_response.async_to_raw_response_wrapper( + individuals.enrolled_ids, + ) + self.retrieve_many_benefits = _legacy_response.async_to_raw_response_wrapper( + individuals.retrieve_many_benefits, + ) + self.unenroll_many = _legacy_response.async_to_raw_response_wrapper( + individuals.unenroll_many, + ) + + +class IndividualsWithStreamingResponse: + def __init__(self, individuals: Individuals) -> None: + self.enroll_many = to_streamed_response_wrapper( + individuals.enroll_many, + ) + self.enrolled_ids = to_streamed_response_wrapper( + individuals.enrolled_ids, + ) + self.retrieve_many_benefits = to_streamed_response_wrapper( + individuals.retrieve_many_benefits, + ) + self.unenroll_many = to_streamed_response_wrapper( + individuals.unenroll_many, + ) + + +class AsyncIndividualsWithStreamingResponse: + def __init__(self, individuals: AsyncIndividuals) -> None: + self.enroll_many = async_to_streamed_response_wrapper( individuals.enroll_many, ) - self.enrolled_ids = async_to_raw_response_wrapper( + self.enrolled_ids = async_to_streamed_response_wrapper( individuals.enrolled_ids, ) - self.retrieve_many_benefits = async_to_raw_response_wrapper( + self.retrieve_many_benefits = async_to_streamed_response_wrapper( individuals.retrieve_many_benefits, ) - self.unenroll_many = async_to_raw_response_wrapper( + self.unenroll_many = async_to_streamed_response_wrapper( individuals.unenroll_many, ) diff --git a/src/finch/resources/hris/company.py b/src/finch/resources/hris/company.py index 2a73d3b3..56570e7c 100644 --- a/src/finch/resources/hris/company.py +++ b/src/finch/resources/hris/company.py @@ -4,10 +4,11 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...types.hris import Company from ..._base_client import ( make_request_options, @@ -21,6 +22,10 @@ class CompanyResource(SyncAPIResource): def with_raw_response(self) -> CompanyResourceWithRawResponse: return CompanyResourceWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> CompanyResourceWithStreamingResponse: + return CompanyResourceWithStreamingResponse(self) + def retrieve( self, *, @@ -46,6 +51,10 @@ class AsyncCompanyResource(AsyncAPIResource): def with_raw_response(self) -> AsyncCompanyResourceWithRawResponse: return AsyncCompanyResourceWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncCompanyResourceWithStreamingResponse: + return AsyncCompanyResourceWithStreamingResponse(self) + async def retrieve( self, *, @@ -68,13 +77,27 @@ async def retrieve( class CompanyResourceWithRawResponse: def __init__(self, company: CompanyResource) -> None: - self.retrieve = to_raw_response_wrapper( + self.retrieve = _legacy_response.to_raw_response_wrapper( company.retrieve, ) class AsyncCompanyResourceWithRawResponse: def __init__(self, company: AsyncCompanyResource) -> None: - self.retrieve = async_to_raw_response_wrapper( + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + company.retrieve, + ) + + +class CompanyResourceWithStreamingResponse: + def __init__(self, company: CompanyResource) -> None: + self.retrieve = to_streamed_response_wrapper( + company.retrieve, + ) + + +class AsyncCompanyResourceWithStreamingResponse: + def __init__(self, company: AsyncCompanyResource) -> None: + self.retrieve = async_to_streamed_response_wrapper( company.retrieve, ) diff --git a/src/finch/resources/hris/directory.py b/src/finch/resources/hris/directory.py index 5c4e3930..ef283cb9 100644 --- a/src/finch/resources/hris/directory.py +++ b/src/finch/resources/hris/directory.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncIndividualsPage, AsyncIndividualsPage from ...types.hris import IndividualInDirectory, directory_list_params from ..._base_client import ( @@ -26,6 +27,10 @@ class Directory(SyncAPIResource): def with_raw_response(self) -> DirectoryWithRawResponse: return DirectoryWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> DirectoryWithStreamingResponse: + return DirectoryWithStreamingResponse(self) + def list( self, *, @@ -117,6 +122,10 @@ class AsyncDirectory(AsyncAPIResource): def with_raw_response(self) -> AsyncDirectoryWithRawResponse: return AsyncDirectoryWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncDirectoryWithStreamingResponse: + return AsyncDirectoryWithStreamingResponse(self) + def list( self, *, @@ -205,19 +214,47 @@ def list_individuals( class DirectoryWithRawResponse: def __init__(self, directory: Directory) -> None: - self.list = to_raw_response_wrapper( + self.list = _legacy_response.to_raw_response_wrapper( directory.list, ) - self.list_individuals = to_raw_response_wrapper( # pyright: ignore[reportDeprecated] - directory.list_individuals # pyright: ignore[reportDeprecated], + self.list_individuals = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + directory.list_individuals # pyright: ignore[reportDeprecated], + ) ) class AsyncDirectoryWithRawResponse: def __init__(self, directory: AsyncDirectory) -> None: - self.list = async_to_raw_response_wrapper( + self.list = _legacy_response.async_to_raw_response_wrapper( + directory.list, + ) + self.list_individuals = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + directory.list_individuals # pyright: ignore[reportDeprecated], + ) + ) + + +class DirectoryWithStreamingResponse: + def __init__(self, directory: Directory) -> None: + self.list = to_streamed_response_wrapper( + directory.list, + ) + self.list_individuals = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + directory.list_individuals # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncDirectoryWithStreamingResponse: + def __init__(self, directory: AsyncDirectory) -> None: + self.list = async_to_streamed_response_wrapper( directory.list, ) - self.list_individuals = async_to_raw_response_wrapper( # pyright: ignore[reportDeprecated] - directory.list_individuals # pyright: ignore[reportDeprecated], + self.list_individuals = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + directory.list_individuals # pyright: ignore[reportDeprecated], + ) ) diff --git a/src/finch/resources/hris/employments.py b/src/finch/resources/hris/employments.py index d44b32a1..ab9d375e 100644 --- a/src/finch/resources/hris/employments.py +++ b/src/finch/resources/hris/employments.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncResponsesPage, AsyncResponsesPage from ...types.hris import EmploymentDataResponse, employment_retrieve_many_params from ..._base_client import ( @@ -26,6 +27,10 @@ class Employments(SyncAPIResource): def with_raw_response(self) -> EmploymentsWithRawResponse: return EmploymentsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> EmploymentsWithStreamingResponse: + return EmploymentsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -72,6 +77,10 @@ class AsyncEmployments(AsyncAPIResource): def with_raw_response(self) -> AsyncEmploymentsWithRawResponse: return AsyncEmploymentsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncEmploymentsWithStreamingResponse: + return AsyncEmploymentsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -115,13 +124,27 @@ def retrieve_many( class EmploymentsWithRawResponse: def __init__(self, employments: Employments) -> None: - self.retrieve_many = to_raw_response_wrapper( + self.retrieve_many = _legacy_response.to_raw_response_wrapper( employments.retrieve_many, ) class AsyncEmploymentsWithRawResponse: def __init__(self, employments: AsyncEmployments) -> None: - self.retrieve_many = async_to_raw_response_wrapper( + self.retrieve_many = _legacy_response.async_to_raw_response_wrapper( + employments.retrieve_many, + ) + + +class EmploymentsWithStreamingResponse: + def __init__(self, employments: Employments) -> None: + self.retrieve_many = to_streamed_response_wrapper( + employments.retrieve_many, + ) + + +class AsyncEmploymentsWithStreamingResponse: + def __init__(self, employments: AsyncEmployments) -> None: + self.retrieve_many = async_to_streamed_response_wrapper( employments.retrieve_many, ) diff --git a/src/finch/resources/hris/hris.py b/src/finch/resources/hris/hris.py index e02ebae1..4cca0f46 100644 --- a/src/finch/resources/hris/hris.py +++ b/src/finch/resources/hris/hris.py @@ -7,19 +7,58 @@ AsyncCompanyResource, CompanyResourceWithRawResponse, AsyncCompanyResourceWithRawResponse, + CompanyResourceWithStreamingResponse, + AsyncCompanyResourceWithStreamingResponse, +) +from .benefits import ( + Benefits, + AsyncBenefits, + BenefitsWithRawResponse, + AsyncBenefitsWithRawResponse, + BenefitsWithStreamingResponse, + AsyncBenefitsWithStreamingResponse, +) +from .payments import ( + Payments, + AsyncPayments, + PaymentsWithRawResponse, + AsyncPaymentsWithRawResponse, + PaymentsWithStreamingResponse, + AsyncPaymentsWithStreamingResponse, ) -from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse -from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse from ..._compat import cached_property -from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse +from .directory import ( + Directory, + AsyncDirectory, + DirectoryWithRawResponse, + AsyncDirectoryWithRawResponse, + DirectoryWithStreamingResponse, + AsyncDirectoryWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource -from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse -from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse +from .employments import ( + Employments, + AsyncEmployments, + EmploymentsWithRawResponse, + AsyncEmploymentsWithRawResponse, + EmploymentsWithStreamingResponse, + AsyncEmploymentsWithStreamingResponse, +) +from .individuals import ( + Individuals, + AsyncIndividuals, + IndividualsWithRawResponse, + AsyncIndividualsWithRawResponse, + IndividualsWithStreamingResponse, + AsyncIndividualsWithStreamingResponse, +) from .pay_statements import ( PayStatements, AsyncPayStatements, PayStatementsWithRawResponse, AsyncPayStatementsWithRawResponse, + PayStatementsWithStreamingResponse, + AsyncPayStatementsWithStreamingResponse, ) from .benefits.benefits import Benefits, AsyncBenefits @@ -59,6 +98,10 @@ def benefits(self) -> Benefits: def with_raw_response(self) -> HRISWithRawResponse: return HRISWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> HRISWithStreamingResponse: + return HRISWithStreamingResponse(self) + class AsyncHRIS(AsyncAPIResource): @cached_property @@ -93,6 +136,10 @@ def benefits(self) -> AsyncBenefits: def with_raw_response(self) -> AsyncHRISWithRawResponse: return AsyncHRISWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncHRISWithStreamingResponse: + return AsyncHRISWithStreamingResponse(self) + class HRISWithRawResponse: def __init__(self, hris: HRIS) -> None: @@ -114,3 +161,25 @@ def __init__(self, hris: AsyncHRIS) -> None: self.payments = AsyncPaymentsWithRawResponse(hris.payments) self.pay_statements = AsyncPayStatementsWithRawResponse(hris.pay_statements) self.benefits = AsyncBenefitsWithRawResponse(hris.benefits) + + +class HRISWithStreamingResponse: + def __init__(self, hris: HRIS) -> None: + self.company = CompanyResourceWithStreamingResponse(hris.company) + self.directory = DirectoryWithStreamingResponse(hris.directory) + self.individuals = IndividualsWithStreamingResponse(hris.individuals) + self.employments = EmploymentsWithStreamingResponse(hris.employments) + self.payments = PaymentsWithStreamingResponse(hris.payments) + self.pay_statements = PayStatementsWithStreamingResponse(hris.pay_statements) + self.benefits = BenefitsWithStreamingResponse(hris.benefits) + + +class AsyncHRISWithStreamingResponse: + def __init__(self, hris: AsyncHRIS) -> None: + self.company = AsyncCompanyResourceWithStreamingResponse(hris.company) + self.directory = AsyncDirectoryWithStreamingResponse(hris.directory) + self.individuals = AsyncIndividualsWithStreamingResponse(hris.individuals) + self.employments = AsyncEmploymentsWithStreamingResponse(hris.employments) + self.payments = AsyncPaymentsWithStreamingResponse(hris.payments) + self.pay_statements = AsyncPayStatementsWithStreamingResponse(hris.pay_statements) + self.benefits = AsyncBenefitsWithStreamingResponse(hris.benefits) diff --git a/src/finch/resources/hris/individuals.py b/src/finch/resources/hris/individuals.py index 4eea801e..dc8fb83f 100644 --- a/src/finch/resources/hris/individuals.py +++ b/src/finch/resources/hris/individuals.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncResponsesPage, AsyncResponsesPage from ...types.hris import IndividualResponse, individual_retrieve_many_params from ..._base_client import ( @@ -26,6 +27,10 @@ class Individuals(SyncAPIResource): def with_raw_response(self) -> IndividualsWithRawResponse: return IndividualsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> IndividualsWithStreamingResponse: + return IndividualsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -73,6 +78,10 @@ class AsyncIndividuals(AsyncAPIResource): def with_raw_response(self) -> AsyncIndividualsWithRawResponse: return AsyncIndividualsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncIndividualsWithStreamingResponse: + return AsyncIndividualsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -117,13 +126,27 @@ def retrieve_many( class IndividualsWithRawResponse: def __init__(self, individuals: Individuals) -> None: - self.retrieve_many = to_raw_response_wrapper( + self.retrieve_many = _legacy_response.to_raw_response_wrapper( individuals.retrieve_many, ) class AsyncIndividualsWithRawResponse: def __init__(self, individuals: AsyncIndividuals) -> None: - self.retrieve_many = async_to_raw_response_wrapper( + self.retrieve_many = _legacy_response.async_to_raw_response_wrapper( + individuals.retrieve_many, + ) + + +class IndividualsWithStreamingResponse: + def __init__(self, individuals: Individuals) -> None: + self.retrieve_many = to_streamed_response_wrapper( + individuals.retrieve_many, + ) + + +class AsyncIndividualsWithStreamingResponse: + def __init__(self, individuals: AsyncIndividuals) -> None: + self.retrieve_many = async_to_streamed_response_wrapper( individuals.retrieve_many, ) diff --git a/src/finch/resources/hris/pay_statements.py b/src/finch/resources/hris/pay_statements.py index 46eea68f..0debe47d 100644 --- a/src/finch/resources/hris/pay_statements.py +++ b/src/finch/resources/hris/pay_statements.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncResponsesPage, AsyncResponsesPage from ...types.hris import PayStatementResponse, pay_statement_retrieve_many_params from ..._base_client import ( @@ -26,6 +27,10 @@ class PayStatements(SyncAPIResource): def with_raw_response(self) -> PayStatementsWithRawResponse: return PayStatementsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> PayStatementsWithStreamingResponse: + return PayStatementsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -73,6 +78,10 @@ class AsyncPayStatements(AsyncAPIResource): def with_raw_response(self) -> AsyncPayStatementsWithRawResponse: return AsyncPayStatementsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncPayStatementsWithStreamingResponse: + return AsyncPayStatementsWithStreamingResponse(self) + def retrieve_many( self, *, @@ -117,13 +126,27 @@ def retrieve_many( class PayStatementsWithRawResponse: def __init__(self, pay_statements: PayStatements) -> None: - self.retrieve_many = to_raw_response_wrapper( + self.retrieve_many = _legacy_response.to_raw_response_wrapper( pay_statements.retrieve_many, ) class AsyncPayStatementsWithRawResponse: def __init__(self, pay_statements: AsyncPayStatements) -> None: - self.retrieve_many = async_to_raw_response_wrapper( + self.retrieve_many = _legacy_response.async_to_raw_response_wrapper( + pay_statements.retrieve_many, + ) + + +class PayStatementsWithStreamingResponse: + def __init__(self, pay_statements: PayStatements) -> None: + self.retrieve_many = to_streamed_response_wrapper( + pay_statements.retrieve_many, + ) + + +class AsyncPayStatementsWithStreamingResponse: + def __init__(self, pay_statements: AsyncPayStatements) -> None: + self.retrieve_many = async_to_streamed_response_wrapper( pay_statements.retrieve_many, ) diff --git a/src/finch/resources/hris/payments.py b/src/finch/resources/hris/payments.py index 50ed186d..6ef8418f 100644 --- a/src/finch/resources/hris/payments.py +++ b/src/finch/resources/hris/payments.py @@ -7,11 +7,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncSinglePage, AsyncSinglePage from ...types.hris import Payment, payment_list_params from ..._base_client import ( @@ -27,6 +28,10 @@ class Payments(SyncAPIResource): def with_raw_response(self) -> PaymentsWithRawResponse: return PaymentsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> PaymentsWithStreamingResponse: + return PaymentsWithStreamingResponse(self) + def list( self, *, @@ -82,6 +87,10 @@ class AsyncPayments(AsyncAPIResource): def with_raw_response(self) -> AsyncPaymentsWithRawResponse: return AsyncPaymentsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncPaymentsWithStreamingResponse: + return AsyncPaymentsWithStreamingResponse(self) + def list( self, *, @@ -134,13 +143,27 @@ def list( class PaymentsWithRawResponse: def __init__(self, payments: Payments) -> None: - self.list = to_raw_response_wrapper( + self.list = _legacy_response.to_raw_response_wrapper( payments.list, ) class AsyncPaymentsWithRawResponse: def __init__(self, payments: AsyncPayments) -> None: - self.list = async_to_raw_response_wrapper( + self.list = _legacy_response.async_to_raw_response_wrapper( + payments.list, + ) + + +class PaymentsWithStreamingResponse: + def __init__(self, payments: Payments) -> None: + self.list = to_streamed_response_wrapper( + payments.list, + ) + + +class AsyncPaymentsWithStreamingResponse: + def __init__(self, payments: AsyncPayments) -> None: + self.list = async_to_streamed_response_wrapper( payments.list, ) diff --git a/src/finch/resources/jobs/__init__.py b/src/finch/resources/jobs/__init__.py index 112d3130..261436d7 100644 --- a/src/finch/resources/jobs/__init__.py +++ b/src/finch/resources/jobs/__init__.py @@ -1,20 +1,47 @@ # File generated from our OpenAPI spec by Stainless. -from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse -from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse -from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse +from .jobs import ( + Jobs, + AsyncJobs, + JobsWithRawResponse, + AsyncJobsWithRawResponse, + JobsWithStreamingResponse, + AsyncJobsWithStreamingResponse, +) +from .manual import ( + Manual, + AsyncManual, + ManualWithRawResponse, + AsyncManualWithRawResponse, + ManualWithStreamingResponse, + AsyncManualWithStreamingResponse, +) +from .automated import ( + Automated, + AsyncAutomated, + AutomatedWithRawResponse, + AsyncAutomatedWithRawResponse, + AutomatedWithStreamingResponse, + AsyncAutomatedWithStreamingResponse, +) __all__ = [ "Automated", "AsyncAutomated", "AutomatedWithRawResponse", "AsyncAutomatedWithRawResponse", + "AutomatedWithStreamingResponse", + "AsyncAutomatedWithStreamingResponse", "Manual", "AsyncManual", "ManualWithRawResponse", "AsyncManualWithRawResponse", + "ManualWithStreamingResponse", + "AsyncManualWithStreamingResponse", "Jobs", "AsyncJobs", "JobsWithRawResponse", "AsyncJobsWithRawResponse", + "JobsWithStreamingResponse", + "AsyncJobsWithStreamingResponse", ] diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py index 990f9033..3d6718ad 100644 --- a/src/finch/resources/jobs/automated.py +++ b/src/finch/resources/jobs/automated.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncPage, AsyncPage from ...types.jobs import AutomatedAsyncJob, AutomatedCreateResponse, automated_list_params, automated_create_params from ..._base_client import ( @@ -26,6 +27,10 @@ class Automated(SyncAPIResource): def with_raw_response(self) -> AutomatedWithRawResponse: return AutomatedWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AutomatedWithStreamingResponse: + return AutomatedWithStreamingResponse(self) + def create( self, *, @@ -157,6 +162,10 @@ class AsyncAutomated(AsyncAPIResource): def with_raw_response(self) -> AsyncAutomatedWithRawResponse: return AsyncAutomatedWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncAutomatedWithStreamingResponse: + return AsyncAutomatedWithStreamingResponse(self) + async def create( self, *, @@ -285,25 +294,51 @@ def list( class AutomatedWithRawResponse: def __init__(self, automated: Automated) -> None: - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( automated.create, ) - self.retrieve = to_raw_response_wrapper( + self.retrieve = _legacy_response.to_raw_response_wrapper( automated.retrieve, ) - self.list = to_raw_response_wrapper( + self.list = _legacy_response.to_raw_response_wrapper( automated.list, ) class AsyncAutomatedWithRawResponse: def __init__(self, automated: AsyncAutomated) -> None: - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + automated.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + automated.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + automated.list, + ) + + +class AutomatedWithStreamingResponse: + def __init__(self, automated: Automated) -> None: + self.create = to_streamed_response_wrapper( + automated.create, + ) + self.retrieve = to_streamed_response_wrapper( + automated.retrieve, + ) + self.list = to_streamed_response_wrapper( + automated.list, + ) + + +class AsyncAutomatedWithStreamingResponse: + def __init__(self, automated: AsyncAutomated) -> None: + self.create = async_to_streamed_response_wrapper( automated.create, ) - self.retrieve = async_to_raw_response_wrapper( + self.retrieve = async_to_streamed_response_wrapper( automated.retrieve, ) - self.list = async_to_raw_response_wrapper( + self.list = async_to_streamed_response_wrapper( automated.list, ) diff --git a/src/finch/resources/jobs/jobs.py b/src/finch/resources/jobs/jobs.py index 314cd630..da6edf59 100644 --- a/src/finch/resources/jobs/jobs.py +++ b/src/finch/resources/jobs/jobs.py @@ -2,9 +2,23 @@ from __future__ import annotations -from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse +from .manual import ( + Manual, + AsyncManual, + ManualWithRawResponse, + AsyncManualWithRawResponse, + ManualWithStreamingResponse, + AsyncManualWithStreamingResponse, +) from ..._compat import cached_property -from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse +from .automated import ( + Automated, + AsyncAutomated, + AutomatedWithRawResponse, + AsyncAutomatedWithRawResponse, + AutomatedWithStreamingResponse, + AsyncAutomatedWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource __all__ = ["Jobs", "AsyncJobs"] @@ -23,6 +37,10 @@ def manual(self) -> Manual: def with_raw_response(self) -> JobsWithRawResponse: return JobsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> JobsWithStreamingResponse: + return JobsWithStreamingResponse(self) + class AsyncJobs(AsyncAPIResource): @cached_property @@ -37,6 +55,10 @@ def manual(self) -> AsyncManual: def with_raw_response(self) -> AsyncJobsWithRawResponse: return AsyncJobsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncJobsWithStreamingResponse: + return AsyncJobsWithStreamingResponse(self) + class JobsWithRawResponse: def __init__(self, jobs: Jobs) -> None: @@ -48,3 +70,15 @@ class AsyncJobsWithRawResponse: def __init__(self, jobs: AsyncJobs) -> None: self.automated = AsyncAutomatedWithRawResponse(jobs.automated) self.manual = AsyncManualWithRawResponse(jobs.manual) + + +class JobsWithStreamingResponse: + def __init__(self, jobs: Jobs) -> None: + self.automated = AutomatedWithStreamingResponse(jobs.automated) + self.manual = ManualWithStreamingResponse(jobs.manual) + + +class AsyncJobsWithStreamingResponse: + def __init__(self, jobs: AsyncJobs) -> None: + self.automated = AsyncAutomatedWithStreamingResponse(jobs.automated) + self.manual = AsyncManualWithStreamingResponse(jobs.manual) diff --git a/src/finch/resources/jobs/manual.py b/src/finch/resources/jobs/manual.py index 565513a4..85b919a6 100644 --- a/src/finch/resources/jobs/manual.py +++ b/src/finch/resources/jobs/manual.py @@ -4,10 +4,11 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...types.jobs import ManualAsyncJob from ..._base_client import ( make_request_options, @@ -21,6 +22,10 @@ class Manual(SyncAPIResource): def with_raw_response(self) -> ManualWithRawResponse: return ManualWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> ManualWithStreamingResponse: + return ManualWithStreamingResponse(self) + def retrieve( self, job_id: str, @@ -60,6 +65,10 @@ class AsyncManual(AsyncAPIResource): def with_raw_response(self) -> AsyncManualWithRawResponse: return AsyncManualWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncManualWithStreamingResponse: + return AsyncManualWithStreamingResponse(self) + async def retrieve( self, job_id: str, @@ -96,13 +105,27 @@ async def retrieve( class ManualWithRawResponse: def __init__(self, manual: Manual) -> None: - self.retrieve = to_raw_response_wrapper( + self.retrieve = _legacy_response.to_raw_response_wrapper( manual.retrieve, ) class AsyncManualWithRawResponse: def __init__(self, manual: AsyncManual) -> None: - self.retrieve = async_to_raw_response_wrapper( + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + manual.retrieve, + ) + + +class ManualWithStreamingResponse: + def __init__(self, manual: Manual) -> None: + self.retrieve = to_streamed_response_wrapper( + manual.retrieve, + ) + + +class AsyncManualWithStreamingResponse: + def __init__(self, manual: AsyncManual) -> None: + self.retrieve = async_to_streamed_response_wrapper( manual.retrieve, ) diff --git a/src/finch/resources/providers.py b/src/finch/resources/providers.py index bac6a203..ba090b6d 100644 --- a/src/finch/resources/providers.py +++ b/src/finch/resources/providers.py @@ -4,11 +4,12 @@ import httpx +from .. import _legacy_response from ..types import Provider from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..pagination import SyncSinglePage, AsyncSinglePage from .._base_client import ( AsyncPaginator, @@ -23,6 +24,10 @@ class Providers(SyncAPIResource): def with_raw_response(self) -> ProvidersWithRawResponse: return ProvidersWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> ProvidersWithStreamingResponse: + return ProvidersWithStreamingResponse(self) + def list( self, *, @@ -49,6 +54,10 @@ class AsyncProviders(AsyncAPIResource): def with_raw_response(self) -> AsyncProvidersWithRawResponse: return AsyncProvidersWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncProvidersWithStreamingResponse: + return AsyncProvidersWithStreamingResponse(self) + def list( self, *, @@ -72,13 +81,27 @@ def list( class ProvidersWithRawResponse: def __init__(self, providers: Providers) -> None: - self.list = to_raw_response_wrapper( + self.list = _legacy_response.to_raw_response_wrapper( providers.list, ) class AsyncProvidersWithRawResponse: def __init__(self, providers: AsyncProviders) -> None: - self.list = async_to_raw_response_wrapper( + self.list = _legacy_response.async_to_raw_response_wrapper( + providers.list, + ) + + +class ProvidersWithStreamingResponse: + def __init__(self, providers: Providers) -> None: + self.list = to_streamed_response_wrapper( + providers.list, + ) + + +class AsyncProvidersWithStreamingResponse: + def __init__(self, providers: AsyncProviders) -> None: + self.list = async_to_streamed_response_wrapper( providers.list, ) diff --git a/src/finch/resources/request_forwarding.py b/src/finch/resources/request_forwarding.py index 90bd0f13..f89250fc 100644 --- a/src/finch/resources/request_forwarding.py +++ b/src/finch/resources/request_forwarding.py @@ -6,12 +6,13 @@ import httpx +from .. import _legacy_response from ..types import RequestForwardingForwardResponse, request_forwarding_forward_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .._base_client import ( make_request_options, ) @@ -24,6 +25,10 @@ class RequestForwarding(SyncAPIResource): def with_raw_response(self) -> RequestForwardingWithRawResponse: return RequestForwardingWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> RequestForwardingWithStreamingResponse: + return RequestForwardingWithStreamingResponse(self) + def forward( self, *, @@ -96,6 +101,10 @@ class AsyncRequestForwarding(AsyncAPIResource): def with_raw_response(self) -> AsyncRequestForwardingWithRawResponse: return AsyncRequestForwardingWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncRequestForwardingWithStreamingResponse: + return AsyncRequestForwardingWithStreamingResponse(self) + async def forward( self, *, @@ -165,13 +174,27 @@ async def forward( class RequestForwardingWithRawResponse: def __init__(self, request_forwarding: RequestForwarding) -> None: - self.forward = to_raw_response_wrapper( + self.forward = _legacy_response.to_raw_response_wrapper( request_forwarding.forward, ) class AsyncRequestForwardingWithRawResponse: def __init__(self, request_forwarding: AsyncRequestForwarding) -> None: - self.forward = async_to_raw_response_wrapper( + self.forward = _legacy_response.async_to_raw_response_wrapper( + request_forwarding.forward, + ) + + +class RequestForwardingWithStreamingResponse: + def __init__(self, request_forwarding: RequestForwarding) -> None: + self.forward = to_streamed_response_wrapper( + request_forwarding.forward, + ) + + +class AsyncRequestForwardingWithStreamingResponse: + def __init__(self, request_forwarding: AsyncRequestForwarding) -> None: + self.forward = async_to_streamed_response_wrapper( request_forwarding.forward, ) diff --git a/src/finch/resources/sandbox/__init__.py b/src/finch/resources/sandbox/__init__.py index 41f27f60..0c8d6436 100644 --- a/src/finch/resources/sandbox/__init__.py +++ b/src/finch/resources/sandbox/__init__.py @@ -1,45 +1,117 @@ # File generated from our OpenAPI spec by Stainless. -from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse -from .company import Company, AsyncCompany, CompanyWithRawResponse, AsyncCompanyWithRawResponse -from .payment import Payment, AsyncPayment, PaymentWithRawResponse, AsyncPaymentWithRawResponse -from .sandbox import Sandbox, AsyncSandbox, SandboxWithRawResponse, AsyncSandboxWithRawResponse -from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse -from .employment import Employment, AsyncEmployment, EmploymentWithRawResponse, AsyncEmploymentWithRawResponse -from .individual import Individual, AsyncIndividual, IndividualWithRawResponse, AsyncIndividualWithRawResponse -from .connections import Connections, AsyncConnections, ConnectionsWithRawResponse, AsyncConnectionsWithRawResponse +from .jobs import ( + Jobs, + AsyncJobs, + JobsWithRawResponse, + AsyncJobsWithRawResponse, + JobsWithStreamingResponse, + AsyncJobsWithStreamingResponse, +) +from .company import ( + Company, + AsyncCompany, + CompanyWithRawResponse, + AsyncCompanyWithRawResponse, + CompanyWithStreamingResponse, + AsyncCompanyWithStreamingResponse, +) +from .payment import ( + Payment, + AsyncPayment, + PaymentWithRawResponse, + AsyncPaymentWithRawResponse, + PaymentWithStreamingResponse, + AsyncPaymentWithStreamingResponse, +) +from .sandbox import ( + Sandbox, + AsyncSandbox, + SandboxWithRawResponse, + AsyncSandboxWithRawResponse, + SandboxWithStreamingResponse, + AsyncSandboxWithStreamingResponse, +) +from .directory import ( + Directory, + AsyncDirectory, + DirectoryWithRawResponse, + AsyncDirectoryWithRawResponse, + DirectoryWithStreamingResponse, + AsyncDirectoryWithStreamingResponse, +) +from .employment import ( + Employment, + AsyncEmployment, + EmploymentWithRawResponse, + AsyncEmploymentWithRawResponse, + EmploymentWithStreamingResponse, + AsyncEmploymentWithStreamingResponse, +) +from .individual import ( + Individual, + AsyncIndividual, + IndividualWithRawResponse, + AsyncIndividualWithRawResponse, + IndividualWithStreamingResponse, + AsyncIndividualWithStreamingResponse, +) +from .connections import ( + Connections, + AsyncConnections, + ConnectionsWithRawResponse, + AsyncConnectionsWithRawResponse, + ConnectionsWithStreamingResponse, + AsyncConnectionsWithStreamingResponse, +) __all__ = [ "Connections", "AsyncConnections", "ConnectionsWithRawResponse", "AsyncConnectionsWithRawResponse", + "ConnectionsWithStreamingResponse", + "AsyncConnectionsWithStreamingResponse", "Company", "AsyncCompany", "CompanyWithRawResponse", "AsyncCompanyWithRawResponse", + "CompanyWithStreamingResponse", + "AsyncCompanyWithStreamingResponse", "Directory", "AsyncDirectory", "DirectoryWithRawResponse", "AsyncDirectoryWithRawResponse", + "DirectoryWithStreamingResponse", + "AsyncDirectoryWithStreamingResponse", "Individual", "AsyncIndividual", "IndividualWithRawResponse", "AsyncIndividualWithRawResponse", + "IndividualWithStreamingResponse", + "AsyncIndividualWithStreamingResponse", "Employment", "AsyncEmployment", "EmploymentWithRawResponse", "AsyncEmploymentWithRawResponse", + "EmploymentWithStreamingResponse", + "AsyncEmploymentWithStreamingResponse", "Payment", "AsyncPayment", "PaymentWithRawResponse", "AsyncPaymentWithRawResponse", + "PaymentWithStreamingResponse", + "AsyncPaymentWithStreamingResponse", "Jobs", "AsyncJobs", "JobsWithRawResponse", "AsyncJobsWithRawResponse", + "JobsWithStreamingResponse", + "AsyncJobsWithStreamingResponse", "Sandbox", "AsyncSandbox", "SandboxWithRawResponse", "AsyncSandboxWithRawResponse", + "SandboxWithStreamingResponse", + "AsyncSandboxWithStreamingResponse", ] diff --git a/src/finch/resources/sandbox/company.py b/src/finch/resources/sandbox/company.py index 82bb0239..531c8a71 100644 --- a/src/finch/resources/sandbox/company.py +++ b/src/finch/resources/sandbox/company.py @@ -6,12 +6,13 @@ import httpx +from ... import _legacy_response from ...types import LocationParam from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._base_client import ( make_request_options, ) @@ -25,6 +26,10 @@ class Company(SyncAPIResource): def with_raw_response(self) -> CompanyWithRawResponse: return CompanyWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> CompanyWithStreamingResponse: + return CompanyWithStreamingResponse(self) + def update( self, *, @@ -96,6 +101,10 @@ class AsyncCompany(AsyncAPIResource): def with_raw_response(self) -> AsyncCompanyWithRawResponse: return AsyncCompanyWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncCompanyWithStreamingResponse: + return AsyncCompanyWithStreamingResponse(self) + async def update( self, *, @@ -164,13 +173,27 @@ async def update( class CompanyWithRawResponse: def __init__(self, company: Company) -> None: - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( company.update, ) class AsyncCompanyWithRawResponse: def __init__(self, company: AsyncCompany) -> None: - self.update = async_to_raw_response_wrapper( + self.update = _legacy_response.async_to_raw_response_wrapper( + company.update, + ) + + +class CompanyWithStreamingResponse: + def __init__(self, company: Company) -> None: + self.update = to_streamed_response_wrapper( + company.update, + ) + + +class AsyncCompanyWithStreamingResponse: + def __init__(self, company: AsyncCompany) -> None: + self.update = async_to_streamed_response_wrapper( company.update, ) diff --git a/src/finch/resources/sandbox/connections/__init__.py b/src/finch/resources/sandbox/connections/__init__.py index 747635e9..053ae309 100644 --- a/src/finch/resources/sandbox/connections/__init__.py +++ b/src/finch/resources/sandbox/connections/__init__.py @@ -1,15 +1,33 @@ # File generated from our OpenAPI spec by Stainless. -from .accounts import Accounts, AsyncAccounts, AccountsWithRawResponse, AsyncAccountsWithRawResponse -from .connections import Connections, AsyncConnections, ConnectionsWithRawResponse, AsyncConnectionsWithRawResponse +from .accounts import ( + Accounts, + AsyncAccounts, + AccountsWithRawResponse, + AsyncAccountsWithRawResponse, + AccountsWithStreamingResponse, + AsyncAccountsWithStreamingResponse, +) +from .connections import ( + Connections, + AsyncConnections, + ConnectionsWithRawResponse, + AsyncConnectionsWithRawResponse, + ConnectionsWithStreamingResponse, + AsyncConnectionsWithStreamingResponse, +) __all__ = [ "Accounts", "AsyncAccounts", "AccountsWithRawResponse", "AsyncAccountsWithRawResponse", + "AccountsWithStreamingResponse", + "AsyncAccountsWithStreamingResponse", "Connections", "AsyncConnections", "ConnectionsWithRawResponse", "AsyncConnectionsWithRawResponse", + "ConnectionsWithStreamingResponse", + "AsyncConnectionsWithStreamingResponse", ] diff --git a/src/finch/resources/sandbox/connections/accounts.py b/src/finch/resources/sandbox/connections/accounts.py index 98008ee3..14770673 100644 --- a/src/finch/resources/sandbox/connections/accounts.py +++ b/src/finch/resources/sandbox/connections/accounts.py @@ -7,11 +7,12 @@ import httpx +from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._base_client import ( make_request_options, ) @@ -31,6 +32,10 @@ class Accounts(SyncAPIResource): def with_raw_response(self) -> AccountsWithRawResponse: return AccountsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AccountsWithStreamingResponse: + return AccountsWithStreamingResponse(self) + def create( self, *, @@ -117,6 +122,10 @@ class AsyncAccounts(AsyncAPIResource): def with_raw_response(self) -> AsyncAccountsWithRawResponse: return AsyncAccountsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncAccountsWithStreamingResponse: + return AsyncAccountsWithStreamingResponse(self) + async def create( self, *, @@ -200,19 +209,39 @@ async def update( class AccountsWithRawResponse: def __init__(self, accounts: Accounts) -> None: - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( accounts.create, ) - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( accounts.update, ) class AsyncAccountsWithRawResponse: def __init__(self, accounts: AsyncAccounts) -> None: - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + accounts.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + accounts.update, + ) + + +class AccountsWithStreamingResponse: + def __init__(self, accounts: Accounts) -> None: + self.create = to_streamed_response_wrapper( + accounts.create, + ) + self.update = to_streamed_response_wrapper( + accounts.update, + ) + + +class AsyncAccountsWithStreamingResponse: + def __init__(self, accounts: AsyncAccounts) -> None: + self.create = async_to_streamed_response_wrapper( accounts.create, ) - self.update = async_to_raw_response_wrapper( + self.update = async_to_streamed_response_wrapper( accounts.update, ) diff --git a/src/finch/resources/sandbox/connections/connections.py b/src/finch/resources/sandbox/connections/connections.py index b3b522bc..5fa11a27 100644 --- a/src/finch/resources/sandbox/connections/connections.py +++ b/src/finch/resources/sandbox/connections/connections.py @@ -7,12 +7,20 @@ import httpx -from .accounts import Accounts, AsyncAccounts, AccountsWithRawResponse, AsyncAccountsWithRawResponse +from .... import _legacy_response +from .accounts import ( + Accounts, + AsyncAccounts, + AccountsWithRawResponse, + AsyncAccountsWithRawResponse, + AccountsWithStreamingResponse, + AsyncAccountsWithStreamingResponse, +) from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._base_client import ( make_request_options, ) @@ -30,6 +38,10 @@ def accounts(self) -> Accounts: def with_raw_response(self) -> ConnectionsWithRawResponse: return ConnectionsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> ConnectionsWithStreamingResponse: + return ConnectionsWithStreamingResponse(self) + def create( self, *, @@ -86,6 +98,10 @@ def accounts(self) -> AsyncAccounts: def with_raw_response(self) -> AsyncConnectionsWithRawResponse: return AsyncConnectionsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncConnectionsWithStreamingResponse: + return AsyncConnectionsWithStreamingResponse(self) + async def create( self, *, @@ -137,7 +153,7 @@ class ConnectionsWithRawResponse: def __init__(self, connections: Connections) -> None: self.accounts = AccountsWithRawResponse(connections.accounts) - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( connections.create, ) @@ -146,6 +162,24 @@ class AsyncConnectionsWithRawResponse: def __init__(self, connections: AsyncConnections) -> None: self.accounts = AsyncAccountsWithRawResponse(connections.accounts) - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + connections.create, + ) + + +class ConnectionsWithStreamingResponse: + def __init__(self, connections: Connections) -> None: + self.accounts = AccountsWithStreamingResponse(connections.accounts) + + self.create = to_streamed_response_wrapper( + connections.create, + ) + + +class AsyncConnectionsWithStreamingResponse: + def __init__(self, connections: AsyncConnections) -> None: + self.accounts = AsyncAccountsWithStreamingResponse(connections.accounts) + + self.create = async_to_streamed_response_wrapper( connections.create, ) diff --git a/src/finch/resources/sandbox/directory.py b/src/finch/resources/sandbox/directory.py index 3249c71e..eb904c93 100644 --- a/src/finch/resources/sandbox/directory.py +++ b/src/finch/resources/sandbox/directory.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._base_client import ( make_request_options, ) @@ -24,6 +25,10 @@ class Directory(SyncAPIResource): def with_raw_response(self) -> DirectoryWithRawResponse: return DirectoryWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> DirectoryWithStreamingResponse: + return DirectoryWithStreamingResponse(self) + def create( self, *, @@ -65,6 +70,10 @@ class AsyncDirectory(AsyncAPIResource): def with_raw_response(self) -> AsyncDirectoryWithRawResponse: return AsyncDirectoryWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncDirectoryWithStreamingResponse: + return AsyncDirectoryWithStreamingResponse(self) + async def create( self, *, @@ -103,13 +112,27 @@ async def create( class DirectoryWithRawResponse: def __init__(self, directory: Directory) -> None: - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( directory.create, ) class AsyncDirectoryWithRawResponse: def __init__(self, directory: AsyncDirectory) -> None: - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + directory.create, + ) + + +class DirectoryWithStreamingResponse: + def __init__(self, directory: Directory) -> None: + self.create = to_streamed_response_wrapper( + directory.create, + ) + + +class AsyncDirectoryWithStreamingResponse: + def __init__(self, directory: AsyncDirectory) -> None: + self.create = async_to_streamed_response_wrapper( directory.create, ) diff --git a/src/finch/resources/sandbox/employment.py b/src/finch/resources/sandbox/employment.py index b38757b4..ba4c243e 100644 --- a/src/finch/resources/sandbox/employment.py +++ b/src/finch/resources/sandbox/employment.py @@ -6,12 +6,13 @@ import httpx +from ... import _legacy_response from ...types import IncomeParam, LocationParam from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._base_client import ( make_request_options, ) @@ -25,6 +26,10 @@ class Employment(SyncAPIResource): def with_raw_response(self) -> EmploymentWithRawResponse: return EmploymentWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> EmploymentWithStreamingResponse: + return EmploymentWithStreamingResponse(self) + def update( self, individual_id: str, @@ -131,6 +136,10 @@ class AsyncEmployment(AsyncAPIResource): def with_raw_response(self) -> AsyncEmploymentWithRawResponse: return AsyncEmploymentWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncEmploymentWithStreamingResponse: + return AsyncEmploymentWithStreamingResponse(self) + async def update( self, individual_id: str, @@ -234,13 +243,27 @@ async def update( class EmploymentWithRawResponse: def __init__(self, employment: Employment) -> None: - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( employment.update, ) class AsyncEmploymentWithRawResponse: def __init__(self, employment: AsyncEmployment) -> None: - self.update = async_to_raw_response_wrapper( + self.update = _legacy_response.async_to_raw_response_wrapper( + employment.update, + ) + + +class EmploymentWithStreamingResponse: + def __init__(self, employment: Employment) -> None: + self.update = to_streamed_response_wrapper( + employment.update, + ) + + +class AsyncEmploymentWithStreamingResponse: + def __init__(self, employment: AsyncEmployment) -> None: + self.update = async_to_streamed_response_wrapper( employment.update, ) diff --git a/src/finch/resources/sandbox/individual.py b/src/finch/resources/sandbox/individual.py index d0da230a..dd1a5a2a 100644 --- a/src/finch/resources/sandbox/individual.py +++ b/src/finch/resources/sandbox/individual.py @@ -7,12 +7,13 @@ import httpx +from ... import _legacy_response from ...types import LocationParam from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._base_client import ( make_request_options, ) @@ -26,6 +27,10 @@ class Individual(SyncAPIResource): def with_raw_response(self) -> IndividualWithRawResponse: return IndividualWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> IndividualWithStreamingResponse: + return IndividualWithStreamingResponse(self) + def update( self, individual_id: str, @@ -126,6 +131,10 @@ class AsyncIndividual(AsyncAPIResource): def with_raw_response(self) -> AsyncIndividualWithRawResponse: return AsyncIndividualWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncIndividualWithStreamingResponse: + return AsyncIndividualWithStreamingResponse(self) + async def update( self, individual_id: str, @@ -223,13 +232,27 @@ async def update( class IndividualWithRawResponse: def __init__(self, individual: Individual) -> None: - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( individual.update, ) class AsyncIndividualWithRawResponse: def __init__(self, individual: AsyncIndividual) -> None: - self.update = async_to_raw_response_wrapper( + self.update = _legacy_response.async_to_raw_response_wrapper( + individual.update, + ) + + +class IndividualWithStreamingResponse: + def __init__(self, individual: Individual) -> None: + self.update = to_streamed_response_wrapper( + individual.update, + ) + + +class AsyncIndividualWithStreamingResponse: + def __init__(self, individual: AsyncIndividual) -> None: + self.update = async_to_streamed_response_wrapper( individual.update, ) diff --git a/src/finch/resources/sandbox/jobs/__init__.py b/src/finch/resources/sandbox/jobs/__init__.py index 1a21f174..c4f1bba4 100644 --- a/src/finch/resources/sandbox/jobs/__init__.py +++ b/src/finch/resources/sandbox/jobs/__init__.py @@ -1,11 +1,20 @@ # File generated from our OpenAPI spec by Stainless. -from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse +from .jobs import ( + Jobs, + AsyncJobs, + JobsWithRawResponse, + AsyncJobsWithRawResponse, + JobsWithStreamingResponse, + AsyncJobsWithStreamingResponse, +) from .configuration import ( Configuration, AsyncConfiguration, ConfigurationWithRawResponse, AsyncConfigurationWithRawResponse, + ConfigurationWithStreamingResponse, + AsyncConfigurationWithStreamingResponse, ) __all__ = [ @@ -13,8 +22,12 @@ "AsyncConfiguration", "ConfigurationWithRawResponse", "AsyncConfigurationWithRawResponse", + "ConfigurationWithStreamingResponse", + "AsyncConfigurationWithStreamingResponse", "Jobs", "AsyncJobs", "JobsWithRawResponse", "AsyncJobsWithRawResponse", + "JobsWithStreamingResponse", + "AsyncJobsWithStreamingResponse", ] diff --git a/src/finch/resources/sandbox/jobs/configuration.py b/src/finch/resources/sandbox/jobs/configuration.py index f3e8d6ab..aa35738b 100644 --- a/src/finch/resources/sandbox/jobs/configuration.py +++ b/src/finch/resources/sandbox/jobs/configuration.py @@ -6,11 +6,12 @@ import httpx +from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._base_client import ( make_request_options, ) @@ -24,6 +25,10 @@ class Configuration(SyncAPIResource): def with_raw_response(self) -> ConfigurationWithRawResponse: return ConfigurationWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> ConfigurationWithStreamingResponse: + return ConfigurationWithStreamingResponse(self) + def retrieve( self, *, @@ -88,6 +93,10 @@ class AsyncConfiguration(AsyncAPIResource): def with_raw_response(self) -> AsyncConfigurationWithRawResponse: return AsyncConfigurationWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncConfigurationWithStreamingResponse: + return AsyncConfigurationWithStreamingResponse(self) + async def retrieve( self, *, @@ -149,19 +158,39 @@ async def update( class ConfigurationWithRawResponse: def __init__(self, configuration: Configuration) -> None: - self.retrieve = to_raw_response_wrapper( + self.retrieve = _legacy_response.to_raw_response_wrapper( configuration.retrieve, ) - self.update = to_raw_response_wrapper( + self.update = _legacy_response.to_raw_response_wrapper( configuration.update, ) class AsyncConfigurationWithRawResponse: def __init__(self, configuration: AsyncConfiguration) -> None: - self.retrieve = async_to_raw_response_wrapper( + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + configuration.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + configuration.update, + ) + + +class ConfigurationWithStreamingResponse: + def __init__(self, configuration: Configuration) -> None: + self.retrieve = to_streamed_response_wrapper( + configuration.retrieve, + ) + self.update = to_streamed_response_wrapper( + configuration.update, + ) + + +class AsyncConfigurationWithStreamingResponse: + def __init__(self, configuration: AsyncConfiguration) -> None: + self.retrieve = async_to_streamed_response_wrapper( configuration.retrieve, ) - self.update = async_to_raw_response_wrapper( + self.update = async_to_streamed_response_wrapper( configuration.update, ) diff --git a/src/finch/resources/sandbox/jobs/jobs.py b/src/finch/resources/sandbox/jobs/jobs.py index 3f45e345..799e9661 100644 --- a/src/finch/resources/sandbox/jobs/jobs.py +++ b/src/finch/resources/sandbox/jobs/jobs.py @@ -9,6 +9,8 @@ AsyncConfiguration, ConfigurationWithRawResponse, AsyncConfigurationWithRawResponse, + ConfigurationWithStreamingResponse, + AsyncConfigurationWithStreamingResponse, ) __all__ = ["Jobs", "AsyncJobs"] @@ -23,6 +25,10 @@ def configuration(self) -> Configuration: def with_raw_response(self) -> JobsWithRawResponse: return JobsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> JobsWithStreamingResponse: + return JobsWithStreamingResponse(self) + class AsyncJobs(AsyncAPIResource): @cached_property @@ -33,6 +39,10 @@ def configuration(self) -> AsyncConfiguration: def with_raw_response(self) -> AsyncJobsWithRawResponse: return AsyncJobsWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncJobsWithStreamingResponse: + return AsyncJobsWithStreamingResponse(self) + class JobsWithRawResponse: def __init__(self, jobs: Jobs) -> None: @@ -42,3 +52,13 @@ def __init__(self, jobs: Jobs) -> None: class AsyncJobsWithRawResponse: def __init__(self, jobs: AsyncJobs) -> None: self.configuration = AsyncConfigurationWithRawResponse(jobs.configuration) + + +class JobsWithStreamingResponse: + def __init__(self, jobs: Jobs) -> None: + self.configuration = ConfigurationWithStreamingResponse(jobs.configuration) + + +class AsyncJobsWithStreamingResponse: + def __init__(self, jobs: AsyncJobs) -> None: + self.configuration = AsyncConfigurationWithStreamingResponse(jobs.configuration) diff --git a/src/finch/resources/sandbox/payment.py b/src/finch/resources/sandbox/payment.py index 18753bd6..04d9e05d 100644 --- a/src/finch/resources/sandbox/payment.py +++ b/src/finch/resources/sandbox/payment.py @@ -6,11 +6,12 @@ import httpx +from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._base_client import ( make_request_options, ) @@ -24,6 +25,10 @@ class Payment(SyncAPIResource): def with_raw_response(self) -> PaymentWithRawResponse: return PaymentWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> PaymentWithStreamingResponse: + return PaymentWithStreamingResponse(self) + def create( self, *, @@ -71,6 +76,10 @@ class AsyncPayment(AsyncAPIResource): def with_raw_response(self) -> AsyncPaymentWithRawResponse: return AsyncPaymentWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncPaymentWithStreamingResponse: + return AsyncPaymentWithStreamingResponse(self) + async def create( self, *, @@ -115,13 +124,27 @@ async def create( class PaymentWithRawResponse: def __init__(self, payment: Payment) -> None: - self.create = to_raw_response_wrapper( + self.create = _legacy_response.to_raw_response_wrapper( payment.create, ) class AsyncPaymentWithRawResponse: def __init__(self, payment: AsyncPayment) -> None: - self.create = async_to_raw_response_wrapper( + self.create = _legacy_response.async_to_raw_response_wrapper( + payment.create, + ) + + +class PaymentWithStreamingResponse: + def __init__(self, payment: Payment) -> None: + self.create = to_streamed_response_wrapper( + payment.create, + ) + + +class AsyncPaymentWithStreamingResponse: + def __init__(self, payment: AsyncPayment) -> None: + self.create = async_to_streamed_response_wrapper( payment.create, ) diff --git a/src/finch/resources/sandbox/sandbox.py b/src/finch/resources/sandbox/sandbox.py index 23b1994d..6c208e89 100644 --- a/src/finch/resources/sandbox/sandbox.py +++ b/src/finch/resources/sandbox/sandbox.py @@ -2,16 +2,65 @@ from __future__ import annotations -from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse -from .company import Company, AsyncCompany, CompanyWithRawResponse, AsyncCompanyWithRawResponse -from .payment import Payment, AsyncPayment, PaymentWithRawResponse, AsyncPaymentWithRawResponse +from .jobs import ( + Jobs, + AsyncJobs, + JobsWithRawResponse, + AsyncJobsWithRawResponse, + JobsWithStreamingResponse, + AsyncJobsWithStreamingResponse, +) +from .company import ( + Company, + AsyncCompany, + CompanyWithRawResponse, + AsyncCompanyWithRawResponse, + CompanyWithStreamingResponse, + AsyncCompanyWithStreamingResponse, +) +from .payment import ( + Payment, + AsyncPayment, + PaymentWithRawResponse, + AsyncPaymentWithRawResponse, + PaymentWithStreamingResponse, + AsyncPaymentWithStreamingResponse, +) from ..._compat import cached_property -from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse +from .directory import ( + Directory, + AsyncDirectory, + DirectoryWithRawResponse, + AsyncDirectoryWithRawResponse, + DirectoryWithStreamingResponse, + AsyncDirectoryWithStreamingResponse, +) from .jobs.jobs import Jobs, AsyncJobs -from .employment import Employment, AsyncEmployment, EmploymentWithRawResponse, AsyncEmploymentWithRawResponse -from .individual import Individual, AsyncIndividual, IndividualWithRawResponse, AsyncIndividualWithRawResponse +from .employment import ( + Employment, + AsyncEmployment, + EmploymentWithRawResponse, + AsyncEmploymentWithRawResponse, + EmploymentWithStreamingResponse, + AsyncEmploymentWithStreamingResponse, +) +from .individual import ( + Individual, + AsyncIndividual, + IndividualWithRawResponse, + AsyncIndividualWithRawResponse, + IndividualWithStreamingResponse, + AsyncIndividualWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource -from .connections import Connections, AsyncConnections, ConnectionsWithRawResponse, AsyncConnectionsWithRawResponse +from .connections import ( + Connections, + AsyncConnections, + ConnectionsWithRawResponse, + AsyncConnectionsWithRawResponse, + ConnectionsWithStreamingResponse, + AsyncConnectionsWithStreamingResponse, +) from .connections.connections import Connections, AsyncConnections __all__ = ["Sandbox", "AsyncSandbox"] @@ -50,6 +99,10 @@ def jobs(self) -> Jobs: def with_raw_response(self) -> SandboxWithRawResponse: return SandboxWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> SandboxWithStreamingResponse: + return SandboxWithStreamingResponse(self) + class AsyncSandbox(AsyncAPIResource): @cached_property @@ -84,6 +137,10 @@ def jobs(self) -> AsyncJobs: def with_raw_response(self) -> AsyncSandboxWithRawResponse: return AsyncSandboxWithRawResponse(self) + @cached_property + def with_streaming_response(self) -> AsyncSandboxWithStreamingResponse: + return AsyncSandboxWithStreamingResponse(self) + class SandboxWithRawResponse: def __init__(self, sandbox: Sandbox) -> None: @@ -105,3 +162,25 @@ def __init__(self, sandbox: AsyncSandbox) -> None: self.employment = AsyncEmploymentWithRawResponse(sandbox.employment) self.payment = AsyncPaymentWithRawResponse(sandbox.payment) self.jobs = AsyncJobsWithRawResponse(sandbox.jobs) + + +class SandboxWithStreamingResponse: + def __init__(self, sandbox: Sandbox) -> None: + self.connections = ConnectionsWithStreamingResponse(sandbox.connections) + self.company = CompanyWithStreamingResponse(sandbox.company) + self.directory = DirectoryWithStreamingResponse(sandbox.directory) + self.individual = IndividualWithStreamingResponse(sandbox.individual) + self.employment = EmploymentWithStreamingResponse(sandbox.employment) + self.payment = PaymentWithStreamingResponse(sandbox.payment) + self.jobs = JobsWithStreamingResponse(sandbox.jobs) + + +class AsyncSandboxWithStreamingResponse: + def __init__(self, sandbox: AsyncSandbox) -> None: + self.connections = AsyncConnectionsWithStreamingResponse(sandbox.connections) + self.company = AsyncCompanyWithStreamingResponse(sandbox.company) + self.directory = AsyncDirectoryWithStreamingResponse(sandbox.directory) + self.individual = AsyncIndividualWithStreamingResponse(sandbox.individual) + self.employment = AsyncEmploymentWithStreamingResponse(sandbox.employment) + self.payment = AsyncPaymentWithStreamingResponse(sandbox.payment) + self.jobs = AsyncJobsWithStreamingResponse(sandbox.jobs) diff --git a/tests/api_resources/hris/benefits/test_individuals.py b/tests/api_resources/hris/benefits/test_individuals.py index 3c45aa12..d30345fe 100644 --- a/tests/api_resources/hris/benefits/test_individuals.py +++ b/tests/api_resources/hris/benefits/test_individuals.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -40,10 +41,26 @@ def test_raw_response_enroll_many(self, client: Finch) -> None: "string", individuals=[{}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(SyncSinglePage[EnrolledIndividual], individual, path=["response"]) + @parametrize + def test_streaming_response_enroll_many(self, client: Finch) -> None: + with client.hris.benefits.individuals.with_streaming_response.enroll_many( + "string", + individuals=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(SyncSinglePage[EnrolledIndividual], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_enrolled_ids(self, client: Finch) -> None: individual = client.hris.benefits.individuals.enrolled_ids( @@ -56,10 +73,25 @@ def test_raw_response_enrolled_ids(self, client: Finch) -> None: response = client.hris.benefits.individuals.with_raw_response.enrolled_ids( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(IndividualEnrolledIDsResponse, individual, path=["response"]) + @parametrize + def test_streaming_response_enrolled_ids(self, client: Finch) -> None: + with client.hris.benefits.individuals.with_streaming_response.enrolled_ids( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(IndividualEnrolledIDsResponse, individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_retrieve_many_benefits(self, client: Finch) -> None: individual = client.hris.benefits.individuals.retrieve_many_benefits( @@ -80,10 +112,25 @@ def test_raw_response_retrieve_many_benefits(self, client: Finch) -> None: response = client.hris.benefits.individuals.with_raw_response.retrieve_many_benefits( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(SyncSinglePage[IndividualBenefit], individual, path=["response"]) + @parametrize + def test_streaming_response_retrieve_many_benefits(self, client: Finch) -> None: + with client.hris.benefits.individuals.with_streaming_response.retrieve_many_benefits( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(SyncSinglePage[IndividualBenefit], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_unenroll_many(self, client: Finch) -> None: individual = client.hris.benefits.individuals.unenroll_many( @@ -104,10 +151,25 @@ def test_raw_response_unenroll_many(self, client: Finch) -> None: response = client.hris.benefits.individuals.with_raw_response.unenroll_many( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(SyncSinglePage[UnenrolledIndividual], individual, path=["response"]) + @parametrize + def test_streaming_response_unenroll_many(self, client: Finch) -> None: + with client.hris.benefits.individuals.with_streaming_response.unenroll_many( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(SyncSinglePage[UnenrolledIndividual], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncIndividuals: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -128,10 +190,26 @@ async def test_raw_response_enroll_many(self, client: AsyncFinch) -> None: "string", individuals=[{}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(AsyncSinglePage[EnrolledIndividual], individual, path=["response"]) + @parametrize + async def test_streaming_response_enroll_many(self, client: AsyncFinch) -> None: + async with client.hris.benefits.individuals.with_streaming_response.enroll_many( + "string", + individuals=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(AsyncSinglePage[EnrolledIndividual], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_enrolled_ids(self, client: AsyncFinch) -> None: individual = await client.hris.benefits.individuals.enrolled_ids( @@ -144,10 +222,25 @@ async def test_raw_response_enrolled_ids(self, client: AsyncFinch) -> None: response = await client.hris.benefits.individuals.with_raw_response.enrolled_ids( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(IndividualEnrolledIDsResponse, individual, path=["response"]) + @parametrize + async def test_streaming_response_enrolled_ids(self, client: AsyncFinch) -> None: + async with client.hris.benefits.individuals.with_streaming_response.enrolled_ids( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(IndividualEnrolledIDsResponse, individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_retrieve_many_benefits(self, client: AsyncFinch) -> None: individual = await client.hris.benefits.individuals.retrieve_many_benefits( @@ -168,10 +261,25 @@ async def test_raw_response_retrieve_many_benefits(self, client: AsyncFinch) -> response = await client.hris.benefits.individuals.with_raw_response.retrieve_many_benefits( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(AsyncSinglePage[IndividualBenefit], individual, path=["response"]) + @parametrize + async def test_streaming_response_retrieve_many_benefits(self, client: AsyncFinch) -> None: + async with client.hris.benefits.individuals.with_streaming_response.retrieve_many_benefits( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(AsyncSinglePage[IndividualBenefit], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_unenroll_many(self, client: AsyncFinch) -> None: individual = await client.hris.benefits.individuals.unenroll_many( @@ -192,6 +300,21 @@ async def test_raw_response_unenroll_many(self, client: AsyncFinch) -> None: response = await client.hris.benefits.individuals.with_raw_response.unenroll_many( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(AsyncSinglePage[UnenrolledIndividual], individual, path=["response"]) + + @parametrize + async def test_streaming_response_unenroll_many(self, client: AsyncFinch) -> None: + async with client.hris.benefits.individuals.with_streaming_response.unenroll_many( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(AsyncSinglePage[UnenrolledIndividual], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_benefits.py b/tests/api_resources/hris/test_benefits.py index 77f4caff..0bf4b035 100644 --- a/tests/api_resources/hris/test_benefits.py +++ b/tests/api_resources/hris/test_benefits.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -43,10 +44,23 @@ def test_method_create_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_create(self, client: Finch) -> None: response = client.hris.benefits.with_raw_response.create() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(CreateCompanyBenefitsResponse, benefit, path=["response"]) + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.hris.benefits.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = response.parse() + assert_matches_type(CreateCompanyBenefitsResponse, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_retrieve(self, client: Finch) -> None: benefit = client.hris.benefits.retrieve( @@ -59,10 +73,25 @@ def test_raw_response_retrieve(self, client: Finch) -> None: response = client.hris.benefits.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(CompanyBenefit, benefit, path=["response"]) + @parametrize + def test_streaming_response_retrieve(self, client: Finch) -> None: + with client.hris.benefits.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = response.parse() + assert_matches_type(CompanyBenefit, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_update(self, client: Finch) -> None: benefit = client.hris.benefits.update( @@ -83,10 +112,25 @@ def test_raw_response_update(self, client: Finch) -> None: response = client.hris.benefits.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(UpdateCompanyBenefitResponse, benefit, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.hris.benefits.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = response.parse() + assert_matches_type(UpdateCompanyBenefitResponse, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list(self, client: Finch) -> None: benefit = client.hris.benefits.list() @@ -95,10 +139,23 @@ def test_method_list(self, client: Finch) -> None: @parametrize def test_raw_response_list(self, client: Finch) -> None: response = client.hris.benefits.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(SyncSinglePage[CompanyBenefit], benefit, path=["response"]) + @parametrize + def test_streaming_response_list(self, client: Finch) -> None: + with client.hris.benefits.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = response.parse() + assert_matches_type(SyncSinglePage[CompanyBenefit], benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list_supported_benefits(self, client: Finch) -> None: benefit = client.hris.benefits.list_supported_benefits() @@ -107,10 +164,23 @@ def test_method_list_supported_benefits(self, client: Finch) -> None: @parametrize def test_raw_response_list_supported_benefits(self, client: Finch) -> None: response = client.hris.benefits.with_raw_response.list_supported_benefits() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(SyncSinglePage[SupportedBenefit], benefit, path=["response"]) + @parametrize + def test_streaming_response_list_supported_benefits(self, client: Finch) -> None: + with client.hris.benefits.with_streaming_response.list_supported_benefits() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = response.parse() + assert_matches_type(SyncSinglePage[SupportedBenefit], benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncBenefits: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -134,10 +204,23 @@ async def test_method_create_with_all_params(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_create(self, client: AsyncFinch) -> None: response = await client.hris.benefits.with_raw_response.create() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(CreateCompanyBenefitsResponse, benefit, path=["response"]) + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.hris.benefits.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = await response.parse() + assert_matches_type(CreateCompanyBenefitsResponse, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_retrieve(self, client: AsyncFinch) -> None: benefit = await client.hris.benefits.retrieve( @@ -150,10 +233,25 @@ async def test_raw_response_retrieve(self, client: AsyncFinch) -> None: response = await client.hris.benefits.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(CompanyBenefit, benefit, path=["response"]) + @parametrize + async def test_streaming_response_retrieve(self, client: AsyncFinch) -> None: + async with client.hris.benefits.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = await response.parse() + assert_matches_type(CompanyBenefit, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_update(self, client: AsyncFinch) -> None: benefit = await client.hris.benefits.update( @@ -174,10 +272,25 @@ async def test_raw_response_update(self, client: AsyncFinch) -> None: response = await client.hris.benefits.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(UpdateCompanyBenefitResponse, benefit, path=["response"]) + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.hris.benefits.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = await response.parse() + assert_matches_type(UpdateCompanyBenefitResponse, benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list(self, client: AsyncFinch) -> None: benefit = await client.hris.benefits.list() @@ -186,10 +299,23 @@ async def test_method_list(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_list(self, client: AsyncFinch) -> None: response = await client.hris.benefits.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(AsyncSinglePage[CompanyBenefit], benefit, path=["response"]) + @parametrize + async def test_streaming_response_list(self, client: AsyncFinch) -> None: + async with client.hris.benefits.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = await response.parse() + assert_matches_type(AsyncSinglePage[CompanyBenefit], benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list_supported_benefits(self, client: AsyncFinch) -> None: benefit = await client.hris.benefits.list_supported_benefits() @@ -198,6 +324,19 @@ async def test_method_list_supported_benefits(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_list_supported_benefits(self, client: AsyncFinch) -> None: response = await client.hris.benefits.with_raw_response.list_supported_benefits() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" benefit = response.parse() assert_matches_type(AsyncSinglePage[SupportedBenefit], benefit, path=["response"]) + + @parametrize + async def test_streaming_response_list_supported_benefits(self, client: AsyncFinch) -> None: + async with client.hris.benefits.with_streaming_response.list_supported_benefits() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + benefit = await response.parse() + assert_matches_type(AsyncSinglePage[SupportedBenefit], benefit, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_company.py b/tests/api_resources/hris/test_company.py index 2f51d84f..a8ae716d 100644 --- a/tests/api_resources/hris/test_company.py +++ b/tests/api_resources/hris/test_company.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -28,10 +29,23 @@ def test_method_retrieve(self, client: Finch) -> None: @parametrize def test_raw_response_retrieve(self, client: Finch) -> None: response = client.hris.company.with_raw_response.retrieve() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" company = response.parse() assert_matches_type(Company, company, path=["response"]) + @parametrize + def test_streaming_response_retrieve(self, client: Finch) -> None: + with client.hris.company.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + company = response.parse() + assert_matches_type(Company, company, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncCompany: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -46,6 +60,19 @@ async def test_method_retrieve(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_retrieve(self, client: AsyncFinch) -> None: response = await client.hris.company.with_raw_response.retrieve() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" company = response.parse() assert_matches_type(Company, company, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, client: AsyncFinch) -> None: + async with client.hris.company.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + company = await response.parse() + assert_matches_type(Company, company, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_directory.py b/tests/api_resources/hris/test_directory.py index 53dd541d..52e39ec2 100644 --- a/tests/api_resources/hris/test_directory.py +++ b/tests/api_resources/hris/test_directory.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -39,14 +40,28 @@ def test_method_list_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_list(self, client: Finch) -> None: response = client.hris.directory.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + @parametrize + def test_streaming_response_list(self, client: Finch) -> None: + with client.hris.directory.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list_individuals(self, client: Finch) -> None: with pytest.warns(DeprecationWarning): directory = client.hris.directory.list_individuals() + assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) @parametrize @@ -56,16 +71,31 @@ def test_method_list_individuals_with_all_params(self, client: Finch) -> None: limit=0, offset=0, ) + assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) @parametrize def test_raw_response_list_individuals(self, client: Finch) -> None: with pytest.warns(DeprecationWarning): response = client.hris.directory.with_raw_response.list_individuals() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + @parametrize + def test_streaming_response_list_individuals(self, client: Finch) -> None: + with pytest.warns(DeprecationWarning): + with client.hris.directory.with_streaming_response.list_individuals() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(SyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncDirectory: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -88,14 +118,28 @@ async def test_method_list_with_all_params(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_list(self, client: AsyncFinch) -> None: response = await client.hris.directory.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + @parametrize + async def test_streaming_response_list(self, client: AsyncFinch) -> None: + async with client.hris.directory.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list_individuals(self, client: AsyncFinch) -> None: with pytest.warns(DeprecationWarning): directory = await client.hris.directory.list_individuals() + assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) @parametrize @@ -105,12 +149,27 @@ async def test_method_list_individuals_with_all_params(self, client: AsyncFinch) limit=0, offset=0, ) + assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) @parametrize async def test_raw_response_list_individuals(self, client: AsyncFinch) -> None: with pytest.warns(DeprecationWarning): response = await client.hris.directory.with_raw_response.list_individuals() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + + @parametrize + async def test_streaming_response_list_individuals(self, client: AsyncFinch) -> None: + with pytest.warns(DeprecationWarning): + async with client.hris.directory.with_streaming_response.list_individuals() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(AsyncIndividualsPage[IndividualInDirectory], directory, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_employments.py b/tests/api_resources/hris/test_employments.py index fd6d2499..90cc3b49 100644 --- a/tests/api_resources/hris/test_employments.py +++ b/tests/api_resources/hris/test_employments.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -33,10 +34,25 @@ def test_raw_response_retrieve_many(self, client: Finch) -> None: response = client.hris.employments.with_raw_response.retrieve_many( requests=[{"individual_id": "string"}, {"individual_id": "string"}, {"individual_id": "string"}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" employment = response.parse() assert_matches_type(SyncResponsesPage[EmploymentDataResponse], employment, path=["response"]) + @parametrize + def test_streaming_response_retrieve_many(self, client: Finch) -> None: + with client.hris.employments.with_streaming_response.retrieve_many( + requests=[{"individual_id": "string"}, {"individual_id": "string"}, {"individual_id": "string"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + employment = response.parse() + assert_matches_type(SyncResponsesPage[EmploymentDataResponse], employment, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncEmployments: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -55,6 +71,21 @@ async def test_raw_response_retrieve_many(self, client: AsyncFinch) -> None: response = await client.hris.employments.with_raw_response.retrieve_many( requests=[{"individual_id": "string"}, {"individual_id": "string"}, {"individual_id": "string"}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" employment = response.parse() assert_matches_type(AsyncResponsesPage[EmploymentDataResponse], employment, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_many(self, client: AsyncFinch) -> None: + async with client.hris.employments.with_streaming_response.retrieve_many( + requests=[{"individual_id": "string"}, {"individual_id": "string"}, {"individual_id": "string"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + employment = await response.parse() + assert_matches_type(AsyncResponsesPage[EmploymentDataResponse], employment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_individuals.py b/tests/api_resources/hris/test_individuals.py index d109dbe9..328f515f 100644 --- a/tests/api_resources/hris/test_individuals.py +++ b/tests/api_resources/hris/test_individuals.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -37,10 +38,23 @@ def test_method_retrieve_many_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_retrieve_many(self, client: Finch) -> None: response = client.hris.individuals.with_raw_response.retrieve_many() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(SyncResponsesPage[IndividualResponse], individual, path=["response"]) + @parametrize + def test_streaming_response_retrieve_many(self, client: Finch) -> None: + with client.hris.individuals.with_streaming_response.retrieve_many() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(SyncResponsesPage[IndividualResponse], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncIndividuals: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -63,6 +77,19 @@ async def test_method_retrieve_many_with_all_params(self, client: AsyncFinch) -> @parametrize async def test_raw_response_retrieve_many(self, client: AsyncFinch) -> None: response = await client.hris.individuals.with_raw_response.retrieve_many() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(AsyncResponsesPage[IndividualResponse], individual, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_many(self, client: AsyncFinch) -> None: + async with client.hris.individuals.with_streaming_response.retrieve_many() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(AsyncResponsesPage[IndividualResponse], individual, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_pay_statements.py b/tests/api_resources/hris/test_pay_statements.py index ec2cac24..159311f0 100644 --- a/tests/api_resources/hris/test_pay_statements.py +++ b/tests/api_resources/hris/test_pay_statements.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -33,10 +34,25 @@ def test_raw_response_retrieve_many(self, client: Finch) -> None: response = client.hris.pay_statements.with_raw_response.retrieve_many( requests=[{"payment_id": "string"}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" pay_statement = response.parse() assert_matches_type(SyncResponsesPage[PayStatementResponse], pay_statement, path=["response"]) + @parametrize + def test_streaming_response_retrieve_many(self, client: Finch) -> None: + with client.hris.pay_statements.with_streaming_response.retrieve_many( + requests=[{"payment_id": "string"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pay_statement = response.parse() + assert_matches_type(SyncResponsesPage[PayStatementResponse], pay_statement, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncPayStatements: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -55,6 +71,21 @@ async def test_raw_response_retrieve_many(self, client: AsyncFinch) -> None: response = await client.hris.pay_statements.with_raw_response.retrieve_many( requests=[{"payment_id": "string"}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" pay_statement = response.parse() assert_matches_type(AsyncResponsesPage[PayStatementResponse], pay_statement, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_many(self, client: AsyncFinch) -> None: + async with client.hris.pay_statements.with_streaming_response.retrieve_many( + requests=[{"payment_id": "string"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pay_statement = await response.parse() + assert_matches_type(AsyncResponsesPage[PayStatementResponse], pay_statement, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/hris/test_payments.py b/tests/api_resources/hris/test_payments.py index b117122b..5ab7ea90 100644 --- a/tests/api_resources/hris/test_payments.py +++ b/tests/api_resources/hris/test_payments.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -36,10 +37,26 @@ def test_raw_response_list(self, client: Finch) -> None: end_date=parse_date("2021-01-01"), start_date=parse_date("2021-01-01"), ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" payment = response.parse() assert_matches_type(SyncSinglePage[Payment], payment, path=["response"]) + @parametrize + def test_streaming_response_list(self, client: Finch) -> None: + with client.hris.payments.with_streaming_response.list( + end_date=parse_date("2021-01-01"), + start_date=parse_date("2021-01-01"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + payment = response.parse() + assert_matches_type(SyncSinglePage[Payment], payment, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncPayments: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -60,6 +77,22 @@ async def test_raw_response_list(self, client: AsyncFinch) -> None: end_date=parse_date("2021-01-01"), start_date=parse_date("2021-01-01"), ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" payment = response.parse() assert_matches_type(AsyncSinglePage[Payment], payment, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, client: AsyncFinch) -> None: + async with client.hris.payments.with_streaming_response.list( + end_date=parse_date("2021-01-01"), + start_date=parse_date("2021-01-01"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + payment = await response.parse() + assert_matches_type(AsyncSinglePage[Payment], payment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/jobs/test_automated.py b/tests/api_resources/jobs/test_automated.py index ae4ff4fa..b4261dde 100644 --- a/tests/api_resources/jobs/test_automated.py +++ b/tests/api_resources/jobs/test_automated.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -33,10 +34,25 @@ def test_raw_response_create(self, client: Finch) -> None: response = client.jobs.automated.with_raw_response.create( type="data_sync_all", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.jobs.automated.with_streaming_response.create( + type="data_sync_all", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = response.parse() + assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_retrieve(self, client: Finch) -> None: automated = client.jobs.automated.retrieve( @@ -49,10 +65,25 @@ def test_raw_response_retrieve(self, client: Finch) -> None: response = client.jobs.automated.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(AutomatedAsyncJob, automated, path=["response"]) + @parametrize + def test_streaming_response_retrieve(self, client: Finch) -> None: + with client.jobs.automated.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = response.parse() + assert_matches_type(AutomatedAsyncJob, automated, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list(self, client: Finch) -> None: automated = client.jobs.automated.list() @@ -69,10 +100,23 @@ def test_method_list_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_list(self, client: Finch) -> None: response = client.jobs.automated.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(SyncPage[AutomatedAsyncJob], automated, path=["response"]) + @parametrize + def test_streaming_response_list(self, client: Finch) -> None: + with client.jobs.automated.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = response.parse() + assert_matches_type(SyncPage[AutomatedAsyncJob], automated, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncAutomated: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -91,10 +135,25 @@ async def test_raw_response_create(self, client: AsyncFinch) -> None: response = await client.jobs.automated.with_raw_response.create( type="data_sync_all", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.jobs.automated.with_streaming_response.create( + type="data_sync_all", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = await response.parse() + assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_retrieve(self, client: AsyncFinch) -> None: automated = await client.jobs.automated.retrieve( @@ -107,10 +166,25 @@ async def test_raw_response_retrieve(self, client: AsyncFinch) -> None: response = await client.jobs.automated.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(AutomatedAsyncJob, automated, path=["response"]) + @parametrize + async def test_streaming_response_retrieve(self, client: AsyncFinch) -> None: + async with client.jobs.automated.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = await response.parse() + assert_matches_type(AutomatedAsyncJob, automated, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list(self, client: AsyncFinch) -> None: automated = await client.jobs.automated.list() @@ -127,6 +201,19 @@ async def test_method_list_with_all_params(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_list(self, client: AsyncFinch) -> None: response = await client.jobs.automated.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" automated = response.parse() assert_matches_type(AsyncPage[AutomatedAsyncJob], automated, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, client: AsyncFinch) -> None: + async with client.jobs.automated.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automated = await response.parse() + assert_matches_type(AsyncPage[AutomatedAsyncJob], automated, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/jobs/test_manual.py b/tests/api_resources/jobs/test_manual.py index 9df08a02..5efb033e 100644 --- a/tests/api_resources/jobs/test_manual.py +++ b/tests/api_resources/jobs/test_manual.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -32,10 +33,25 @@ def test_raw_response_retrieve(self, client: Finch) -> None: response = client.jobs.manual.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" manual = response.parse() assert_matches_type(ManualAsyncJob, manual, path=["response"]) + @parametrize + def test_streaming_response_retrieve(self, client: Finch) -> None: + with client.jobs.manual.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + manual = response.parse() + assert_matches_type(ManualAsyncJob, manual, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncManual: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -54,6 +70,21 @@ async def test_raw_response_retrieve(self, client: AsyncFinch) -> None: response = await client.jobs.manual.with_raw_response.retrieve( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" manual = response.parse() assert_matches_type(ManualAsyncJob, manual, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, client: AsyncFinch) -> None: + async with client.jobs.manual.with_streaming_response.retrieve( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + manual = await response.parse() + assert_matches_type(ManualAsyncJob, manual, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/connections/test_accounts.py b/tests/api_resources/sandbox/connections/test_accounts.py index ef1b3f3c..16f3496e 100644 --- a/tests/api_resources/sandbox/connections/test_accounts.py +++ b/tests/api_resources/sandbox/connections/test_accounts.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -50,10 +51,27 @@ def test_raw_response_create(self, client: Finch) -> None: company_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", provider_id="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(AccountCreateResponse, account, path=["response"]) + @pytest.mark.skip(reason="Auth isn't setup correctly in this test") + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.sandbox.connections.accounts.with_streaming_response.create( + company_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + provider_id="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(AccountCreateResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_update(self, client: Finch) -> None: account = client.sandbox.connections.accounts.update() @@ -69,10 +87,23 @@ def test_method_update_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_update(self, client: Finch) -> None: response = client.sandbox.connections.accounts.with_raw_response.update() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(AccountUpdateResponse, account, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.sandbox.connections.accounts.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(AccountUpdateResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncAccounts: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -106,10 +137,27 @@ async def test_raw_response_create(self, client: AsyncFinch) -> None: company_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", provider_id="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(AccountCreateResponse, account, path=["response"]) + @pytest.mark.skip(reason="Auth isn't setup correctly in this test") + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.sandbox.connections.accounts.with_streaming_response.create( + company_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + provider_id="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AccountCreateResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_update(self, client: AsyncFinch) -> None: account = await client.sandbox.connections.accounts.update() @@ -125,6 +173,19 @@ async def test_method_update_with_all_params(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_update(self, client: AsyncFinch) -> None: response = await client.sandbox.connections.accounts.with_raw_response.update() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(AccountUpdateResponse, account, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.sandbox.connections.accounts.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AccountUpdateResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/jobs/test_configuration.py b/tests/api_resources/sandbox/jobs/test_configuration.py index c9a6f5e2..41aee24e 100644 --- a/tests/api_resources/sandbox/jobs/test_configuration.py +++ b/tests/api_resources/sandbox/jobs/test_configuration.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -28,10 +29,23 @@ def test_method_retrieve(self, client: Finch) -> None: @parametrize def test_raw_response_retrieve(self, client: Finch) -> None: response = client.sandbox.jobs.configuration.with_raw_response.retrieve() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" configuration = response.parse() assert_matches_type(ConfigurationRetrieveResponse, configuration, path=["response"]) + @parametrize + def test_streaming_response_retrieve(self, client: Finch) -> None: + with client.sandbox.jobs.configuration.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = response.parse() + assert_matches_type(ConfigurationRetrieveResponse, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_update(self, client: Finch) -> None: configuration = client.sandbox.jobs.configuration.update( @@ -46,10 +60,26 @@ def test_raw_response_update(self, client: Finch) -> None: completion_status="complete", type="data_sync_all", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" configuration = response.parse() assert_matches_type(SandboxJobConfiguration, configuration, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.sandbox.jobs.configuration.with_streaming_response.update( + completion_status="complete", + type="data_sync_all", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = response.parse() + assert_matches_type(SandboxJobConfiguration, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncConfiguration: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -64,10 +94,23 @@ async def test_method_retrieve(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_retrieve(self, client: AsyncFinch) -> None: response = await client.sandbox.jobs.configuration.with_raw_response.retrieve() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" configuration = response.parse() assert_matches_type(ConfigurationRetrieveResponse, configuration, path=["response"]) + @parametrize + async def test_streaming_response_retrieve(self, client: AsyncFinch) -> None: + async with client.sandbox.jobs.configuration.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = await response.parse() + assert_matches_type(ConfigurationRetrieveResponse, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_update(self, client: AsyncFinch) -> None: configuration = await client.sandbox.jobs.configuration.update( @@ -82,6 +125,22 @@ async def test_raw_response_update(self, client: AsyncFinch) -> None: completion_status="complete", type="data_sync_all", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" configuration = response.parse() assert_matches_type(SandboxJobConfiguration, configuration, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.sandbox.jobs.configuration.with_streaming_response.update( + completion_status="complete", + type="data_sync_all", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = await response.parse() + assert_matches_type(SandboxJobConfiguration, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_company.py b/tests/api_resources/sandbox/test_company.py index 23a76f9c..f4fc204e 100644 --- a/tests/api_resources/sandbox/test_company.py +++ b/tests/api_resources/sandbox/test_company.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -129,10 +130,32 @@ def test_raw_response_update(self, client: Finch) -> None: primary_email="string", primary_phone_number="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" company = response.parse() assert_matches_type(CompanyUpdateResponse, company, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.sandbox.company.with_streaming_response.update( + accounts=[{}, {}, {}], + departments=[{}, {}, {}], + ein="string", + entity={}, + legal_name="string", + locations=[{}, {}, {}], + primary_email="string", + primary_phone_number="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + company = response.parse() + assert_matches_type(CompanyUpdateResponse, company, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncCompany: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -248,6 +271,28 @@ async def test_raw_response_update(self, client: AsyncFinch) -> None: primary_email="string", primary_phone_number="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" company = response.parse() assert_matches_type(CompanyUpdateResponse, company, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.sandbox.company.with_streaming_response.update( + accounts=[{}, {}, {}], + departments=[{}, {}, {}], + ein="string", + entity={}, + legal_name="string", + locations=[{}, {}, {}], + primary_email="string", + primary_phone_number="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + company = await response.parse() + assert_matches_type(CompanyUpdateResponse, company, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_connections.py b/tests/api_resources/sandbox/test_connections.py index f505c56b..3eb39ea9 100644 --- a/tests/api_resources/sandbox/test_connections.py +++ b/tests/api_resources/sandbox/test_connections.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -45,10 +46,26 @@ def test_raw_response_create(self, client: Finch) -> None: response = client.sandbox.connections.with_raw_response.create( provider_id="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connection = response.parse() assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + @pytest.mark.skip(reason="Auth isn't setup correctly in this test") + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.sandbox.connections.with_streaming_response.create( + provider_id="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncConnections: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -80,6 +97,22 @@ async def test_raw_response_create(self, client: AsyncFinch) -> None: response = await client.sandbox.connections.with_raw_response.create( provider_id="string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connection = response.parse() assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @pytest.mark.skip(reason="Auth isn't setup correctly in this test") + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.sandbox.connections.with_streaming_response.create( + provider_id="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_directory.py b/tests/api_resources/sandbox/test_directory.py index ef7776db..430b24d6 100644 --- a/tests/api_resources/sandbox/test_directory.py +++ b/tests/api_resources/sandbox/test_directory.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -32,10 +33,25 @@ def test_raw_response_create(self, client: Finch) -> None: response = client.sandbox.directory.with_raw_response.create( body=[{}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(DirectoryCreateResponse, directory, path=["response"]) + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.sandbox.directory.with_streaming_response.create( + body=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(DirectoryCreateResponse, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncDirectory: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -54,6 +70,21 @@ async def test_raw_response_create(self, client: AsyncFinch) -> None: response = await client.sandbox.directory.with_raw_response.create( body=[{}], ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" directory = response.parse() assert_matches_type(DirectoryCreateResponse, directory, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.sandbox.directory.with_streaming_response.create( + body=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(DirectoryCreateResponse, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_employment.py b/tests/api_resources/sandbox/test_employment.py index 9a1c9bf2..89d421bd 100644 --- a/tests/api_resources/sandbox/test_employment.py +++ b/tests/api_resources/sandbox/test_employment.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -104,10 +105,25 @@ def test_raw_response_update(self, client: Finch) -> None: response = client.sandbox.employment.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" employment = response.parse() assert_matches_type(EmploymentUpdateResponse, employment, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.sandbox.employment.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + employment = response.parse() + assert_matches_type(EmploymentUpdateResponse, employment, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncEmployment: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -198,6 +214,21 @@ async def test_raw_response_update(self, client: AsyncFinch) -> None: response = await client.sandbox.employment.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" employment = response.parse() assert_matches_type(EmploymentUpdateResponse, employment, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.sandbox.employment.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + employment = await response.parse() + assert_matches_type(EmploymentUpdateResponse, employment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_individual.py b/tests/api_resources/sandbox/test_individual.py index 8a32a64c..356f5269 100644 --- a/tests/api_resources/sandbox/test_individual.py +++ b/tests/api_resources/sandbox/test_individual.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -86,10 +87,25 @@ def test_raw_response_update(self, client: Finch) -> None: response = client.sandbox.individual.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(IndividualUpdateResponse, individual, path=["response"]) + @parametrize + def test_streaming_response_update(self, client: Finch) -> None: + with client.sandbox.individual.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = response.parse() + assert_matches_type(IndividualUpdateResponse, individual, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncIndividual: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -162,6 +178,21 @@ async def test_raw_response_update(self, client: AsyncFinch) -> None: response = await client.sandbox.individual.with_raw_response.update( "string", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" individual = response.parse() assert_matches_type(IndividualUpdateResponse, individual, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, client: AsyncFinch) -> None: + async with client.sandbox.individual.with_streaming_response.update( + "string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + individual = await response.parse() + assert_matches_type(IndividualUpdateResponse, individual, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sandbox/test_payment.py b/tests/api_resources/sandbox/test_payment.py index ee4a2a1d..02caa7fd 100644 --- a/tests/api_resources/sandbox/test_payment.py +++ b/tests/api_resources/sandbox/test_payment.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -127,10 +128,23 @@ def test_method_create_with_all_params(self, client: Finch) -> None: @parametrize def test_raw_response_create(self, client: Finch) -> None: response = client.sandbox.payment.with_raw_response.create() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" payment = response.parse() assert_matches_type(PaymentCreateResponse, payment, path=["response"]) + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.sandbox.payment.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + payment = response.parse() + assert_matches_type(PaymentCreateResponse, payment, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncPayment: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -244,6 +258,19 @@ async def test_method_create_with_all_params(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_create(self, client: AsyncFinch) -> None: response = await client.sandbox.payment.with_raw_response.create() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" payment = response.parse() assert_matches_type(PaymentCreateResponse, payment, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.sandbox.payment.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + payment = await response.parse() + assert_matches_type(PaymentCreateResponse, payment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_access_tokens.py b/tests/api_resources/test_access_tokens.py index 4a89d515..6bedf634 100644 --- a/tests/api_resources/test_access_tokens.py +++ b/tests/api_resources/test_access_tokens.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -38,10 +39,28 @@ def test_raw_response_create(self, client: Finch) -> None: code="", redirect_uri="https://example.com", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" access_token = response.parse() assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"]) + @parametrize + def test_streaming_response_create(self, client: Finch) -> None: + with client.access_tokens.with_streaming_response.create( + client_id="", + client_secret="", + code="", + redirect_uri="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_token = response.parse() + assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncAccessTokens: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -66,6 +85,24 @@ async def test_raw_response_create(self, client: AsyncFinch) -> None: code="", redirect_uri="https://example.com", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" access_token = response.parse() assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, client: AsyncFinch) -> None: + async with client.access_tokens.with_streaming_response.create( + client_id="", + client_secret="", + code="", + redirect_uri="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_token = await response.parse() + assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_account.py b/tests/api_resources/test_account.py index 33933b69..28f52433 100644 --- a/tests/api_resources/test_account.py +++ b/tests/api_resources/test_account.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -28,10 +29,23 @@ def test_method_disconnect(self, client: Finch) -> None: @parametrize def test_raw_response_disconnect(self, client: Finch) -> None: response = client.account.with_raw_response.disconnect() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(DisconnectResponse, account, path=["response"]) + @parametrize + def test_streaming_response_disconnect(self, client: Finch) -> None: + with client.account.with_streaming_response.disconnect() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(DisconnectResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_introspect(self, client: Finch) -> None: account = client.account.introspect() @@ -40,10 +54,23 @@ def test_method_introspect(self, client: Finch) -> None: @parametrize def test_raw_response_introspect(self, client: Finch) -> None: response = client.account.with_raw_response.introspect() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(Introspection, account, path=["response"]) + @parametrize + def test_streaming_response_introspect(self, client: Finch) -> None: + with client.account.with_streaming_response.introspect() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(Introspection, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncAccount: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -58,10 +85,23 @@ async def test_method_disconnect(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_disconnect(self, client: AsyncFinch) -> None: response = await client.account.with_raw_response.disconnect() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(DisconnectResponse, account, path=["response"]) + @parametrize + async def test_streaming_response_disconnect(self, client: AsyncFinch) -> None: + async with client.account.with_streaming_response.disconnect() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(DisconnectResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_introspect(self, client: AsyncFinch) -> None: account = await client.account.introspect() @@ -70,6 +110,19 @@ async def test_method_introspect(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_introspect(self, client: AsyncFinch) -> None: response = await client.account.with_raw_response.introspect() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" account = response.parse() assert_matches_type(Introspection, account, path=["response"]) + + @parametrize + async def test_streaming_response_introspect(self, client: AsyncFinch) -> None: + async with client.account.with_streaming_response.introspect() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(Introspection, account, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_providers.py b/tests/api_resources/test_providers.py index bb0803d5..c78a5c4b 100644 --- a/tests/api_resources/test_providers.py +++ b/tests/api_resources/test_providers.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -29,10 +30,23 @@ def test_method_list(self, client: Finch) -> None: @parametrize def test_raw_response_list(self, client: Finch) -> None: response = client.providers.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" provider = response.parse() assert_matches_type(SyncSinglePage[Provider], provider, path=["response"]) + @parametrize + def test_streaming_response_list(self, client: Finch) -> None: + with client.providers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + provider = response.parse() + assert_matches_type(SyncSinglePage[Provider], provider, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncProviders: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -47,6 +61,19 @@ async def test_method_list(self, client: AsyncFinch) -> None: @parametrize async def test_raw_response_list(self, client: AsyncFinch) -> None: response = await client.providers.with_raw_response.list() + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" provider = response.parse() assert_matches_type(AsyncSinglePage[Provider], provider, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, client: AsyncFinch) -> None: + async with client.providers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + provider = await response.parse() + assert_matches_type(AsyncSinglePage[Provider], provider, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_request_forwarding.py b/tests/api_resources/test_request_forwarding.py index 66d2dbdf..541cc151 100644 --- a/tests/api_resources/test_request_forwarding.py +++ b/tests/api_resources/test_request_forwarding.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import Any, cast import pytest @@ -48,10 +49,26 @@ def test_raw_response_forward(self, client: Finch) -> None: method="POST", route="/people/search", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" request_forwarding = response.parse() assert_matches_type(RequestForwardingForwardResponse, request_forwarding, path=["response"]) + @parametrize + def test_streaming_response_forward(self, client: Finch) -> None: + with client.request_forwarding.with_streaming_response.forward( + method="POST", + route="/people/search", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request_forwarding = response.parse() + assert_matches_type(RequestForwardingForwardResponse, request_forwarding, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncRequestForwarding: strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True) @@ -86,6 +103,22 @@ async def test_raw_response_forward(self, client: AsyncFinch) -> None: method="POST", route="/people/search", ) + + assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" request_forwarding = response.parse() assert_matches_type(RequestForwardingForwardResponse, request_forwarding, path=["response"]) + + @parametrize + async def test_streaming_response_forward(self, client: AsyncFinch) -> None: + async with client.request_forwarding.with_streaming_response.forward( + method="POST", + route="/people/search", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request_forwarding = await response.parse() + assert_matches_type(RequestForwardingForwardResponse, request_forwarding, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/test_client.py b/tests/test_client.py index e7480def..e0d17951 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -211,6 +211,7 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic # to_raw_response_wrapper leaks through the @functools.wraps() decorator. # # removing the decorator fixes the leak for reasons we don't understand. + "finch/_legacy_response.py", "finch/_response.py", # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. "finch/_compat.py", @@ -946,6 +947,7 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic # to_raw_response_wrapper leaks through the @functools.wraps() decorator. # # removing the decorator fixes the leak for reasons we don't understand. + "finch/_legacy_response.py", "finch/_response.py", # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. "finch/_compat.py", diff --git a/tests/test_response.py b/tests/test_response.py new file mode 100644 index 00000000..29d8a319 --- /dev/null +++ b/tests/test_response.py @@ -0,0 +1,50 @@ +from typing import List + +import httpx +import pytest + +from finch._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + BinaryAPIResponse, + AsyncBinaryAPIResponse, + extract_response_type, +) + + +class ConcreteBaseAPIResponse(APIResponse[bytes]): + ... + + +class ConcreteAPIResponse(APIResponse[List[str]]): + ... + + +class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): + ... + + +def test_extract_response_type_direct_classes() -> None: + assert extract_response_type(BaseAPIResponse[str]) == str + assert extract_response_type(APIResponse[str]) == str + assert extract_response_type(AsyncAPIResponse[str]) == str + + +def test_extract_response_type_direct_class_missing_type_arg() -> None: + with pytest.raises( + RuntimeError, + match="Expected type to have a type argument at index 0 but it did not", + ): + extract_response_type(AsyncAPIResponse) + + +def test_extract_response_type_concrete_subclasses() -> None: + assert extract_response_type(ConcreteBaseAPIResponse) == bytes + assert extract_response_type(ConcreteAPIResponse) == List[str] + assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response + + +def test_extract_response_type_binary_response() -> None: + assert extract_response_type(BinaryAPIResponse) == bytes + assert extract_response_type(AsyncBinaryAPIResponse) == bytes diff --git a/tests/utils.py b/tests/utils.py index da96975e..3217f048 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,7 @@ from __future__ import annotations import os +import inspect import traceback import contextlib from typing import Any, TypeVar, Iterator, cast @@ -68,6 +69,8 @@ def assert_matches_type( assert isinstance(value, bool) elif origin == float: assert isinstance(value, float) + elif origin == bytes: + assert isinstance(value, bytes) elif origin == datetime: assert isinstance(value, datetime) elif origin == date: @@ -100,6 +103,8 @@ def assert_matches_type( elif issubclass(origin, BaseModel): assert isinstance(value, type_) assert assert_matches_model(type_, cast(Any, value), path=path) + elif inspect.isclass(origin) and origin.__name__ == "HttpxBinaryResponseContent": + assert value.__class__.__name__ == "HttpxBinaryResponseContent" else: assert None, f"Unhandled field type: {type_}"