nui-python-shared-utils 2.2__tar.gz → 2.3__tar.gz
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.
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/PKG-INFO +1 -1
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/powertools-integration.md +16 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/powertools_helpers.py +29 -2
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_powertools_helpers.py +147 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/.editorconfig +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/.github/workflows/ci.yml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/.github/workflows/publish.yml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/.github/workflows/test.yml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/.markdownlint-cli2.yaml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/AGENTS.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/CLAUDE.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/CONTRIBUTING.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/LICENSE +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/MANIFEST.in +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/README.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/README.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-001-structured-logging-field-vocabulary.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-002-keep-shared-utilities-generic.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-003-lazy-load-integrations.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-004-credential-resolution-precedence.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-005-explicit-secrets-manager-region.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-006-snowflake-sql-api-client.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-007-elasticsearch-client-version-range.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/ADR-008-stdlib-zoneinfo-over-pytz.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/decisions/README.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/development/testing.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/configuration.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/installation.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/quickstart.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/cli-tools.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/elasticsearch-integration.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/jwt-authentication.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/lambda-utilities.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/llm-integration.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/log-processing.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/shared-types.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/slack-integration.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/snowflake-integration.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/structured-logging-contract.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/mypy.ini +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_python_shared_utils.egg-info/SOURCES.txt +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/__init__.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/base_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/cli.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/cloudwatch_metrics.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/config.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/db_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/error_handler.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/es_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/es_query_builder.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/jwt_auth.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/lambda_helpers.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/llm.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/log_processors.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/__init__.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/binding.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/fields.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/redaction.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/secrets_helper.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_formatter.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_setup/__init__.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_setup/channel_creator.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_setup/channel_definitions.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_setup/setup_helpers.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/snowflake_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/timezone.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/utils.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/pyproject.toml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/pytest.ini +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/redirect/README.md +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/redirect/pyproject.toml +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/redirect/setup.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/requirements-test.txt +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/scripts/bench_imports.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/setup.cfg +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/setup.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/__init__.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_aws_utils.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_base_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_cloudwatch_metrics.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_config.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_db_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_error_handler.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_es_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_es_client_compat.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_es_query_builder.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_jwt_auth.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_lambda_helpers.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_lazy_imports.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_llm.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_log_processors.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_logging_binding.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_logging_fields.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_redaction.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_secrets_helper.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_slack_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_slack_formatter.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_snowflake_client.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_timezone.py +0 -0
- {nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nui-python-shared-utils
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3
|
|
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
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/powertools-integration.md
RENAMED
|
@@ -179,6 +179,22 @@ def powertools_handler(
|
|
|
179
179
|
"""
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
+
### When the Handler Raises
|
|
183
|
+
|
|
184
|
+
The decorator logs the exception and sends the Slack alert (if configured), then:
|
|
185
|
+
|
|
186
|
+
- **SQS events** (`Records[0].eventSource == "aws:sqs"`, checked before the handler runs):
|
|
187
|
+
re-raises. A returned error dict tells the event source mapping the batch succeeded (with
|
|
188
|
+
`ReportBatchItemFailures`, a response without `batchItemFailures` means every record did),
|
|
189
|
+
so the batch would be deleted. Re-raising leaves it on the queue for redelivery; it moves
|
|
190
|
+
to a DLQ after `maxReceiveCount` only if the queue has a redrive policy. The whole batch
|
|
191
|
+
comes back, records the handler already processed included, so a handler with
|
|
192
|
+
`batchSize` above 1 must be idempotent or catch per record. On a FIFO queue the message
|
|
193
|
+
group waits until the batch succeeds or redrives, and the Slack alert fires on every
|
|
194
|
+
receive. For per-record retries, enable `ReportBatchItemFailures` on the mapping and
|
|
195
|
+
return `{"batchItemFailures": [...]}` from the handler; the decorator passes it through.
|
|
196
|
+
- **Every other event**: returns `{"statusCode": 500, "body": "Internal Server Error"}`.
|
|
197
|
+
|
|
182
198
|
### Basic Usage (Logging Only)
|
|
183
199
|
|
|
184
200
|
```python
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/powertools_helpers.py
RENAMED
|
@@ -145,6 +145,17 @@ 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,
|
|
@@ -199,8 +210,17 @@ def powertools_handler(
|
|
|
199
210
|
... return {"statusCode": 200}
|
|
200
211
|
|
|
201
212
|
Note:
|
|
202
|
-
The
|
|
203
|
-
|
|
213
|
+
The handler's return value passes through unchanged: a ``statusCode`` dict
|
|
214
|
+
for API Gateway, ``{"batchItemFailures": [...]}`` for an SQS mapping with
|
|
215
|
+
``ReportBatchItemFailures``.
|
|
216
|
+
|
|
217
|
+
On exception, returns ``{"statusCode": 500, "body": "Internal Server Error"}``,
|
|
218
|
+
except for SQS events, where the exception is re-raised after logging and
|
|
219
|
+
alerting. A returned value tells the SQS mapping the batch succeeded (with
|
|
220
|
+
``ReportBatchItemFailures``, a response without ``batchItemFailures`` means
|
|
221
|
+
every record did), so the 500 dict would delete the batch. Re-raising leaves
|
|
222
|
+
it on the queue for redelivery, and in the DLQ after ``maxReceiveCount``
|
|
223
|
+
when the queue has a redrive policy.
|
|
204
224
|
"""
|
|
205
225
|
|
|
206
226
|
def decorator(func: Callable) -> Callable:
|
|
@@ -231,6 +251,9 @@ def powertools_handler(
|
|
|
231
251
|
if slack_client:
|
|
232
252
|
slack_client.set_handler_context(context)
|
|
233
253
|
|
|
254
|
+
# Classify before the handler runs: it may consume or mutate event["Records"].
|
|
255
|
+
is_sqs = _is_sqs_event(event)
|
|
256
|
+
|
|
234
257
|
try:
|
|
235
258
|
# Apply logger context injection
|
|
236
259
|
# Note: inject_lambda_context is added dynamically to logging.Logger (line 95)
|
|
@@ -274,6 +297,10 @@ def powertools_handler(
|
|
|
274
297
|
except Exception as slack_error:
|
|
275
298
|
logger.warning("Failed to send Slack alert: %s", slack_error)
|
|
276
299
|
|
|
300
|
+
# Re-raise for SQS so the batch stays on the queue; see the Note above.
|
|
301
|
+
if is_sqs:
|
|
302
|
+
raise
|
|
303
|
+
|
|
277
304
|
# Return proper Lambda error response
|
|
278
305
|
return {
|
|
279
306
|
"statusCode": 500,
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_powertools_helpers.py
RENAMED
|
@@ -334,6 +334,153 @@ class TestPowertoolsHandler:
|
|
|
334
334
|
assert result["body"] == "Internal Server Error"
|
|
335
335
|
|
|
336
336
|
|
|
337
|
+
def _sqs_event(*message_ids):
|
|
338
|
+
return {"Records": [{"messageId": mid, "eventSource": "aws:sqs", "body": "{}"} for mid in message_ids]}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class TestPowertoolsHandlerSqs:
|
|
342
|
+
"""An SQS batch must stay on the queue when the handler raises.
|
|
343
|
+
|
|
344
|
+
Any value returned to an SQS event source mapping counts as success, so
|
|
345
|
+
returning the 500 dict deletes the batch: no redelivery, no DLQ.
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def test_sqs_exception_is_reraised(self, monkeypatch):
|
|
349
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
350
|
+
|
|
351
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
352
|
+
|
|
353
|
+
error = ConnectionError("Error reading SSH protocol banner")
|
|
354
|
+
|
|
355
|
+
@powertools_handler(service_name="test-service")
|
|
356
|
+
def handler(event, context):
|
|
357
|
+
raise error
|
|
358
|
+
|
|
359
|
+
with pytest.raises(ConnectionError) as excinfo:
|
|
360
|
+
handler(_sqs_event("m-1", "m-2"), MagicMock())
|
|
361
|
+
|
|
362
|
+
assert excinfo.value is error
|
|
363
|
+
|
|
364
|
+
def test_sqs_exception_alerts_slack_before_reraising(self, monkeypatch):
|
|
365
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
366
|
+
|
|
367
|
+
mock_slack_client = MagicMock()
|
|
368
|
+
|
|
369
|
+
with patch("nui_shared_utils.powertools_helpers.SLACK_CLIENT_AVAILABLE", True):
|
|
370
|
+
with patch("nui_shared_utils.powertools_helpers.SlackClient", return_value=mock_slack_client):
|
|
371
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
372
|
+
|
|
373
|
+
@powertools_handler(service_name="test-service", slack_alert_channel="#errors")
|
|
374
|
+
def handler(event, context):
|
|
375
|
+
raise ValueError("Test error")
|
|
376
|
+
|
|
377
|
+
with pytest.raises(ValueError):
|
|
378
|
+
handler(_sqs_event("m-1"), MagicMock())
|
|
379
|
+
|
|
380
|
+
mock_slack_client.send_message.assert_called_once()
|
|
381
|
+
|
|
382
|
+
def test_sqs_reraises_original_exception_when_slack_fails(self, monkeypatch):
|
|
383
|
+
"""A failed alert must not replace the handler's exception or swallow it."""
|
|
384
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
385
|
+
|
|
386
|
+
mock_slack_client = MagicMock()
|
|
387
|
+
mock_slack_client.send_message.side_effect = RuntimeError("Slack API error")
|
|
388
|
+
|
|
389
|
+
with patch("nui_shared_utils.powertools_helpers.SLACK_CLIENT_AVAILABLE", True):
|
|
390
|
+
with patch("nui_shared_utils.powertools_helpers.SlackClient", return_value=mock_slack_client):
|
|
391
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
392
|
+
|
|
393
|
+
@powertools_handler(service_name="test-service", slack_alert_channel="#errors")
|
|
394
|
+
def handler(event, context):
|
|
395
|
+
raise ValueError("Test error")
|
|
396
|
+
|
|
397
|
+
with pytest.raises(ValueError, match="Test error"):
|
|
398
|
+
handler(_sqs_event("m-1"), MagicMock())
|
|
399
|
+
|
|
400
|
+
def test_sqs_detected_before_the_handler_consumes_records(self, monkeypatch):
|
|
401
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
402
|
+
|
|
403
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
404
|
+
|
|
405
|
+
@powertools_handler(service_name="test-service")
|
|
406
|
+
def handler(event, context):
|
|
407
|
+
event.pop("Records")
|
|
408
|
+
raise ValueError("Test error")
|
|
409
|
+
|
|
410
|
+
with pytest.raises(ValueError):
|
|
411
|
+
handler(_sqs_event("m-1"), MagicMock())
|
|
412
|
+
|
|
413
|
+
def test_sqs_reraises_after_metrics_flush(self, monkeypatch):
|
|
414
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
415
|
+
|
|
416
|
+
flushed = []
|
|
417
|
+
|
|
418
|
+
def log_metrics(func):
|
|
419
|
+
def inner(event, context):
|
|
420
|
+
try:
|
|
421
|
+
return func(event, context)
|
|
422
|
+
finally:
|
|
423
|
+
flushed.append(True)
|
|
424
|
+
|
|
425
|
+
return inner
|
|
426
|
+
|
|
427
|
+
mock_metrics = MagicMock()
|
|
428
|
+
mock_metrics.log_metrics = log_metrics
|
|
429
|
+
|
|
430
|
+
with patch("nui_shared_utils.powertools_helpers.POWERTOOLS_AVAILABLE", True):
|
|
431
|
+
with patch("nui_shared_utils.powertools_helpers.Metrics", return_value=mock_metrics):
|
|
432
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
433
|
+
|
|
434
|
+
@powertools_handler(service_name="test-service", metrics_namespace="Test/Metrics")
|
|
435
|
+
def handler(event, context):
|
|
436
|
+
raise ValueError("Test error")
|
|
437
|
+
|
|
438
|
+
with pytest.raises(ValueError):
|
|
439
|
+
handler(_sqs_event("m-1"), MagicMock())
|
|
440
|
+
|
|
441
|
+
assert flushed == [True]
|
|
442
|
+
|
|
443
|
+
def test_sqs_success_returns_handler_result(self, monkeypatch):
|
|
444
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
445
|
+
|
|
446
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
447
|
+
|
|
448
|
+
@powertools_handler(service_name="test-service")
|
|
449
|
+
def handler(event, context):
|
|
450
|
+
return {"batchItemFailures": [{"itemIdentifier": "m-2"}]}
|
|
451
|
+
|
|
452
|
+
result = handler(_sqs_event("m-1", "m-2"), MagicMock())
|
|
453
|
+
|
|
454
|
+
assert result == {"batchItemFailures": [{"itemIdentifier": "m-2"}]}
|
|
455
|
+
|
|
456
|
+
@pytest.mark.parametrize(
|
|
457
|
+
"event",
|
|
458
|
+
[
|
|
459
|
+
{"Records": [{"EventSource": "aws:sns", "Sns": {}}]},
|
|
460
|
+
{"Records": [{"eventSource": "aws:kinesis", "kinesis": {}}]},
|
|
461
|
+
{"Records": [{"eventSource": "aws:dynamodb", "dynamodb": {}}]},
|
|
462
|
+
{"Records": [{"eventSource": "aws:s3", "s3": {}}]},
|
|
463
|
+
{"Records": []},
|
|
464
|
+
{"Records": "not-a-list"},
|
|
465
|
+
{"source": "aws.events", "detail-type": "Scheduled Event"},
|
|
466
|
+
["not", "a", "dict"],
|
|
467
|
+
],
|
|
468
|
+
ids=["sns", "kinesis", "dynamodb", "s3", "empty-records", "records-not-list", "scheduled", "non-dict"],
|
|
469
|
+
)
|
|
470
|
+
def test_non_sqs_events_keep_returning_500(self, monkeypatch, event):
|
|
471
|
+
monkeypatch.delenv("AWS_LAMBDA_RUNTIME_API", raising=False)
|
|
472
|
+
|
|
473
|
+
from nui_shared_utils.powertools_helpers import powertools_handler
|
|
474
|
+
|
|
475
|
+
@powertools_handler(service_name="test-service")
|
|
476
|
+
def handler(event, context):
|
|
477
|
+
raise ValueError("Test error")
|
|
478
|
+
|
|
479
|
+
result = handler(event, MagicMock())
|
|
480
|
+
|
|
481
|
+
assert result == {"statusCode": 500, "body": "Internal Server Error"}
|
|
482
|
+
|
|
483
|
+
|
|
337
484
|
class TestOptionalImports:
|
|
338
485
|
"""Tests for graceful degradation of optional dependencies"""
|
|
339
486
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/configuration.md
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/installation.md
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/getting-started/quickstart.md
RENAMED
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/elasticsearch-integration.md
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/jwt-authentication.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/slack-integration.md
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/docs/guides/snowflake-integration.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/cloudwatch_metrics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/error_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/es_query_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/lambda_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/log_processors.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/__init__.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/binding.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/fields.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/logging/redaction.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/secrets_helper.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_client.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_formatter.py
RENAMED
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/slack_setup/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/nui_shared_utils/snowflake_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nui_python_shared_utils-2.2 → nui_python_shared_utils-2.3}/tests/test_cloudwatch_metrics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|