0

How can I pass arguments to a default handler function while converting data to JSON using Bottle's json_dumps?

EDIT: I missed a point where I convert the data from json_dumps, back to the previous format using json_loads. The reason I use json_dumps is because i need to convert the datetime format to string

I have the result of a MySQL query as list of tuples:

data = [(u'user1', u'Topic1', datetime.datetime(2015, 8, 3, 23, 55), 2.0, 5), (u'user2', u'Topic2', datetime.datetime(2015, 8, 4, 23, 55), 3.0, 5)]

It contains some data in datetime format. And I send this data as response to an AJAX call, in JSON format, because of which I perform json_dumps on it.

Now, I can't simply perform json_dumps(data) as it gives this error:

TypeError: datetime.datetime(2015, 8, 3, 23, 55) is not JSON serializable

So, I define this handler function and use it as follows:

def dataHandler(obj):
    if isinstance(obj, datetime):
        return obj.strftime('%Y-%m-%d %H:%M')

json_dumps(data, default=dataHandler)

This works fine and the output is:

'[["user1", "Topic1", "2015-08-03 23:55", 2.0, 5], ["user2", "Topic2", "2015-08-04 23:55", 3.0, 5]

Now at different points in my code, for different data, I need different formats of datetime. So, I redefined the function like this:

def dataHandler(obj, showTime='no'):
    if isinstance(obj, datetime):
        if str(showTime).lower() == 'no':
            return obj.strftime('%Y-%m-%d')
        elif str(showTime).lower() == 'yes':
            return obj.strftime('%Y-%m-%d %H:%M')

Now if I perform json_dumps(data, default=dataHandler), it works properly, considers showTime as no and gives output same as above.

The problem comes when I try to pass it an argument:

json_dumps(data, default=dataHandler('Yes'))

It gives this error:

TypeError: datetime.datetime(2015, 8, 10, 23, 55) is not JSON serializable

How can I have different such cases defined in the same function?

Thanks.

1 Answer 1

2

You could use a @decorator (PEP-318).

Example:

def json_handler(show_time=True):
    def decorated(obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime('%FT%T' if show_time else '%F')
        if isinstance(obj, datetime.date):
            return obj.strftime('%F')
        return repr(obj) # catch-all
    return decorated

Then:

>>> json.dumps(data, default=json_handler())
'[["user1", "Topic1", "2015-08-03T23:55:00", 2.0, 5], ["user2", "Topic2", "2015-08-04T23:55:00", 3.0, 5]]'
>>> json.dumps(data, default=json_handler(False))
'[["user1", "Topic1", "2015-08-03", 2.0, 5], ["user2", "Topic2", "2015-08-04", 3.0, 5]]'

Edit

The line return repr(obj) # catch-all will use the representation of the object instead of refusing to dump it (ie: "<object object at 0x7f934f6ef0c0>" instead of TypeError: <object object at 0x7f934f6ef0e0> is not JSON serializable); this might or might not be desired.

Do not forget to call the decorator!
Failing to do so (ie: json.dumps(data, default=json_handler) instead of json.dumps(data, default=json_handler())) will result in a RuntimeError: maximum recursion depth exceeded while calling a Python object or Segmentation Faults.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.