Search code examples
pythonjsonnonetype

Python loads None to Json without emitting error


I am parsing dictionaries into nested Json (Python 2.7). The problem I have that sometimes there is no value for the variable so it takes None, it depends if the variable came or not. It would be ok, but I want to avoid escape characters before quotations. Before I get nested Json I do json.loads() to remove string escapes.

The problem is to return None if there is no dict.

Example code:

import json

data1 = '{"foo":"bar"}'
data2 = None
sensor = {'header':'Info',
          'data1': json.loads(data1),
          'data2': json.loads(data2)}
output = json.dumps(sensor)
print(output)

Expected outcome:

{"data2": null, "data1": {"foo": "bar"}, "header": "Info"}

Received error:

Traceback (most recent call last):
  File "\jsonDecoding.py", line 7, in <module>
    'data2': json.loads(data2)}
  File "\Python\Python35\lib\json\__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'NoneType'

Tried solution:

class Decoder(json.JSONDecoder):
    def default(self, obj):
        if obj is None::
            return None
        else: return super(Decoder, self).default(obj)

data1 = '{"foo":"bar"}'
data2 = None
sensor = {'header':'Info',
          'data1': json.loads(data1),
          'data2': json.loads(data2, cls=Decoder)}
output = json.dumps(sensor)

I thought implementing Decoder.default() should solve the problem but it calls the class but does not call the default method.

There are plenty of talks about None in place of key or value but I did not find in place of whole object


Solution

  • I think you make the problem harder than it is. We can construct a None-safe function:

    def nonesafe_loads(obj):
        if obj is not None:
            return json.loads(obj)
    

    This will return the json.loads(obj) in case obj is not None, and otherwise it will return None. Or we can construct a "best effort" JSON loads, that aims to json.loads the string, or in case that fails, returns the obj itself:

    def besteffort_loads(obj):
        try:
            return json.loads(obj)
        except (TypeError, ValueError):
            return obj
    

    Now we can just use our nonesafe_loads in the program:

    data1 = '{"foo":"bar"}'
    data2 = None
    sensor = {'header':'Info',
              'data1': nonesafe_loads(data1),
              'data2': nonesafe_loads(data2)}
    output = json.dumps(sensor)