Skip to content

release: 0.16.0 #297

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 8 commits into from
Mar 1, 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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
if: github.repository == 'Finch-API/finch-api-python'

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Install Rye
run: |
Expand Down
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.15.0"
".": "0.16.0"
}
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## 0.16.0 (2024-03-01)

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

### Features

* **api:** make redirect_uri optional ([#298](https://github.com/Finch-API/finch-api-python/issues/298)) ([8d42399](https://github.com/Finch-API/finch-api-python/commit/8d42399f838fc6274053977c4b648db181199bdf))


### Chores

* **client:** use anyio.sleep instead of asyncio.sleep ([#300](https://github.com/Finch-API/finch-api-python/issues/300)) ([3af8e4c](https://github.com/Finch-API/finch-api-python/commit/3af8e4ca2391a818c4bfafa9d7e0efbf7a7b0d67))
* **docs:** mention install from git repo ([#303](https://github.com/Finch-API/finch-api-python/issues/303)) ([f4b2c3c](https://github.com/Finch-API/finch-api-python/commit/f4b2c3c217c226db6af3a8dd11892ae2a95efac6))
* **internal:** bump pyright ([#299](https://github.com/Finch-API/finch-api-python/issues/299)) ([75e91f6](https://github.com/Finch-API/finch-api-python/commit/75e91f636e11472f298ed8796f318b97a15338cc))
* **internal:** minor core client restructuring ([#301](https://github.com/Finch-API/finch-api-python/issues/301)) ([b2552a1](https://github.com/Finch-API/finch-api-python/commit/b2552a162373430d773de362982538a0b268dd1f))
* **internal:** update deps ([#296](https://github.com/Finch-API/finch-api-python/issues/296)) ([6e94884](https://github.com/Finch-API/finch-api-python/commit/6e94884a9a9051c17d7c38686fcc182f48d5d805))


### Documentation

* **contributing:** improve wording ([#302](https://github.com/Finch-API/finch-api-python/issues/302)) ([46c5cba](https://github.com/Finch-API/finch-api-python/commit/46c5cba7021ca9af3dc0a741c72b3530c4be74f4))

## 0.15.0 (2024-02-20)

Full Changelog: [v0.14.2...v0.15.0](https://github.com/Finch-API/finch-api-python/compare/v0.14.2...v0.15.0)
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ If you’d like to use the repository from source, you can either install from g
To install via git:

```bash
pip install git+ssh://[email protected]:Finch-API/finch-api-python.git
pip install git+ssh://[email protected]/Finch-API/finch-api-python.git
```

Alternatively, you can build from source and install the wheel file:
Expand All @@ -82,7 +82,7 @@ pip install ./path-to-wheel-file.whl

## Running tests

Most tests will require you to [setup a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.

```bash
# you will need npm installed
Expand Down Expand Up @@ -117,7 +117,7 @@ the changes aren't made through the automated pipeline, you may want to make rel

### Publish with a GitHub workflow

You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/Finch-API/finch-api-python/actions/workflows/publish-pypi.yml). This will require a setup organization or repository secret to be set up.
You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/Finch-API/finch-api-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up.

### Publish manually

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The REST API documentation can be found [in the Finch Documentation Center](http
## Installation

```sh
# install from PyPI
pip install finch-api
```

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.15.0"
version = "0.16.0"
description = "The official Python library for the Finch API"
readme = "README.md"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pydantic==2.4.2
# via finch-api
pydantic-core==2.10.1
# via pydantic
pyright==1.1.332
pyright==1.1.351
pytest==7.1.1
# via pytest-asyncio
pytest-asyncio==0.21.1
Expand Down
5 changes: 4 additions & 1 deletion src/finch/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
RAW_RESPONSE_HEADER,
OVERRIDE_CAST_TO_HEADER,
)
from ._streaming import Stream, AsyncStream
from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder
from ._exceptions import (
APIStatusError,
APITimeoutError,
Expand Down Expand Up @@ -431,6 +431,9 @@ def _prepare_url(self, url: str) -> URL:

return merge_url

def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder:
return SSEDecoder()

def _build_request(
self,
options: FinalRequestOptions,
Expand Down
4 changes: 2 additions & 2 deletions src/finch/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ def get_access_token(
self,
code: str,
*,
redirect_uri: str,
redirect_uri: str | None = None,
) -> str:
"""Returns an access token for the Finch API given an authorization code.

Expand Down Expand Up @@ -657,7 +657,7 @@ async def get_access_token(
self,
code: str,
*,
redirect_uri: str,
redirect_uri: str | None = None,
) -> str:
"""Returns an access token for the Finch API given an authorization code.

Expand Down
2 changes: 1 addition & 1 deletion src/finch/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def construct_type(*, value: object, type_: type) -> object:

if is_union(origin):
try:
return validate_type(type_=type_, value=value)
return validate_type(type_=cast("type[object]", type_), value=value)
except Exception:
pass

Expand Down
5 changes: 3 additions & 2 deletions src/finch/_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from __future__ import annotations

import time
import asyncio
from typing import TYPE_CHECKING

import anyio

if TYPE_CHECKING:
from ._client import Finch, AsyncFinch

Expand Down Expand Up @@ -39,4 +40,4 @@ def __init__(self, client: AsyncFinch) -> None:
self._get_api_list = client.get_api_list

async def _sleep(self, seconds: float) -> None:
await asyncio.sleep(seconds)
await anyio.sleep(seconds)
34 changes: 28 additions & 6 deletions src/finch/_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import inspect
from types import TracebackType
from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast
from typing_extensions import Self, TypeGuard, override, get_origin
from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable

import httpx

Expand All @@ -23,6 +23,8 @@ class Stream(Generic[_T]):

response: httpx.Response

_decoder: SSEDecoder | SSEBytesDecoder

def __init__(
self,
*,
Expand All @@ -33,7 +35,7 @@ def __init__(
self.response = response
self._cast_to = cast_to
self._client = client
self._decoder = SSEDecoder()
self._decoder = client._make_sse_decoder()
self._iterator = self.__stream__()

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

def _iter_events(self) -> Iterator[ServerSentEvent]:
yield from self._decoder.iter(self.response.iter_lines())
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())

def __stream__(self) -> Iterator[_T]:
cast_to = cast(Any, self._cast_to)
Expand Down Expand Up @@ -84,6 +89,8 @@ class AsyncStream(Generic[_T]):

response: httpx.Response

_decoder: SSEDecoder | SSEBytesDecoder

def __init__(
self,
*,
Expand All @@ -94,7 +101,7 @@ def __init__(
self.response = response
self._cast_to = cast_to
self._client = client
self._decoder = SSEDecoder()
self._decoder = client._make_sse_decoder()
self._iterator = self.__stream__()

async def __anext__(self) -> _T:
Expand All @@ -105,8 +112,12 @@ async def __aiter__(self) -> AsyncIterator[_T]:
yield item

async def _iter_events(self) -> AsyncIterator[ServerSentEvent]:
async for sse in self._decoder.aiter(self.response.aiter_lines()):
yield sse
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 def __stream__(self) -> AsyncIterator[_T]:
cast_to = cast(Any, self._cast_to)
Expand Down Expand Up @@ -259,6 +270,17 @@ def decode(self, line: str) -> ServerSentEvent | None:
return None


@runtime_checkable
class SSEBytesDecoder(Protocol):
def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]:
"""Given an iterator that yields raw binary data, iterate over it & yield every event encountered"""
...

def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]:
"""Given an async iterator that yields raw binary data, iterate over it & yield every event encountered"""
...


def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]:
"""TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`"""
origin = get_origin(typ) or typ
Expand Down
2 changes: 1 addition & 1 deletion src/finch/_utils/_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __dir__(self) -> Iterable[str]:

@property # type: ignore
@override
def __class__(self) -> type:
def __class__(self) -> type: # pyright: ignore
proxied = self.__get_proxied__()
if issubclass(type(proxied), LazyProxy):
return type(proxied)
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.

__title__ = "finch"
__version__ = "0.15.0" # x-release-please-version
__version__ = "0.16.0" # x-release-please-version
4 changes: 2 additions & 2 deletions src/finch/resources/access_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def create(
self,
*,
code: str,
redirect_uri: str,
client_id: str | NotGiven = NOT_GIVEN,
client_secret: str | NotGiven = NOT_GIVEN,
redirect_uri: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand Down Expand Up @@ -98,9 +98,9 @@ async def create(
self,
*,
code: str,
redirect_uri: str,
client_id: str | NotGiven = NOT_GIVEN,
client_secret: str | NotGiven = NOT_GIVEN,
redirect_uri: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand Down
4 changes: 2 additions & 2 deletions src/finch/types/access_token_create_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
class AccessTokenCreateParams(TypedDict, total=False):
code: Required[str]

redirect_uri: Required[str]

client_id: str

client_secret: str

redirect_uri: str
10 changes: 2 additions & 8 deletions tests/api_resources/test_access_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,23 @@ class TestAccessTokens:
def test_method_create(self, client: Finch) -> None:
access_token = client.access_tokens.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
def test_method_create_with_all_params(self, client: Finch) -> None:
access_token = client.access_tokens.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
client_id="<your_client_id>",
client_secret="<your_client_secret>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
def test_raw_response_create(self, client: Finch) -> None:
response = client.access_tokens.with_raw_response.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
)

assert response.is_closed is True
Expand All @@ -51,7 +49,6 @@ def test_raw_response_create(self, client: Finch) -> None:
def test_streaming_response_create(self, client: Finch) -> None:
with client.access_tokens.with_streaming_response.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
Expand All @@ -69,25 +66,23 @@ class TestAsyncAccessTokens:
async def test_method_create(self, async_client: AsyncFinch) -> None:
access_token = await async_client.access_tokens.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncFinch) -> None:
access_token = await async_client.access_tokens.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
client_id="<your_client_id>",
client_secret="<your_client_secret>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
async def test_raw_response_create(self, async_client: AsyncFinch) -> None:
response = await async_client.access_tokens.with_raw_response.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
)

assert response.is_closed is True
Expand All @@ -99,7 +94,6 @@ async def test_raw_response_create(self, async_client: AsyncFinch) -> None:
async def test_streaming_response_create(self, async_client: AsyncFinch) -> None:
async with async_client.access_tokens.with_streaming_response.create(
code="<your_authorization_code>",
redirect_uri="https://example.com",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
Expand Down