nui-python-shared-utils 2.2__py3-none-any.whl → 2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nui-python-shared-utils
3
- Version: 2.2
3
+ Version: 2.4
4
4
  Summary: Shared Python utilities for AWS Lambda, CLI tools, and agents with Slack, Elasticsearch, and monitoring integrations
5
5
  Home-page: https://github.com/nuimarkets/nui-python-shared-utils
6
6
  Author: NUI Markets
@@ -1,4 +1,4 @@
1
- nui_python_shared_utils-2.2.dist-info/licenses/LICENSE,sha256=vGe2mC5yLUb8toYlY3T36ZwCB5zQUW5hlCtEMiqokhM,1071
1
+ nui_python_shared_utils-2.4.dist-info/licenses/LICENSE,sha256=vGe2mC5yLUb8toYlY3T36ZwCB5zQUW5hlCtEMiqokhM,1071
2
2
  nui_shared_utils/__init__.py,sha256=wbm10x7THNbrCBGClWiWSVkTNxcBKcHZ-HjYpRQBFrk,13354
3
3
  nui_shared_utils/base_client.py,sha256=I1lKQGhrKyvujV2zps0TrtEdPDqMCwRQaIh6ceGONXQ,11016
4
4
  nui_shared_utils/cli.py,sha256=JJpSoQWKvAz4b8cO30yFNi5vY9jmqrCHzbFpvrVTkbU,8747
@@ -12,7 +12,7 @@ nui_shared_utils/jwt_auth.py,sha256=2Ag1zZKxd2R8QBz3aQA4h8OtKHQvUVKrjUp6lXpJxJU,
12
12
  nui_shared_utils/lambda_helpers.py,sha256=psHVotpmOfnmyQCoOt4MSIEj7VwWcy6gZM3vYSZwjOk,3041
13
13
  nui_shared_utils/llm.py,sha256=adNUO8Qbeb3__GvpROxWSUERkpiazKiGJFE5xzU5eZ0,8351
14
14
  nui_shared_utils/log_processors.py,sha256=x5gz1LEkbmoMCZ3ZB6q-mbn26dSzwh1trz4wSkBGxqk,5538
15
- nui_shared_utils/powertools_helpers.py,sha256=qc-lYLfY-QX20gALfPOJcihrtJhiCU-fJW8rsPT7LJE,11037
15
+ nui_shared_utils/powertools_helpers.py,sha256=DGM6L0nBkhRpcQvj58s15jVfB3IH_4274aAoyW2Xi1o,13030
16
16
  nui_shared_utils/secrets_helper.py,sha256=_jQkMWzjayZ8vvyHG2yuuxur-SQYUUONfcsZ0MF8qOw,7025
17
17
  nui_shared_utils/slack_client.py,sha256=jvkLeBMA8WHOqdRzCEpG42FfBlMeWue8bZ1g1ZxF-UI,40304
18
18
  nui_shared_utils/slack_formatter.py,sha256=QT9VXApE0q09n_PmEVvaLCSfLW24vmowlCXF3Dzimfk,10850
@@ -27,8 +27,8 @@ nui_shared_utils/slack_setup/__init__.py,sha256=OElyS3xk4F_YKH5uUUTDpN0ah1dOO3e5
27
27
  nui_shared_utils/slack_setup/channel_creator.py,sha256=0gyCBIS0EC96SVn1Z2dD4Fpzk0xNdHSWyiCxoUQIUe8,10667
28
28
  nui_shared_utils/slack_setup/channel_definitions.py,sha256=atfz5ZhpqefOeLh1gShbWd-TLzgjPmhv95bfuTdmZog,5676
29
29
  nui_shared_utils/slack_setup/setup_helpers.py,sha256=pzzXMs12GI9sdZttWeYzgLPgC0xqPz7ZLHM1GUPNNXc,7219
30
- nui_python_shared_utils-2.2.dist-info/METADATA,sha256=QsygJarXaIbwKBA4-jRoTNQdsUHPvdgA0vtiVHWGsBw,22688
31
- nui_python_shared_utils-2.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
32
- nui_python_shared_utils-2.2.dist-info/entry_points.txt,sha256=TrJ3Z4kz3oXfy6InXn20jHu7rnTwo-4EA0KRFX3fkL0,66
33
- nui_python_shared_utils-2.2.dist-info/top_level.txt,sha256=YMRu5cnn3hxHoYq9wNvaI9atVHnTNVdswO5_cQSfnJI,17
34
- nui_python_shared_utils-2.2.dist-info/RECORD,,
30
+ nui_python_shared_utils-2.4.dist-info/METADATA,sha256=APNpREIrigYHIaSvr5yyOi3HSqgu0iRgWpBoRWq_1Xo,22688
31
+ nui_python_shared_utils-2.4.dist-info/WHEEL,sha256=a-udL2m4V_6Yn8b-uKzWb12RjRxwwMo6ohYFM24tpaY,91
32
+ nui_python_shared_utils-2.4.dist-info/entry_points.txt,sha256=TrJ3Z4kz3oXfy6InXn20jHu7rnTwo-4EA0KRFX3fkL0,66
33
+ nui_python_shared_utils-2.4.dist-info/top_level.txt,sha256=YMRu5cnn3hxHoYq9wNvaI9atVHnTNVdswO5_cQSfnJI,17
34
+ nui_python_shared_utils-2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (84.0.0)
2
+ Generator: setuptools (84.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -145,12 +145,24 @@ def get_powertools_logger(
145
145
  return powertools_logger
146
146
 
147
147
 
148
+ def _is_sqs_event(event: Any) -> bool:
149
+ """True when ``event`` is a batch delivered by an SQS event source mapping."""
150
+ if not isinstance(event, dict):
151
+ return False
152
+ records = event.get("Records")
153
+ if not isinstance(records, list) or not records:
154
+ return False
155
+ first = records[0]
156
+ return isinstance(first, dict) and first.get("eventSource") == "aws:sqs"
157
+
158
+
148
159
  def powertools_handler(
149
160
  service_name: str,
150
161
  metrics_namespace: Optional[str] = None,
151
162
  slack_alert_channel: Optional[str] = None,
152
163
  slack_account_names: Optional[Dict[str, str]] = None,
153
164
  slack_account_names_config: Optional[str] = None,
165
+ reraise_exceptions: bool = False,
154
166
  ):
155
167
  """
156
168
  Decorator for Lambda handlers with logging, metrics, and error handling.
@@ -164,6 +176,7 @@ def powertools_handler(
164
176
  - Optional metrics.log_metrics integration (if metrics_namespace provided)
165
177
  - Structured exception logging with traceback
166
178
  - Optional Slack alerts on failures (if slack_alert_channel provided)
179
+ - Optional exception re-raising for event sources that use Lambda failure semantics
167
180
  - Graceful degradation if Slack client unavailable
168
181
  - Proper Lambda error response formatting
169
182
 
@@ -179,6 +192,11 @@ def powertools_handler(
179
192
  Values loaded from this file are used as defaults, but any keys
180
193
  provided in ``slack_account_names`` take precedence and override
181
194
  the YAML-loaded values.
195
+ reraise_exceptions: Re-raise handler exceptions after logging and Slack
196
+ alerting. Enable this for event sources such as Kinesis, DynamoDB
197
+ Streams, SNS, S3, and EventBridge that rely on a raised exception to
198
+ record a failed invocation and apply their retry or failure handling.
199
+ Defaults to False to preserve the existing 500 response behavior.
182
200
 
183
201
  Returns:
184
202
  Decorator function for Lambda handlers
@@ -199,8 +217,18 @@ def powertools_handler(
199
217
  ... return {"statusCode": 200}
200
218
 
201
219
  Note:
202
- The decorated handler must return a dict with statusCode and optional body.
203
- On exception, returns: {"statusCode": 500, "body": "Internal Server Error"}
220
+ The handler's return value passes through unchanged: a ``statusCode`` dict
221
+ for API Gateway, ``{"batchItemFailures": [...]}`` for an SQS mapping with
222
+ ``ReportBatchItemFailures``.
223
+
224
+ On exception, returns ``{"statusCode": 500, "body": "Internal Server Error"}``
225
+ by default. Set ``reraise_exceptions=True`` to re-raise after logging and
226
+ alerting when the event source relies on Lambda failure semantics. SQS events
227
+ are always re-raised, regardless of this option: a returned value tells the
228
+ SQS mapping the batch succeeded (with ``ReportBatchItemFailures``, a response
229
+ without ``batchItemFailures`` means every record did), so the 500 dict would
230
+ delete the batch. Re-raising leaves it on the queue for redelivery, and in the
231
+ DLQ after ``maxReceiveCount`` when the queue has a redrive policy.
204
232
  """
205
233
 
206
234
  def decorator(func: Callable) -> Callable:
@@ -231,6 +259,9 @@ def powertools_handler(
231
259
  if slack_client:
232
260
  slack_client.set_handler_context(context)
233
261
 
262
+ # Classify before the handler runs: it may consume or mutate event["Records"].
263
+ is_sqs = _is_sqs_event(event)
264
+
234
265
  try:
235
266
  # Apply logger context injection
236
267
  # Note: inject_lambda_context is added dynamically to logging.Logger (line 95)
@@ -274,6 +305,11 @@ def powertools_handler(
274
305
  except Exception as slack_error:
275
306
  logger.warning("Failed to send Slack alert: %s", slack_error)
276
307
 
308
+ # Re-raise for SQS so the batch stays on the queue, or when the caller
309
+ # opts into Lambda failure semantics; see the Note above.
310
+ if is_sqs or reraise_exceptions:
311
+ raise
312
+
277
313
  # Return proper Lambda error response
278
314
  return {
279
315
  "statusCode": 500,