source: mauRepo/MolesManager/trunk/cedaMoles/MolesManager/djencoder.py @ 8611

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/MolesManager/trunk/cedaMoles/MolesManager/djencoder.py@8611
Revision 8611, 4.9 KB checked in by mnagni, 7 years ago (diff)

djencoder fix for Windows machines

Line 
1'''
2Created on 9 Feb 2012
3
4@author: mnagni
5'''
6from json.encoder import JSONEncoder
7import logging
8import inspect
9import datetime
10import re
11import os
12from decimal import Decimal
13from sqlalchemy.orm.collections import InstrumentedList
14from cedaMoles.MolesManager.djencoder_patch import encode_basestring_ascii
15
16class DJEncoder(JSONEncoder):
17    __PATTERN = re.compile('\D\D__*')
18    __PATTERN2 = re.compile('\A\w+__id\Z')
19    log = logging.getLogger('DJEncoder')
20
21    def __init__(self):
22        self.__markers = {}
23        super(DJEncoder, self).__init__() 
24
25    def default(self, obj):
26        mydict = {}
27
28        if isinstance(obj, datetime.datetime):
29            # wanted a simple yield str(o) in the next line,
30            # but that would mean a yield on the line with super(...),
31            # which wouldn't work (see my comment below), so...
32            return str(obj)
33       
34        if isinstance(obj, Decimal):
35            # wanted a simple yield str(o) in the next line,
36            # but that would mean a yield on the line with super(...),
37            # which wouldn't work (see my comment below), so...
38            return str(obj) 
39
40        # Convert objects to a dictionary of their representation
41        try:
42            mydict = { '__module__':obj.__module__,
43                 }
44        except Exception as e:
45            return mydict
46        if obj.__class__.__name__ == 'EnumSymbol':
47            mydict['__class__'] = obj._cls.__name__
48        else:
49            mydict['__class__'] = obj.__class__.__name__
50           
51        if mydict['__module__'].startswith('sqlalchemy'):
52            return mydict
53 
54        for key in obj.__dict__.keys():
55            if not (key.startswith("_") \
56                    or DJEncoder.__PATTERN.match(key) \
57                    or DJEncoder.__PATTERN2.match(key)):
58                mydict.update({key: getattr(obj, key)})
59        getters = list(methodsWithDecorator(type(obj), "property"))
60        for name in getters:
61            if hasattr(obj, name):
62                try:
63                    mydict.update({name: getattr(obj, name)})
64                except Exception as e:
65                    DJEncoder.log.error(e)
66       
67        for key, value in mydict.items():   
68            if value is not None:
69                if (isinstance(value, list) \
70                    or isinstance(value, InstrumentedList)) \
71                        and not isPrimitive(value):
72                    for item in value:
73                        if id(item) in getattr(self, '_DJEncoder__markers'):
74                            mydict.pop(key)
75                            break
76                elif id(value) in getattr(self, '_DJEncoder__markers'):
77                    mydict.pop(key)
78        return mydict
79
80    def iterencode(self, o, _one_shot=True):
81        """Encode the given object and yield each string representation as
82        available. The third parameter, '_one_shot' is required for compatibility with
83        the the windows JSONEncoder implementation.
84
85        For example::
86
87            for chunk in JSONEncoder().iterencode(bigobject):
88                mysocket.write(chunk)
89
90        """
91        if self.check_circular and hasattr(self, '_DJEncoder__markers'):
92            markers = getattr(self, '_DJEncoder__markers')
93        else:
94            markers = None
95
96        #Guarantee that works in linux           
97        if os.name != 'nt':
98            return self._iterencode(o, markers)
99
100
101        #Guarantee that works in windows                 
102        if self.ensure_ascii:
103                _encoder = encode_basestring_ascii
104        else:
105            _encoder = encode_basestring_ascii
106        if self.encoding != 'utf-8':
107            def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
108                if isinstance(o, str):
109                    o = o.decode(_encoding)
110                return _orig_encoder(o)
111               
112       
113
114def methodsWithDecorator(cls, decoratorName):
115    #if type(cls).__name__ == 'type' or type(cls).__name__ == 'instancemetho':
116    #    return
117    sourcelines = inspect.getsourcelines(cls)[0]
118    for i,line in enumerate(sourcelines):
119        line = line.strip()
120        if line.split('(')[0].strip() == '@'+decoratorName: # leaving a bit out
121            nextLine = sourcelines[i+1]
122            name = nextLine.split('def')[1].split('(')[0].strip()
123            yield(name)
124
125def encodeToJSON(toEncode):
126    return DJEncoder().encode(toEncode)   
127   
128def escapeForJSON(toEscape):
129    res = toEscape.replace('"', '"')
130    res = res.replace("'", "'")       
131    #res = res.replace("'", "'")
132    res = res.replace('\\', '\\')
133    #res = res.replace('(', '(')       
134    #res = res.replace(')', ')')               
135    return res     
136
137def isPrimitive(obj):
138    # Is a simple primitive?
139    return obj is None \
140            or isinstance(obj, str) \
141            or isinstance(obj, int) \
142            or isinstance(obj, unicode) \
143            or isinstance(obj, Decimal)   
Note: See TracBrowser for help on using the repository browser.