Add constructors for some simple python types.
[pyyaml/python3.git] / lib / yaml / representer.py
blob797d86513483b8f543fd90a790f0674f6db60462
2 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
3 'RepresenterError']
5 from error import *
6 from nodes import *
8 try:
9 import datetime
10 datetime_available = True
11 except ImportError:
12 datetime_available = False
14 try:
15 set
16 except NameError:
17 from sets import Set as set
19 import sys
21 class RepresenterError(YAMLError):
22 pass
24 class BaseRepresenter:
26 yaml_representers = {}
28 def __init__(self):
29 self.represented_objects = {}
31 def represent(self, data):
32 node = self.represent_object(data)
33 self.serialize(node)
34 self.represented_objects = {}
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
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
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__)+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
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)
86 def represent_scalar(self, tag, value, style=None):
87 return ScalarNode(tag, value, style=style)
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)
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)
109 def ignore_aliases(self, data):
110 return False
112 class SafeRepresenter(BaseRepresenter):
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
120 def represent_none(self, data):
121 return self.represent_scalar(u'tag:yaml.org,2002:null',
122 u'null')
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)
140 def represent_unicode(self, data):
141 return self.represent_scalar(u'tag:yaml.org,2002:str', data)
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)
150 def represent_int(self, data):
151 return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
153 def represent_long(self, data):
154 return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
156 inf_value = 1e300000
157 nan_value = inf_value/inf_value
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)
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)
185 def represent_dict(self, data):
186 return self.represent_mapping(u'tag:yaml.org,2002:map', data)
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)
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)
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)
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)
215 def represent_undefined(self, data):
216 raise RepresenterError("cannot represent an object: %s" % data)
218 SafeRepresenter.add_representer(type(None),
219 SafeRepresenter.represent_none)
221 SafeRepresenter.add_representer(str,
222 SafeRepresenter.represent_str)
224 SafeRepresenter.add_representer(unicode,
225 SafeRepresenter.represent_unicode)
227 SafeRepresenter.add_representer(bool,
228 SafeRepresenter.represent_bool)
230 SafeRepresenter.add_representer(int,
231 SafeRepresenter.represent_int)
233 SafeRepresenter.add_representer(long,
234 SafeRepresenter.represent_long)
236 SafeRepresenter.add_representer(float,
237 SafeRepresenter.represent_float)
239 SafeRepresenter.add_representer(list,
240 SafeRepresenter.represent_list)
242 SafeRepresenter.add_representer(tuple,
243 SafeRepresenter.represent_list)
245 SafeRepresenter.add_representer(dict,
246 SafeRepresenter.represent_dict)
248 SafeRepresenter.add_representer(set,
249 SafeRepresenter.represent_set)
251 if datetime_available:
252 SafeRepresenter.add_representer(datetime.date,
253 SafeRepresenter.represent_date)
254 SafeRepresenter.add_representer(datetime.datetime,
255 SafeRepresenter.represent_datetime)
257 SafeRepresenter.add_representer(None,
258 SafeRepresenter.represent_undefined)
260 class Representer(SafeRepresenter):
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)
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)
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))
293 def represent_complex(self, data):
294 if data.real != 0.0:
295 data = u'%r+%rj' % (data.real, data.imag)
296 else:
297 data = u'%rj' % data.imag
298 return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
300 def represent_tuple(self, data):
301 return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
303 def represent_name(self, data):
304 name = u'%s.%s' % (data.__module__, data.__name__)
305 return self.represent_scalar(u'tag:yaml.org,2002:python/name:'+name, u'')
307 def represent_module(self, data):
308 return self.represent_scalar(
309 u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
311 Representer.add_representer(str,
312 Representer.represent_str)
314 Representer.add_representer(unicode,
315 Representer.represent_unicode)
317 Representer.add_representer(long,
318 Representer.represent_long)
320 Representer.add_representer(complex,
321 Representer.represent_complex)
323 Representer.add_representer(tuple,
324 Representer.represent_tuple)
326 Representer.add_representer(type,
327 Representer.represent_name)
329 Representer.add_representer(Representer.classobj_type,
330 Representer.represent_name)
332 Representer.add_representer(Representer.function_type,
333 Representer.represent_name)
335 Representer.add_representer(Representer.builtin_function_type,
336 Representer.represent_name)
338 Representer.add_representer(Representer.module_type,
339 Representer.represent_module)