Skip to content

Commit bfcaf0c

Browse files
authored
Merge branch 'v3' into data_classes_annotations
2 parents 79f8187 + 2d59b7a commit bfcaf0c

19 files changed

+123
-63
lines changed

aws_lambda_powertools/logging/logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def decorate(event, context, *args, **kwargs):
440440

441441
if correlation_id_path:
442442
self.set_correlation_id(
443-
jmespath_utils.extract_data_from_envelope(envelope=correlation_id_path, data=event),
443+
jmespath_utils.query(envelope=correlation_id_path, data=event),
444444
)
445445

446446
if log_event:

aws_lambda_powertools/utilities/batch/decorators.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from __future__ import annotations
22

3+
import warnings
34
from typing import Any, Awaitable, Callable, Dict, List
45

6+
from typing_extensions import deprecated
7+
58
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
69
from aws_lambda_powertools.utilities.batch import (
710
AsyncBatchProcessor,
@@ -11,9 +14,14 @@
1114
)
1215
from aws_lambda_powertools.utilities.batch.types import PartialItemFailureResponse
1316
from aws_lambda_powertools.utilities.typing import LambdaContext
17+
from aws_lambda_powertools.warnings import PowertoolsDeprecationWarning
1418

1519

1620
@lambda_handler_decorator
21+
@deprecated(
22+
"`async_batch_processor` decorator is deprecated; use `async_process_partial_response` function instead.",
23+
category=None,
24+
)
1725
def async_batch_processor(
1826
handler: Callable,
1927
event: Dict,
@@ -61,6 +69,14 @@ def async_batch_processor(
6169
-----------
6270
* Sync batch processors. Use `batch_processor` instead.
6371
"""
72+
73+
warnings.warn(
74+
"The `async_batch_processor` decorator is deprecated in V3 "
75+
"and will be removed in the next major version. Use `async_process_partial_response` function instead.",
76+
category=PowertoolsDeprecationWarning,
77+
stacklevel=2,
78+
)
79+
6480
records = event["Records"]
6581

6682
with processor(records, record_handler, lambda_context=context):
@@ -70,6 +86,10 @@ def async_batch_processor(
7086

7187

7288
@lambda_handler_decorator
89+
@deprecated(
90+
"`batch_processor` decorator is deprecated; use `process_partial_response` function instead.",
91+
category=None,
92+
)
7393
def batch_processor(
7494
handler: Callable,
7595
event: Dict,
@@ -117,6 +137,14 @@ def batch_processor(
117137
-----------
118138
* Async batch processors. Use `async_batch_processor` instead.
119139
"""
140+
141+
warnings.warn(
142+
"The `batch_processor` decorator is deprecated in V3 "
143+
"and will be removed in the next major version. Use `process_partial_response` function instead.",
144+
category=PowertoolsDeprecationWarning,
145+
stacklevel=2,
146+
)
147+
120148
records = event["Records"]
121149

122150
with processor(records, record_handler, lambda_context=context):

aws_lambda_powertools/utilities/feature_flags/appconfig.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def get_configuration(self) -> Dict[str, Any]:
102102

103103
if self.envelope:
104104
self.logger.debug("Envelope enabled; extracting data from config", extra={"envelope": self.envelope})
105-
config = jmespath_utils.extract_data_from_envelope(
105+
config = jmespath_utils.query(
106106
data=config,
107107
envelope=self.envelope,
108108
jmespath_options=self.jmespath_options,

aws_lambda_powertools/utilities/jmespath_utils/__init__.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
import gzip
33
import json
44
import logging
5+
import warnings
56
from typing import Any, Dict, Optional, Union
67

78
import jmespath
89
from jmespath.exceptions import LexerError
910
from jmespath.functions import Functions, signature
11+
from typing_extensions import deprecated
1012

1113
from aws_lambda_powertools.exceptions import InvalidEnvelopeExpressionError
14+
from aws_lambda_powertools.warnings import PowertoolsDeprecationWarning
1215

1316
logger = logging.getLogger(__name__)
1417

@@ -30,7 +33,7 @@ def _func_powertools_base64_gzip(self, value):
3033
return uncompressed.decode()
3134

3235

33-
def extract_data_from_envelope(data: Union[Dict, str], envelope: str, jmespath_options: Optional[Dict] = None) -> Any:
36+
def query(data: Union[Dict, str], envelope: str, jmespath_options: Optional[Dict] = None) -> Any:
3437
"""Searches and extracts data using JMESPath
3538
3639
Envelope being the JMESPath expression to extract the data you're after
@@ -42,13 +45,13 @@ def extract_data_from_envelope(data: Union[Dict, str], envelope: str, jmespath_o
4245
4346
**Deserialize JSON string and extracts data from body key**
4447
45-
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope
48+
from aws_lambda_powertools.utilities.jmespath_utils import query
4649
from aws_lambda_powertools.utilities.typing import LambdaContext
4750
4851
4952
def handler(event: dict, context: LambdaContext):
5053
# event = {"body": "{\"customerId\":\"dd4649e6-2484-4993-acb8-0f9123103394\"}"} # noqa: ERA001
51-
payload = extract_data_from_envelope(data=event, envelope="powertools_json(body)")
54+
payload = query(data=event, envelope="powertools_json(body)")
5255
customer = payload.get("customerId") # now deserialized
5356
...
5457
@@ -76,3 +79,19 @@ def handler(event: dict, context: LambdaContext):
7679
except (LexerError, TypeError, UnicodeError) as e:
7780
message = f"Failed to unwrap event from envelope using expression. Error: {e} Exp: {envelope}, Data: {data}" # noqa: B306, E501
7881
raise InvalidEnvelopeExpressionError(message)
82+
83+
84+
@deprecated("`extract_data_from_envelope` is deprecated; use `query` instead.", category=None)
85+
def extract_data_from_envelope(data: Union[Dict, str], envelope: str, jmespath_options: Optional[Dict] = None) -> Any:
86+
"""Searches and extracts data using JMESPath
87+
88+
*Deprecated*: Use query instead
89+
"""
90+
warnings.warn(
91+
"The extract_data_from_envelope method is deprecated in V3 "
92+
"and will be removed in the next major version. Use query instead.",
93+
category=PowertoolsDeprecationWarning,
94+
stacklevel=2,
95+
)
96+
97+
return query(data=data, envelope=envelope, jmespath_options=jmespath_options)

aws_lambda_powertools/utilities/validation/validator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def handler(event, context):
119119
When JMESPath expression to unwrap event is invalid
120120
""" # noqa: E501
121121
if envelope:
122-
event = jmespath_utils.extract_data_from_envelope(
122+
event = jmespath_utils.query(
123123
data=event,
124124
envelope=envelope,
125125
jmespath_options=jmespath_options,
@@ -223,7 +223,7 @@ def handler(event, context):
223223
When JMESPath expression to unwrap event is invalid
224224
""" # noqa: E501
225225
if envelope:
226-
event = jmespath_utils.extract_data_from_envelope(
226+
event = jmespath_utils.query(
227227
data=event,
228228
envelope=envelope,
229229
jmespath_options=jmespath_options,

docs/utilities/batch.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Processing batches from SQS works in three stages:
119119
--8<-- "examples/batch_processing/src/getting_started_sqs_context_manager.py"
120120
```
121121

122-
=== "As a decorator (legacy)"
122+
=== "As a decorator (deprecated)"
123123

124124
```python hl_lines="4-9 12 18 27 29"
125125
--8<-- "examples/batch_processing/src/getting_started_sqs_decorator.py"
@@ -161,7 +161,7 @@ Enable the `skip_group_on_error` option for seamless processing of messages from
161161
--8<-- "examples/batch_processing/src/getting_started_sqs_fifo_context_manager.py"
162162
```
163163

164-
=== "As a decorator (legacy)"
164+
=== "As a decorator (deprecated)"
165165

166166
```python hl_lines="5-6 11 26"
167167
--8<-- "examples/batch_processing/src/getting_started_sqs_fifo_decorator.py"
@@ -197,7 +197,7 @@ Processing batches from Kinesis works in three stages:
197197
--8<-- "examples/batch_processing/src/getting_started_kinesis_context_manager.py"
198198
```
199199

200-
=== "As a decorator (legacy)"
200+
=== "As a decorator (deprecated)"
201201

202202
```python hl_lines="2-9 12 18 26"
203203
--8<-- "examples/batch_processing/src/getting_started_kinesis_decorator.py"
@@ -241,7 +241,7 @@ Processing batches from DynamoDB Streams works in three stages:
241241
--8<-- "examples/batch_processing/src/getting_started_dynamodb_context_manager.py"
242242
```
243243

244-
=== "As a decorator (legacy)"
244+
=== "As a decorator (deprecated)"
245245

246246
```python hl_lines="4-11 14 20 31"
247247
--8<-- "examples/batch_processing/src/getting_started_dynamodb_decorator.py"
@@ -538,7 +538,7 @@ We can automatically inject the [Lambda context](https://docs.aws.amazon.com/lam
538538
--8<-- "examples/batch_processing/src/advanced_accessing_lambda_context.py"
539539
```
540540

541-
=== "As a decorator (legacy)"
541+
=== "As a decorator (deprecated)"
542542

543543
```python hl_lines="18 26"
544544
--8<-- "examples/batch_processing/src/advanced_accessing_lambda_context_decorator.py"
@@ -673,7 +673,7 @@ Use context manager when you want access to the processed messages or handle `Ba
673673

674674
### What's the difference between the decorator and process_partial_response functions?
675675

676-
`batch_processor` and `async_batch_processor` decorators are now considered legacy. Historically, they were kept due to backwards compatibility and to minimize code changes between V1 and V2.
676+
`batch_processor` and `async_batch_processor` decorators are now marked as deprecated. Historically, they were kept due to backwards compatibility and to minimize code changes between V2 and V3. We will remove both in the next major release.
677677

678678
As 2.12.0, `process_partial_response` and `async_process_partial_response` are the recommended instead. It reduces boilerplate, smaller memory/CPU cycles, and it makes it less error prone - e.g., decorators required an additional return.
679679

docs/utilities/jmespath_functions.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ Powertools for AWS Lambda (Python) also have utilities like [validation](validat
3030

3131
### Extracting data
3232

33-
You can use the `extract_data_from_envelope` function with any [JMESPath expression](https://jmespath.org/tutorial.html){target="_blank" rel="nofollow"}.
33+
You can use the `query` function with any [JMESPath expression](https://jmespath.org/tutorial.html){target="_blank" rel="nofollow"}.
3434

3535
???+ tip
3636
Another common use case is to fetch deeply nested data, filter, flatten, and more.
3737

38-
=== "extract_data_from_envelope.py"
38+
=== "query.py"
3939
```python hl_lines="1 6 10"
40-
--8<-- "examples/jmespath_functions/src/extract_data_from_envelope.py"
40+
--8<-- "examples/jmespath_functions/src/query.py"
4141
```
4242

4343
=== "extract_data_from_envelope.json"
@@ -52,7 +52,7 @@ We provide built-in envelopes for popular AWS Lambda event sources to easily dec
5252

5353
=== "extract_data_from_builtin_envelope.py"
5454

55-
```python hl_lines="1-4 9"
55+
```python hl_lines="4-7 14"
5656
--8<-- "examples/jmespath_functions/src/extract_data_from_builtin_envelope.py"
5757
```
5858

@@ -64,21 +64,21 @@ We provide built-in envelopes for popular AWS Lambda event sources to easily dec
6464

6565
These are all built-in envelopes you can use along with their expression as a reference:
6666

67-
| Envelope | JMESPath expression |
68-
| --------------------------------- | ----------------------------------------------------------------------------------------- |
69-
| **`API_GATEWAY_HTTP`** | `powertools_json(body)` |
70-
| **`API_GATEWAY_REST`** | `powertools_json(body)` |
71-
| **`CLOUDWATCH_EVENTS_SCHEDULED`** | `detail` |
67+
| Envelope | JMESPath expression | |
68+
| --------------------------------- | ----------------------------------------------------------------------------------------- |-|
69+
| **`API_GATEWAY_HTTP`** | `powertools_json(body)` | |
70+
| **`API_GATEWAY_REST`** | `powertools_json(body)` | |
71+
| **`CLOUDWATCH_EVENTS_SCHEDULED`** | `detail` | |
7272
| **`CLOUDWATCH_LOGS`** | `awslogs.powertools_base64_gzip(data) | powertools_json(@).logEvents[*]` |
73-
| **`EVENTBRIDGE`** | `detail` |
74-
| **`KINESIS_DATA_STREAM`** | `Records[*].kinesis.powertools_json(powertools_base64(data))` |
75-
| **`S3_EVENTBRIDGE_SQS`** | `Records[*].powertools_json(body).detail` |
76-
| **`S3_KINESIS_FIREHOSE`** | `records[*].powertools_json(powertools_base64(data)).Records[0]` |
77-
| **`S3_SNS_KINESIS_FIREHOSE`** | `records[*].powertools_json(powertools_base64(data)).powertools_json(Message).Records[0]` |
78-
| **`S3_SNS_SQS`** | `Records[*].powertools_json(body).powertools_json(Message).Records[0]` |
79-
| **`S3_SQS`** | `Records[*].powertools_json(body).Records[0]` |
73+
| **`EVENTBRIDGE`** | `detail` | |
74+
| **`KINESIS_DATA_STREAM`** | `Records[*].kinesis.powertools_json(powertools_base64(data))` | |
75+
| **`S3_EVENTBRIDGE_SQS`** | `Records[*].powertools_json(body).detail` | |
76+
| **`S3_KINESIS_FIREHOSE`** | `records[*].powertools_json(powertools_base64(data)).Records[0]` | |
77+
| **`S3_SNS_KINESIS_FIREHOSE`** | `records[*].powertools_json(powertools_base64(data)).powertools_json(Message).Records[0]` | |
78+
| **`S3_SNS_SQS`** | `Records[*].powertools_json(body).powertools_json(Message).Records[0]` | |
79+
| **`S3_SQS`** | `Records[*].powertools_json(body).Records[0]` | |
8080
| **`SNS`** | `Records[0].Sns.Message | powertools_json(@)` |
81-
| **`SQS`** | `Records[*].powertools_json(body)` |
81+
| **`SQS`** | `Records[*].powertools_json(body)` | |
8282

8383
???+ tip "Using SNS?"
8484
If you don't require SNS metadata, enable [raw message delivery](https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html). It will reduce multiple payload layers and size, when using SNS in combination with other services (_e.g., SQS, S3, etc_).
@@ -102,7 +102,7 @@ This sample will deserialize the JSON string within the `data` key before valida
102102

103103
=== "powertools_json_jmespath_function.py"
104104

105-
```python hl_lines="5 8 34 45 48 51"
105+
```python hl_lines="5 6 34 45 48 51"
106106
--8<-- "examples/jmespath_functions/src/powertools_json_jmespath_function.py"
107107
```
108108

@@ -142,7 +142,7 @@ This sample will decode the base64 value within the `data` key, and deserialize
142142

143143
=== "powertools_base64_jmespath_function.py"
144144

145-
```python hl_lines="7 10 37 49 53 55 57"
145+
```python hl_lines="7 11 36 48 52 54 56"
146146
--8<-- "examples/jmespath_functions/src/powertools_base64_jmespath_function.py"
147147
```
148148

examples/jmespath_functions/src/extract_data_from_builtin_envelope.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
from aws_lambda_powertools import Logger
44
from aws_lambda_powertools.utilities.jmespath_utils import (
55
envelopes,
6-
extract_data_from_envelope,
6+
query,
77
)
88
from aws_lambda_powertools.utilities.typing import LambdaContext
99

1010
logger = Logger()
1111

1212

1313
def handler(event: dict, context: LambdaContext) -> dict:
14-
records: list = extract_data_from_envelope(data=event, envelope=envelopes.SQS)
14+
records: list = query(data=event, envelope=envelopes.SQS)
1515
for record in records: # records is a list
1616
logger.info(record.get("customerId")) # now deserialized
1717

examples/jmespath_functions/src/powertools_base64_gzip_jmespath_function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def lambda_handler(event, context: LambdaContext) -> dict:
1414
try:
1515
validate(event=event, schema=schemas.INPUT, envelope="powertools_base64_gzip(payload) | powertools_json(@)")
1616

17-
# Alternatively, extract_data_from_envelope works here too
17+
# Alternatively, query works here too
1818
encoded_payload = base64.b64decode(event["payload"])
1919
uncompressed_payload = gzip.decompress(encoded_payload).decode()
2020
log: dict = json.loads(uncompressed_payload)

examples/jmespath_functions/src/powertools_base64_jmespath_function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def lambda_handler(event, context: LambdaContext) -> dict:
3535
try:
3636
validate(event=event, schema=schemas.INPUT, envelope="powertools_json(powertools_base64(payload))")
3737

38-
# alternatively, extract_data_from_envelope works here too
38+
# alternatively, query works here too
3939
payload_decoded = base64.b64decode(event["payload"]).decode()
4040

4141
order_payload: dict = json.loads(payload_decoded)

examples/jmespath_functions/src/powertools_custom_jmespath_function.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from aws_lambda_powertools.utilities.jmespath_utils import (
99
PowertoolsFunctions,
10-
extract_data_from_envelope,
10+
query,
1111
)
1212

1313

@@ -27,7 +27,7 @@ def lambda_handler(event, context) -> dict:
2727
try:
2828
logs = []
2929
logs.append(
30-
extract_data_from_envelope(
30+
query(
3131
data=event,
3232
# NOTE: Use the prefix `_func_` before the name of the function
3333
envelope="Records[*].decode_zlib_compression(log)",

examples/jmespath_functions/src/powertools_json_jmespath_function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def lambda_handler(event, context: LambdaContext) -> dict:
3434
validate(event=event, schema=schemas.INPUT, envelope="powertools_json(payload)")
3535

3636
# Deserialize JSON string order as dict
37-
# alternatively, extract_data_from_envelope works here too
37+
# alternatively, query works here too
3838
order_payload: dict = json.loads(event.get("payload"))
3939

4040
return {
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope
1+
from aws_lambda_powertools.utilities.jmespath_utils import query
22
from aws_lambda_powertools.utilities.typing import LambdaContext
33

44

55
def handler(event: dict, context: LambdaContext) -> dict:
6-
payload = extract_data_from_envelope(data=event, envelope="powertools_json(body)")
6+
payload = query(data=event, envelope="powertools_json(body)")
77
customer_id = payload.get("customerId") # now deserialized
88

99
# also works for fetching and flattening deeply nested data
10-
some_data = extract_data_from_envelope(data=event, envelope="deeply_nested[*].some_data[]")
10+
some_data = query(data=event, envelope="deeply_nested[*].some_data[]")
1111

1212
return {"customer_id": customer_id, "message": "success", "context": some_data, "statusCode": 200}

examples/middleware_factory/src/combining_powertools_utilities_function.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
1212
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags
1313
from aws_lambda_powertools.utilities.feature_flags.types import JSONType
14-
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope
14+
from aws_lambda_powertools.utilities.jmespath_utils import query
1515
from aws_lambda_powertools.utilities.typing import LambdaContext
1616
from aws_lambda_powertools.utilities.validation import SchemaValidationError, validate
1717

@@ -42,8 +42,8 @@ def middleware_custom(
4242
}
4343

4444
# extracting headers and requestContext from event
45-
headers = extract_data_from_envelope(data=event, envelope="headers")
46-
request_context = extract_data_from_envelope(data=event, envelope="requestContext")
45+
headers = query(data=event, envelope="headers")
46+
request_context = query(data=event, envelope="requestContext")
4747

4848
logger.debug(f"X-Customer-Id => {headers.get('X-Customer-Id')}")
4949
tracer.put_annotation(key="CustomerId", value=headers.get("X-Customer-Id"))

0 commit comments

Comments
 (0)