""" This file is part of the web2py Web Framework Copyrighted by Massimo Di Pierro License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) """ import datetime import decimal import json as json_parser import gluon.contrib.rss2 as rss2 from gluon._compat import integer_types, long, to_native, unicodeT from gluon.html import TAG, XmlComponent, xmlescape from gluon.languages import lazyT from gluon.storage import Storage have_yaml = True try: import yaml as yamlib except ImportError: have_yaml = False def cast_keys(o, cast=str, encoding="utf-8"): """ Builds a new object with type keys. Use this function if you are in Python < 2.6.5 This avoids syntax errors when unpacking dictionary arguments. Args: o: is the object input cast: (defaults to str) is an object type or function which supports conversion such as: converted = cast(o) encoding: (defaults to utf-8) is the encoding for unicode keys. This is not used for custom cast functions """ if isinstance(o, (dict, Storage)): if isinstance(o, dict): newobj = dict() else: newobj = Storage() for k, v in o.items(): if (cast == str) and isinstance(k, unicodeT): key = k.encode(encoding) else: key = cast(k) newobj[key] = cast_keys(v, cast=cast, encoding=encoding) elif isinstance(o, (tuple, set, list)): newobj = [] for item in o: newobj.append(cast_keys(item, cast=cast, encoding=encoding)) if isinstance(o, tuple): newobj = tuple(newobj) elif isinstance(o, set): newobj = set(newobj) else: # no string cast (unknown object) newobj = o return newobj def loads_json(o, unicode_keys=True, **kwargs): # deserialize a json string result = json_parser.loads(o, **kwargs) if not unicode_keys: # filter non-str keys in dictionary objects result = cast_keys(result, encoding=kwargs.get("encoding", "utf-8")) return result def custom_json(o): if hasattr(o, "custom_json") and callable(o.custom_json): return o.custom_json() if isinstance(o, (datetime.date, datetime.datetime, datetime.time)): return o.isoformat()[:19].replace("T", " ") elif isinstance(o, integer_types): return int(o) elif isinstance(o, decimal.Decimal): return float(o) elif isinstance(o, (bytes, bytearray)): return str(o) if hasattr(str, "decode") else str(o, encoding="utf-8") elif isinstance(o, lazyT): return str(o) elif isinstance(o, XmlComponent): return to_native(o.xml()) elif isinstance(o, set): return list(o) elif hasattr(o, "as_list") and callable(o.as_list): return o.as_list() elif hasattr(o, "as_dict") and callable(o.as_dict): return o.as_dict() else: raise TypeError(repr(o) + " is not JSON serializable") def xml_rec(value, key, quote=True): if hasattr(value, "custom_xml") and callable(value.custom_xml): return value.custom_xml() elif isinstance(value, (dict, Storage)): return TAG[key](*[TAG[k](xml_rec(v, "", quote)) for k, v in value.items()]) elif isinstance(value, list): return TAG[key](*[TAG.item(xml_rec(item, "", quote)) for item in value]) elif hasattr(value, "as_list") and callable(value.as_list): return str(xml_rec(value.as_list(), "", quote)) elif hasattr(value, "as_dict") and callable(value.as_dict): return str(xml_rec(value.as_dict(), "", quote)) else: return xmlescape(value, quote) def xml(value, encoding="UTF-8", key="document", quote=True): return ('' % encoding) + str( xml_rec(value, key, quote) ) class JSONEncoderForHTML(json_parser.JSONEncoder): """An encoder that produces JSON safe to embed in HTML. To embed JSON content in, say, a script tag on a web page, the characters &, < and > should be escaped. They cannot be escaped with the usual entities (e.g. &) because they are not expanded within