| 1 | |
|---|
| 2 | import _syck |
|---|
| 3 | |
|---|
| 4 | try: |
|---|
| 5 | import cStringIO as StringIO |
|---|
| 6 | except ImportError: |
|---|
| 7 | import StringIO |
|---|
| 8 | |
|---|
| 9 | __all__ = ['GenericDumper', 'Dumper', |
|---|
| 10 | 'emit', 'dump', 'emit_documents', 'dump_documents'] |
|---|
| 11 | |
|---|
| 12 | INF = 1e300000 |
|---|
| 13 | NEGINF = -INF |
|---|
| 14 | NAN = INF/INF |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | class GenericDumper(_syck.Emitter): |
|---|
| 18 | |
|---|
| 19 | def dump(self, object): |
|---|
| 20 | self.emit(self._convert(object, {})) |
|---|
| 21 | |
|---|
| 22 | def _convert(self, object, object_to_node): |
|---|
| 23 | if id(object) in object_to_node and self.allow_aliases(object): |
|---|
| 24 | return object_to_node[id(object)][1] |
|---|
| 25 | node = self.represent(object) |
|---|
| 26 | object_to_node[id(object)] = object, node |
|---|
| 27 | if node.kind == 'seq': |
|---|
| 28 | for index in range(len(node.value)): |
|---|
| 29 | item = node.value[index] |
|---|
| 30 | node.value[index] = self._convert(item, object_to_node) |
|---|
| 31 | elif node.kind == 'map': |
|---|
| 32 | for key in node.value.keys(): |
|---|
| 33 | value = node.value[key] |
|---|
| 34 | del node.value[key] |
|---|
| 35 | node.value[self._convert(key, object_to_node)] = \ |
|---|
| 36 | self._convert(value, object_to_node) |
|---|
| 37 | # # Workaround against a Syck bug: |
|---|
| 38 | # if node.kind == 'scalar' and node.style not in ['1quote', '2quote'] \ |
|---|
| 39 | # and node.value and node.value[-1] in [' ', '\t']: |
|---|
| 40 | # node.style = '2quote' |
|---|
| 41 | return node |
|---|
| 42 | |
|---|
| 43 | def represent(self, object): |
|---|
| 44 | if isinstance(object, dict): |
|---|
| 45 | return _syck.Map(object.copy(), tag="tag:yaml.org,2002:map") |
|---|
| 46 | elif isinstance(object, list): |
|---|
| 47 | return _syck.Seq(object[:], tag="tag:yaml.org,2002:seq") |
|---|
| 48 | else: |
|---|
| 49 | return _syck.Scalar(str(object), tag="tag:yaml.org,2002:str") |
|---|
| 50 | |
|---|
| 51 | def allow_aliases(self, object): |
|---|
| 52 | return True |
|---|
| 53 | |
|---|
| 54 | class Dumper(GenericDumper): |
|---|
| 55 | |
|---|
| 56 | def __init__(self, *args, **kwds): |
|---|
| 57 | super(Dumper, self).__init__(*args, **kwds) |
|---|
| 58 | |
|---|
| 59 | def find_representer(self, object): |
|---|
| 60 | for object_type in type(object).__mro__: |
|---|
| 61 | if object_type.__module__ == '__builtin__': |
|---|
| 62 | name = object_type.__name__ |
|---|
| 63 | else: |
|---|
| 64 | name = '%s.%s' % (object_type.__module__, object_type.__name__) |
|---|
| 65 | method = 'represent_' + name.replace('.', '_') |
|---|
| 66 | if hasattr(self, method): |
|---|
| 67 | return getattr(self, method) |
|---|
| 68 | |
|---|
| 69 | def represent(self, object): |
|---|
| 70 | representer = self.find_representer(object) |
|---|
| 71 | if representer: |
|---|
| 72 | return representer(object) |
|---|
| 73 | else: |
|---|
| 74 | return super(Dumper, self).represent(object) |
|---|
| 75 | |
|---|
| 76 | def represent_object(self, object): |
|---|
| 77 | return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:str") |
|---|
| 78 | |
|---|
| 79 | def represent_NoneType(self, object): |
|---|
| 80 | return _syck.Scalar('~', tag="tag:yaml.org,2002:null") |
|---|
| 81 | |
|---|
| 82 | def represent_bool(self, object): |
|---|
| 83 | return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:bool") |
|---|
| 84 | |
|---|
| 85 | def represent_str(self, object): |
|---|
| 86 | return _syck.Scalar(str(object), tag="tag:yaml.org,2002:str") |
|---|
| 87 | |
|---|
| 88 | def represent_list(self, object): |
|---|
| 89 | return _syck.Seq(object[:], tag="tag:yaml.org,2002:seq") |
|---|
| 90 | |
|---|
| 91 | def represent_dict(self, object): |
|---|
| 92 | return _syck.Map(object.copy(), tag="tag:yaml.org,2002:map") |
|---|
| 93 | |
|---|
| 94 | def represent_int(self, object): |
|---|
| 95 | return _syck.Scalar(repr(object), tag="tag:yaml.org,2002:int") |
|---|
| 96 | |
|---|
| 97 | def represent_float(self, object): |
|---|
| 98 | value = repr(object) |
|---|
| 99 | if value == repr(INF): |
|---|
| 100 | value = '.inf' |
|---|
| 101 | elif value == repr(NEGINF): |
|---|
| 102 | value = '-.inf' |
|---|
| 103 | elif value == repr(NAN): |
|---|
| 104 | value = '.nan' |
|---|
| 105 | return _syck.Scalar(value, tag="tag:yaml.org,2002:float") |
|---|
| 106 | |
|---|
| 107 | def represent_sets_Set(self, object): |
|---|
| 108 | return _syck.Seq(list(object), tag="tag:yaml.org,2002:set") |
|---|
| 109 | |
|---|
| 110 | def represent_datetime_datetime(self, object): |
|---|
| 111 | return _syck.Scalar(object.isoformat(), tag="tag:yaml.org,2002:timestamp") |
|---|
| 112 | |
|---|
| 113 | def represent_long(self, object): |
|---|
| 114 | return _syck.Scalar(repr(object), tag="tag:python.yaml.org,2002:long") |
|---|
| 115 | |
|---|
| 116 | def represent_unicode(self, object): |
|---|
| 117 | return _syck.Scalar(object.encode('utf-8'), tag="tag:python.yaml.org,2002:unicode") |
|---|
| 118 | |
|---|
| 119 | def represent_tuple(self, object): |
|---|
| 120 | return _syck.Seq(list(object), tag="tag:python.yaml.org,2002:tuple") |
|---|
| 121 | |
|---|
| 122 | def represent_type(self, object): |
|---|
| 123 | name = '%s.%s' % (object.__module__, object.__name__) |
|---|
| 124 | return _syck.Scalar('', tag="tag:python.yaml.org,2002:name:"+name) |
|---|
| 125 | represent_classobj = represent_type |
|---|
| 126 | represent_function = represent_type |
|---|
| 127 | represent_builtin_function_or_method = represent_type |
|---|
| 128 | |
|---|
| 129 | def represent_instance(self, object): |
|---|
| 130 | cls = object.__class__ |
|---|
| 131 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 132 | args = () |
|---|
| 133 | state = {} |
|---|
| 134 | if hasattr(object, '__getinitargs__'): |
|---|
| 135 | args = object.__getinitargs__() |
|---|
| 136 | if hasattr(object, '__getstate__'): |
|---|
| 137 | state = object.__getstate__() |
|---|
| 138 | elif not hasattr(object, '__getinitargs__'): |
|---|
| 139 | state = object.__dict__.copy() |
|---|
| 140 | if not args and isinstance(state, dict): |
|---|
| 141 | return _syck.Map(state.copy(), |
|---|
| 142 | tag="tag:python.yaml.org,2002:object:"+class_name) |
|---|
| 143 | value = {} |
|---|
| 144 | if args: |
|---|
| 145 | value['args'] = list(args) |
|---|
| 146 | if state or not isinstance(state, dict): |
|---|
| 147 | value['state'] = state |
|---|
| 148 | return _syck.Map(value, |
|---|
| 149 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 150 | |
|---|
| 151 | def represent_object(self, object): # Do you understand this? I don't. |
|---|
| 152 | cls = type(object) |
|---|
| 153 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 154 | args = () |
|---|
| 155 | if cls.__reduce__ is type.__reduce__: |
|---|
| 156 | if hasattr(object, '__reduce_ex__'): |
|---|
| 157 | reduce = object.__reduce_ex__(2) |
|---|
| 158 | args = reduce[1][1:] |
|---|
| 159 | else: |
|---|
| 160 | reduce = object.__reduce__() |
|---|
| 161 | if len(reduce) > 2: |
|---|
| 162 | state = reduce[2] |
|---|
| 163 | if state is None: |
|---|
| 164 | state = {} |
|---|
| 165 | if not args and isinstance(state, dict): |
|---|
| 166 | return _syck.Map(state.copy(), |
|---|
| 167 | tag="tag:python.yaml.org,2002:object:"+class_name) |
|---|
| 168 | if not state and isinstance(state, dict): |
|---|
| 169 | return _syck.Seq(list(args), |
|---|
| 170 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 171 | value = {} |
|---|
| 172 | if args: |
|---|
| 173 | value['args'] = list(args) |
|---|
| 174 | if state or not isinstance(state, dict): |
|---|
| 175 | value['state'] = state |
|---|
| 176 | return _syck.Map(value, |
|---|
| 177 | tag="tag:python.yaml.org,2002:new:"+class_name) |
|---|
| 178 | else: |
|---|
| 179 | reduce = object.__reduce__() |
|---|
| 180 | cls = reduce[0] |
|---|
| 181 | class_name = '%s.%s' % (cls.__module__, cls.__name__) |
|---|
| 182 | args = reduce[1] |
|---|
| 183 | state = None |
|---|
| 184 | if len(reduce) > 2: |
|---|
| 185 | state = reduce[2] |
|---|
| 186 | if state is None: |
|---|
| 187 | state = {} |
|---|
| 188 | if not state and isinstance(state, dict): |
|---|
| 189 | return _syck.Seq(list(args), |
|---|
| 190 | tag="tag:python.yaml.org,2002:apply:"+class_name) |
|---|
| 191 | value = {} |
|---|
| 192 | if args: |
|---|
| 193 | value['args'] = list(args) |
|---|
| 194 | if state or not isinstance(state, dict): |
|---|
| 195 | value['state'] = state |
|---|
| 196 | return _syck.Map(value, |
|---|
| 197 | tag="tag:python.yaml.org,2002:apply:"+class_name) |
|---|
| 198 | |
|---|
| 199 | def allow_aliases(self, object): |
|---|
| 200 | if object is None or type(object) in [int, bool, float]: |
|---|
| 201 | return False |
|---|
| 202 | if type(object) is str and (not object or object.isalnum()): |
|---|
| 203 | return False |
|---|
| 204 | if type(object) is tuple and not object: |
|---|
| 205 | return False |
|---|
| 206 | return True |
|---|
| 207 | |
|---|
| 208 | def emit(node, output=None, Dumper=Dumper, **parameters): |
|---|
| 209 | if output is None: |
|---|
| 210 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 211 | else: |
|---|
| 212 | dumper = Dumper(output, **parameters) |
|---|
| 213 | dumper.emit(node) |
|---|
| 214 | if output is None: |
|---|
| 215 | return dumper.output.getvalue() |
|---|
| 216 | |
|---|
| 217 | def dump(object, output=None, Dumper=Dumper, **parameters): |
|---|
| 218 | if output is None: |
|---|
| 219 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 220 | else: |
|---|
| 221 | dumper = Dumper(output, **parameters) |
|---|
| 222 | dumper.dump(object) |
|---|
| 223 | if output is None: |
|---|
| 224 | return dumper.output.getvalue() |
|---|
| 225 | |
|---|
| 226 | def emit_documents(nodes, output=None, Dumper=Dumper, **parameters): |
|---|
| 227 | if output is None: |
|---|
| 228 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 229 | else: |
|---|
| 230 | dumper = Dumper(output, **parameters) |
|---|
| 231 | for node in nodes: |
|---|
| 232 | dumper.emit(node) |
|---|
| 233 | if output is None: |
|---|
| 234 | return dumper.output.getvalue() |
|---|
| 235 | |
|---|
| 236 | def dump_documents(objects, output=None, Dumper=Dumper, **parameters): |
|---|
| 237 | if output is None: |
|---|
| 238 | dumper = Dumper(StringIO.StringIO(), **parameters) |
|---|
| 239 | else: |
|---|
| 240 | dumper = Dumper(output, **parameters) |
|---|
| 241 | for object in objects: |
|---|
| 242 | dumper.dump(object) |
|---|
| 243 | if output is None: |
|---|
| 244 | return dumper.output.getvalue() |
|---|
| 245 | |
|---|
| 246 | |
|---|