From d03ef4b5d702b3b5cf403bc8a0ac06c8f0eab2ce Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Wed, 8 Dec 2021 17:21:52 +0200 Subject: [PATCH 1/4] fix: parameters: fix return type to bytes in internal function --- aws_lambda_powertools/metrics/metric.py | 6 ++++-- aws_lambda_powertools/utilities/parameters/appconfig.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/metrics/metric.py b/aws_lambda_powertools/metrics/metric.py index 76ff4339dea..94b427738a1 100644 --- a/aws_lambda_powertools/metrics/metric.py +++ b/aws_lambda_powertools/metrics/metric.py @@ -1,7 +1,7 @@ import json import logging from contextlib import contextmanager -from typing import Dict, Optional, Union, Generator +from typing import Dict, Generator, Optional, Union from .base import MetricManager, MetricUnit @@ -61,7 +61,9 @@ def add_metric(self, name: str, unit: Union[MetricUnit, str], value: float) -> N @contextmanager -def single_metric(name: str, unit: MetricUnit, value: float, namespace: Optional[str] = None) -> Generator[SingleMetric, None, None]: +def single_metric( + name: str, unit: MetricUnit, value: float, namespace: Optional[str] = None +) -> Generator[SingleMetric, None, None]: """Context manager to simplify creation of a single metric Example diff --git a/aws_lambda_powertools/utilities/parameters/appconfig.py b/aws_lambda_powertools/utilities/parameters/appconfig.py index d1613c14513..78eaf3f2d14 100644 --- a/aws_lambda_powertools/utilities/parameters/appconfig.py +++ b/aws_lambda_powertools/utilities/parameters/appconfig.py @@ -84,7 +84,7 @@ def __init__( super().__init__() - def _get(self, name: str, **sdk_options) -> str: + def _get(self, name: str, **sdk_options) -> bytes: """ Retrieve a parameter value from AWS App config. From 5070769cfc1a46016a4a176eba9840a6d21083a6 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Wed, 8 Dec 2021 20:18:26 +0200 Subject: [PATCH 2/4] fix: parameters: fix return type to bytes in internal function --- aws_lambda_powertools/utilities/parameters/appconfig.py | 6 +++--- tests/functional/test_utilities_parameters.py | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/aws_lambda_powertools/utilities/parameters/appconfig.py b/aws_lambda_powertools/utilities/parameters/appconfig.py index 78eaf3f2d14..39907bbb4b9 100644 --- a/aws_lambda_powertools/utilities/parameters/appconfig.py +++ b/aws_lambda_powertools/utilities/parameters/appconfig.py @@ -84,7 +84,7 @@ def __init__( super().__init__() - def _get(self, name: str, **sdk_options) -> bytes: + def _get(self, name: str, **sdk_options) -> str: """ Retrieve a parameter value from AWS App config. @@ -104,7 +104,7 @@ def _get(self, name: str, **sdk_options) -> bytes: sdk_options["ClientId"] = CLIENT_ID response = self.client.get_configuration(**sdk_options) - return response["Content"].read() # read() of botocore.response.StreamingBody + return response["Content"].read().decode("utf-8") # read() of botocore.response.StreamingBody def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]: """ @@ -121,7 +121,7 @@ def get_app_config( force_fetch: bool = False, max_age: int = DEFAULT_MAX_AGE_SECS, **sdk_options -) -> Union[str, list, dict, bytes]: +) -> Union[str, list, dict]: """ Retrieve a configuration value from AWS App Config. diff --git a/tests/functional/test_utilities_parameters.py b/tests/functional/test_utilities_parameters.py index 79b8bfb2fd0..9a21e6b2f71 100644 --- a/tests/functional/test_utilities_parameters.py +++ b/tests/functional/test_utilities_parameters.py @@ -1503,9 +1503,8 @@ def test_appconf_provider_get_configuration_no_transform(mock_name, config): stubber.activate() try: - value = provider.get(mock_name) - str_value = value.decode("utf-8") - assert str_value == json.dumps(mock_body_json) + value: str = provider.get(mock_name) + assert value == json.dumps(mock_body_json) stubber.assert_no_pending_responses() finally: stubber.deactivate() From eaebc8b8a8c5c5443ed99d5d8f897bad996d216e Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Thu, 9 Dec 2021 11:59:34 +0200 Subject: [PATCH 3/4] fix: parameters: fix return type to bytes in internal function --- .../utilities/parameters/appconfig.py | 4 +-- .../utilities/parameters/base.py | 4 ++- tests/functional/test_utilities_parameters.py | 32 +++++++++++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/aws_lambda_powertools/utilities/parameters/appconfig.py b/aws_lambda_powertools/utilities/parameters/appconfig.py index 39907bbb4b9..d1613c14513 100644 --- a/aws_lambda_powertools/utilities/parameters/appconfig.py +++ b/aws_lambda_powertools/utilities/parameters/appconfig.py @@ -104,7 +104,7 @@ def _get(self, name: str, **sdk_options) -> str: sdk_options["ClientId"] = CLIENT_ID response = self.client.get_configuration(**sdk_options) - return response["Content"].read().decode("utf-8") # read() of botocore.response.StreamingBody + return response["Content"].read() # read() of botocore.response.StreamingBody def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]: """ @@ -121,7 +121,7 @@ def get_app_config( force_fetch: bool = False, max_age: int = DEFAULT_MAX_AGE_SECS, **sdk_options -) -> Union[str, list, dict]: +) -> Union[str, list, dict, bytes]: """ Retrieve a configuration value from AWS App Config. diff --git a/aws_lambda_powertools/utilities/parameters/base.py b/aws_lambda_powertools/utilities/parameters/base.py index b3b907bc18b..6f3cf3f1430 100644 --- a/aws_lambda_powertools/utilities/parameters/base.py +++ b/aws_lambda_powertools/utilities/parameters/base.py @@ -93,6 +93,8 @@ def get( raise GetParameterError(str(exc)) if transform is not None: + if isinstance(value, bytes): + value = value.decode("utf-8") value = transform_value(value, transform) self.store[key] = ExpirableValue(value, datetime.now() + timedelta(seconds=max_age)) @@ -100,7 +102,7 @@ def get( return value @abstractmethod - def _get(self, name: str, **sdk_options) -> str: + def _get(self, name: str, **sdk_options) -> bytes: """ Retrieve parameter value from the underlying parameter store """ diff --git a/tests/functional/test_utilities_parameters.py b/tests/functional/test_utilities_parameters.py index 9a21e6b2f71..47fc5a0e982 100644 --- a/tests/functional/test_utilities_parameters.py +++ b/tests/functional/test_utilities_parameters.py @@ -1504,7 +1504,8 @@ def test_appconf_provider_get_configuration_no_transform(mock_name, config): try: value: str = provider.get(mock_name) - assert value == json.dumps(mock_body_json) + str_value = value.decode("utf-8") + assert str_value == json.dumps(mock_body_json) stubber.assert_no_pending_responses() finally: stubber.deactivate() @@ -1515,11 +1516,12 @@ def test_appconf_get_app_config_no_transform(monkeypatch, mock_name): Test get_app_config() """ mock_body_json = {"myenvvar1": "Black Panther", "myenvvar2": 3} + mock_body_bytes = str.encode(json.dumps(mock_body_json)) class TestProvider(BaseProvider): - def _get(self, name: str, **kwargs) -> str: + def _get(self, name: str, **kwargs) -> bytes: assert name == mock_name - return json.dumps(mock_body_json).encode("utf-8") + return mock_body_bytes def _get_multiple(self, path: str, **kwargs) -> Dict[str, str]: raise NotImplementedError() @@ -1531,6 +1533,30 @@ def _get_multiple(self, path: str, **kwargs) -> Dict[str, str]: value = parameters.get_app_config(mock_name, environment=environment, application=application) str_value = value.decode("utf-8") assert str_value == json.dumps(mock_body_json) + assert value == mock_body_bytes + + +def test_appconf_get_app_config_transform_json(monkeypatch, mock_name): + """ + Test get_app_config() + """ + mock_body_json = {"myenvvar1": "Black Panther", "myenvvar2": 3} + mock_body_bytes = str.encode(json.dumps(mock_body_json)) + + class TestProvider(BaseProvider): + def _get(self, name: str, **kwargs) -> str: + assert name == mock_name + return mock_body_bytes + + def _get_multiple(self, path: str, **kwargs) -> Dict[str, str]: + raise NotImplementedError() + + monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig", TestProvider()) + + environment = "dev" + application = "myapp" + value = parameters.get_app_config(mock_name, environment=environment, application=application, transform="json") + assert value == mock_body_json def test_appconf_get_app_config_new(monkeypatch, mock_name, mock_value): From 6d00b06e742876c89266b4c5c205edce5328c2ab Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Thu, 9 Dec 2021 11:15:09 +0100 Subject: [PATCH 4/4] fix: _get returns either str or bytes --- aws_lambda_powertools/utilities/parameters/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/utilities/parameters/base.py b/aws_lambda_powertools/utilities/parameters/base.py index 6f3cf3f1430..b059a3b2483 100644 --- a/aws_lambda_powertools/utilities/parameters/base.py +++ b/aws_lambda_powertools/utilities/parameters/base.py @@ -102,7 +102,7 @@ def get( return value @abstractmethod - def _get(self, name: str, **sdk_options) -> bytes: + def _get(self, name: str, **sdk_options) -> Union[str, bytes]: """ Retrieve parameter value from the underlying parameter store """