Skip to content

Commit 518dae7

Browse files
committed
test: add validation that LatestBedrockModelNames geo prefixes are in BEDROCK_GEO_PREFIXES
This test ensures we don't add new model names with geo prefixes that aren't handled by the provider's model_profile method. Also exports BEDROCK_GEO_PREFIXES in __all__.
1 parent 879446f commit 518dae7

File tree

2 files changed

+33
-32
lines changed

2 files changed

+33
-32
lines changed

pydantic_ai_slim/pydantic_ai/providers/bedrock.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from typing import Any, Literal, overload
88

99
from pydantic_ai import ModelProfile
10+
11+
__all__ = ('BedrockModelProfile', 'BedrockProvider', 'BEDROCK_GEO_PREFIXES')
1012
from pydantic_ai.exceptions import UserError
1113
from pydantic_ai.profiles.amazon import amazon_model_profile
1214
from pydantic_ai.profiles.anthropic import anthropic_model_profile
@@ -59,7 +61,7 @@ def bedrock_deepseek_model_profile(model_name: str) -> ModelProfile | None:
5961

6062

6163
# Known geo prefixes for cross-region inference profile IDs
62-
_BEDROCK_GEO_PREFIXES: tuple[str, ...] = ('us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.')
64+
BEDROCK_GEO_PREFIXES: tuple[str, ...] = ('us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.')
6365

6466

6567
def _strip_geo_prefix(model_name: str) -> str:
@@ -69,7 +71,7 @@ def _strip_geo_prefix(model_name: str) -> str:
6971
to route requests to specific regions. This function strips those prefixes so we can
7072
identify the underlying provider and model.
7173
"""
72-
for prefix in _BEDROCK_GEO_PREFIXES:
74+
for prefix in BEDROCK_GEO_PREFIXES:
7375
if model_name.startswith(prefix):
7476
return model_name.removeprefix(prefix)
7577
return model_name
@@ -104,7 +106,6 @@ def model_profile(self, model_name: str) -> ModelProfile | None:
104106
'deepseek': bedrock_deepseek_model_profile,
105107
}
106108

107-
# Strip regional/geo prefix if present (e.g. "us.", "eu.", "us-gov.", "global.")
108109
model_name = _strip_geo_prefix(model_name)
109110

110111
# Split the model name into provider and model parts

tests/providers/test_bedrock.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import cast
1+
from typing import cast, get_args
22

33
import pytest
44
from pytest_mock import MockerFixture
@@ -16,7 +16,8 @@
1616
with try_import() as imports_successful:
1717
from mypy_boto3_bedrock_runtime import BedrockRuntimeClient
1818

19-
from pydantic_ai.providers.bedrock import BedrockModelProfile, BedrockProvider
19+
from pydantic_ai.models.bedrock import LatestBedrockModelNames
20+
from pydantic_ai.providers.bedrock import BEDROCK_GEO_PREFIXES, BedrockModelProfile, BedrockProvider
2021

2122

2223
pytestmark = pytest.mark.skipif(not imports_successful(), reason='bedrock not installed')
@@ -102,7 +103,7 @@ def test_bedrock_provider_model_profile(env: TestEnv, mocker: MockerFixture):
102103
assert unknown_model is None
103104

104105

105-
@pytest.mark.parametrize('prefix', ['us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.'])
106+
@pytest.mark.parametrize('prefix', BEDROCK_GEO_PREFIXES)
106107
def test_bedrock_provider_model_profile_all_geo_prefixes(env: TestEnv, prefix: str):
107108
"""Test that all cross-region inference geo prefixes are correctly handled.
108109
@@ -117,33 +118,32 @@ def test_bedrock_provider_model_profile_all_geo_prefixes(env: TestEnv, prefix: s
117118
profile = provider.model_profile(model_name)
118119

119120
assert profile is not None, f'model_profile returned None for {model_name}'
120-
assert isinstance(profile, BedrockModelProfile)
121-
assert profile.bedrock_supports_tool_choice is True
122-
assert profile.bedrock_send_back_thinking_parts is True
123121

124122

125-
def test_bedrock_provider_model_profile_us_gov_anthropic(env: TestEnv, mocker: MockerFixture):
126-
"""Test that us-gov. prefixed Anthropic models get the correct profile.
123+
def test_latest_bedrock_model_names_geo_prefixes_are_supported():
124+
"""Ensure all geo prefixes used in LatestBedrockModelNames are in BEDROCK_GEO_PREFIXES.
127125
128-
This specifically tests the us-gov. prefix which was previously broken
129-
because the provider only handled 2-character prefixes.
126+
This test prevents adding new model names with geo prefixes that aren't handled
127+
by the provider's model_profile method.
130128
"""
131-
env.set('AWS_DEFAULT_REGION', 'us-east-1')
132-
provider = BedrockProvider()
133-
134-
ns = 'pydantic_ai.providers.bedrock'
135-
anthropic_model_profile_mock = mocker.patch(f'{ns}.anthropic_model_profile', wraps=anthropic_model_profile)
136-
137-
# Test us-gov. prefix (AWS GovCloud cross-region inference)
138-
profile = provider.model_profile('us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0')
139-
anthropic_model_profile_mock.assert_called_with('claude-sonnet-4-5-20250929')
140-
assert isinstance(profile, BedrockModelProfile)
141-
assert profile.bedrock_supports_tool_choice is True
142-
assert profile.bedrock_send_back_thinking_parts is True
143-
144-
# Test global. prefix
145-
profile = provider.model_profile('global.anthropic.claude-opus-4-5-20251101-v1:0')
146-
anthropic_model_profile_mock.assert_called_with('claude-opus-4-5-20251101')
147-
assert isinstance(profile, BedrockModelProfile)
148-
assert profile.bedrock_supports_tool_choice is True
149-
assert profile.bedrock_send_back_thinking_parts is True
129+
model_names = get_args(LatestBedrockModelNames)
130+
131+
# Known providers that appear after the geo prefix
132+
known_providers = ('anthropic', 'amazon', 'meta', 'mistral', 'cohere', 'deepseek')
133+
134+
missing_prefixes: set[str] = set()
135+
136+
for model_name in model_names:
137+
# Check if this model name has a geo prefix by seeing if it has 3+ dot-separated parts
138+
# and the second part is a known provider
139+
parts = model_name.split('.')
140+
if len(parts) >= 3 and parts[1] in known_providers:
141+
# This model has a geo prefix (e.g., "us.anthropic.claude...")
142+
geo_prefix = parts[0] + '.'
143+
if geo_prefix not in BEDROCK_GEO_PREFIXES:
144+
missing_prefixes.add(geo_prefix)
145+
146+
assert not missing_prefixes, (
147+
f'Found geo prefixes in LatestBedrockModelNames that are not in BEDROCK_GEO_PREFIXES: {missing_prefixes}. '
148+
f'Please add them to BEDROCK_GEO_PREFIXES in pydantic_ai/providers/bedrock.py'
149+
)

0 commit comments

Comments
 (0)