generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 28
Add config source interface and environment variable source for config resolution #640
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
Merged
ubaskota
merged 4 commits into
smithy-lang:config_resolution_main
from
ubaskota:config_source
Feb 19, 2026
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
packages/smithy-aws-core/src/smithy_aws_core/config/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| from .sources import EnvironmentSource | ||
|
|
||
| __all__ = [ | ||
| "EnvironmentSource", | ||
| ] |
35 changes: 35 additions & 0 deletions
35
packages/smithy-aws-core/src/smithy_aws_core/config/sources.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||||||||||||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||||||||||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||||||||||
| import os | ||||||||||||||
| from typing import Any | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| class EnvironmentSource: | ||||||||||||||
| """Configuration from environment variables.""" | ||||||||||||||
|
|
||||||||||||||
| SOURCE = "environment" | ||||||||||||||
|
|
||||||||||||||
| def __init__(self, prefix: str = "AWS_"): | ||||||||||||||
| """Initialize the EnvironmentSource with environment variable prefix. | ||||||||||||||
|
|
||||||||||||||
| :param prefix: Prefix for environment variables (default: 'AWS_') | ||||||||||||||
| """ | ||||||||||||||
| self._prefix = prefix | ||||||||||||||
|
|
||||||||||||||
| @property | ||||||||||||||
| def name(self) -> str: | ||||||||||||||
ubaskota marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| """Returns the source name.""" | ||||||||||||||
| return self.SOURCE | ||||||||||||||
|
|
||||||||||||||
| def get(self, key: str) -> Any | None: | ||||||||||||||
ubaskota marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| """Returns a configuration value from environment variables. | ||||||||||||||
|
|
||||||||||||||
| :param key: The standard configuration key (e.g., 'region', 'retry_mode'). | ||||||||||||||
|
|
||||||||||||||
| :returns: The value from the corresponding environment variable, or None if not set or empty. | ||||||||||||||
ubaskota marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| """ | ||||||||||||||
| env_var = f"{self._prefix}{key.upper()}" | ||||||||||||||
| config_value = os.environ.get(env_var) | ||||||||||||||
| if config_value is None: | ||||||||||||||
| return None | ||||||||||||||
| return config_value.strip() | ||||||||||||||
|
Comment on lines
+32
to
+35
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternate option, commit this if you think it's more readable. Functionally, these are equivalent, just does the same thing in two fewer lines
Suggested change
ubaskota marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
87 changes: 87 additions & 0 deletions
87
packages/smithy-aws-core/tests/unit/config/test_sources.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| import os | ||
| from unittest.mock import patch | ||
|
|
||
| from smithy_aws_core.config.sources import EnvironmentSource | ||
|
|
||
|
|
||
| class TestEnvironmentSource: | ||
| def test_source_name(self): | ||
| source = EnvironmentSource() | ||
| assert source.name == "environment" | ||
|
|
||
| def test_get_region_from_aws_region(self): | ||
| with patch.dict(os.environ, {"AWS_REGION": "us-west-2"}, clear=False): | ||
ubaskota marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| source = EnvironmentSource() | ||
| value = source.get("region") | ||
| assert value == "us-west-2" | ||
|
|
||
| def test_get_returns_none_when_env_var_not_set(self): | ||
| with patch.dict(os.environ, {}, clear=True): | ||
| source = EnvironmentSource() | ||
| value = source.get("region") | ||
| assert value is None | ||
|
|
||
| def test_get_returns_none_for_unknown_key(self): | ||
| source = EnvironmentSource() | ||
| value = source.get("unknown_config_key") | ||
| assert value is None | ||
|
|
||
| def test_get_handles_empty_string_env_var(self): | ||
| with patch.dict(os.environ, {"AWS_REGION": ""}, clear=False): | ||
| source = EnvironmentSource() | ||
| value = source.get("region") | ||
| # Empty string should be treated as None | ||
| assert value == "" | ||
ubaskota marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| def test_get_handles_whitespace_env_var(self): | ||
| with patch.dict(os.environ, {"AWS_REGION": " us-west-2 "}, clear=False): | ||
| source = EnvironmentSource() | ||
| value = source.get("region") | ||
| # Whitespaces should be stripped | ||
| assert value == "us-west-2" | ||
|
|
||
| def test_get_handles_whole_whitespace_env_var(self): | ||
| with patch.dict(os.environ, {"AWS_REGION": " "}, clear=False): | ||
| source = EnvironmentSource() | ||
| value = source.get("region") | ||
| # Whitespaces should be stripped | ||
| assert value == "" | ||
ubaskota marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def test_multiple_keys_with_different_env_vars(self): | ||
| env_vars = {"AWS_REGION": "eu-west-1", "AWS_RETRY_MODE": "standard"} | ||
| with patch.dict(os.environ, env_vars, clear=False): | ||
| source = EnvironmentSource() | ||
|
|
||
| region = source.get("region") | ||
| retry_mode = source.get("retry_mode") | ||
|
|
||
| assert region == "eu-west-1" | ||
| assert retry_mode == "standard" | ||
|
|
||
| def test_get_is_idempotent(self): | ||
| with patch.dict(os.environ, {"AWS_REGION": "ap-south-1"}, clear=False): | ||
| source = EnvironmentSource() | ||
| # Calling get on source multiple times should return the same value | ||
| value1 = source.get("region") | ||
| value2 = source.get("region") | ||
| value3 = source.get("region") | ||
|
|
||
| assert value1 == value2 == value3 == "ap-south-1" | ||
|
|
||
| def test_source_does_not_cache_env_vars(self): | ||
| source = EnvironmentSource() | ||
|
|
||
| # First read | ||
| with patch.dict(os.environ, {"AWS_REGION": "us-east-1"}, clear=False): | ||
| value1 = source.get("region") | ||
| assert value1 == "us-east-1" | ||
|
|
||
| # Environment changes | ||
| with patch.dict(os.environ, {"AWS_REGION": "us-west-2"}, clear=False): | ||
| value2 = source.get("region") | ||
| assert value2 == "us-west-2" | ||
|
|
||
| # Source reads from os.environ and not from cache | ||
| assert value1 != value2 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| from typing import Any, Protocol, runtime_checkable | ||
|
|
||
|
|
||
| @runtime_checkable | ||
| class ConfigSource(Protocol): | ||
| """Protocol for configuration sources that provide values from various locations | ||
| like environment variables and configuration files. | ||
| """ | ||
|
|
||
| @property | ||
| def name(self) -> str: | ||
| """Returns a string identifying the source. | ||
|
|
||
| :returns: A string identifier for this source. | ||
| """ | ||
| ... | ||
|
|
||
| def get(self, key: str) -> Any | None: | ||
| """Returns a configuration value from the source. | ||
|
|
||
| :param key: The configuration key to retrieve (e.g., 'region') | ||
|
|
||
| :returns: The value associated with the key, or None if not found. | ||
| """ | ||
| ... |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.