3 """Add representers to YAML to support Hooke.
5 Without introspection, YAML cannot decide how to save some
6 objects. By refusing to save these objects, we obviously loose
7 that information, so make sure the things you drop are either
8 stored somewhere else or not important.
11 >>> a = numpy.array([1,2,3])
12 >>> print yaml.dump(a)
17 The default behavior is to crash.
19 >>> yaml.Dumper.yaml_representers.pop(numpy.ndarray) # doctest: +ELLIPSIS
20 <function none_representer at 0x...>
21 >>> print yaml.dump(a)
22 !!python/object/apply:numpy.core.multiarray._reconstruct
24 - !!python/name:numpy.ndarray ''
32 - "\\x01\\0\\0\\0\\x02\\0\\0\\0\\x03\\0\\0\\0"
35 Hmm, at one point that crashed like this::
37 Traceback (most recent call last):
39 if data in [None, ()]:
40 TypeError: data type not understood
42 Must be because of the other representers I've loaded since.
44 Restore the representer for future tests.
46 >>> yaml.add_representer(numpy.ndarray, none_representer)
49 from __future__ import absolute_import
56 import yaml.constructor
57 import yaml.representer
59 from ..curve import Data, Curve
60 from ..playlist import FilePlaylist
63 if False: # YAML dump debugging code
64 """To help isolate data types etc. that give YAML problems.
66 This is usually caused by external C modules (e.g. numpy) that
67 define new types (e.g. numpy.ndarray) which YAML cannot inspect.
69 def ignore_aliases(data):
70 print data, repr(data), type(data), repr(type(data))
72 if data in [None, ()]:
74 if isinstance(data, (str, unicode, bool, int, float)):
76 yaml.representer.SafeRepresenter.ignore_aliases = staticmethod(
80 # numpy.dtype(numpy.int32) in [None, ()]
82 # http://projects.scipy.org/numpy/ticket/1001
83 def ignore_aliases(data):
85 if data in [None, ()]:
87 if isinstance(data, (str, unicode, bool, int, float)):
91 yaml.representer.SafeRepresenter.ignore_aliases = staticmethod(
95 def none_representer(dumper, data):
96 return dumper.represent_none(None)
97 yaml.add_representer(numpy.ndarray, none_representer)
98 yaml.add_representer(numpy.dtype, none_representer)
100 def bool_representer(dumper, data):
101 return dumper.represent_bool(data)
102 yaml.add_representer(numpy.bool_, bool_representer)
104 def int_representer(dumper, data):
105 return dumper.represent_int(data)
106 yaml.add_representer(numpy.int32, int_representer)
107 yaml.add_representer(numpy.dtype(numpy.int32), int_representer)
109 def long_representer(dumper, data):
110 return dumper.represent_long(data)
111 yaml.add_representer(numpy.int64, int_representer)
113 def float_representer(dumper, data):
114 return dumper.represent_float(data)
115 yaml.add_representer(numpy.float32, float_representer)
116 yaml.add_representer(numpy.float64, float_representer)
118 def data_representer(dumper, data):
119 info = dict(data.info)
120 for key in info.keys():
121 if key.startswith('raw '):
123 return dumper.represent_mapping(u'!hooke.curve.DataInfo', info)
124 yaml.add_representer(Data, data_representer)
126 def object_representer(dumper, data):
128 if cls in copy_reg.dispatch_table:
129 reduce = copy_reg.dispatch_table[cls](data)
130 elif hasattr(data, '__reduce_ex__'):
131 reduce = data.__reduce_ex__(2)
132 elif hasattr(data, '__reduce__'):
133 reduce = data.__reduce__()
135 raise RepresenterError("cannot represent object: %r" % data)
136 reduce = (list(reduce)+[None]*5)[:5]
137 function, args, state, listitems, dictitems = reduce
141 if isinstance(state, dict) and '_default_attrs' in state:
142 for key in state['_default_attrs']:
143 if key in state and state[key] == state['_default_attrs'][key]:
145 del(state['_default_attrs'])
146 if listitems is not None:
147 listitems = list(listitems)
148 if dictitems is not None:
149 dictitems = dict(dictitems)
150 if function.__name__ == '__newobj__':
153 tag = u'tag:yaml.org,2002:python/object/new:'
156 tag = u'tag:yaml.org,2002:python/object/apply:'
158 function_name = u'%s.%s' % (function.__module__, function.__name__)
159 if not args and not listitems and not dictitems \
160 and isinstance(state, dict) and newobj:
161 return dumper.represent_mapping(
162 u'tag:yaml.org,2002:python/object:'+function_name, state)
163 if not listitems and not dictitems \
164 and isinstance(state, dict) and not state:
165 return dumper.represent_sequence(tag+function_name, args)
169 if state or not isinstance(state, dict):
170 value['state'] = state
172 value['listitems'] = listitems
174 value['dictitems'] = dictitems
175 return dumper.represent_mapping(tag+function_name, value)
176 yaml.add_representer(FilePlaylist, object_representer)
177 yaml.add_representer(Curve, object_representer)
180 # Monkey patch PyYAML bug 159.
181 # Yaml failed to restore loops in objects when __setstate__ is defined
182 # http://pyyaml.org/ticket/159
183 # With viktor.x.voroshylo@jpmchase.com's patch
184 def construct_object(self, node, deep=False):
186 old_deep = self.deep_construct
187 self.deep_construct = True
188 if node in self.constructed_objects:
189 return self.constructed_objects[node]
190 if node in self.recursive_objects:
191 obj = self.recursive_objects[node]
193 raise ConstructorError(None, None,
194 "found unconstructable recursive node", node.start_mark)
196 self.recursive_objects[node] = None
199 if node.tag in self.yaml_constructors:
200 constructor = self.yaml_constructors[node.tag]
202 for tag_prefix in self.yaml_multi_constructors:
203 if node.tag.startswith(tag_prefix):
204 tag_suffix = node.tag[len(tag_prefix):]
205 constructor = self.yaml_multi_constructors[tag_prefix]
208 if None in self.yaml_multi_constructors:
209 tag_suffix = node.tag
210 constructor = self.yaml_multi_constructors[None]
211 elif None in self.yaml_constructors:
212 constructor = self.yaml_constructors[None]
213 elif isinstance(node, ScalarNode):
214 constructor = self.__class__.construct_scalar
215 elif isinstance(node, SequenceNode):
216 constructor = self.__class__.construct_sequence
217 elif isinstance(node, MappingNode):
218 constructor = self.__class__.construct_mapping
219 if tag_suffix is None:
220 data = constructor(self, node)
222 data = constructor(self, tag_suffix, node)
223 if isinstance(data, types.GeneratorType):
225 data = generator.next()
226 if self.deep_construct:
227 self.recursive_objects[node] = data
228 for dummy in generator:
231 self.state_generators.append(generator)
232 self.constructed_objects[node] = data
233 del self.recursive_objects[node]
235 self.deep_construct = old_deep
237 yaml.constructor.BaseConstructor.construct_object = construct_object