Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decode JSON to str and not unicode in Python (2.6)? [duplicate]

I have a configuration file in JSON that contains a few variables as strings (always ascii). These strings are decoded to unicode by default but since I have to pass these variables to my Python C Extensions I need them as normal Python strings. At the moment I'm using str(unicode) to convert the JSON strings but a more elegant and less verbose solution would be much appreciated.

Is there a way to change the default translation from string to unicode with a custom JSONDecoder or object hook?

like image 997
Adrian Avatar asked Jan 18 '11 11:01

Adrian


1 Answers

Not if you're not willing to lose some speed. If being somewhat slower is OK, you have to consider that using plain json.loads and recursively converting to str is probably cheaper and maybe faster.

With all that said, if you do want a loads that returns strings badly enough to accept going through extending code that wasn't meant to, here's one possible result (mostly extending through copy-n-paste) this was asinine, thanks Lennart for making me see the light (i.e., you just need to extend JSONDecoder and a couple of tricks):

import json
from json import decoder, scanner

from json.scanner import make_scanner
from _json import scanstring as c_scanstring

_CONSTANTS = json.decoder._CONSTANTS

py_make_scanner = scanner.py_make_scanner

# Convert from unicode to str
def str_scanstring(*args, **kwargs):
    result = c_scanstring(*args, **kwargs)
    return str(result[0]), result[1]

# Little dirty trick here
json.decoder.scanstring = str_scanstring

class StrJSONDecoder(decoder.JSONDecoder):
    def __init__(self, encoding=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, strict=True,
            object_pairs_hook=None):
        self.encoding = encoding
        self.object_hook = object_hook
        self.object_pairs_hook = object_pairs_hook
        self.parse_float = parse_float or float
        self.parse_int = parse_int or int
        self.parse_constant = parse_constant or _CONSTANTS.__getitem__
        self.strict = strict
        self.parse_object = decoder.JSONObject
        self.parse_array = decoder.JSONArray
        self.parse_string = str_scanstring
        self.scan_once = py_make_scanner(self)

# And another little dirty trick there    
_default_decoder = StrJSONDecoder(encoding=None, object_hook=None,
                               object_pairs_hook=None)

json._default_decoder = _default_decoder

j = {1:'2', 1.1:[1,2,3], u'test': {12:12, 13:'o'}}
print json.loads(json.dumps(j))
like image 168
TryPyPy Avatar answered Nov 09 '22 21:11

TryPyPy