Skip to content

Commit 9246525

Browse files
author
Alexander Melnyk
committed
Merge branch 'develop' of github.com:awslabs/aws-lambda-powertools-python into develop
2 parents 745ac9f + f627b02 commit 9246525

File tree

22 files changed

+908
-97
lines changed

22 files changed

+908
-97
lines changed

.github/workflows/python_build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- name: Complexity baseline
3838
run: make complexity-baseline
3939
- name: Upload coverage to Codecov
40-
uses: codecov/[email protected].1
40+
uses: codecov/[email protected].2
4141
with:
4242
file: ./coverage.xml
4343
# flags: unittests

.github/workflows/python_docs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
push:
55
branches:
66
- develop
7+
paths:
8+
- 'docs/**'
9+
- 'CHANGELOG.md'
10+
- 'mkdocs.yml'
711

812
jobs:
913
docs:

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,51 @@ This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) fo
77

88
## [Unreleased]
99

10+
## [1.19.0] - 2021-08-11
11+
12+
### Bug Fixes
13+
14+
* **deps:** bump poetry to latest ([#592](https://github.com/awslabs/aws-lambda-powertools-python/issues/592))
15+
* **feature-flags:** bug handling multiple conditions ([#599](https://github.com/awslabs/aws-lambda-powertools-python/issues/599))
16+
* **parser:** API Gateway WebSocket validation under check_message_id; plus some housekeeping ([#553](https://github.com/awslabs/aws-lambda-powertools-python/issues/553))
17+
* **feature-toggles:** correct cdk example ([#601](https://github.com/awslabs/aws-lambda-powertools-python/issues/601))
18+
19+
### Code Refactoring
20+
21+
* **feature-flags:** add debug statements for all feature evaluations ([#590](https://github.com/awslabs/aws-lambda-powertools-python/issues/590))
22+
* **feature-flags:** optimize UX and maintenance ([#563](https://github.com/awslabs/aws-lambda-powertools-python/issues/563))
23+
24+
### Documentation
25+
26+
* **event-handler:** new custom serializer option
27+
* **feature-flags:** create concrete documentation ([#594](https://github.com/awslabs/aws-lambda-powertools-python/issues/594))
28+
* **feature-flags:** correct docs and typing ([#588](https://github.com/awslabs/aws-lambda-powertools-python/issues/588))
29+
* **parameters:** auto-transforming values based on suffix ([#573](https://github.com/awslabs/aws-lambda-powertools-python/issues/573))
30+
* **readme:** add code coverage badge ([#577](https://github.com/awslabs/aws-lambda-powertools-python/issues/577))
31+
* **tracer:** update wording that it auto-disables on non-Lambda env
32+
* **feature-flags:** fix SAM infra, convert CDK to Python
33+
* **feature-flags:** fix sample feature name in evaluate method
34+
* **feature-flags:** add guidance when to use vs env vars vs parameters
35+
### Features
36+
37+
* **api-gateway:** add support for custom serializer ([#568](https://github.com/awslabs/aws-lambda-powertools-python/issues/568))
38+
* **data-classes:** decode json_body if based64 encoded ([#560](https://github.com/awslabs/aws-lambda-powertools-python/issues/560))
39+
* **feature-flags:** Add not_in action and rename contains to in ([#589](https://github.com/awslabs/aws-lambda-powertools-python/issues/589))
40+
* **params:** expose params `max_age`, `raise_on_transform_error` to high level functions ([#567](https://github.com/awslabs/aws-lambda-powertools-python/issues/567))
41+
* **tracer:** auto-disable tracer for non-Lambda environments to ease testing ([#598](https://github.com/awslabs/aws-lambda-powertools-python/issues/598))
42+
43+
### Maintenance
44+
45+
* **deps:** bump boto3 from 1.18.1 to 1.18.15 ([#591](https://github.com/awslabs/aws-lambda-powertools-python/issues/591))
46+
* **deps:** bump codecov/codecov-action from 2.0.1 to 2.0.2 ([#558](https://github.com/awslabs/aws-lambda-powertools-python/issues/558))
47+
* **deps:** bump boto3 from 1.18.15 to 1.18.17 ([#597](https://github.com/awslabs/aws-lambda-powertools-python/issues/597))
48+
* **deps-dev:** bump mkdocs-material from 7.2.2 to 7.2.3 ([#596](https://github.com/awslabs/aws-lambda-powertools-python/issues/596))
49+
* **deps-dev:** bump mkdocs-material from 7.2.1 to 7.2.2 ([#582](https://github.com/awslabs/aws-lambda-powertools-python/issues/582))
50+
* **deps-dev:** bump pdoc3 from 0.9.2 to 0.10.0 ([#584](https://github.com/awslabs/aws-lambda-powertools-python/issues/584))
51+
* **deps-dev:** bump isort from 5.9.2 to 5.9.3 ([#574](https://github.com/awslabs/aws-lambda-powertools-python/issues/574))
52+
* **deps-dev:** bump mkdocs-material from 7.2.0 to 7.2.1 ([#566](https://github.com/awslabs/aws-lambda-powertools-python/issues/566))
53+
* **deps-dev:** bump mkdocs-material from 7.1.11 to 7.2.0 ([#551](https://github.com/awslabs/aws-lambda-powertools-python/issues/551))
54+
* **deps-dev:** bump flake8-black from 0.2.1 to 0.2.3 ([#541](https://github.com/awslabs/aws-lambda-powertools-python/issues/541))
1055
## [1.18.1] - 2021-07-23
1156

1257
### Bug Fixes

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ target:
55
@$(MAKE) pr
66

77
dev:
8-
pip install --upgrade pip pre-commit poetry==1.1.4
8+
pip install --upgrade pip pre-commit poetry
99
poetry install --extras "pydantic"
1010
pre-commit install
1111

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ A suite of Python utilities for AWS Lambda functions to ease adopting best pract
2525
* **[Event source data classes](https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/data_classes/)** - Data classes describing the schema of common Lambda event triggers
2626
* **[Parser](https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/parser/)** - Data parsing and deep validation using Pydantic
2727
* **[Idempotency](https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/idempotency/)** - Convert your Lambda functions into idempotent operations which are safe to retry
28+
* **[Feature Flags](./utilities/feature_flags.md)** - A simple rule engine to evaluate when one or multiple features should be enabled depending on the input
2829

2930
### Installation
3031

aws_lambda_powertools/shared/constants.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212

1313
EVENT_HANDLER_DEBUG_ENV: str = "POWERTOOLS_EVENT_HANDLER_DEBUG"
1414

15-
SAM_LOCAL_ENV: str = "AWS_SAM_LOCAL"
16-
CHALICE_LOCAL_ENV: str = "AWS_CHALICE_CLI_MODE"
1715
SERVICE_NAME_ENV: str = "POWERTOOLS_SERVICE_NAME"
1816
XRAY_TRACE_ID_ENV: str = "_X_AMZN_TRACE_ID"
17+
LAMBDA_TASK_ROOT_ENV: str = "LAMBDA_TASK_ROOT"
1918

2019
XRAY_SDK_MODULE: str = "aws_xray_sdk"
2120
XRAY_SDK_CORE_MODULE: str = "aws_xray_sdk.core"

aws_lambda_powertools/tracing/tracer.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -719,16 +719,15 @@ def _is_tracer_disabled() -> Union[bool, str]:
719719
Union[bool, str]
720720
"""
721721
logger.debug("Verifying whether Tracing has been disabled")
722-
is_lambda_sam_cli = os.getenv(constants.SAM_LOCAL_ENV)
723-
is_chalice_cli = os.getenv(constants.CHALICE_LOCAL_ENV)
722+
is_lambda_env = os.getenv(constants.LAMBDA_TASK_ROOT_ENV)
724723
is_disabled = resolve_truthy_env_var_choice(env=os.getenv(constants.TRACER_DISABLED_ENV, "false"))
725724

726725
if is_disabled:
727726
logger.debug("Tracing has been disabled via env var POWERTOOLS_TRACE_DISABLED")
728727
return is_disabled
729728

730-
if is_lambda_sam_cli or is_chalice_cli:
731-
logger.debug("Running under SAM CLI env or not in Lambda env; disabling Tracing")
729+
if not is_lambda_env:
730+
logger.debug("Running outside Lambda env; disabling Tracing")
732731
return True
733732

734733
return False

aws_lambda_powertools/utilities/feature_flags/appconfig.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def __init__(
2121
environment: str,
2222
application: str,
2323
name: str,
24-
cache_seconds: int,
24+
max_age: int = 5,
2525
sdk_config: Optional[Config] = None,
2626
envelope: Optional[str] = "",
2727
jmespath_options: Optional[Dict] = None,
@@ -36,8 +36,8 @@ def __init__(
3636
AppConfig application name, e.g. 'powertools'
3737
name: str
3838
AppConfig configuration name e.g. `my_conf`
39-
cache_seconds: int
40-
cache expiration time, how often to call AppConfig to fetch latest configuration
39+
max_age: int
40+
cache expiration time in seconds, or how often to call AppConfig to fetch latest configuration
4141
sdk_config: Optional[Config]
4242
Botocore Config object to pass during client initialization
4343
envelope : Optional[str]
@@ -49,7 +49,7 @@ def __init__(
4949
self.environment = environment
5050
self.application = application
5151
self.name = name
52-
self.cache_seconds = cache_seconds
52+
self.cache_seconds = max_age
5353
self.config = sdk_config
5454
self.envelope = envelope
5555
self.jmespath_options = jmespath_options

aws_lambda_powertools/utilities/feature_flags/feature_flags.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def __init__(self, store: StoreProvider):
2424
environment="test",
2525
application="powertools",
2626
name="test_conf_name",
27-
cache_seconds=300,
27+
max_age=300,
2828
envelope="features"
2929
)
3030
@@ -46,7 +46,8 @@ def _match_by_action(action: str, condition_value: Any, context_value: Any) -> b
4646
schema.RuleAction.EQUALS.value: lambda a, b: a == b,
4747
schema.RuleAction.STARTSWITH.value: lambda a, b: a.startswith(b),
4848
schema.RuleAction.ENDSWITH.value: lambda a, b: a.endswith(b),
49-
schema.RuleAction.CONTAINS.value: lambda a, b: a in b,
49+
schema.RuleAction.IN.value: lambda a, b: a in b,
50+
schema.RuleAction.NOT_IN.value: lambda a, b: a not in b,
5051
}
5152

5253
try:
@@ -63,6 +64,13 @@ def _evaluate_conditions(
6364
rule_match_value = rule.get(schema.RULE_MATCH_VALUE)
6465
conditions = cast(List[Dict], rule.get(schema.CONDITIONS_KEY))
6566

67+
if not conditions:
68+
logger.debug(
69+
f"rule did not match, no conditions to match, rule_name={rule_name}, rule_value={rule_match_value}, "
70+
f"name={feature_name} "
71+
)
72+
return False
73+
6674
for condition in conditions:
6775
context_value = context.get(str(condition.get(schema.CONDITION_KEY)))
6876
cond_action = condition.get(schema.CONDITION_ACTION, "")
@@ -75,9 +83,8 @@ def _evaluate_conditions(
7583
)
7684
return False # context doesn't match condition
7785

78-
logger.debug(f"rule matched, rule_name={rule_name}, rule_value={rule_match_value}, name={feature_name}")
79-
return True
80-
return False
86+
logger.debug(f"rule matched, rule_name={rule_name}, rule_value={rule_match_value}, name={feature_name}")
87+
return True
8188

8289
def _evaluate_rules(
8390
self, *, feature_name: str, context: Dict[str, Any], feat_default: bool, rules: Dict[str, Any]
@@ -237,6 +244,7 @@ def get_enabled_features(self, *, context: Optional[Dict[str, Any]] = None) -> L
237244
logger.debug(f"Failed to fetch feature flags from store, returning empty list, reason={err}")
238245
return features_enabled
239246

247+
logger.debug("Evaluating all features")
240248
for name, feature in features.items():
241249
rules = feature.get(schema.RULES_KEY, {})
242250
feature_default_value = feature.get(schema.FEATURE_DEFAULT_VAL_KEY)

aws_lambda_powertools/utilities/feature_flags/schema.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ class RuleAction(str, Enum):
2020
EQUALS = "EQUALS"
2121
STARTSWITH = "STARTSWITH"
2222
ENDSWITH = "ENDSWITH"
23-
CONTAINS = "CONTAINS"
23+
IN = "IN"
24+
NOT_IN = "NOT_IN"
2425

2526

2627
class SchemaValidator(BaseValidator):
@@ -79,7 +80,7 @@ class SchemaValidator(BaseValidator):
7980
The value MUST contain the following members:
8081
8182
* **action**: `str`. Operation to perform to match a key and value.
82-
The value MUST be either EQUALS, STARTSWITH, ENDSWITH, CONTAINS
83+
The value MUST be either EQUALS, STARTSWITH, ENDSWITH, IN, NOT_IN
8384
* **key**: `str`. Key in given context to perform operation
8485
* **value**: `Any`. Value in given context that should match action operation.
8586

docs/core/event_handler/api_gateway.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,49 @@ This will enable full tracebacks errors in the response, print request and respo
730730
return app.resolve(event, context)
731731
```
732732

733+
### Custom serializer
734+
735+
You can instruct API Gateway handler to use a custom serializer to best suit your needs, for example take into account Enums when serializing.
736+
737+
=== "custom_serializer.py"
738+
```python hl_lines="19-20 24"
739+
import json
740+
from enum import Enum
741+
from json import JSONEncoder
742+
from typing import Dict
743+
744+
class CustomEncoder(JSONEncoder):
745+
"""Your customer json encoder"""
746+
def default(self, obj):
747+
if isinstance(obj, Enum):
748+
return obj.value
749+
try:
750+
iterable = iter(obj)
751+
except TypeError:
752+
pass
753+
else:
754+
return sorted(iterable)
755+
return JSONEncoder.default(self, obj)
756+
757+
def custom_serializer(obj) -> str:
758+
"""Your custom serializer function ApiGatewayResolver will use"""
759+
return json.dumps(obj, cls=CustomEncoder)
760+
761+
# Assigning your custom serializer
762+
app = ApiGatewayResolver(serializer=custom_serializer)
763+
764+
class Color(Enum):
765+
RED = 1
766+
BLUE = 2
767+
768+
@app.get("/colors")
769+
def get_color() -> Dict:
770+
return {
771+
# Color.RED will be serialized to 1 as expected now
772+
"color": Color.RED,
773+
"variations": {"light", "dark"},
774+
}
775+
```
733776

734777
## Testing your code
735778

docs/core/tracer.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ Tracer is an opinionated thin wrapper for [AWS X-Ray Python SDK](https://github.
1010
## Key features
1111

1212
* Auto capture cold start as annotation, and responses or full exceptions as metadata
13-
* Run functions locally with SAM CLI without code change to disable tracing
14-
* Explicitly disable tracing via env var `POWERTOOLS_TRACE_DISABLED="true"`
13+
* Auto-disable when not running in AWS Lambda environment
1514
* Support tracing async methods, generators, and context managers
1615
* Auto patch supported modules by AWS X-Ray
1716

@@ -357,11 +356,7 @@ Tracer keeps a copy of its configuration after the first initialization. This is
357356

358357
## Testing your code
359358

360-
You can safely disable Tracer when unit testing your code using `POWERTOOLS_TRACE_DISABLED` environment variable.
361-
362-
```bash
363-
POWERTOOLS_TRACE_DISABLED=1 python -m pytest
364-
```
359+
Tracer is disabled by default when not running in the AWS Lambda environment - This means no code changes or environment variables to be set.
365360

366361
## Tips
367362

docs/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ aws serverlessrepo list-application-versions \
212212
[Event source data classes](./utilities/data_classes.md) | Data classes describing the schema of common Lambda event triggers
213213
[Parser](./utilities/parser.md) | Data parsing and deep validation using Pydantic
214214
[Idempotency](./utilities/idempotency.md) | Idempotent Lambda handler
215+
[Feature Flags](./utilities/feature_flags.md) | A simple rule engine to evaluate when one or multiple features should be enabled depending on the input
215216

216217
## Environment variables
217218

@@ -222,7 +223,7 @@ aws serverlessrepo list-application-versions \
222223
| ------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------- |
223224
| **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `"service_undefined"` |
224225
| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics) | `None` |
225-
| **POWERTOOLS_TRACE_DISABLED** | Disables tracing | [Tracing](./core/tracer) | `false` |
226+
| **POWERTOOLS_TRACE_DISABLED** | Explicitly disables tracing | [Tracing](./core/tracer) | `false` |
226227
| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracing](./core/tracer) | `true` |
227228
| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracing](./core/tracer) | `true` |
228229
| **POWERTOOLS_TRACE_MIDDLEWARES** | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory) | `false` |
69 KB
Loading

0 commit comments

Comments
 (0)