Skip to content

Commit 77c41a2

Browse files
feat(parameters) - environment default variables - refactor maxage code
1 parent b4c2d48 commit 77c41a2

File tree

6 files changed

+93
-21
lines changed

6 files changed

+93
-21
lines changed

aws_lambda_powertools/shared/functions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def resolve_truthy_env_var_choice(env: str, choice: Optional[bool] = None) -> bo
5151
return choice if choice is not None else strtobool(env)
5252

5353

54+
def resolve_max_age(env: str, choice: Optional[int]) -> int:
55+
"""Resolve max age value"""
56+
return choice if choice is not None else int(env)
57+
58+
5459
@overload
5560
def resolve_env_var_choice(env: Optional[str], choice: float) -> float:
5661
...

aws_lambda_powertools/utilities/parameters/appconfig.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
if TYPE_CHECKING:
1515
from mypy_boto3_appconfigdata import AppConfigDataClient
1616

17-
from ...shared import constants
18-
from ...shared.functions import resolve_env_var_choice
17+
from aws_lambda_powertools.shared import constants
18+
from aws_lambda_powertools.shared.functions import (
19+
resolve_env_var_choice,
20+
resolve_max_age,
21+
)
22+
1923
from .base import DEFAULT_MAX_AGE_SECS, DEFAULT_PROVIDERS, BaseProvider
2024

2125

@@ -136,7 +140,7 @@ def get_app_config(
136140
application: Optional[str] = None,
137141
transform: TransformOptions = None,
138142
force_fetch: bool = False,
139-
max_age: int = DEFAULT_MAX_AGE_SECS,
143+
max_age: Optional[int] = None,
140144
**sdk_options
141145
) -> Union[str, list, dict, bytes]:
142146
"""
@@ -187,6 +191,8 @@ def get_app_config(
187191
>>> print(value)
188192
My configuration's JSON value
189193
"""
194+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
195+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
190196

191197
# Only create the provider if this function is called at least once
192198
if "appconfig" not in DEFAULT_PROVIDERS:

aws_lambda_powertools/utilities/parameters/base.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from botocore.config import Config
2727

2828
from aws_lambda_powertools.shared import constants
29+
from aws_lambda_powertools.shared.functions import resolve_max_age
2930
from aws_lambda_powertools.utilities.parameters.types import TransformOptions
3031

3132
from .exceptions import GetParameterError, TransformParameterError
@@ -38,7 +39,7 @@
3839

3940

4041
# If the environment variable is not set, the default value is 5
41-
DEFAULT_MAX_AGE_SECS: int = int(os.getenv(constants.PARAMETERS_MAX_AGE, 5))
42+
DEFAULT_MAX_AGE_SECS = "5"
4243

4344
# These providers will be dynamically initialized on first use of the helper functions
4445
DEFAULT_PROVIDERS: Dict[str, Any] = {}
@@ -81,7 +82,7 @@ def has_not_expired_in_cache(self, key: Tuple[str, TransformOptions]) -> bool:
8182
def get(
8283
self,
8384
name: str,
84-
max_age: int = DEFAULT_MAX_AGE_SECS,
85+
max_age: Optional[int] = None,
8586
transform: TransformOptions = None,
8687
force_fetch: bool = False,
8788
**sdk_options,
@@ -125,6 +126,9 @@ def get(
125126
value: Optional[Union[str, bytes, dict]] = None
126127
key = (name, transform)
127128

129+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
130+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
131+
128132
if not force_fetch and self.has_not_expired_in_cache(key):
129133
return self.store[key].value
130134

@@ -153,7 +157,7 @@ def _get(self, name: str, **sdk_options) -> Union[str, bytes]:
153157
def get_multiple(
154158
self,
155159
path: str,
156-
max_age: int = DEFAULT_MAX_AGE_SECS,
160+
max_age: Optional[int] = None,
157161
transform: TransformOptions = None,
158162
raise_on_transform_error: bool = False,
159163
force_fetch: bool = False,
@@ -190,6 +194,9 @@ def get_multiple(
190194
"""
191195
key = (path, transform)
192196

197+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
198+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
199+
193200
if not force_fetch and self.has_not_expired_in_cache(key):
194201
return self.store[key].value # type: ignore # need to revisit entire typing here
195202

aws_lambda_powertools/utilities/parameters/secrets.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55

6+
import os
67
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
78

89
import boto3
@@ -11,6 +12,9 @@
1112
if TYPE_CHECKING:
1213
from mypy_boto3_secretsmanager import SecretsManagerClient
1314

15+
from aws_lambda_powertools.shared import constants
16+
from aws_lambda_powertools.shared.functions import resolve_max_age
17+
1418
from .base import DEFAULT_MAX_AGE_SECS, DEFAULT_PROVIDERS, BaseProvider
1519

1620

@@ -111,11 +115,7 @@ def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]:
111115

112116

113117
def get_secret(
114-
name: str,
115-
transform: Optional[str] = None,
116-
force_fetch: bool = False,
117-
max_age: int = DEFAULT_MAX_AGE_SECS,
118-
**sdk_options
118+
name: str, transform: Optional[str] = None, force_fetch: bool = False, max_age: Optional[int] = None, **sdk_options
119119
) -> Union[str, dict, bytes]:
120120
"""
121121
Retrieve a parameter value from AWS Secrets Manager
@@ -162,6 +162,9 @@ def get_secret(
162162
>>> get_secret("my-secret", VersionId="f658cac0-98a5-41d9-b993-8a76a7799194")
163163
"""
164164

165+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
166+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
167+
165168
# Only create the provider if this function is called at least once
166169
if "secrets" not in DEFAULT_PROVIDERS:
167170
DEFAULT_PROVIDERS["secrets"] = SecretsProvider()

aws_lambda_powertools/utilities/parameters/ssm.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from aws_lambda_powertools.shared import constants
1414
from aws_lambda_powertools.shared.functions import (
15+
resolve_max_age,
1516
resolve_truthy_env_var_choice,
1617
slice_dictionary,
1718
)
@@ -115,7 +116,7 @@ def __init__(
115116
def get( # type: ignore[override]
116117
self,
117118
name: str,
118-
max_age: int = DEFAULT_MAX_AGE_SECS,
119+
max_age: Optional[int] = None,
119120
transform: TransformOptions = None,
120121
decrypt: Optional[bool] = None,
121122
force_fetch: bool = False,
@@ -150,7 +151,10 @@ def get( # type: ignore[override]
150151
When the parameter provider fails to transform a parameter value.
151152
"""
152153

153-
# Resolving if will use the value passed by parameter or the environment
154+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
155+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
156+
157+
# Resolving if will use the default value (False), the value passed by parameter or the environment variable
154158
decrypt = resolve_truthy_env_var_choice(
155159
env=os.getenv(constants.PARAMETERS_DEFAULT_DECRYPT, "false"), choice=decrypt
156160
)
@@ -223,7 +227,7 @@ def get_parameters_by_name(
223227
parameters: Dict[str, Dict],
224228
transform: TransformOptions = None,
225229
decrypt: Optional[bool] = None,
226-
max_age: int = DEFAULT_MAX_AGE_SECS,
230+
max_age: Optional[int] = None,
227231
raise_on_error: bool = True,
228232
) -> Dict[str, str] | Dict[str, bytes] | Dict[str, dict]:
229233
"""
@@ -270,6 +274,9 @@ def get_parameters_by_name(
270274
When "_errors" reserved key is in parameters to be fetched from SSM.
271275
"""
272276

277+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
278+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
279+
273280
# Resolving if will use the default value (False), the value passed by parameter or the environment variable
274281
decrypt = resolve_truthy_env_var_choice(
275282
env=os.getenv(constants.PARAMETERS_DEFAULT_DECRYPT, "false"), choice=decrypt
@@ -505,7 +512,7 @@ def get_parameter(
505512
transform: Optional[str] = None,
506513
decrypt: Optional[bool] = None,
507514
force_fetch: bool = False,
508-
max_age: int = DEFAULT_MAX_AGE_SECS,
515+
max_age: Optional[int] = None,
509516
**sdk_options,
510517
) -> Union[str, dict, bytes]:
511518
"""
@@ -559,6 +566,9 @@ def get_parameter(
559566
if "ssm" not in DEFAULT_PROVIDERS:
560567
DEFAULT_PROVIDERS["ssm"] = SSMProvider()
561568

569+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
570+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
571+
562572
# Resolving if will use the default value (False), the value passed by parameter or the environment variable
563573
decrypt = resolve_truthy_env_var_choice(
564574
env=os.getenv(constants.PARAMETERS_DEFAULT_DECRYPT, "false"), choice=decrypt
@@ -578,7 +588,7 @@ def get_parameters(
578588
recursive: bool = True,
579589
decrypt: Optional[bool] = None,
580590
force_fetch: bool = False,
581-
max_age: int = DEFAULT_MAX_AGE_SECS,
591+
max_age: Optional[int] = None,
582592
raise_on_transform_error: bool = False,
583593
**sdk_options,
584594
) -> Union[Dict[str, str], Dict[str, dict], Dict[str, bytes]]:
@@ -638,6 +648,9 @@ def get_parameters(
638648
if "ssm" not in DEFAULT_PROVIDERS:
639649
DEFAULT_PROVIDERS["ssm"] = SSMProvider()
640650

651+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
652+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
653+
641654
# Resolving if will use the default value (False), the value passed by parameter or the environment variable
642655
decrypt = resolve_truthy_env_var_choice(
643656
env=os.getenv(constants.PARAMETERS_DEFAULT_DECRYPT, "false"), choice=decrypt
@@ -661,7 +674,7 @@ def get_parameters_by_name(
661674
parameters: Dict[str, Dict],
662675
transform: None = None,
663676
decrypt: Optional[bool] = None,
664-
max_age: int = DEFAULT_MAX_AGE_SECS,
677+
max_age: Optional[int] = None,
665678
raise_on_error: bool = True,
666679
) -> Dict[str, str]:
667680
...
@@ -672,7 +685,7 @@ def get_parameters_by_name(
672685
parameters: Dict[str, Dict],
673686
transform: Literal["binary"],
674687
decrypt: Optional[bool] = None,
675-
max_age: int = DEFAULT_MAX_AGE_SECS,
688+
max_age: Optional[int] = None,
676689
raise_on_error: bool = True,
677690
) -> Dict[str, bytes]:
678691
...
@@ -683,7 +696,7 @@ def get_parameters_by_name(
683696
parameters: Dict[str, Dict],
684697
transform: Literal["json"],
685698
decrypt: Optional[bool] = None,
686-
max_age: int = DEFAULT_MAX_AGE_SECS,
699+
max_age: Optional[int] = None,
687700
raise_on_error: bool = True,
688701
) -> Dict[str, Dict[str, Any]]:
689702
...
@@ -694,7 +707,7 @@ def get_parameters_by_name(
694707
parameters: Dict[str, Dict],
695708
transform: Literal["auto"],
696709
decrypt: Optional[bool] = None,
697-
max_age: int = DEFAULT_MAX_AGE_SECS,
710+
max_age: Optional[int] = None,
698711
raise_on_error: bool = True,
699712
) -> Union[Dict[str, str], Dict[str, dict]]:
700713
...
@@ -704,7 +717,7 @@ def get_parameters_by_name(
704717
parameters: Dict[str, Any],
705718
transform: TransformOptions = None,
706719
decrypt: Optional[bool] = None,
707-
max_age: int = DEFAULT_MAX_AGE_SECS,
720+
max_age: Optional[int] = None,
708721
raise_on_error: bool = True,
709722
) -> Union[Dict[str, str], Dict[str, bytes], Dict[str, dict]]:
710723
"""
@@ -758,6 +771,9 @@ def get_parameters_by_name(
758771
# NOTE: Decided against using multi-thread due to single-thread outperforming in 128M and 1G + timeout risk
759772
# see: https://github.com/awslabs/aws-lambda-powertools-python/issues/1040#issuecomment-1299954613
760773

774+
# Resolving if will use the default value (5), the value passed by parameter or the environment variable
775+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=max_age)
776+
761777
# Resolving if will use the default value (False), the value passed by parameter or the environment variable
762778
decrypt = resolve_truthy_env_var_choice(
763779
env=os.getenv(constants.PARAMETERS_DEFAULT_DECRYPT, "false"), choice=decrypt

tests/unit/test_shared_functions.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import warnings
23
from dataclasses import dataclass
34

@@ -10,10 +11,12 @@
1011
powertools_debug_is_set,
1112
powertools_dev_is_set,
1213
resolve_env_var_choice,
14+
resolve_max_age,
1315
resolve_truthy_env_var_choice,
1416
strtobool,
1517
)
1618
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
19+
from aws_lambda_powertools.utilities.parameters.base import DEFAULT_MAX_AGE_SECS
1720

1821

1922
def test_resolve_env_var_choice_explicit_wins_over_env_var():
@@ -103,3 +106,35 @@ class DummyDataclass:
103106
@pytest.mark.parametrize("data", [False, True, "", 10, [], {}, object])
104107
def test_extract_event_any(data):
105108
assert extract_event_from_common_models(data) == data
109+
110+
111+
def test_resolve_max_age_explicit_wins_over_env_var(monkeypatch: pytest.MonkeyPatch):
112+
# GIVEN POWERTOOLS_PARAMETERS_MAX_AGE environment variable is set
113+
monkeypatch.setenv(constants.PARAMETERS_MAX_AGE, "20")
114+
115+
# WHEN the choice is set explicitly
116+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=10)
117+
118+
# THEN the result must be the choice
119+
assert max_age == 10
120+
121+
122+
def test_resolve_max_age_with_default_value():
123+
# GIVEN POWERTOOLS_PARAMETERS_MAX_AGE is not set
124+
125+
# WHEN the choice is set to None
126+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=None)
127+
128+
# THEN the result must be the default value (DEFAULT_MAX_AGE_SECS)
129+
assert max_age == int(DEFAULT_MAX_AGE_SECS)
130+
131+
132+
def test_resolve_max_age_env_var_wins_over_default_value(monkeypatch: pytest.MonkeyPatch):
133+
# GIVEN POWERTOOLS_PARAMETERS_MAX_AGE environment variable is set
134+
monkeypatch.setenv(constants.PARAMETERS_MAX_AGE, "20")
135+
136+
# WHEN the choice is set to None
137+
max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE, DEFAULT_MAX_AGE_SECS), choice=None)
138+
139+
# THEN the result must be the environment variable value
140+
assert max_age == 20

0 commit comments

Comments
 (0)