Skip to content
Open
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
21 changes: 14 additions & 7 deletions src/anthropic/lib/bedrock/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,24 @@ def _prepare_options(input_options: FinalRequestOptions) -> FinalRequestOptions:
return options


def _infer_region() -> str:
def _infer_region(aws_profile: str | None = None) -> str:
"""
Infer the AWS region from the environment variables or
from the boto3 session if available.

The resolution order is:
1. ``AWS_REGION`` environment variable
2. ``AWS_DEFAULT_REGION`` environment variable
3. Region resolved by a ``boto3.Session`` (respects ``AWS_PROFILE``,
``~/.aws/config``, and the explicit *aws_profile* parameter)
4. Hard-coded ``us-east-1`` fallback (legacy behaviour)
"""
aws_region = os.environ.get("AWS_REGION")
aws_region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
if aws_region is None:
try:
import boto3

session = boto3.Session()
session = boto3.Session(profile_name=aws_profile)
if session.region_name:
aws_region = session.region_name
except ImportError:
Expand Down Expand Up @@ -178,8 +185,8 @@ def __init__(

self.aws_access_key = aws_access_key

self.aws_region = _infer_region() if aws_region is None else aws_region
self.aws_profile = aws_profile
self.aws_region = _infer_region(aws_profile=aws_profile) if aws_region is None else aws_region

self.aws_session_token = aws_session_token

Expand Down Expand Up @@ -228,7 +235,7 @@ def _prepare_request(self, request: httpx.Request) -> None:
aws_access_key=self.aws_access_key,
aws_secret_key=self.aws_secret_key,
aws_session_token=self.aws_session_token,
region=self.aws_region or "us-east-1",
region=self.aws_region,
profile=self.aws_profile,
data=data,
)
Expand Down Expand Up @@ -343,8 +350,8 @@ def __init__(

self.aws_access_key = aws_access_key

self.aws_region = _infer_region() if aws_region is None else aws_region
self.aws_profile = aws_profile
self.aws_region = _infer_region(aws_profile=aws_profile) if aws_region is None else aws_region

self.aws_session_token = aws_session_token

Expand Down Expand Up @@ -393,7 +400,7 @@ async def _prepare_request(self, request: httpx.Request) -> None:
aws_access_key=self.aws_access_key,
aws_secret_key=self.aws_secret_key,
aws_session_token=self.aws_session_token,
region=self.aws_region or "us-east-1",
region=self.aws_region,
profile=self.aws_profile,
data=data,
)
Expand Down
65 changes: 65 additions & 0 deletions tests/lib/test_bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,68 @@ def test_region_infer_from_specified_profile(
client = AnthropicBedrock()

assert client.aws_region == next(profile for profile in profiles if profile["name"] == aws_profile)["region"]


def test_region_infer_from_aws_default_region(monkeypatch: t.Any) -> None:
"""AWS_DEFAULT_REGION should be respected when AWS_REGION is not set."""
monkeypatch.delenv("AWS_REGION", raising=False)
monkeypatch.setenv("AWS_DEFAULT_REGION", "eu-west-1")
client = AnthropicBedrock(
aws_access_key="example-access-key",
aws_secret_key="example-secret-key",
)
assert client.aws_region == "eu-west-1"


def test_aws_region_takes_precedence_over_aws_default_region(monkeypatch: t.Any) -> None:
"""AWS_REGION should take precedence over AWS_DEFAULT_REGION."""
monkeypatch.setenv("AWS_REGION", "us-west-2")
monkeypatch.setenv("AWS_DEFAULT_REGION", "eu-west-1")
client = AnthropicBedrock(
aws_access_key="example-access-key",
aws_secret_key="example-secret-key",
)
assert client.aws_region == "us-west-2"


@pytest.mark.parametrize(
"profiles",
[
pytest.param(
[{"name": "default", "region": "us-east-2"}, {"name": "custom", "region": "ap-southeast-1"}],
id="custom profile via constructor",
),
],
)
def test_region_infer_from_explicit_aws_profile_param(
mock_aws_config: None, # noqa: ARG001
monkeypatch: t.Any,
) -> None:
"""When aws_profile is passed to the constructor, its region should be used
even without setting the AWS_PROFILE env var."""
monkeypatch.delenv("AWS_REGION", raising=False)
monkeypatch.delenv("AWS_DEFAULT_REGION", raising=False)
monkeypatch.delenv("AWS_PROFILE", raising=False)
client = AnthropicBedrock(aws_profile="custom")
assert client.aws_region == "ap-southeast-1"


@pytest.mark.parametrize(
"profiles",
[
pytest.param(
[{"name": "default", "region": "us-east-2"}, {"name": "custom", "region": "ap-southeast-1"}],
id="async custom profile via constructor",
),
],
)
def test_region_infer_from_explicit_aws_profile_param_async(
mock_aws_config: None, # noqa: ARG001
monkeypatch: t.Any,
) -> None:
"""AsyncAnthropicBedrock should also respect the aws_profile parameter for region inference."""
monkeypatch.delenv("AWS_REGION", raising=False)
monkeypatch.delenv("AWS_DEFAULT_REGION", raising=False)
monkeypatch.delenv("AWS_PROFILE", raising=False)
client = AsyncAnthropicBedrock(aws_profile="custom")
assert client.aws_region == "ap-southeast-1"