Skip to content

Commit dc35984

Browse files
authored
refactor: env vars multiple handlers local tests support, update pip (#23)
1 parent d0af58b commit dc35984

File tree

8 files changed

+78
-98
lines changed

8 files changed

+78
-98
lines changed

Pipfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ isort = "*"
2222
boto3 = "*"
2323
mkdocs-material = "*"
2424
mkdocs-git-revision-date-plugin = "*"
25+
cattrs = "==1.10.0"
2526

2627
[packages]
2728
pydantic = {extras = ["email"],version = "*"}

Pipfile.lock

Lines changed: 38 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev_requirements.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
-i https://pypi.org/simple
22
-e ./cdk
33
attrs==21.4.0
4-
aws-cdk-lib==2.19.0
4+
aws-cdk-lib==2.20.0
55
aws-cdk.aws-lambda-python-alpha==2.19.0a0
6-
boto3==1.21.32
7-
botocore==1.24.32
8-
cattrs==1.10.0 ; python_version >= '3.7'
6+
boto3==1.21.39
7+
botocore==1.24.39
8+
cattrs==1.10.0
99
certifi==2021.10.8
1010
cfgv==3.3.1
1111
charset-normalizer==2.0.12 ; python_version >= '3'
1212
click==8.1.2
1313
colorama==0.4.4 ; python_version > '3.4'
14-
constructs==10.0.104
14+
constructs==10.0.113
1515
coverage[toml]==6.3.2
1616
distlib==0.3.4
1717
filelock==3.6.0
@@ -27,15 +27,15 @@ iniconfig==1.1.1
2727
isort==5.10.1
2828
jinja2==3.1.1
2929
jmespath==0.10.0
30-
jsii==1.55.1
30+
jsii==1.56.0
3131
mando==0.6.4
3232
markdown==3.3.6
3333
markupsafe==2.1.1
3434
mccabe==0.6.1
3535
mergedeep==1.3.4
3636
mkdocs-git-revision-date-plugin==0.3.2
3737
mkdocs-material-extensions==1.0.3
38-
mkdocs-material==8.2.8
38+
mkdocs-material==8.2.9
3939
mkdocs==1.3.0
4040
nodeenv==1.6.0
4141
packaging==21.3
@@ -48,7 +48,7 @@ pycodestyle==2.8.0
4848
pyflakes==2.4.0
4949
pygments==2.11.2
5050
pymdown-extensions==9.3
51-
pyparsing==3.0.7
51+
pyparsing==3.0.8
5252
pytest-cov==3.0.0
5353
pytest-html==3.1.1
5454
pytest-metadata==2.0.1
@@ -67,8 +67,8 @@ toml==0.10.2
6767
tomli==2.0.1
6868
typing-extensions==4.1.1
6969
urllib3==1.26.9
70-
virtualenv==20.14.0
70+
virtualenv==20.14.1
7171
watchdog==2.1.7
7272
xenon==0.9.0
7373
yapf==0.32.0
74-
zipp==3.7.0
74+
zipp==3.8.0

docs/best_practices/environment_variables.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ It can be used *anywhere* in the function code, not just the handler.
100100

101101
@init_environment_variables(model=MyHandlerEnvVars)
102102
def my_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Any]:
103-
env_vars: MyHandlerEnvVars = get_environment_variables()
103+
env_vars: MyHandlerEnvVars = get_environment_variables(model=MyHandlerEnvVars)
104104
return {'statusCode': HTTPStatus.OK, 'headers': {'Content-Type': 'application/json'}, 'body': json.dumps({'message': 'success'})}
105105
```
106106

lambda_requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-i https://pypi.org/simple
2-
aws-lambda-powertools==1.25.6
2+
aws-lambda-powertools==1.25.7
33
aws-xray-sdk==2.9.0
4-
boto3==1.21.32
5-
botocore==1.24.32
4+
boto3==1.21.39
5+
botocore==1.24.39
66
dnspython==2.2.1
77
email-validator==1.1.3
88
fastjsonschema==2.15.3

service/handlers/my_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def my_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Any]:
2626
logger.set_correlation_id(context.aws_request_id)
2727
logger.info('my_handler is called, calling inner_function_example')
2828

29-
env_vars: MyHandlerEnvVars = get_environment_variables()
29+
env_vars: MyHandlerEnvVars = get_environment_variables(model=MyHandlerEnvVars)
3030
logger.debug('environment variables', extra=env_vars.dict())
3131

3232
try:
Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
11
import os
2+
from functools import lru_cache
23
from typing import Any, TypeVar
34

45
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
56
from pydantic import BaseModel, ValidationError
67

78
Model = TypeVar('Model', bound=BaseModel)
89

9-
# global instance of the parsed Pydantic data class
10-
ENV_CONF: BaseModel = None
1110

12-
13-
@lambda_handler_decorator
14-
def init_environment_variables(handler, event, context, model: Model) -> Any:
15-
global ENV_CONF
11+
@lru_cache
12+
def __parse_model(model: Model) -> BaseModel:
1613
try:
17-
# parse the os environment variables dict
18-
ENV_CONF = model(**os.environ)
14+
return model(**os.environ)
1915
except (ValidationError, TypeError) as exc:
2016
raise ValueError(f'failed to load environment variables, exception={str(exc)}') from exc
2117

22-
return handler(event, context)
23-
2418

25-
def get_environment_variables() -> BaseModel:
26-
global ENV_CONF
27-
if ENV_CONF is None:
28-
raise ValueError('get_environment_variables was called before init_environment_variables, environment variables were not loaded')
29-
return ENV_CONF
19+
@lambda_handler_decorator
20+
def init_environment_variables(handler, event, context, model: Model) -> Any:
21+
__parse_model(model)
22+
return handler(event, context)
3023

3124

32-
# used for testing purposes
33-
def _clear_env_conf() -> None:
34-
global ENV_CONF
35-
ENV_CONF = None
25+
def get_environment_variables(model: Model) -> BaseModel:
26+
return __parse_model(model)

tests/unit/test_env_vars_parser.py

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pydantic import BaseModel, HttpUrl
77

88
from cdk.aws_lambda_handler_cookbook.service_stack.constants import POWER_TOOLS_LOG_LEVEL, POWERTOOLS_SERVICE_NAME, SERVICE_NAME
9-
from service.handlers.utils.env_vars_parser import _clear_env_conf, get_environment_variables, init_environment_variables
9+
from service.handlers.utils.env_vars_parser import get_environment_variables, init_environment_variables
1010
from tests.utils import generate_context
1111

1212

@@ -16,25 +16,6 @@ class MySchema(BaseModel):
1616
REST_API: HttpUrl
1717

1818

19-
@mock.patch.dict(os.environ, {
20-
POWERTOOLS_SERVICE_NAME: SERVICE_NAME,
21-
POWER_TOOLS_LOG_LEVEL: 'DEBUG',
22-
'REST_API': 'https://www.ranthebuilder.cloud/api'
23-
})
24-
def test_handler_schema_ok():
25-
26-
@init_environment_variables(model=MySchema)
27-
def my_handler(event, context) -> Dict[str, Any]:
28-
env_vars: MySchema = get_environment_variables()
29-
assert env_vars.POWERTOOLS_SERVICE_NAME == SERVICE_NAME
30-
assert env_vars.LOG_LEVEL == 'DEBUG'
31-
assert str(env_vars.REST_API) == 'https://www.ranthebuilder.cloud/api'
32-
return {}
33-
34-
my_handler({}, generate_context())
35-
_clear_env_conf()
36-
37-
3819
def test_handler_missing_env_var():
3920

4021
@init_environment_variables(model=MySchema)
@@ -56,12 +37,19 @@ def my_handler2(event, context) -> Dict[str, Any]:
5637
my_handler2({}, generate_context())
5738

5839

59-
@mock.patch.dict(os.environ, {POWERTOOLS_SERVICE_NAME: SERVICE_NAME, POWER_TOOLS_LOG_LEVEL: 'DEBUG', 'REST_API': 'fakeapi'})
60-
def test_handler_get_env_var_without_init():
40+
@mock.patch.dict(os.environ, {
41+
POWERTOOLS_SERVICE_NAME: SERVICE_NAME,
42+
POWER_TOOLS_LOG_LEVEL: 'DEBUG',
43+
'REST_API': 'https://www.ranthebuilder.cloud/api'
44+
})
45+
def test_handler_schema_ok():
6146

62-
def my_handler3(event, context) -> Dict[str, Any]:
63-
get_environment_variables()
47+
@init_environment_variables(model=MySchema)
48+
def my_handler(event, context) -> Dict[str, Any]:
49+
env_vars: MySchema = get_environment_variables(model=MySchema)
50+
assert env_vars.POWERTOOLS_SERVICE_NAME == SERVICE_NAME
51+
assert env_vars.LOG_LEVEL == 'DEBUG'
52+
assert str(env_vars.REST_API) == 'https://www.ranthebuilder.cloud/api'
6453
return {}
6554

66-
with pytest.raises(ValueError):
67-
my_handler3({}, generate_context())
55+
my_handler({}, generate_context())

0 commit comments

Comments
 (0)