d0a47640041c08cdbbfa17ca7a35a4001ecc6414
[OpenSRF.git] / src / python / osrf / json.py
1 import simplejson, types 
2 from osrf.net_obj import NetworkObject, parse_net_object
3 from osrf.const import OSRF_JSON_PAYLOAD_KEY, OSRF_JSON_CLASS_KEY
4 import osrf.log
5
6 class NetworkEncoder(simplejson.JSONEncoder):
7     def default(self, obj):
8
9         if isinstance(obj, NetworkObject):
10             reg = obj.get_registry()
11             data = obj.get_data()
12
13             # re-encode the object as an array if necessary
14             if reg.protocol == 'array':
15                 objarray = []
16                 for key in reg.keys:
17                     objarray.append(data.get(key)) 
18                 data = objarray
19
20             return { 
21                 OSRF_JSON_CLASS_KEY: reg.hint,
22                 OSRF_JSON_PAYLOAD_KEY: self.default(data)
23             }   
24         return obj
25
26
27 def to_json(obj):
28     """Turns a python object into a wrapped JSON object"""
29     return simplejson.dumps(obj, cls=NetworkEncoder)
30
31
32 def to_object(json):
33     """Turns a JSON string into python objects"""
34     obj = simplejson.loads(json)
35     return parse_net_object(obj)
36
37 def parse_json_raw(json):
38     """Parses JSON the old fashioned way."""
39     return simplejson.loads(json)
40
41 def to_json_raw(obj):
42     """Stringifies an object as JSON with no additional logic."""
43     return simplejson.dumps(obj)
44
45 def __tabs(depth):
46     space = ''
47     for i in range(depth):
48         space += '   '
49     return space
50
51 def debug_net_object(obj, depth=1):
52     """Returns a debug string for a given object.
53
54     If it's an NetworkObject and has registered keys, key/value pairs
55     are returned.  Otherwise formatted JSON is returned"""
56
57     debug_str = ''
58     if isinstance(obj, NetworkObject):
59         osrf.log.log_internal("Returning key/value pairs for NetworkObject")
60         reg = obj.get_registry()
61         keys = list(reg.keys) # clone it, so sorting won't break the original
62         keys.sort()
63
64         for k in keys:
65
66             key = str(k)
67             while len(key) < 24:
68                 key += '.' # pad the names to make the values line up somewhat
69             val = getattr(obj, k)()
70
71             subobj = val and not (isinstance(val, unicode) or \
72                 isinstance(val, int) or isinstance(val, float) or isinstance(val, long))
73
74             debug_str += __tabs(depth) + key + ' = '
75
76             if subobj:
77                 osrf.log.log_internal("Returning key/value pairs for subobject")
78                 debug_str += '\n'
79                 val = debug_net_object(val, depth+1)
80
81             debug_str += str(val)
82
83             if not subobj: debug_str += '\n'
84
85     else:
86         osrf.log.log_internal("Pretty-printing NetworkObject")
87         debug_str = pprint(to_json(obj))
88     return debug_str
89
90 def pprint(json):
91     """JSON pretty-printer"""
92     r = ''
93     t = 0
94     instring = False
95     inescape = False
96     done = False
97     eatws = False
98
99     for c in json:
100
101         if eatws: # simpljson adds a pesky space after array and object items
102             if c == ' ': 
103                 continue
104
105         eatws = False
106         done = False
107         if (c == '{' or c == '[') and not instring:
108             t += 1
109             r += c + '\n' + __tabs(t)
110             done = True
111
112         if (c == '}' or c == ']') and not instring:
113             t -= 1
114             r += '\n' + __tabs(t) + c
115             done = True
116
117         if c == ',' and not instring:
118             r += c + '\n' + __tabs(t)
119             done = True
120             eatws = True
121
122         if c == ':' and not instring:
123             eatws = True
124
125         if c == '"' and not inescape:
126             instring = not instring
127
128         if inescape: 
129             inescape = False
130
131         if c == '\\':
132             inescape = True
133
134         if not done:
135             r += c
136
137     return r