Changeset 147
- Timestamp:
- 04/22/06 16:40:43 (2 years ago)
- Files:
-
- pyyaml/trunk/lib/yaml/__init__.py (modified) (1 diff)
- pyyaml/trunk/lib/yaml/constructor.py (modified) (2 diffs)
- pyyaml/trunk/lib/yaml/representer.py (modified) (9 diffs)
- pyyaml/trunk/tests/data/construct-python-object.code (added)
- pyyaml/trunk/tests/data/construct-python-object.data (added)
- pyyaml/trunk/tests/test_constructor.py (modified) (1 diff)
- pyyaml/trunk/tests/test_representer.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
pyyaml/trunk/lib/yaml/__init__.py
r146 r147 232 232 Dumper.add_representer(data_type, representer) 233 233 234 def add_multi_representer(data_type, multi_representer, Dumper=Dumper): 235 """ 236 Add a representer for the given type. 237 Multi-representer is a function accepting a Dumper instance 238 and an instance of the given data type or subtype 239 and producing the corresponding representation node. 240 """ 241 Dumper.add_multi_representer(data_type, multi_representer) 242 234 243 class YAMLObjectMetaclass(type): 235 244 """ pyyaml/trunk/lib/yaml/constructor.py
r146 r147 493 493 return self.find_python_module(suffix, node.start_mark) 494 494 495 class classobj: pass 496 497 def make_python_instance(self, suffix, node, 498 args=None, kwds=None, newobj=False): 499 if not args: 500 args = [] 501 if not kwds: 502 kwds = {} 503 cls = self.find_python_name(suffix, node.start_mark) 504 if newobj and isinstance(cls, type(self.classobj)) \ 505 and not args and not kwds: 506 instance = self.classobj() 507 instance.__class__ = cls 508 return instance 509 elif newobj and isinstance(cls, type): 510 return cls.__new__(cls, *args, **kwds) 511 else: 512 return cls(*args, **kwds) 513 514 def set_python_instance_state(self, instance, state): 515 if hasattr(instance, '__setstate__'): 516 instance.__setstate__(state) 517 else: 518 slotstate = {} 519 if isinstance(state, tuple) and len(state) == 2: 520 state, slotstate = state 521 if hasattr(instance, '__dict__'): 522 instance.__dict__.update(state) 523 elif state: 524 slotstate.update(state) 525 for key, value in slotstate.items(): 526 setattr(object, key, value) 527 528 def construct_python_object(self, suffix, node): 529 # Format: 530 # !!python/object:module.name { ... state ... } 531 instance = self.make_python_instance(suffix, node, newobj=True) 532 state = self.construct_mapping(node) 533 self.set_python_instance_state(instance, state) 534 return instance 535 536 def construct_python_object_apply(self, suffix, node, newobj=False): 537 # Format: 538 # !!python/object/apply # (or !!python/object/new) 539 # args: [ ... arguments ... ] 540 # kwds: { ... keywords ... } 541 # state: ... state ... 542 # listitems: [ ... listitems ... ] 543 # dictitems: { ... dictitems ... } 544 # or short format: 545 # !!python/object/apply [ ... arguments ... ] 546 # The difference between !!python/object/apply and !!python/object/new 547 # is how an object is created, check make_python_instance for details. 548 if isinstance(node, SequenceNode): 549 args = self.construct_sequence(node) 550 kwds = {} 551 state = {} 552 listitems = [] 553 dictitems = {} 554 else: 555 value = self.construct_mapping(node) 556 args = value.get('args', []) 557 kwds = value.get('kwds', {}) 558 state = value.get('state', {}) 559 listitems = value.get('listitems', []) 560 dictitems = value.get('dictitems', {}) 561 instance = self.make_python_instance(suffix, node, args, kwds, newobj) 562 if state: 563 self.set_python_instance_state(instance, state) 564 if listitems: 565 instance.extend(listitems) 566 if dictitems: 567 for key in dictitems: 568 instance[key] = dictitems[key] 569 return instance 570 571 def construct_python_object_new(self, suffix, node): 572 return self.construct_python_object_apply(suffix, node, newobj=True) 573 574 495 575 Constructor.add_constructor( 496 576 u'tag:yaml.org,2002:python/none', … … 545 625 Constructor.construct_python_module) 546 626 627 Constructor.add_multi_constructor( 628 u'tag:yaml.org,2002:python/object:', 629 Constructor.construct_python_object) 630 631 Constructor.add_multi_constructor( 632 u'tag:yaml.org,2002:python/object/apply:', 633 Constructor.construct_python_object_apply) 634 635 Constructor.add_multi_constructor( 636 u'tag:yaml.org,2002:python/object/new:', 637 Constructor.construct_python_object_new) 638 pyyaml/trunk/lib/yaml/representer.py
r143 r147 17 17 from sets import Set as set 18 18 19 import sys 19 import sys, copy_reg 20 20 21 21 class RepresenterError(YAMLError): … … 25 25 26 26 yaml_representers = {} 27 yaml_multi_representers = {} 27 28 28 29 def __init__(self): … … 30 31 31 32 def represent(self, data): 32 node = self.represent_ object(data)33 node = self.represent_data(data) 33 34 self.serialize(node) 34 35 self.represented_objects = {} … … 50 51 return bases 51 52 52 def represent_ object(self, data):53 def represent_data(self, data): 53 54 if self.ignore_aliases(data): 54 55 alias_key = None … … 65 66 if type(data) is self.instance_type: 66 67 data_types = self.get_classobj_bases(data.__class__)+list(data_types) 67 for data_type in data_types:68 if data_type in self.yaml_representers:69 node = self.yaml_representers[data_type](self, data)70 break71 else:72 if None in self.yaml_representers:73 node = self.yaml_representers[None](self, data)68 if data_types[0] in self.yaml_representers: 69 node = self.yaml_representers[data_types[0]](self, data) 70 else: 71 for data_type in data_types: 72 if data_type in self.yaml_multi_representers: 73 node = self.yaml_multi_representers[data_type](self, data) 74 break 74 75 else: 75 node = ScalarNode(None, unicode(data)) 76 if None in self.yaml_multi_representers: 77 node = self.yaml_multi_representers[None](self, data) 78 elif None in self.yaml_representers: 79 node = self.yaml_representers[None](self, data) 80 else: 81 node = ScalarNode(None, unicode(data)) 76 82 if alias_key is not None: 77 83 self.represented_objects[alias_key] = node … … 84 90 add_representer = classmethod(add_representer) 85 91 92 def add_multi_representer(cls, data_type, representer): 93 if not 'yaml_multi_representers' in cls.__dict__: 94 cls.yaml_multi_representers = cls.yaml_multi_representers.copy() 95 cls.yaml_multi_representers[data_type] = representer 96 add_multi_representer = classmethod(add_multi_representer) 97 86 98 def represent_scalar(self, tag, value, style=None): 87 99 return ScalarNode(tag, value, style=style) 88 100 89 101 def represent_sequence(self, tag, sequence, flow_style=None): 102 best_style = True 90 103 value = [] 91 104 for item in sequence: 92 value.append(self.represent_object(item)) 105 node_item = self.represent_data(item) 106 if not (isinstance(node_item, ScalarNode) and not node_item.style): 107 best_style = False 108 value.append(self.represent_data(item)) 109 if flow_style is None: 110 flow_style = best_style 93 111 return SequenceNode(tag, value, flow_style=flow_style) 94 112 95 113 def represent_mapping(self, tag, mapping, flow_style=None): 114 best_style = True 96 115 if hasattr(mapping, 'keys'): 97 116 value = {} 98 117 for item_key in mapping.keys(): 99 118 item_value = mapping[item_key] 100 value[self.represent_object(item_key)] = \ 101 self.represent_object(item_value) 119 node_key = self.represent_data(item_key) 120 node_value = self.represent_data(item_value) 121 if not (isinstance(node_key, ScalarNode) and not node_key.style): 122 best_style = False 123 if not (isinstance(node_value, ScalarNode) and not node_value.style): 124 best_style = False 125 value[node_key] = node_value 102 126 else: 103 127 value = [] 104 128 for item_key, item_value in mapping: 105 value.append((self.represent_object(item_key), 106 self.represent_object(item_value))) 129 node_key = self.represent_data(item_key) 130 node_value = self.represent_data(item_value) 131 if not (isinstance(node_key, ScalarNode) and not node_key.style): 132 best_style = False 133 if not (isinstance(node_value, ScalarNode) and not node_value.style): 134 best_style = False 135 value.append((node_key, node_value)) 136 if flow_style is None: 137 flow_style = best_style 107 138 return MappingNode(tag, value, flow_style=flow_style) 108 139 … … 259 290 260 291 class Representer(SafeRepresenter): 261 292 262 293 def represent_str(self, data): 263 294 tag = None … … 313 344 u'tag:yaml.org,2002:python/module:'+data.__name__, u'') 314 345 346 def represent_instance(self, data): 347 # For instances of classic classes, we use __getinitargs__ and 348 # __getstate__ to serialize the data. 349 350 # If data.__getinitargs__ exists, the object must be reconstructed by 351 # calling cls(**args), where args is a tuple returned by 352 # __getinitargs__. Otherwise, the cls.__init__ method should never be 353 # called and the class instance is created by instantiating a trivial 354 # class and assigning to the instance's __class__ variable. 355 356 # If data.__getstate__ exists, it returns the state of the object. 357 # Otherwise, the state of the object is data.__dict__. 358 359 # We produce either a !!python/object or !!python/object/new node. 360 # If data.__getinitargs__ does not exist and state is a dictionary, we 361 # produce a !!python/object node . Otherwise we produce a 362 # !!python/object/new node. 363 364 cls = data.__class__ 365 class_name = u'%s.%s' % (cls.__module__, cls.__name__) 366 args = None 367 state = None 368 if hasattr(data, '__getinitargs__'): 369 args = list(data.__getinitargs__()) 370 if hasattr(data, '__getstate__'): 371 state = data.__getstate__() 372 else: 373 state = data.__dict__ 374 if args is None and isinstance(state, dict): 375 return self.represent_mapping( 376 u'tag:yaml.org,2002:python/object:'+class_name, state) 377 if isinstance(state, dict) and not state: 378 return self.represent_sequence( 379 u'tag:yaml.org,2002:python/object/new:'+class_name, args) 380 value = {} 381 if args: 382 value['args'] = args 383 value['state'] = state 384 return self.represent_mapping( 385 u'tag:yaml.org,2002:python/object/new:'+class_name, value) 386 387 def represent_object(self, data): 388 # We use __reduce__ API to save the data. data.__reduce__ returns 389 # a tuple of length 2-5: 390 # (function, args, state, listitems, dictitems) 391 392 # For reconstructing, we calls function(*args), then set its state, 393 # listitems, and dictitems if they are not None. 394 395 # A special case is when function.__name__ == '__newobj__'. In this 396 # case we create the object with args[0].__new__(*args). 397 398 # Another special case is when __reduce__ returns a string - we don't 399 # support it. 400 401 # We produce a !!python/object, !!python/object/new or 402 # !!python/object/apply node. 403 404 cls = type(data) 405 if cls in copy_reg.dispatch_table: 406 reduce = copy_reg.dispatch_table[cls] 407 elif hasattr(data, '__reduce_ex__'): 408 reduce = data.__reduce_ex__(2) 409 elif hasattr(data, '__reduce__'): 410 reduce = data.__reduce__() 411 else: 412 raise RepresenterError("cannot represent object: %r" % data) 413 reduce = (list(reduce)+[None]*5)[:5] 414 function, args, state, listitems, dictitems = reduce 415 args = list(args) 416 if state is None: 417 state = {} 418 if listitems is not None: 419 listitems = list(listitems) 420 if dictitems is not None: 421 dictitems = dict(dictitems) 422 if function.__name__ == '__newobj__': 423 function = args[0] 424 args = args[1:] 425 tag = u'tag:yaml.org,2002:python/object/new:' 426 newobj = True 427 else: 428 tag = u'tag:yaml.org,2002:python/object/apply:' 429 newobj = False 430 function_name = u'%s.%s' % (function.__module__, function.__name__) 431 if not args and not listitems and not dictitems \ 432 and isinstance(state, dict) and newobj: 433 return self.represent_mapping( 434 u'tag:yaml.org,2002:python/object:'+function_name, state) 435 if not listitems and not dictitems \ 436 and isinstance(state, dict) and not state: 437 return self.represent_sequence(tag+function_name, args) 438 value = {} 439 if args: 440 value['args'] = args 441 if state or not isinstance(state, dict): 442 value['state'] = state 443 if listitems: 444 value['listitems'] = listitems 445 if dictitems: 446 value['dictitems'] = dictitems 447 return self.represent_mapping(tag+function_name, value) 448 315 449 Representer.add_representer(str, 316 450 Representer.represent_str) … … 343 477 Representer.represent_module) 344 478 479 Representer.add_multi_representer(Representer.instance_type, 480 Representer.represent_instance) 481 482 Representer.add_multi_representer(object, 483 Representer.represent_object) 484 pyyaml/trunk/tests/test_constructor.py
r146 r147 113 113 else: 114 114 return False 115 116 class AnObject(object): 117 118 def __new__(cls, foo=None, bar=None, baz=None): 119 self = object.__new__(cls) 120 self.foo = foo 121 self.bar = bar 122 self.baz = baz 123 return self 124 125 def __cmp__(self, other): 126 return cmp((type(self), self.foo, self.bar, self.baz), 127 (type(other), other.foo, other.bar, other.baz)) 128 129 def __eq__(self, other): 130 return type(self) is type(other) and \ 131 (self.foo, self.bar, self.baz) == (other.foo, other.bar, other.baz) 132 133 class AnInstance: 134 135 def __init__(self, foo=None, bar=None, baz=None): 136 self.foo = foo 137 self.bar = bar 138 self.baz = baz 139 140 def __cmp__(self, other): 141 return cmp((type(self), self.foo, self.bar, self.baz), 142 (type(other), other.foo, other.bar, other.baz)) 143 144 def __eq__(self, other): 145 return type(self) is type(other) and \ 146 (self.foo, self.bar, self.baz) == (other.foo, other.bar, other.baz) 147 148 class AState(AnInstance): 149 150 def __getstate__(self): 151 return { 152 '_foo': self.foo, 153 '_bar': self.bar, 154 '_baz': self.baz, 155 } 156 157 def __setstate__(self, state): 158 self.foo = state['_foo'] 159 self.bar = state['_bar'] 160 self.baz = state['_baz'] 161 162 class ACustomState(AnInstance): 163 164 def __getstate__(self): 165 return (self.foo, self.bar, self.baz) 166 167 def __setstate__(self, state): 168 self.foo, self.bar, self.baz = state 169 170 class InitArgs(AnInstance): 171 172 def __getinitargs__(self): 173 return (self.foo, self.bar, self.baz) 174 175 def __getstate__(self): 176 return {} 177 178 class InitArgsWithState(AnInstance): 179 180 def __getinitargs__(self): 181 return (self.foo, self.bar) 182 183 def __getstate__(self): 184 return self.baz 185 186 def __setstate__(self, state): 187 self.baz = state 188 189 class NewArgs(AnObject): 190 191 def __getnewargs__(self): 192 return (self.foo, self.bar, self.baz) 193 194 def __getstate__(self): 195 return {} 196 197 class NewArgsWithState(AnObject): 198 199 def __getnewargs__(self): 200 return (self.foo, self.bar) 201 202 def __getstate__(self): 203 return self.baz 204 205 def __setstate__(self, state): 206 self.baz = state 207 208 class Reduce(AnObject): 209 210 def __reduce__(self): 211 return self.__class__, (self.foo, self.bar, self.baz) 212 213 class ReduceWithState(AnObject): 214 215 def __reduce__(self): 216 return self.__class__, (self.foo, self.bar), self.baz 217 218 def __setstate__(self, state): 219 self.baz = state 220 221 class MyInt(int): 222 223 def __eq__(self, other): 224 return type(self) is type(other) and int(self) == int(other) 225 226 class MyList(list): 227 228 def __init__(self, n=1): 229 self.extend([None]*n) 230 231 def __eq__(self, other): 232 return type(self) is type(other) and list(self) == list(other) 233 234 class MyDict(dict): 235 236 def __init__(self, n=1): 237 for k in range(n): 238 self[k] = None 239 240 def __eq__(self, other): 241 return type(self) is type(other) and dict(self) == dict(other) 115 242 116 243 class TestConstructorTypes(test_appliance.TestAppliance): pyyaml/trunk/tests/test_representer.py
r144 r147 25 25 data2.sort() 26 26 data2 = repr(data2) 27 if data1 != data2: 27 if data1 != data2: 28 raise 29 elif isinstance(data1, list): 30 self.failUnlessEqual(type(data1), type(data2)) 31 self.failUnlessEqual(len(data1), len(data2)) 32 for item1, item2 in zip(data1, data2): 33 self.failUnlessEqual(item1, item2) 34 else: 28 35 raise 29 36 except:
