Skip to content

Commit 2dd5f15

Browse files
committed
Don't bubble up Application User errors
1 parent 7d946a4 commit 2dd5f15

2 files changed

Lines changed: 35 additions & 9 deletions

File tree

examples/chem-sync-local-flask/local_app/benchling_app/handler.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Any
22

3+
from benchling_sdk.apps.status.errors import AppUserFacingError
34
from benchling_sdk.models.webhooks.v0 import (
45
CanvasInitializeWebhookV0,
56
CanvasInteractionWebhookV0,
@@ -25,11 +26,17 @@ def handle_webhook(webhook_dict: dict[str, Any]) -> None:
2526
# Could also choose to route on webhook.message.type
2627
# Note: if your manifest specifies more than one item in `features`,
2728
# then `webhook.message.feature_id` may also need to be part of your routing logic
28-
if isinstance(webhook.message, CanvasInitializeWebhookV0):
29-
render_search_canvas(app, webhook.message)
30-
elif isinstance(webhook.message, CanvasInteractionWebhookV0):
31-
route_interaction_webhook(app, webhook.message)
32-
else:
33-
# Should only happen if the app's manifest requests webhooks that aren't handled in its code paths
34-
raise UnsupportedWebhookError(f"Received an unsupported webhook type: {webhook}")
35-
logger.debug("Successfully completed request for webhook: %s", webhook_dict)
29+
try:
30+
if isinstance(webhook.message, CanvasInitializeWebhookV0):
31+
render_search_canvas(app, webhook.message)
32+
elif isinstance(webhook.message, CanvasInteractionWebhookV0):
33+
route_interaction_webhook(app, webhook.message)
34+
else:
35+
# Should only happen if the app's manifest requests webhooks that aren't handled in its code paths
36+
raise UnsupportedWebhookError(f"Received an unsupported webhook type: {webhook}") # noqa: TRY301
37+
logger.debug("Successfully completed request for webhook: %s", webhook_dict)
38+
# We want errors shown to the user to end control flow, but we don't want them to propagate
39+
# and show as errors in our logs.
40+
# For this example, Flask error handler won't intercept this since we're within a thread
41+
except AppUserFacingError as e:
42+
logger.debug("Exiting with client error: %s", e)

examples/chem-sync-local-flask/tests/unit/local_app/benchling_app/test_handler.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from pathlib import Path
2-
from unittest.mock import MagicMock, patch
2+
from unittest.mock import MagicMock, call, patch
33

44
import pytest
55
from benchling_sdk.apps.framework import App
6+
from benchling_sdk.apps.status.errors import AppUserFacingError
67

78
from local_app.benchling_app.handler import UnsupportedWebhookError, handle_webhook
89
from tests.helpers import load_webhook_json
@@ -40,3 +41,21 @@ def test_handle_webhook_unsupported(self, mock_init_app_from_webhook) -> None:
4041
mock_init_app_from_webhook.return_value = mock_app
4142
with pytest.raises(UnsupportedWebhookError):
4243
handle_webhook(webhook.to_dict())
44+
45+
@patch("local_app.benchling_app.handler.logger")
46+
@patch("local_app.benchling_app.handler.render_search_canvas")
47+
@patch("local_app.benchling_app.handler.init_app_from_webhook")
48+
def test_handle_webhook_user_error(self,
49+
mock_init_app_from_webhook,
50+
mock_render_search_canvas,
51+
mock_logger) -> None:
52+
webhook = load_webhook_json(_TEST_FILES_PATH / "canvas_initialize_webhook.json")
53+
mock_app = MagicMock(App)
54+
mock_init_app_from_webhook.return_value = mock_app
55+
mock_error = AppUserFacingError("Client error")
56+
mock_render_search_canvas.side_effect = [mock_error]
57+
handle_webhook(webhook.to_dict())
58+
mock_logger.debug.assert_has_calls(
59+
[call("Exiting with client error: %s", mock_error)],
60+
any_order=True,
61+
)

0 commit comments

Comments
 (0)