]> arthur.barton.de Git - netdata.git/blob - python.d/python_modules/pyyaml3/representer.py
bundle pyyaml
[netdata.git] / python.d / python_modules / pyyaml3 / representer.py
1
2 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
3     'RepresenterError']
4
5 from .error import *
6 from .nodes import *
7
8 import datetime, sys, copyreg, types, base64
9
10 class RepresenterError(YAMLError):
11     pass
12
13 class BaseRepresenter:
14
15     yaml_representers = {}
16     yaml_multi_representers = {}
17
18     def __init__(self, default_style=None, default_flow_style=None):
19         self.default_style = default_style
20         self.default_flow_style = default_flow_style
21         self.represented_objects = {}
22         self.object_keeper = []
23         self.alias_key = None
24
25     def represent(self, data):
26         node = self.represent_data(data)
27         self.serialize(node)
28         self.represented_objects = {}
29         self.object_keeper = []
30         self.alias_key = None
31
32     def represent_data(self, data):
33         if self.ignore_aliases(data):
34             self.alias_key = None
35         else:
36             self.alias_key = id(data)
37         if self.alias_key is not None:
38             if self.alias_key in self.represented_objects:
39                 node = self.represented_objects[self.alias_key]
40                 #if node is None:
41                 #    raise RepresenterError("recursive objects are not allowed: %r" % data)
42                 return node
43             #self.represented_objects[alias_key] = None
44             self.object_keeper.append(data)
45         data_types = type(data).__mro__
46         if data_types[0] in self.yaml_representers:
47             node = self.yaml_representers[data_types[0]](self, data)
48         else:
49             for data_type in data_types:
50                 if data_type in self.yaml_multi_representers:
51                     node = self.yaml_multi_representers[data_type](self, data)
52                     break
53             else:
54                 if None in self.yaml_multi_representers:
55                     node = self.yaml_multi_representers[None](self, data)
56                 elif None in self.yaml_representers:
57                     node = self.yaml_representers[None](self, data)
58                 else:
59                     node = ScalarNode(None, str(data))
60         #if alias_key is not None:
61         #    self.represented_objects[alias_key] = node
62         return node
63
64     @classmethod
65     def add_representer(cls, data_type, representer):
66         if not 'yaml_representers' in cls.__dict__:
67             cls.yaml_representers = cls.yaml_representers.copy()
68         cls.yaml_representers[data_type] = representer
69
70     @classmethod
71     def add_multi_representer(cls, data_type, representer):
72         if not 'yaml_multi_representers' in cls.__dict__:
73             cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
74         cls.yaml_multi_representers[data_type] = representer
75
76     def represent_scalar(self, tag, value, style=None):
77         if style is None:
78             style = self.default_style
79         node = ScalarNode(tag, value, style=style)
80         if self.alias_key is not None:
81             self.represented_objects[self.alias_key] = node
82         return node
83
84     def represent_sequence(self, tag, sequence, flow_style=None):
85         value = []
86         node = SequenceNode(tag, value, flow_style=flow_style)
87         if self.alias_key is not None:
88             self.represented_objects[self.alias_key] = node
89         best_style = True
90         for item in sequence:
91             node_item = self.represent_data(item)
92             if not (isinstance(node_item, ScalarNode) and not node_item.style):
93                 best_style = False
94             value.append(node_item)
95         if flow_style is None:
96             if self.default_flow_style is not None:
97                 node.flow_style = self.default_flow_style
98             else:
99                 node.flow_style = best_style
100         return node
101
102     def represent_mapping(self, tag, mapping, flow_style=None):
103         value = []
104         node = MappingNode(tag, value, flow_style=flow_style)
105         if self.alias_key is not None:
106             self.represented_objects[self.alias_key] = node
107         best_style = True
108         if hasattr(mapping, 'items'):
109             mapping = list(mapping.items())
110             try:
111                 mapping = sorted(mapping)
112             except TypeError:
113                 pass
114         for item_key, item_value in mapping:
115             node_key = self.represent_data(item_key)
116             node_value = self.represent_data(item_value)
117             if not (isinstance(node_key, ScalarNode) and not node_key.style):
118                 best_style = False
119             if not (isinstance(node_value, ScalarNode) and not node_value.style):
120                 best_style = False
121             value.append((node_key, node_value))
122         if flow_style is None:
123             if self.default_flow_style is not None:
124                 node.flow_style = self.default_flow_style
125             else:
126                 node.flow_style = best_style
127         return node
128
129     def ignore_aliases(self, data):
130         return False
131
132 class SafeRepresenter(BaseRepresenter):
133
134     def ignore_aliases(self, data):
135         if data in [None, ()]:
136             return True
137         if isinstance(data, (str, bytes, bool, int, float)):
138             return True
139
140     def represent_none(self, data):
141         return self.represent_scalar('tag:yaml.org,2002:null', 'null')
142
143     def represent_str(self, data):
144         return self.represent_scalar('tag:yaml.org,2002:str', data)
145
146     def represent_binary(self, data):
147         if hasattr(base64, 'encodebytes'):
148             data = base64.encodebytes(data).decode('ascii')
149         else:
150             data = base64.encodestring(data).decode('ascii')
151         return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|')
152
153     def represent_bool(self, data):
154         if data:
155             value = 'true'
156         else:
157             value = 'false'
158         return self.represent_scalar('tag:yaml.org,2002:bool', value)
159
160     def represent_int(self, data):
161         return self.represent_scalar('tag:yaml.org,2002:int', str(data))
162
163     inf_value = 1e300
164     while repr(inf_value) != repr(inf_value*inf_value):
165         inf_value *= inf_value
166
167     def represent_float(self, data):
168         if data != data or (data == 0.0 and data == 1.0):
169             value = '.nan'
170         elif data == self.inf_value:
171             value = '.inf'
172         elif data == -self.inf_value:
173             value = '-.inf'
174         else:
175             value = repr(data).lower()
176             # Note that in some cases `repr(data)` represents a float number
177             # without the decimal parts.  For instance:
178             #   >>> repr(1e17)
179             #   '1e17'
180             # Unfortunately, this is not a valid float representation according
181             # to the definition of the `!!float` tag.  We fix this by adding
182             # '.0' before the 'e' symbol.
183             if '.' not in value and 'e' in value:
184                 value = value.replace('e', '.0e', 1)
185         return self.represent_scalar('tag:yaml.org,2002:float', value)
186
187     def represent_list(self, data):
188         #pairs = (len(data) > 0 and isinstance(data, list))
189         #if pairs:
190         #    for item in data:
191         #        if not isinstance(item, tuple) or len(item) != 2:
192         #            pairs = False
193         #            break
194         #if not pairs:
195             return self.represent_sequence('tag:yaml.org,2002:seq', data)
196         #value = []
197         #for item_key, item_value in data:
198         #    value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
199         #        [(item_key, item_value)]))
200         #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
201
202     def represent_dict(self, data):
203         return self.represent_mapping('tag:yaml.org,2002:map', data)
204
205     def represent_set(self, data):
206         value = {}
207         for key in data:
208             value[key] = None
209         return self.represent_mapping('tag:yaml.org,2002:set', value)
210
211     def represent_date(self, data):
212         value = data.isoformat()
213         return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
214
215     def represent_datetime(self, data):
216         value = data.isoformat(' ')
217         return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
218
219     def represent_yaml_object(self, tag, data, cls, flow_style=None):
220         if hasattr(data, '__getstate__'):
221             state = data.__getstate__()
222         else:
223             state = data.__dict__.copy()
224         return self.represent_mapping(tag, state, flow_style=flow_style)
225
226     def represent_undefined(self, data):
227         raise RepresenterError("cannot represent an object: %s" % data)
228
229 SafeRepresenter.add_representer(type(None),
230         SafeRepresenter.represent_none)
231
232 SafeRepresenter.add_representer(str,
233         SafeRepresenter.represent_str)
234
235 SafeRepresenter.add_representer(bytes,
236         SafeRepresenter.represent_binary)
237
238 SafeRepresenter.add_representer(bool,
239         SafeRepresenter.represent_bool)
240
241 SafeRepresenter.add_representer(int,
242         SafeRepresenter.represent_int)
243
244 SafeRepresenter.add_representer(float,
245         SafeRepresenter.represent_float)
246
247 SafeRepresenter.add_representer(list,
248         SafeRepresenter.represent_list)
249
250 SafeRepresenter.add_representer(tuple,
251         SafeRepresenter.represent_list)
252
253 SafeRepresenter.add_representer(dict,
254         SafeRepresenter.represent_dict)
255
256 SafeRepresenter.add_representer(set,
257         SafeRepresenter.represent_set)
258
259 SafeRepresenter.add_representer(datetime.date,
260         SafeRepresenter.represent_date)
261
262 SafeRepresenter.add_representer(datetime.datetime,
263         SafeRepresenter.represent_datetime)
264
265 SafeRepresenter.add_representer(None,
266         SafeRepresenter.represent_undefined)
267
268 class Representer(SafeRepresenter):
269
270     def represent_complex(self, data):
271         if data.imag == 0.0:
272             data = '%r' % data.real
273         elif data.real == 0.0:
274             data = '%rj' % data.imag
275         elif data.imag > 0:
276             data = '%r+%rj' % (data.real, data.imag)
277         else:
278             data = '%r%rj' % (data.real, data.imag)
279         return self.represent_scalar('tag:yaml.org,2002:python/complex', data)
280
281     def represent_tuple(self, data):
282         return self.represent_sequence('tag:yaml.org,2002:python/tuple', data)
283
284     def represent_name(self, data):
285         name = '%s.%s' % (data.__module__, data.__name__)
286         return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '')
287
288     def represent_module(self, data):
289         return self.represent_scalar(
290                 'tag:yaml.org,2002:python/module:'+data.__name__, '')
291
292     def represent_object(self, data):
293         # We use __reduce__ API to save the data. data.__reduce__ returns
294         # a tuple of length 2-5:
295         #   (function, args, state, listitems, dictitems)
296
297         # For reconstructing, we calls function(*args), then set its state,
298         # listitems, and dictitems if they are not None.
299
300         # A special case is when function.__name__ == '__newobj__'. In this
301         # case we create the object with args[0].__new__(*args).
302
303         # Another special case is when __reduce__ returns a string - we don't
304         # support it.
305
306         # We produce a !!python/object, !!python/object/new or
307         # !!python/object/apply node.
308
309         cls = type(data)
310         if cls in copyreg.dispatch_table:
311             reduce = copyreg.dispatch_table[cls](data)
312         elif hasattr(data, '__reduce_ex__'):
313             reduce = data.__reduce_ex__(2)
314         elif hasattr(data, '__reduce__'):
315             reduce = data.__reduce__()
316         else:
317             raise RepresenterError("cannot represent object: %r" % data)
318         reduce = (list(reduce)+[None]*5)[:5]
319         function, args, state, listitems, dictitems = reduce
320         args = list(args)
321         if state is None:
322             state = {}
323         if listitems is not None:
324             listitems = list(listitems)
325         if dictitems is not None:
326             dictitems = dict(dictitems)
327         if function.__name__ == '__newobj__':
328             function = args[0]
329             args = args[1:]
330             tag = 'tag:yaml.org,2002:python/object/new:'
331             newobj = True
332         else:
333             tag = 'tag:yaml.org,2002:python/object/apply:'
334             newobj = False
335         function_name = '%s.%s' % (function.__module__, function.__name__)
336         if not args and not listitems and not dictitems \
337                 and isinstance(state, dict) and newobj:
338             return self.represent_mapping(
339                     'tag:yaml.org,2002:python/object:'+function_name, state)
340         if not listitems and not dictitems  \
341                 and isinstance(state, dict) and not state:
342             return self.represent_sequence(tag+function_name, args)
343         value = {}
344         if args:
345             value['args'] = args
346         if state or not isinstance(state, dict):
347             value['state'] = state
348         if listitems:
349             value['listitems'] = listitems
350         if dictitems:
351             value['dictitems'] = dictitems
352         return self.represent_mapping(tag+function_name, value)
353
354 Representer.add_representer(complex,
355         Representer.represent_complex)
356
357 Representer.add_representer(tuple,
358         Representer.represent_tuple)
359
360 Representer.add_representer(type,
361         Representer.represent_name)
362
363 Representer.add_representer(types.FunctionType,
364         Representer.represent_name)
365
366 Representer.add_representer(types.BuiltinFunctionType,
367         Representer.represent_name)
368
369 Representer.add_representer(types.ModuleType,
370         Representer.represent_module)
371
372 Representer.add_multi_representer(object,
373         Representer.represent_object)
374