Skip to content

Commit

Permalink
add feature (#704) Check if args/kwargs are JSON Serializable while r…
Browse files Browse the repository at this point in the history
…unning locally (#1154)

* ✨ add feature (#705)
- JSON unserializable content passed to asyncronous task during local develop will raise exception on purpose to allow developers to catch JSON unserializable errors during development.

:white_check_mark: add `test_async_call_arg_not_json_seralizable` testcase
:fire: remove unnecessary coding comment in `test_async.py`

* :art: fix flake8

* :pencil: fix typo
:wrench: add specific `UnserializableJsonError` exception for clarity

* :white_check_mark: expand testcase to include custome exception, `UnserializableJsonError`.

* :art: run isort/black

* :fire: remove unnecessary assert

Co-authored-by: javulticat <[email protected]>

* :recycle: simplify `validate_json_serializable()` to accept *args, **kwargs as per review comment

* :fire: remove unnecessary import and use `object()` as unserializable_object sample.

Co-authored-by: javulticat <[email protected]>
  • Loading branch information
monkut and javulticat authored Sep 15, 2022
1 parent bef5c5a commit c048ea2
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 2 deletions.
9 changes: 8 additions & 1 deletion tests/tests_async.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf8 -*-
import os
import unittest

Expand All @@ -17,6 +16,7 @@
get_func_task_path,
import_and_get_task,
)
from zappa.utilities import UnserializableJsonError


class TestZappa(unittest.TestCase):
Expand Down Expand Up @@ -94,3 +94,10 @@ def test_async_call_with_defaults(self):
lambda_function_name="MyLambda",
)
lambda_async_mock.return_value.send.assert_called_with(get_func_task_path(async_me), ("qux",), {})

def test_async_call_arg_not_json_serializable(self):
"""Exception is raised when calling an async function locally (not on aws)"""
async_me = import_and_get_task("tests.test_app.async_me")
unserializable_object = object()
with self.assertRaises(UnserializableJsonError):
async_me(unserializable_object)
3 changes: 2 additions & 1 deletion zappa/asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def my_async_func(*args, **kwargs):
import boto3
import botocore

from .utilities import get_topic_name
from .utilities import get_topic_name, validate_json_serializable

try:
from zappa_settings import ASYNC_RESPONSE_TABLE
Expand Down Expand Up @@ -430,6 +430,7 @@ def _run_async(*args, **kwargs):
).send(task_path, args, kwargs)
return send_result
else:
validate_json_serializable(*args, **kwargs)
return func(*args, **kwargs)

update_wrapper(_run_async, func)
Expand Down
15 changes: 15 additions & 0 deletions zappa/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@
import shutil
import stat
import sys
from typing import Any
from urllib.parse import urlparse

import botocore
import durationpy

LOG = logging.getLogger(__name__)


class UnserializableJsonError(TypeError):
"""Exception class for JSON encoding errors"""

pass


##
# Settings / Packaging
##
Expand Down Expand Up @@ -592,3 +600,10 @@ def merge_headers(event):
for h in multi_headers.keys():
multi_headers[h] = ", ".join(multi_headers[h])
return multi_headers


def validate_json_serializable(*args: Any, **kwargs: Any) -> None:
try:
json.dumps((args, kwargs))
except (TypeError, OverflowError):
raise UnserializableJsonError("Arguments to an asynchronous.task must be JSON serializable!")

0 comments on commit c048ea2

Please sign in to comment.