Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting a Runtime.MarshalError when using this code in Zapier?

Tags:

python

zapier

The following code is giving me:

Runtime.MarshalError: Unable to marshal response: {'Yes'} is not JSON serializable

from calendar import monthrange

def time_remaining_less_than_fourteen(year, month, day):
    a_year = int(input['year'])
    b_month = int(input['month'])
    c_day = int(input['day'])
    days_in_month = monthrange(int(a_year), int(b_month))[1]
    time_remaining = ""

    if (days_in_month - c_day) < 14:
        time_remaining = "No"
        return time_remaining

    else:
        time_remaining = "Yes"
        return time_remaining


output = {time_remaining_less_than_fourteen((input['year']), (input['month']), (input['day']))}

#print(output)

When I remove {...} it then throws: 'unicode' object has no attribute 'copy'

like image 357
Samuel Hart Avatar asked Jan 28 '19 17:01

Samuel Hart


2 Answers

I encountered this issue when working with lambda transformation blueprint kinesis-firehose-process-record-python for Kinesis Firehose which led me here. Thus I will post a solution to anyone who also finds this questions when having issues with the lambda.

The blueprint is:

from __future__ import print_function

import base64

print('Loading function')


def lambda_handler(event, context):
    output = []

    for record in event['records']:
        print(record['recordId'])
        payload = base64.b64decode(record['data'])

        # Do custom processing on the payload here

        output_record = {
            'recordId': record['recordId'],
            'result': 'Ok',
            'data': base64.b64encode(payload)
        }
        output.append(output_record)

    print('Successfully processed {} records.'.format(len(event['records'])))

    return {'records': output}

The thing to note is that the Firehose lambda blueprints for python provided by AWS are for Python 2.7, and they don't work with Python 3. The reason is that in Python 3, strings and byte arrays are different.

The key change to make it work with lambda powered by Python 3.x runtime was:

changing

'data': base64.b64encode(payload)

into

'data': base64.b64encode(payload).decode("utf-8")

Otherwise, the lambda had an error due to inability to serialize JSON with byte array returned from base64.b64encode.

like image 173
Marcin Avatar answered Oct 21 '22 19:10

Marcin


David here, from the Zapier Platform team.

Per the docs:

output: A dictionary or list of dictionaries that will be the "return value" of this code. You can explicitly return early if you like. This must be JSON serializable!

In your case, output is a set:

>>> output = {'Yes'}
>>> type(output)
<class 'set'>
>>> json.dumps(output)
Object of type set is not JSON serializable

To be serializable, you need a dict (which has keys and values). Change your last line to include a key and it'll work like you expect:

#         \ here /
output = {'result': time_remaining_less_than_fourteen((input['year']), (input['month']), (input['day']))}
like image 3
xavdid Avatar answered Oct 21 '22 19:10

xavdid