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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/MolesManager/trunk/cedaMoles/MolesManager/djencoder.py
Revision 8612, 5.0 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        try:
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        except Exception as e:
112            DJEncoder.log.error(e)
113               
114       
115
116def methodsWithDecorator(cls, decoratorName):
117    #if type(cls).__name__ == 'type' or type(cls).__name__ == 'instancemetho':
118    #    return
119    sourcelines = inspect.getsourcelines(cls)[0]
120    for i,line in enumerate(sourcelines):
121        line = line.strip()
122        if line.split('(')[0].strip() == '@'+decoratorName: # leaving a bit out
123            nextLine = sourcelines[i+1]
124            name = nextLine.split('def')[1].split('(')[0].strip()
125            yield(name)
126
127def encodeToJSON(toEncode):
128    return DJEncoder().encode(toEncode)   
129   
130def escapeForJSON(toEscape):
131    res = toEscape.replace('"', '"')
132    res = res.replace("'", "'")       
133    #res = res.replace("'", "'")
134    res = res.replace('\\', '\\')
135    #res = res.replace('(', '(')       
136    #res = res.replace(')', ')')               
137    return res     
138
139def isPrimitive(obj):
140    # Is a simple primitive?
141    return obj is None \
142            or isinstance(obj, str) \
143            or isinstance(obj, int) \
144            or isinstance(obj, unicode) \
145            or isinstance(obj, Decimal)   
Note: See TracBrowser for help on using the repository browser.