Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a python decoder that produces VALID json and handles NaNs

I want to serialize mongoDb's output to actual VALID json in python. I've found several libraries, but none of them seems to both produce valid json and handle incompatible values with null (undefined would be fine also).

Example input:

{
    "_id" : ObjectId("57f3e32c71285f85b46d6fb5"),
    "rate" : Infinity
    "value" : NaN
}

Expected output:

(tried json.dumps and its allow_nan option, but it throws errors and it doesn't help at all)

{
    "_id" : { $oid: "57f3e32c71285f85b46d6fb5" },
    "rate" : null,
    "value" : null
}

Anyone knows a way / library to achieve this ?

As an example, Javascript's JSON does this fine:

Object {_id: "57f3e32c71285f85b46d6fb5", rate: Infinity, value: NaN}
JSON.stringify(tg)
"{"_id":"57f3e32c71285f85b46d6fb5","rate":null,"value":null}"
like image 920
BiAiB Avatar asked Nov 19 '25 12:11

BiAiB


1 Answers

you can always make your own encoder (I stole this one from https://gist.github.com/pauloalem/6244976 )

import json


class FloatEncoder(json.JSONEncoder):
    def __init__(self, nan_str="null", **kwargs):
        super(FloatEncoder, self).__init__(**kwargs)
        self.nan_str = nan_str

    def iterencode(self, o, _one_shot=False):
        """Encode the given object and yield each string
        representation as available.

        For example::

            for chunk in JSONEncoder().iterencode(bigobject):
                mysocket.write(chunk)
        """
        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = json.encoder.encode_basestring_ascii
        else:
            _encoder = json.encoder.encode_basestring
        # if self.encoding != 'utf-8':
        #     def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
        #         if isinstance(o, str):
        #             o = o.decode(_encoding)
        #         return _orig_encoder(o)

        def floatstr(o, allow_nan=self.allow_nan, _repr=json.encoder.encode_basestring,
                _inf=json.encoder.INFINITY, _neginf=-json.encoder.INFINITY,
                nan_str=self.nan_str):
            # Check for specials.  Note that this type of test is processor
            # and/or platform-specific, so do tests which don't depend on the
            # internals.

            if o != o:
                text = nan_str
            elif o == _inf:
                text = 'Infinity'
            elif o == _neginf:
                text = '-Infinity'
            else:
                return _repr(o)

            if not allow_nan:
                raise ValueError(
                    "Out of range float values are not JSON compliant: " +
                    repr(o))

            return text

        _iterencode = json.encoder._make_iterencode(
                markers, self.default, _encoder, self.indent, floatstr,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, _one_shot)
        return _iterencode(o, 0)


d = {"i_will_byte_you_in_the_ass": float("NaN")}
print( json.dumps(d, cls=FloatEncoder) )
like image 141
Joran Beasley Avatar answered Nov 21 '25 03:11

Joran Beasley