Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public List<RuntimeClientPlugin> getClientPlugins(GenerationContext context) {
"A unique and opaque application ID that is appended to the User-Agent header.")
.type(Symbol.builder().name("str").build())
.nullable(true)
.useDescriptor(true)
.validator(Symbol.builder()
.name("validate_ua_string")
.namespace("smithy_aws_core.config.validators", ".")
.addDependency(AwsPythonDependency.SMITHY_AWS_CORE)
.build())
.build();

final String user_agent_plugin_file = "user_agent";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,25 @@ def validate_retry_strategy(
f"retry_strategy must be RetryStrategy or RetryStrategyOptions, got {type(value).__name__}",
source,
)


def validate_ua_string(value: Any, source: SourceInfo | None = None) -> str | None:
"""Validate a User-Agent string component.

:param value: The UA string value to validate
:param source: The source that provided this value

:returns: The UA string or None if value is None

:raises ConfigValidationError: If the value is not a string
"""
if value is None:
return None
if not isinstance(value, str):
raise ConfigValidationError(
"sdk_ua_app_id",
value,
f"UA string must be a string, got {type(value).__name__}",
source,
)
return value
7 changes: 2 additions & 5 deletions packages/smithy-aws-core/tests/unit/config/test_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ def _create_config_with_validator(

class ConfigWithValidator:
region = ConfigProperty("region", validator=validator)
retry_strategy = ConfigProperty("retry_strategy", validator=validator)

def __init__(self, resolver: ConfigResolver) -> None:
self._resolver = resolver
Expand Down Expand Up @@ -153,9 +152,7 @@ class ConfigWithComplexResolver:
retry_strategy = ConfigProperty(
"retry_strategy",
resolver_func=mock_resolver,
default_value=RetryStrategyOptions(
retry_mode="standard", max_attempts=3
),
default_value=RetryStrategyOptions(retry_mode="standard"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand why we are making these changes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for retry_strategy should only specify retry_mode, since max_attempts will be determined later based on the selected retry mode. It would have worked either way though.

)

def __init__(self, resolver: ConfigResolver) -> None:
Expand All @@ -171,7 +168,7 @@ def __init__(self, resolver: ConfigResolver) -> None:

assert isinstance(result, RetryStrategyOptions)
assert result.retry_mode == "standard"
assert result.max_attempts == 3
assert result.max_attempts is None
assert source_info == SimpleSource("default")

def test_validator_not_called_on_cached_access(self) -> None:
Expand Down
18 changes: 18 additions & 0 deletions packages/smithy-aws-core/tests/unit/config/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
validate_max_attempts,
validate_region,
validate_retry_mode,
validate_ua_string,
)


Expand Down Expand Up @@ -49,3 +50,20 @@ def test_invalid_retry_mode_error_message(self) -> None:
"Invalid value for 'retry_mode': 'random_mode'. retry_mode must be one "
"of ('standard',), got random_mode" in str(exc_info.value)
)


class TestValidateUaString:
def test_allows_string(self) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: all of these tests except the error test could easily be one test with pytest.mark.parametrize; everything is only validating that it's passed through, so the test body could just be
assert validate_ua_string(value) == value

assert validate_ua_string("abc123") == "abc123"

def test_none_returns_none(self) -> None:
assert validate_ua_string(None) is None

def test_empty_string_passthrough(self) -> None:
assert validate_ua_string("") == ""

def test_rejects_non_string(self) -> None:
with pytest.raises(ConfigValidationError) as exc_info:
validate_ua_string(123)

assert exc_info.value.key == "sdk_ua_app_id"
Loading