source: trunk/lib/syck/dumpers.py @ 49

Revision 49, 11.9 KB checked in by xi, 9 years ago (diff)

Fix segfault under Python2.3.

Support for complex numbers.

Add /usr/local to the search path.

RevLine 
[25]1"""
2syck.dumpers is a high-level wrapper for the Syck YAML emitter.
3Do not use it directly, use the module 'syck' instead.
4"""
[19]5
6import _syck
7
8try:
9    import cStringIO as StringIO
10except ImportError:
11    import StringIO
12
13__all__ = ['GenericDumper', 'Dumper',
14    'emit', 'dump', 'emit_documents', 'dump_documents']
15
16class GenericDumper(_syck.Emitter):
[25]17    """
18    GenericDumper dumps native Python objects into YAML documents.
19    """
[19]20
21    def dump(self, object):
[25]22        """Dumps the given Python object as a YAML document."""
[19]23        self.emit(self._convert(object, {}))
24
25    def _convert(self, object, object_to_node):
[20]26        if id(object) in object_to_node and self.allow_aliases(object):
[21]27            return object_to_node[id(object)][1]
[19]28        node = self.represent(object)
[21]29        object_to_node[id(object)] = object, node
[19]30        if node.kind == 'seq':
[23]31            for index in range(len(node.value)):
32                item = node.value[index]
[19]33                node.value[index] = self._convert(item, object_to_node)
34        elif node.kind == 'map':
[25]35            if isinstance(node.value, dict):
36                for key in node.value.keys():
37                    value = node.value[key]
38                    del node.value[key]
39                    node.value[self._convert(key, object_to_node)] =    \
40                            self._convert(value, object_to_node)
41            elif isinstance(node.value, list):
42                for index in range(len(node.value)):
43                    key, value = node.value[index]
44                    node.value[index] = (self._convert(key, object_to_node),
45                            self._convert(value, object_to_node))
[20]46#        # Workaround against a Syck bug:
47#        if node.kind == 'scalar' and node.style not in ['1quote', '2quote'] \
48#                and node.value and node.value[-1] in [' ', '\t']:
49#            node.style = '2quote'
[19]50        return node
51
52    def represent(self, object):
[25]53        """Represents the given Python object as a 'Node'."""
[19]54        if isinstance(object, dict):
55            return _syck.Map(object.copy(), tag="tag:yaml.org,2002:map")
56        elif isinstance(object, list):
57            return _syck.Seq(object[:], tag="tag:yaml.org,2002:seq")
58        else:
59            return _syck.Scalar(str(object), tag="tag:yaml.org,2002:str")
60
[20]61    def allow_aliases(self, object):
[25]62        """Checks whether the given object can be aliased."""
[20]63        return True
64
[19]65class Dumper(GenericDumper):
[25]66    """
67    Dumper dumps native Python objects into YAML documents.
68    """
[19]69
[25]70    INF = 1e300000
71    inf_value = repr(INF)
72    neginf_value = repr(-INF)
73    nan_value = repr(INF/INF)
[20]74
[21]75    def find_representer(self, object):
[25]76        """
77        For the given object, find a method that can represent it as a 'Node'
78        object.
79
80        If the type of the object has the form 'package.module.type',
81        find_representer() returns the method 'represent_package_module_type'.
82        If this method does not exist, it checks the base types.
83        """
[20]84        for object_type in type(object).__mro__:
85            if object_type.__module__ == '__builtin__':
86                name = object_type.__name__
87            else:
88                name = '%s.%s' % (object_type.__module__, object_type.__name__)
[21]89            method = 'represent_' + name.replace('.', '_')
[20]90            if hasattr(self, method):
[21]91                return getattr(self, method)
[19]92
[21]93    def represent(self, object):
[25]94        """Represents the given Python object as a 'Node'."""
[21]95        representer = self.find_representer(object)
96        if representer:
97            return representer(object)
98        else:
99            return super(Dumper, self).represent(object)
100
[20]101    def represent_object(self, object):
102        return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:str")
103
104    def represent_NoneType(self, object):
105        return _syck.Scalar('~', tag="tag:yaml.org,2002:null")
106
107    def represent_bool(self, object):
108        return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:bool")
109
110    def represent_str(self, object):
[36]111        try:
112            return _syck.Scalar(object.encode('ascii'), tag="tag:yaml.org,2002:str")
113        except UnicodeDecodeError:
114            try:
115                return _syck.Scalar(unicode(object, 'utf-8').encode('utf-8'),
116                        tag="tag:python.yaml.org,2002:str")
117            except UnicodeDecodeError:
118                return _syck.Scalar(object.encode('base64'),
119                        tag="tag:yaml.org,2002:binary")
[20]120
[36]121    def represent_unicode(self, object):
122        try:
123            return _syck.Scalar(object.encode('ascii'), tag="tag:python.yaml.org,2002:unicode")
124        except UnicodeEncodeError:
125            return _syck.Scalar(object.encode('utf-8'), tag="tag:yaml.org,2002:str")
126
[20]127    def represent_list(self, object):
128        return _syck.Seq(object[:], tag="tag:yaml.org,2002:seq")
129
130    def represent_dict(self, object):
131        return _syck.Map(object.copy(), tag="tag:yaml.org,2002:map")
132
133    def represent_int(self, object):
134        return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:int")
135
136    def represent_float(self, object):
137        value = repr(object)
[25]138        if value == self.inf_value:
[20]139            value = '.inf'
[25]140        elif value == self.neginf_value:
[20]141            value = '-.inf'
[25]142        elif value == self.nan_value:
[20]143            value = '.nan'
144        return _syck.Scalar(value, tag="tag:yaml.org,2002:float")
145
[49]146    def represent_complex(self, object):
147        if object.real != 0.0:
148            value = '%s+%sj' % (repr(object.real), repr(object.imag))
149        else:
150            value = '%sj' % repr(object.imag)
151        return _syck.Scalar(value, tag="tag:python.yaml.org,2002:complex")
152
[20]153    def represent_sets_Set(self, object):
154        return _syck.Seq(list(object), tag="tag:yaml.org,2002:set")
[25]155    represent_set = represent_sets_Set
[20]156
157    def represent_datetime_datetime(self, object):
158        return _syck.Scalar(object.isoformat(), tag="tag:yaml.org,2002:timestamp")
159
[21]160    def represent_long(self, object):
161        return _syck.Scalar(repr(object), tag="tag:python.yaml.org,2002:long")
162
163    def represent_tuple(self, object):
164        return _syck.Seq(list(object), tag="tag:python.yaml.org,2002:tuple")
165
166    def represent_type(self, object):
167        name = '%s.%s' % (object.__module__, object.__name__)
168        return _syck.Scalar('', tag="tag:python.yaml.org,2002:name:"+name)
169    represent_classobj = represent_type
[24]170    represent_class = represent_type
[25]171    # TODO: Python 2.2 does not provide the module name of a function
[21]172    represent_function = represent_type
173    represent_builtin_function_or_method = represent_type
174
[49]175    def represent_module(self, object):
176        return _syck.Scalar('', tag="tag:python.yaml.org,2002:module:"+object.__name__)
177
[21]178    def represent_instance(self, object):
179        cls = object.__class__
180        class_name = '%s.%s' % (cls.__module__, cls.__name__)
181        args = ()
182        state = {}
183        if hasattr(object, '__getinitargs__'):
184            args = object.__getinitargs__()
185        if hasattr(object, '__getstate__'):
186            state = object.__getstate__()
187        elif not hasattr(object, '__getinitargs__'):
188            state = object.__dict__.copy()
189        if not args and isinstance(state, dict):
190            return _syck.Map(state.copy(),
191                    tag="tag:python.yaml.org,2002:object:"+class_name)
192        value = {}
193        if args:
194            value['args'] = list(args)
195        if state or not isinstance(state, dict):
196            value['state'] = state
197        return _syck.Map(value,
198                tag="tag:python.yaml.org,2002:new:"+class_name)
199
200    def represent_object(self, object): # Do you understand this? I don't.
201        cls = type(object)
202        class_name = '%s.%s' % (cls.__module__, cls.__name__)
203        args = ()
[24]204        state = {}
[21]205        if cls.__reduce__ is type.__reduce__:
206            if hasattr(object, '__reduce_ex__'):
207                reduce = object.__reduce_ex__(2)
208                args = reduce[1][1:]
209            else:
210                reduce = object.__reduce__()
211            if len(reduce) > 2:
212                state = reduce[2]
213            if state is None:
214                state = {}
215            if not args and isinstance(state, dict):
216                return _syck.Map(state.copy(),
217                        tag="tag:python.yaml.org,2002:object:"+class_name)
218            if not state and isinstance(state, dict):
219                return _syck.Seq(list(args),
220                        tag="tag:python.yaml.org,2002:new:"+class_name)
221            value = {}
222            if args:
223                value['args'] = list(args)
224            if state or not isinstance(state, dict):
225                value['state'] = state
226            return _syck.Map(value,
227                    tag="tag:python.yaml.org,2002:new:"+class_name)
228        else:
229            reduce = object.__reduce__()
230            cls = reduce[0]
231            class_name = '%s.%s' % (cls.__module__, cls.__name__)
232            args = reduce[1]
233            state = None
234            if len(reduce) > 2:
235                state = reduce[2]
236            if state is None:
237                state = {}
238            if not state and isinstance(state, dict):
239                return _syck.Seq(list(args),
240                        tag="tag:python.yaml.org,2002:apply:"+class_name)
241            value = {}
242            if args:
243                value['args'] = list(args)
244            if state or not isinstance(state, dict):
245                value['state'] = state
246            return _syck.Map(value,
247                    tag="tag:python.yaml.org,2002:apply:"+class_name)
248
[25]249    def represent__syck_Node(self, object):
250        object_type = type(object)
251        type_name = '%s.%s' % (object_type.__module__, object_type.__name__)
252        state = []
253        if hasattr(object_type, '__slotnames__'):
254            for name in object_type.__slotnames__:
255                value = getattr(object, name)
256                if value:
257                    state.append((name, value))
258        return _syck.Map(state,
259                tag="tag:python.yaml.org,2002:object:"+type_name)
260
[20]261    def allow_aliases(self, object):
[25]262        """Checks whether the given object can be aliased."""
[20]263        if object is None or type(object) in [int, bool, float]:
264            return False
265        if type(object) is str and (not object or object.isalnum()):
266            return False
[21]267        if type(object) is tuple and not object:
268            return False
[20]269        return True
270
[22]271def emit(node, output=None, Dumper=Dumper, **parameters):
[25]272    """
273    Emits the given node to the output.
274
275    If output is None, returns the produced YAML document.
276    """
[19]277    if output is None:
278        dumper = Dumper(StringIO.StringIO(), **parameters)
279    else:
280        dumper = Dumper(output, **parameters)
281    dumper.emit(node)
282    if output is None:
283        return dumper.output.getvalue()
284
[22]285def dump(object, output=None, Dumper=Dumper, **parameters):
[25]286    """
287    Dumps the given object to the output.
288
289    If output is None, returns the produced YAML document.
290    """
[19]291    if output is None:
292        dumper = Dumper(StringIO.StringIO(), **parameters)
293    else:
294        dumper = Dumper(output, **parameters)
295    dumper.dump(object)
296    if output is None:
297        return dumper.output.getvalue()
298
[22]299def emit_documents(nodes, output=None, Dumper=Dumper, **parameters):
[25]300    """
301    Emits the list of nodes to the output.
302   
303    If output is None, returns the produced YAML document.
304    """
[19]305    if output is None:
306        dumper = Dumper(StringIO.StringIO(), **parameters)
307    else:
308        dumper = Dumper(output, **parameters)
309    for node in nodes:
310        dumper.emit(node)
311    if output is None:
312        return dumper.output.getvalue()
313
[22]314def dump_documents(objects, output=None, Dumper=Dumper, **parameters):
[25]315    """
316    Dumps the list of objects to the output.
317   
318    If output is None, returns the produced YAML document.
319    """
[19]320    if output is None:
321        dumper = Dumper(StringIO.StringIO(), **parameters)
322    else:
323        dumper = Dumper(output, **parameters)
324    for object in objects:
325        dumper.dump(object)
326    if output is None:
327        return dumper.output.getvalue()
328
329
Note: See TracBrowser for help on using the repository browser.