Skip to content

release: 0.17.1 #338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.17.0"
".": "0.17.1"
}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 0.17.1 (2024-04-04)

Full Changelog: [v0.17.0...v0.17.1](https://github.com/Finch-API/finch-api-python/compare/v0.17.0...v0.17.1)

### Chores

* **api:** improve descriptions ([#341](https://github.com/Finch-API/finch-api-python/issues/341)) ([43c477f](https://github.com/Finch-API/finch-api-python/commit/43c477f4da8e71a6b28598993dd15b8557017641))
* **client:** validate that max_retries is not None ([#337](https://github.com/Finch-API/finch-api-python/issues/337)) ([6558aeb](https://github.com/Finch-API/finch-api-python/commit/6558aebd5ea0c2716a5e321787e24420dd8f203a))
* **internal:** defer model build for import latency ([#339](https://github.com/Finch-API/finch-api-python/issues/339)) ([8e383bc](https://github.com/Finch-API/finch-api-python/commit/8e383bc6893f3344256368c0de28b55f385a09d2))
* **internal:** streaming updates ([#340](https://github.com/Finch-API/finch-api-python/issues/340)) ([71fca9d](https://github.com/Finch-API/finch-api-python/commit/71fca9d60e40b63ff14df78f4a0cbccaaa5fff18))

## 0.17.0 (2024-03-29)

Full Changelog: [v0.16.8...v0.17.0](https://github.com/Finch-API/finch-api-python/compare/v0.16.8...v0.17.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "finch-api"
version = "0.17.0"
version = "0.17.1"
description = "The official Python library for the Finch API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
5 changes: 5 additions & 0 deletions src/finch/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,11 @@ def __init__(
self._strict_response_validation = _strict_response_validation
self._idempotency_header = None

if max_retries is None: # pyright: ignore[reportUnnecessaryComparison]
raise TypeError(
"max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `finch-api.DEFAULT_MAX_RETRIES`"
)

def _enforce_trailing_slash(self, url: URL) -> URL:
if url.raw_path.endswith(b"/"):
return url
Expand Down
6 changes: 5 additions & 1 deletion src/finch/_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import os
import inspect
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
from datetime import date, datetime
Expand Down Expand Up @@ -38,6 +39,7 @@
is_given,
is_mapping,
parse_date,
coerce_boolean,
parse_datetime,
strip_not_given,
extract_type_arg,
Expand Down Expand Up @@ -74,7 +76,9 @@ class _ConfigProtocol(Protocol):

class BaseModel(pydantic.BaseModel):
if PYDANTIC_V2:
model_config: ClassVar[ConfigDict] = ConfigDict(extra="allow")
model_config: ClassVar[ConfigDict] = ConfigDict(
extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true"))
)
else:

@property
Expand Down
73 changes: 47 additions & 26 deletions src/finch/_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Stream(Generic[_T]):

response: httpx.Response

_decoder: SSEDecoder | SSEBytesDecoder
_decoder: SSEBytesDecoder

def __init__(
self,
Expand All @@ -46,10 +46,7 @@ def __iter__(self) -> Iterator[_T]:
yield item

def _iter_events(self) -> Iterator[ServerSentEvent]:
if isinstance(self._decoder, SSEBytesDecoder):
yield from self._decoder.iter_bytes(self.response.iter_bytes())
else:
yield from self._decoder.iter(self.response.iter_lines())
yield from self._decoder.iter_bytes(self.response.iter_bytes())

def __stream__(self) -> Iterator[_T]:
cast_to = cast(Any, self._cast_to)
Expand Down Expand Up @@ -112,12 +109,8 @@ async def __aiter__(self) -> AsyncIterator[_T]:
yield item

async def _iter_events(self) -> AsyncIterator[ServerSentEvent]:
if isinstance(self._decoder, SSEBytesDecoder):
async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()):
yield sse
else:
async for sse in self._decoder.aiter(self.response.aiter_lines()):
yield sse
async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()):
yield sse

async def __stream__(self) -> AsyncIterator[_T]:
cast_to = cast(Any, self._cast_to)
Expand Down Expand Up @@ -205,21 +198,49 @@ def __init__(self) -> None:
self._last_event_id = None
self._retry = None

def iter(self, iterator: Iterator[str]) -> Iterator[ServerSentEvent]:
"""Given an iterator that yields lines, iterate over it & yield every event encountered"""
for line in iterator:
line = line.rstrip("\n")
sse = self.decode(line)
if sse is not None:
yield sse

async def aiter(self, iterator: AsyncIterator[str]) -> AsyncIterator[ServerSentEvent]:
"""Given an async iterator that yields lines, iterate over it & yield every event encountered"""
async for line in iterator:
line = line.rstrip("\n")
sse = self.decode(line)
if sse is not None:
yield sse
def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]:
"""Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
for chunk in self._iter_chunks(iterator):
# Split before decoding so splitlines() only uses \r and \n
for raw_line in chunk.splitlines():
line = raw_line.decode("utf-8")
sse = self.decode(line)
if sse:
yield sse

def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]:
"""Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks"""
data = b""
for chunk in iterator:
for line in chunk.splitlines(keepends=True):
data += line
if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")):
yield data
data = b""
if data:
yield data

async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]:
"""Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
async for chunk in self._aiter_chunks(iterator):
# Split before decoding so splitlines() only uses \r and \n
for raw_line in chunk.splitlines():
line = raw_line.decode("utf-8")
sse = self.decode(line)
if sse:
yield sse

async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]:
"""Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks"""
data = b""
async for chunk in iterator:
for line in chunk.splitlines(keepends=True):
data += line
if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")):
yield data
data = b""
if data:
yield data

def decode(self, line: str) -> ServerSentEvent | None:
# See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
Expand Down
2 changes: 1 addition & 1 deletion src/finch/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "finch"
__version__ = "0.17.0" # x-release-please-version
__version__ = "0.17.1" # x-release-please-version
5 changes: 2 additions & 3 deletions src/finch/types/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ class Introspection(BaseModel):
connection_type: Literal["provider", "finch"]
"""The type of the connection associated with the token.

`provider` - connection to an external provider

`finch` - finch-generated data.
- `provider` - connection to an external provider
- `finch` - finch-generated data.
"""

manual: bool
Expand Down
24 changes: 8 additions & 16 deletions src/finch/types/shared/operation_support_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,45 @@

class OperationSupportMatrix(BaseModel):
create: Optional[OperationSupport] = None
"""- `supported`: This operation is supported by both the provider and Finch

"""
- `supported`: This operation is supported by both the provider and Finch
- `not_supported_by_finch`: This operation is not supported by Finch but
supported by the provider

- `not_supported_by_provider`: This operation is not supported by the provider,
so Finch cannot support

- `client_access_only`: This behavior is supported by the provider, but only
available to the client and not to Finch
"""

delete: Optional[OperationSupport] = None
"""- `supported`: This operation is supported by both the provider and Finch

"""
- `supported`: This operation is supported by both the provider and Finch
- `not_supported_by_finch`: This operation is not supported by Finch but
supported by the provider

- `not_supported_by_provider`: This operation is not supported by the provider,
so Finch cannot support

- `client_access_only`: This behavior is supported by the provider, but only
available to the client and not to Finch
"""

read: Optional[OperationSupport] = None
"""- `supported`: This operation is supported by both the provider and Finch

"""
- `supported`: This operation is supported by both the provider and Finch
- `not_supported_by_finch`: This operation is not supported by Finch but
supported by the provider

- `not_supported_by_provider`: This operation is not supported by the provider,
so Finch cannot support

- `client_access_only`: This behavior is supported by the provider, but only
available to the client and not to Finch
"""

update: Optional[OperationSupport] = None
"""- `supported`: This operation is supported by both the provider and Finch

"""
- `supported`: This operation is supported by both the provider and Finch
- `not_supported_by_finch`: This operation is not supported by Finch but
supported by the provider

- `not_supported_by_provider`: This operation is not supported by the provider,
so Finch cannot support

- `client_access_only`: This behavior is supported by the provider, but only
available to the client and not to Finch
"""
22 changes: 22 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,17 @@ class Model(BaseModel):

assert isinstance(exc.value.__cause__, ValidationError)

def test_client_max_retries_validation(self) -> None:
with pytest.raises(TypeError, match=r"max_retries cannot be None"):
Finch(
base_url=base_url,
access_token=access_token,
client_id=client_id,
client_secret=client_secret,
_strict_response_validation=True,
max_retries=cast(Any, None),
)

@pytest.mark.respx(base_url=base_url)
def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None:
class Model(BaseModel):
Expand Down Expand Up @@ -1782,6 +1793,17 @@ class Model(BaseModel):

assert isinstance(exc.value.__cause__, ValidationError)

async def test_client_max_retries_validation(self) -> None:
with pytest.raises(TypeError, match=r"max_retries cannot be None"):
AsyncFinch(
base_url=base_url,
access_token=access_token,
client_id=client_id,
client_secret=client_secret,
_strict_response_validation=True,
max_retries=cast(Any, None),
)

@pytest.mark.respx(base_url=base_url)
@pytest.mark.asyncio
async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None:
Expand Down
Loading