From 592f44bcb66cfe8928b499f91e73187035368166 Mon Sep 17 00:00:00 2001 From: Vladyslav Zaiets Date: Thu, 28 May 2026 18:57:42 +0000 Subject: [PATCH] Fix Bedrock client region detection to respect aws_profile and AWS_DEFAULT_REGION The _infer_region() function was not receiving the aws_profile parameter, so when a user passed aws_profile="my-profile" to AnthropicBedrock(), the profile-specific region from ~/.aws/config was ignored during region inference. The function also only checked AWS_REGION, missing the AWS_DEFAULT_REGION environment variable that boto3 and AWS CLI support. Changes: - Pass aws_profile to _infer_region() so boto3.Session resolves the correct profile-specific region - Check AWS_DEFAULT_REGION as fallback when AWS_REGION is unset - Set self.aws_profile before calling _infer_region() so it is available - Remove redundant "or us-east-1" fallbacks in _prepare_request since _infer_region() already guarantees a non-None return value Fixes #892 --- src/anthropic/lib/bedrock/_client.py | 21 ++++++--- tests/lib/test_bedrock.py | 65 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/anthropic/lib/bedrock/_client.py b/src/anthropic/lib/bedrock/_client.py index cda0690df..73b265c09 100644 --- a/src/anthropic/lib/bedrock/_client.py +++ b/src/anthropic/lib/bedrock/_client.py @@ -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: @@ -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 @@ -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, ) @@ -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 @@ -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, ) diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py index 6e45c27f7..3ee8a45b2 100644 --- a/tests/lib/test_bedrock.py +++ b/tests/lib/test_bedrock.py @@ -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"