1 # -----------------------------------------------------------------------
2 # Copyright (C) 2007 Georgia Public Library Service
3 # Bill Erickson <billserickson@gmail.com>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 # -----------------------------------------------------------------------
17 import simplejson, types
18 from osrf.net_obj import *
20 JSON_PAYLOAD_KEY = '__p'
21 JSON_CLASS_KEY = '__c'
23 #class osrfNetworkObject(object):
24 # """Base class for serializable network objects."""
26 # """Returns a dict of data contained by this object"""
30 #class __unknown(osrfNetworkObject):
31 # """Default class for un-registered network objects."""
32 # def __init__(self, data=None):
35 #setattr(__unknown,'__keys', [])
36 #setattr(osrfNetworkObject,'__unknown', __unknown)
39 #def osrfNetworkRegisterHint(hint, keys, type='hash'):
40 # """Register a network hint.
42 # This creates a new class at osrfNetworkObject.<hint> with
43 # methods for accessing/mutating the object's data.
44 # Method names will match the names found in the keys array
46 # hint - The hint name to encode with the object
47 # type - The data container type.
48 # keys - An array of data keys. If type is an 'array', the order of
49 # the keys will determine how the data is accessed
52 # estr = "class %s(osrfNetworkObject):\n" % hint
53 # estr += "\tdef __init__(self, data=None):\n"
54 # estr += "\t\tself.data = data\n"
55 # estr += "\t\tif data:\n"
58 # estr += "\t\t\tpass\n"
60 # # we have to make sure the array is large enough
61 # estr += "\t\t\twhile len(data) < %d:\n" % len(keys)
62 # estr += "\t\t\t\tdata.append(None)\n"
64 # estr += "\t\telse:\n"
67 # estr += "\t\t\tself.data = []\n"
68 # estr += "\t\t\tfor i in range(%s):\n" % len(keys)
69 # estr += "\t\t\t\tself.data.append(None)\n"
70 # for i in range(len(keys)):
71 # estr += "\tdef %s(self, *args):\n"\
72 # "\t\tif len(args) != 0:\n"\
73 # "\t\t\tself.data[%s] = args[0]\n"\
74 # "\t\treturn self.data[%s]\n" % (keys[i], i, i)
77 # estr += "\t\t\tself.data = {}\n"
78 # estr += "\t\t\tfor i in %s:\n" % str(keys)
79 # estr += "\t\t\t\tself.data[i] = None\n"
81 # estr += "\tdef %s(self, *args):\n"\
82 # "\t\tif len(args) != 0:\n"\
83 # "\t\t\tself.data['%s'] = args[0]\n"\
85 # "\t\ttry: val = self.data['%s']\n"\
86 # "\t\texcept: return None\n"\
87 # "\t\treturn val\n" % (i, i, i)
89 # estr += "setattr(osrfNetworkObject, '%s', %s)\n" % (hint,hint)
90 # estr += "setattr(osrfNetworkObject.%s, '__keys', keys)" % hint
95 ## -------------------------------------------------------------------
96 ## Define the custom object parsing behavior
97 ## -------------------------------------------------------------------
98 #def __parseNetObject(obj):
102 # hint = obj[JSON_CLASS_KEY]
103 # obj = obj[JSON_PAYLOAD_KEY]
105 # if isinstance(obj,list):
107 # for i in range(len(obj)):
108 # obj[i] = __parseNetObject(obj[i])
110 # if isinstance(obj,dict):
111 # for k,v in obj.iteritems():
112 # obj[k] = __parseNetObject(v)
114 # if hint: # Now, "bless" the object into an osrfNetworkObject
115 # estr = 'obj = osrfNetworkObject.%s(obj)' % hint
118 # except AttributeError:
119 # # this object has not been registered, shove it into the default container
120 # obj = osrfNetworkObject.__unknown(obj)
125 ## -------------------------------------------------------------------
126 # Define the custom object encoding behavior
127 # -------------------------------------------------------------------
129 class osrfJSONNetworkEncoder(simplejson.JSONEncoder):
130 def default(self, obj):
131 if isinstance(obj, osrfNetworkObject):
133 JSON_CLASS_KEY: obj.__class__.__name__,
134 JSON_PAYLOAD_KEY: self.default(obj.getData())
139 def osrfObjectToJSON(obj):
140 """Turns a python object into a wrapped JSON object"""
141 return simplejson.dumps(obj, cls=osrfJSONNetworkEncoder)
144 def osrfJSONToObject(json):
145 """Turns a JSON string into python objects"""
146 obj = simplejson.loads(json)
147 return parseNetObject(obj)
149 def osrfParseJSONRaw(json):
150 """Parses JSON the old fashioned way."""
151 return simplejson.loads(json)
153 def osrfToJSONRaw(obj):
154 """Stringifies an object as JSON with no additional logic."""
155 return simplejson.dumps(obj)
159 for i in range(t): r += ' '
162 def osrfDebugNetworkObject(obj, t=1):
163 """Returns a debug string for a given object.
165 If it's an osrfNetworkObject and has registered keys, key/value p
166 pairs are returned. Otherwise formatted JSON is returned"""
169 if isinstance(obj, osrfNetworkObject) and len(obj.__keys):
175 while len(key) < 24: key += '.' # pad the names to make the values line up somewhat
176 val = getattr(obj, k)()
178 subobj = val and not (isinstance(val,unicode) or \
179 isinstance(val, int) or isinstance(val, float) or isinstance(val, long))
182 s += __tabs(t) + key + ' = '
186 val = osrfDebugNetworkObject(val, t+1)
190 if not subobj: s += '\n'
193 s = osrfFormatJSON(osrfObjectToJSON(obj))
196 def osrfFormatJSON(json):
197 """JSON pretty-printer"""
207 if (c == '{' or c == '[') and not instring:
209 r += c + '\n' + __tabs(t)
212 if (c == '}' or c == ']') and not instring:
214 r += '\n' + __tabs(t) + c
217 if c == ',' and not instring:
218 r += c + '\n' + __tabs(t)
221 if c == '"' and not inescape:
222 instring = not instring