Skip to content
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

release: 0.31.1 #585

Merged
merged 8 commits into from
Jul 15, 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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
pull_request:
branches:
- main
- next

jobs:
lint:
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.31.0"
".": "0.31.1"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
configured_endpoints: 2
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic-ce067ae8303fa9b7aae2e8ebf0b6e9e41509f169ba93c1807e6ed9c9e541be1a.yml
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic-e2a51f04a202c13736b6fa2061a89a0c443f99ab166d965d702baf371eb1ca8f.yml
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## 0.31.1 (2024-07-15)

Full Changelog: [v0.31.0...v0.31.1](https://github.com/anthropics/anthropic-sdk-python/compare/v0.31.0...v0.31.1)

### Bug Fixes

* **bedrock:** correct request options for retries ([#593](https://github.com/anthropics/anthropic-sdk-python/issues/593)) ([f68c81d](https://github.com/anthropics/anthropic-sdk-python/commit/f68c81d072fceb46d4c0d8ee62cf274eeea99415))


### Chores

* **ci:** also run workflows for PRs targeting `next` ([#587](https://github.com/anthropics/anthropic-sdk-python/issues/587)) ([f7e49f2](https://github.com/anthropics/anthropic-sdk-python/commit/f7e49f2f2ceb62cccd6961fc1bd799655ccd83ab))
* **internal:** minor changes to tests ([#591](https://github.com/anthropics/anthropic-sdk-python/issues/591)) ([fabd591](https://github.com/anthropics/anthropic-sdk-python/commit/fabd5910f2e769b8bfbeaaa8b65ca8383b4954e3))
* **internal:** minor formatting changes ([a71927b](https://github.com/anthropics/anthropic-sdk-python/commit/a71927b7c7cff4e83eb485d3b0eef928a18acef6))
* **internal:** minor import restructuring ([#588](https://github.com/anthropics/anthropic-sdk-python/issues/588)) ([1d9db4f](https://github.com/anthropics/anthropic-sdk-python/commit/1d9db4f6c1393c3879e83e1a3e1d1b4fedc33b5a))
* **internal:** minor options / compat functions updates ([#592](https://github.com/anthropics/anthropic-sdk-python/issues/592)) ([d41a880](https://github.com/anthropics/anthropic-sdk-python/commit/d41a8807057958d4505e16325e4a06359a760260))
* **internal:** update mypy ([#584](https://github.com/anthropics/anthropic-sdk-python/issues/584)) ([0a0edce](https://github.com/anthropics/anthropic-sdk-python/commit/0a0edce53e9eebd47770e71493302527e7f43751))

## 0.31.0 (2024-07-10)

Full Changelog: [v0.30.1...v0.31.0](https://github.com/anthropics/anthropic-sdk-python/compare/v0.30.1...v0.31.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 = "anthropic"
version = "0.31.0"
version = "0.31.1"
description = "The official Python library for the anthropic API"
dynamic = ["readme"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
mypy==1.7.1
mypy==1.10.1
mypy-extensions==1.0.0
# via mypy
nodeenv==1.8.0
Expand Down
12 changes: 6 additions & 6 deletions src/anthropic/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -880,9 +880,9 @@ def __exit__(
def _prepare_options(
self,
options: FinalRequestOptions, # noqa: ARG002
) -> None:
) -> FinalRequestOptions:
"""Hook for mutating the given options"""
return None
return options

def _prepare_request(
self,
Expand Down Expand Up @@ -962,7 +962,7 @@ def _request(
input_options = model_copy(options)

cast_to = self._maybe_override_cast_to(cast_to, options)
self._prepare_options(options)
options = self._prepare_options(options)

retries = self._remaining_retries(remaining_retries, options)
request = self._build_request(options)
Expand Down Expand Up @@ -1457,9 +1457,9 @@ async def __aexit__(
async def _prepare_options(
self,
options: FinalRequestOptions, # noqa: ARG002
) -> None:
) -> FinalRequestOptions:
"""Hook for mutating the given options"""
return None
return options

async def _prepare_request(
self,
Expand Down Expand Up @@ -1544,7 +1544,7 @@ async def _request(
input_options = model_copy(options)

cast_to = self._maybe_override_cast_to(cast_to, options)
await self._prepare_options(options)
options = await self._prepare_options(options)

retries = self._remaining_retries(remaining_retries, options)
request = self._build_request(options)
Expand Down
6 changes: 3 additions & 3 deletions src/anthropic/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]:
return model.__fields__ # type: ignore


def model_copy(model: _ModelT) -> _ModelT:
def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT:
if PYDANTIC_V2:
return model.model_copy()
return model.copy() # type: ignore
return model.model_copy(deep=deep)
return model.copy(deep=deep) # type: ignore


def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
Expand Down
2 changes: 1 addition & 1 deletion src/anthropic/_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__ = "anthropic"
__version__ = "0.31.0" # x-release-please-version
__version__ = "0.31.1" # x-release-please-version
44 changes: 26 additions & 18 deletions src/anthropic/lib/bedrock/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ... import _exceptions
from ..._types import NOT_GIVEN, Timeout, NotGiven
from ..._utils import is_dict, is_given
from ..._compat import model_copy
from ..._version import __version__
from ..._streaming import Stream, AsyncStream
from ..._exceptions import APIStatusError
Expand All @@ -29,28 +30,27 @@
_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])


class BaseBedrockClient(BaseClient[_HttpxClientT, _DefaultStreamT]):
@override
def _build_request(
self,
options: FinalRequestOptions,
) -> httpx.Request:
if is_dict(options.json_data):
options.json_data.setdefault("anthropic_version", DEFAULT_VERSION)
def _prepare_options(input_options: FinalRequestOptions) -> FinalRequestOptions:
options = model_copy(input_options, deep=True)

if is_dict(options.json_data):
options.json_data.setdefault("anthropic_version", DEFAULT_VERSION)

if options.url in {"/v1/complete", "/v1/messages"} and options.method == "post":
if not is_dict(options.json_data):
raise RuntimeError("Expected dictionary json_data for post /completions endpoint")

if options.url in {"/v1/complete", "/v1/messages"} and options.method == "post":
if not is_dict(options.json_data):
raise RuntimeError("Expected dictionary json_data for post /completions endpoint")
model = options.json_data.pop("model", None)
stream = options.json_data.pop("stream", False)
if stream:
options.url = f"/model/{model}/invoke-with-response-stream"
else:
options.url = f"/model/{model}/invoke"

model = options.json_data.pop("model", None)
stream = options.json_data.pop("stream", False)
if stream:
options.url = f"/model/{model}/invoke-with-response-stream"
else:
options.url = f"/model/{model}/invoke"
return options

return super()._build_request(options)

class BaseBedrockClient(BaseClient[_HttpxClientT, _DefaultStreamT]):
@override
def _make_status_error(
self,
Expand Down Expand Up @@ -145,6 +145,10 @@ def __init__(
def _make_sse_decoder(self) -> AWSEventStreamDecoder:
return AWSEventStreamDecoder()

@override
def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
return _prepare_options(options)

@override
def _prepare_request(self, request: httpx.Request) -> None:
from ._auth import get_auth_headers
Expand Down Expand Up @@ -280,6 +284,10 @@ def __init__(
def _make_sse_decoder(self) -> AWSEventStreamDecoder:
return AWSEventStreamDecoder()

@override
async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
return _prepare_options(options)

@override
async def _prepare_request(self, request: httpx.Request) -> None:
from ._auth import get_auth_headers
Expand Down
4 changes: 1 addition & 3 deletions src/anthropic/resources/completions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
from .._streaming import Stream, AsyncStream
from .._base_client import (
make_request_options,
)
from .._base_client import make_request_options
from ..types.completion import Completion

__all__ = ["Completions", "AsyncCompletions"]
Expand Down
4 changes: 1 addition & 3 deletions src/anthropic/resources/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
from .._streaming import Stream, AsyncStream
from .._base_client import (
make_request_options,
)
from .._base_client import make_request_options
from ..lib.streaming import MessageStreamManager, AsyncMessageStreamManager
from ..types.message import Message
from ..types.tool_param import ToolParam
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/content_block_delta_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_content_block_delta_event import RawContentBlockDeltaEvent

__all__ = ["ContentBlockDeltaEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/content_block_start_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_content_block_start_event import RawContentBlockStartEvent

__all__ = ["ContentBlockStartEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/content_block_stop_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_content_block_stop_event import RawContentBlockStopEvent

__all__ = ["ContentBlockStopEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/message_delta_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_message_delta_event import RawMessageDeltaEvent

__all__ = ["MessageDeltaEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/message_start_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_message_start_event import RawMessageStartEvent

__all__ = ["MessageStartEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/message_stop_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_message_stop_event import RawMessageStopEvent

__all__ = ["MessageStopEvent"]
Expand Down
1 change: 0 additions & 1 deletion src/anthropic/types/message_stream_event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.



from .raw_message_stream_event import RawMessageStreamEvent

__all__ = ["MessageStreamEvent"]
Expand Down
93 changes: 93 additions & 0 deletions tests/lib/test_bedrock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import re
from typing import cast
from typing_extensions import Protocol

import httpx
import pytest
from respx import MockRouter

from anthropic import AnthropicBedrock, AsyncAnthropicBedrock

sync_client = AnthropicBedrock(
aws_region="us-east-1",
aws_access_key="example-access-key",
aws_secret_key="example-secret-key",
)
async_client = AsyncAnthropicBedrock(
aws_region="us-east-1",
aws_access_key="example-access-key",
aws_secret_key="example-secret-key",
)


class MockRequestCall(Protocol):
request: httpx.Request


@pytest.mark.respx()
def test_messages_retries(respx_mock: MockRouter) -> None:
respx_mock.post(re.compile(r"https://bedrock-runtime\.us-east-1\.amazonaws\.com/model/.*/invoke")).mock(
side_effect=[
httpx.Response(500, json={"error": "server error"}),
httpx.Response(200, json={"foo": "bar"}),
]
)

sync_client.messages.create(
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Say hello there!",
}
],
model="anthropic.claude-3-sonnet-20240229-v1:0",
)

calls = cast("list[MockRequestCall]", respx_mock.calls)

assert len(calls) == 2

assert (
calls[0].request.url
== "https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke"
)
assert (
calls[1].request.url
== "https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke"
)


@pytest.mark.respx()
@pytest.mark.asyncio()
async def test_messages_retries_async(respx_mock: MockRouter) -> None:
respx_mock.post(re.compile(r"https://bedrock-runtime\.us-east-1\.amazonaws\.com/model/.*/invoke")).mock(
side_effect=[
httpx.Response(500, json={"error": "server error"}),
httpx.Response(200, json={"foo": "bar"}),
]
)

await async_client.messages.create(
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Say hello there!",
}
],
model="anthropic.claude-3-sonnet-20240229-v1:0",
)

calls = cast("list[MockRequestCall]", respx_mock.calls)

assert len(calls) == 2

assert (
calls[0].request.url
== "https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke"
)
assert (
calls[1].request.url
== "https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke"
)
Loading