| [25] | 1 | """ |
|---|
| 2 | syck.dumpers is a high-level wrapper for the Syck YAML emitter. |
|---|
| 3 | Do not use it directly, use the module 'syck' instead. |
|---|
| 4 | """ |
|---|
| [19] | 5 | |
|---|
| 6 | import _syck |
|---|
| 7 | |
|---|
| 8 | try: |
|---|
| 9 | import cStringIO as StringIO |
|---|
| 10 | except ImportError: |
|---|
| 11 | import StringIO |
|---|
| 12 | |
|---|
| 13 | __all__ = ['GenericDumper', 'Dumper', |
|---|
| 14 | 'emit', 'dump', 'emit_documents', 'dump_documents'] |
|---|
| 15 | |
|---|
| 16 | class 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] | 65 | class 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 | |
|---|
| 146 | def represent_sets_Set(self, object): |
|---|
| 147 | return _syck.Seq(list(object), tag="tag:yaml.org,2002:set") |
|---|
| [25] | 148 | represent_set = represent_sets_Set |
|---|
| [20] | 149 | |
|---|
| 150 | def represent_datetime_datetime(self, object): |
|---|
| 151 | return _syck.Scalar(object.isoformat(), tag="tag:yaml.org,2002:timestamp") |
|---|
| 152 | |
|---|
| [21] | 153 | def represent_long(self, object): |
|---|
| 154 | return _syck.Scalar(repr(object), tag="tag:python.yaml.org,2002:long") |
|---|
| 155 | |
|---|
| 156 | def represent_tuple(self, object): |
|---|
| 157 | return _syck.Seq(list(object), tag="tag:python.yaml.org,2002:tuple") |
|---|
| 158 | |
|---|
| 159 | def represent_type(self, object): |
|---|
| 160 | name = '%s.%s' % (object.__module__, object.__name__) |
|---|
| 161 | return _syck.Scalar('', tag="tag:python.yaml.org,2002:name:"+name) |
|---|
| 162 | represent_classobj = represent_type |
|---|
| [24] | 163 | represent_class = represent_type |
|---|
| [25] | 164 | # TODO: Python 2.2 does not provide the module name of a function |
|---|
| [21] | 165 | represent_function = represent_type |
|---|
| 166 | represent_builtin_function_or_method = represent_type |
|---|
| 167 | |
|---|
| 168 | def represent_instance(self, object): |
|---|
| 169 | cls = object.__class__ |
|---|
| 170 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 171 | args = () |
|---|
| 172 | state = {} |
|---|
| 173 | if hasattr(object, '__getinitargs__'): |
|---|
| 174 | args = object.__getinitargs__() |
|---|
| 175 | if hasattr(object, '__getstate__'): |
|---|
| 176 | state = object.__getstate__() |
|---|
| 177 | elif not hasattr(object, '__getinitargs__'): |
|---|
| 178 | state = object.__dict__.copy() |
|---|
| 179 | if not args and isinstance(state, dict): |
|---|
| 180 | return _syck.Map(state.copy(), |
|---|
| 181 | tag="tag:python.yaml.org,2002:object:"+class_name) |
|---|
| 182 | value = {} |
|---|
| 183 | if args: |
|---|
| 184 | value['args'] = list(args) |
|---|
| 185 | if state or not isinstance(state, dict): |
|---|
| 186 | value['state'] = state |
|---|
| 187 | return _syck.Map(value, |
|---|
| 188 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 189 | |
|---|
| 190 | def represent_object(self, object): # Do you understand this? I don't. |
|---|
| 191 | cls = type(object) |
|---|
| 192 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 193 | args = () |
|---|
| [24] | 194 | state = {} |
|---|
| [21] | 195 | if cls.__reduce__ is type.__reduce__: |
|---|
| 196 | if hasattr(object, '__reduce_ex__'): |
|---|
| 197 | reduce = object.__reduce_ex__(2) |
|---|
| 198 | args = reduce[1][1:] |
|---|
| 199 | else: |
|---|
| 200 | reduce = object.__reduce__() |
|---|
| 201 | if len(reduce) > 2: |
|---|
| 202 | state = reduce[2] |
|---|
| 203 | if state is None: |
|---|
| 204 | state = {} |
|---|
| 205 | if not args and isinstance(state, dict): |
|---|
| 206 | return _syck.Map(state.copy(), |
|---|
| 207 | tag="tag:python.yaml.org,2002:object:"+class_name) |
|---|
| 208 | if not state and isinstance(state, dict): |
|---|
| 209 | return _syck.Seq(list(args), |
|---|
| 210 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 211 | value = {} |
|---|
| 212 | if args: |
|---|
| 213 | value['args'] = list(args) |
|---|
| 214 | if state or not isinstance(state, dict): |
|---|
| 215 | value['state'] = state |
|---|
| 216 | return _syck.Map(value, |
|---|
| 217 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 218 | else: |
|---|
| 219 | reduce = object.__reduce__() |
|---|
| 220 | cls = reduce[0] |
|---|
| 221 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 222 | args = reduce[1] |
|---|
| 223 | state = None |
|---|
| 224 | if len(reduce) > 2: |
|---|
| 225 | state = reduce[2] |
|---|
| 226 | if state is None: |
|---|
| 227 | state = {} |
|---|
| 228 | if not state and isinstance(state, dict): |
|---|
| 229 | return _syck.Seq(list(args), |
|---|
| 230 | tag="tag:python.yaml.org,2002:apply:"+class_name) |
|---|
| 231 | value = {} |
|---|
| 232 | if args: |
|---|
| 233 | value['args'] = list(args) |
|---|
| 234 | if state or not isinstance(state, dict): |
|---|
| 235 | value['state'] = state |
|---|
| 236 | return _syck.Map(value, |
|---|
| 237 | tag="tag:python.yaml.org,2002:apply:"+class_name) |
|---|
| 238 | |
|---|
| [25] | 239 | def represent__syck_Node(self, object): |
|---|
| 240 | object_type = type(object) |
|---|
| 241 | type_name = '%s.%s' % (object_type.__module__, object_type.__name__) |
|---|
| 242 | state = [] |
|---|
| 243 | if hasattr(object_type, '__slotnames__'): |
|---|
| 244 | for name in object_type.__slotnames__: |
|---|
| 245 | value = getattr(object, name) |
|---|
| 246 | if value: |
|---|
| 247 | state.append((name, value)) |
|---|
| 248 | return _syck.Map(state, |
|---|
| 249 | tag="tag:python.yaml.org,2002:object:"+type_name) |
|---|
| 250 | |
|---|
| [20] | 251 | def allow_aliases(self, object): |
|---|
| [25] | 252 | """Checks whether the given object can be aliased.""" |
|---|
| [20] | 253 | if object is None or type(object) in [int, bool, float]: |
|---|
| 254 | return False |
|---|
| 255 | if type(object) is str and (not object or object.isalnum()): |
|---|
| 256 | return False |
|---|
| [21] | 257 | if type(object) is tuple and not object: |
|---|
| 258 | return False |
|---|
| [20] | 259 | return True |
|---|
| 260 | |
|---|
| [22] | 261 | def emit(node, output=None, Dumper=Dumper, **parameters): |
|---|
| [25] | 262 | """ |
|---|
| 263 | Emits the given node to the output. |
|---|
| 264 | |
|---|
| 265 | If output is None, returns the produced YAML document. |
|---|
| 266 | """ |
|---|
| [19] | 267 | if output is None: |
|---|
| 268 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 269 | else: |
|---|
| 270 | dumper = Dumper(output, **parameters) |
|---|
| 271 | dumper.emit(node) |
|---|
| 272 | if output is None: |
|---|
| 273 | return dumper.output.getvalue() |
|---|
| 274 | |
|---|
| [22] | 275 | def dump(object, output=None, Dumper=Dumper, **parameters): |
|---|
| [25] | 276 | """ |
|---|
| 277 | Dumps the given object to the output. |
|---|
| 278 | |
|---|
| 279 | If output is None, returns the produced YAML document. |
|---|
| 280 | """ |
|---|
| [19] | 281 | if output is None: |
|---|
| 282 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 283 | else: |
|---|
| 284 | dumper = Dumper(output, **parameters) |
|---|
| 285 | dumper.dump(object) |
|---|
| 286 | if output is None: |
|---|
| 287 | return dumper.output.getvalue() |
|---|
| 288 | |
|---|
| [22] | 289 | def emit_documents(nodes, output=None, Dumper=Dumper, **parameters): |
|---|
| [25] | 290 | """ |
|---|
| 291 | Emits the list of nodes to the output. |
|---|
| 292 | |
|---|
| 293 | If output is None, returns the produced YAML document. |
|---|
| 294 | """ |
|---|
| [19] | 295 | if output is None: |
|---|
| 296 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 297 | else: |
|---|
| 298 | dumper = Dumper(output, **parameters) |
|---|
| 299 | for node in nodes: |
|---|
| 300 | dumper.emit(node) |
|---|
| 301 | if output is None: |
|---|
| 302 | return dumper.output.getvalue() |
|---|
| 303 | |
|---|
| [22] | 304 | def dump_documents(objects, output=None, Dumper=Dumper, **parameters): |
|---|
| [25] | 305 | """ |
|---|
| 306 | Dumps the list of objects to the output. |
|---|
| 307 | |
|---|
| 308 | If output is None, returns the produced YAML document. |
|---|
| 309 | """ |
|---|
| [19] | 310 | if output is None: |
|---|
| 311 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 312 | else: |
|---|
| 313 | dumper = Dumper(output, **parameters) |
|---|
| 314 | for object in objects: |
|---|
| 315 | dumper.dump(object) |
|---|
| 316 | if output is None: |
|---|
| 317 | return dumper.output.getvalue() |
|---|
| 318 | |
|---|
| 319 | |
|---|