source: pyyaml/trunk/lib/yaml/representer.py @ 143

Revision 143, 10.9 KB checked in by xi, 9 years ago (diff)

Fix bugs in emitter and representer.

Line 
1
2__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
3    'RepresenterError']
4
5from error import *
6from nodes import *
7
8try:
9    import datetime
10    datetime_available = True
11except ImportError:
12    datetime_available = False
13
14try:
15    set
16except NameError:
17    from sets import Set as set
18
19import sys
20
21class RepresenterError(YAMLError):
22    pass
23
24class BaseRepresenter:
25
26    yaml_representers = {}
27
28    def __init__(self):
29        self.represented_objects = {}
30
31    def represent(self, data):
32        node = self.represent_object(data)
33        self.serialize(node)
34        self.represented_objects = {}
35
36    class C: pass
37    c = C()
38    def f(): pass
39    classobj_type = type(C)
40    instance_type = type(c)
41    function_type = type(f)
42    builtin_function_type = type(abs)
43    module_type = type(sys)
44    del C, c, f
45
46    def get_classobj_bases(self, cls):
47        bases = [cls]
48        for base in cls.__bases__:
49            bases.extend(self.get_classobj_bases(base))
50        return bases
51
52    def represent_object(self, data):
53        if self.ignore_aliases(data):
54            alias_key = None
55        else:
56            alias_key = id(data)
57        if alias_key is not None:
58            if alias_key in self.represented_objects:
59                node = self.represented_objects[alias_key]
60                if node is None:
61                    raise RepresenterError("recursive objects are not allowed: %r" % data)
62                return node
63            self.represented_objects[alias_key] = None
64        data_types = type(data).__mro__
65        if type(data) is self.instance_type:
66            data_types = self.get_classobj_bases(data.__class__)+list(data_types)
67        for data_type in data_types:
68            if data_type in self.yaml_representers:
69                node = self.yaml_representers[data_type](self, data)
70                break
71        else:
72            if None in self.yaml_representers:
73                node = self.yaml_representers[None](self, data)
74            else:
75                node = ScalarNode(None, unicode(data))
76        if alias_key is not None:
77            self.represented_objects[alias_key] = node
78        return node
79
80    def add_representer(cls, data_type, representer):
81        if not 'yaml_representers' in cls.__dict__:
82            cls.yaml_representers = cls.yaml_representers.copy()
83        cls.yaml_representers[data_type] = representer
84    add_representer = classmethod(add_representer)
85
86    def represent_scalar(self, tag, value, style=None):
87        return ScalarNode(tag, value, style=style)
88
89    def represent_sequence(self, tag, sequence, flow_style=None):
90        value = []
91        for item in sequence:
92            value.append(self.represent_object(item))
93        return SequenceNode(tag, value, flow_style=flow_style)
94
95    def represent_mapping(self, tag, mapping, flow_style=None):
96        if hasattr(mapping, 'keys'):
97            value = {}
98            for item_key in mapping.keys():
99                item_value = mapping[item_key]
100                value[self.represent_object(item_key)] =    \
101                        self.represent_object(item_value)
102        else:
103            value = []
104            for item_key, item_value in mapping:
105                value.append((self.represent_object(item_key),
106                        self.represent_object(item_value)))
107        return MappingNode(tag, value, flow_style=flow_style)
108
109    def ignore_aliases(self, data):
110        return False
111
112class SafeRepresenter(BaseRepresenter):
113
114    def ignore_aliases(self, data):
115        if data in [None, ()]:
116            return True
117        if isinstance(data, (str, unicode, bool, int, float)):
118            return True
119
120    def represent_none(self, data):
121        return self.represent_scalar(u'tag:yaml.org,2002:null',
122                u'null')
123
124    def represent_str(self, data):
125        tag = None
126        style = None
127        try:
128            data = unicode(data, 'ascii')
129            tag = u'tag:yaml.org,2002:str'
130        except UnicodeDecodeError:
131            try:
132                data = unicode(data, 'utf-8')
133                tag = u'tag:yaml.org,2002:str'
134            except UnicodeDecodeError:
135                data = data.encode('base64')
136                tag = u'tag:yaml.org,2002:binary'
137                style = '|'
138        return self.represent_scalar(tag, data, style=style)
139
140    def represent_unicode(self, data):
141        return self.represent_scalar(u'tag:yaml.org,2002:str', data)
142
143    def represent_bool(self, data):
144        if data:
145            value = u'true'
146        else:
147            value = u'false'
148        return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
149
150    def represent_int(self, data):
151        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
152
153    def represent_long(self, data):
154        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
155
156    inf_value = 1e300000
157    nan_value = inf_value/inf_value
158
159    def represent_float(self, data):
160        if data == self.inf_value:
161            value = u'.inf'
162        elif data == -self.inf_value:
163            value = u'-.inf'
164        elif data == self.nan_value or data != data:
165            value = u'.nan'
166        else:
167            value = unicode(repr(data))
168        return self.represent_scalar(u'tag:yaml.org,2002:float', value)
169
170    def represent_list(self, data):
171        pairs = (len(data) > 0 and isinstance(data, list))
172        if pairs:
173            for item in data:
174                if not isinstance(item, tuple) or len(item) != 2:
175                    pairs = False
176                    break
177        if not pairs:
178            return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
179        value = []
180        for item_key, item_value in data:
181            value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
182                [(item_key, item_value)]))
183        return SequenceNode(u'tag:yaml.org,2002:pairs', value)
184
185    def represent_dict(self, data):
186        return self.represent_mapping(u'tag:yaml.org,2002:map', data)
187
188    def represent_set(self, data):
189        value = {}
190        for key in data:
191            value[key] = None
192        return self.represent_mapping(u'tag:yaml.org,2002:set', value)
193
194    def represent_date(self, data):
195        value = u'%04d-%02d-%02d' % (data.year, data.month, data.day)
196        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
197
198    def represent_datetime(self, data):
199        value = u'%04d-%02d-%02d %02d:%02d:%02d' \
200                % (data.year, data.month, data.day,
201                    data.hour, data.minute, data.second)
202        if data.microsecond:
203            value += u'.' + unicode(data.microsecond/1000000.0).split(u'.')[1]
204        if data.utcoffset():
205            value += unicode(data.utcoffset())
206        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
207
208    def represent_yaml_object(self, tag, data, cls, flow_style=None):
209        if hasattr(data, '__getstate__'):
210            state = data.__getstate__()
211        else:
212            state = data.__dict__.copy()
213        return self.represent_mapping(tag, state, flow_style=flow_style)
214
215    def represent_undefined(self, data):
216        raise RepresenterError("cannot represent an object: %s" % data)
217
218SafeRepresenter.add_representer(type(None),
219        SafeRepresenter.represent_none)
220
221SafeRepresenter.add_representer(str,
222        SafeRepresenter.represent_str)
223
224SafeRepresenter.add_representer(unicode,
225        SafeRepresenter.represent_unicode)
226
227SafeRepresenter.add_representer(bool,
228        SafeRepresenter.represent_bool)
229
230SafeRepresenter.add_representer(int,
231        SafeRepresenter.represent_int)
232
233SafeRepresenter.add_representer(long,
234        SafeRepresenter.represent_long)
235
236SafeRepresenter.add_representer(float,
237        SafeRepresenter.represent_float)
238
239SafeRepresenter.add_representer(list,
240        SafeRepresenter.represent_list)
241
242SafeRepresenter.add_representer(tuple,
243        SafeRepresenter.represent_list)
244
245SafeRepresenter.add_representer(dict,
246        SafeRepresenter.represent_dict)
247
248SafeRepresenter.add_representer(set,
249        SafeRepresenter.represent_set)
250
251if datetime_available:
252    SafeRepresenter.add_representer(datetime.date,
253            SafeRepresenter.represent_date)
254    SafeRepresenter.add_representer(datetime.datetime,
255            SafeRepresenter.represent_datetime)
256
257SafeRepresenter.add_representer(None,
258        SafeRepresenter.represent_undefined)
259
260class Representer(SafeRepresenter):
261   
262    def represent_str(self, data):
263        tag = None
264        style = None
265        try:
266            data = unicode(data, 'ascii')
267            tag = u'tag:yaml.org,2002:str'
268        except UnicodeDecodeError:
269            try:
270                data = unicode(data, 'utf-8')
271                tag = u'tag:yaml.org,2002:python/str'
272            except UnicodeDecodeError:
273                data = data.encode('base64')
274                tag = u'tag:yaml.org,2002:binary'
275                style = '|'
276        return self.represent_scalar(tag, data, style=style)
277
278    def represent_unicode(self, data):
279        tag = None
280        try:
281            data.encode('ascii')
282            tag = u'tag:yaml.org,2002:python/unicode'
283        except UnicodeEncodeError:
284            tag = u'tag:yaml.org,2002:str'
285        return self.represent_scalar(tag, data)
286
287    def represent_long(self, data):
288        tag = u'tag:yaml.org,2002:int'
289        if int(data) is not data:
290            tag = u'tag:yaml.org,2002:python/long'
291        return self.represent_scalar(tag, unicode(data))
292
293    def represent_complex(self, data):
294        if data.imag == 0.0:
295            data = u'%r' % data.real
296        elif data.real == 0.0:
297            data = u'%rj' % data.imag
298        elif data.imag > 0:
299            data = u'%r+%rj' % (data.real, data.imag)
300        else:
301            data = u'%r%rj' % (data.real, data.imag)
302        return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
303
304    def represent_tuple(self, data):
305        return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
306
307    def represent_name(self, data):
308        name = u'%s.%s' % (data.__module__, data.__name__)
309        return self.represent_scalar(u'tag:yaml.org,2002:python/name:'+name, u'')
310
311    def represent_module(self, data):
312        return self.represent_scalar(
313                u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
314
315Representer.add_representer(str,
316        Representer.represent_str)
317
318Representer.add_representer(unicode,
319        Representer.represent_unicode)
320
321Representer.add_representer(long,
322        Representer.represent_long)
323
324Representer.add_representer(complex,
325        Representer.represent_complex)
326
327Representer.add_representer(tuple,
328        Representer.represent_tuple)
329
330Representer.add_representer(type,
331        Representer.represent_name)
332
333Representer.add_representer(Representer.classobj_type,
334        Representer.represent_name)
335
336Representer.add_representer(Representer.function_type,
337        Representer.represent_name)
338
339Representer.add_representer(Representer.builtin_function_type,
340        Representer.represent_name)
341
342Representer.add_representer(Representer.module_type,
343        Representer.represent_module)
344
Note: See TracBrowser for help on using the repository browser.