From: Steve H. <sh...@zi...> - 2002-08-16 18:55:12
|
I have put a new PyYaml tarball at the following location: http://mountainwebtools.com/PyYaml/PyYaml_16Aug2002.tgz (about 42K) (I don't have access to yaml.org at the moment, so the tarball on the download page there is now a version behind.) The new PyYaml adds features for serializing objects. The distribution also includes a file called TestClasses.py, which shows various use cases for dumping and loading objects. Here is some working code for your perusal: import yaml from test import assertEquals from here import flushLeft from math import sqrt """ DUMPING OBJECTS: > YAML has several ways of persisting objects. One view of an object is that it's nothing more than it's dictionary. By default, YAML emits self.__dict__ from objects. """ class SimpleObject: def __init__(self): self.x = 100 self.y = 20 def xyz(self): return self.x + self.y + self.z def testDumpingDictionary(): obj = SimpleObject() obj.z = 3 output = yaml.dump(obj) expected = simpleObjectYaml() assertEquals(output, expected) def simpleObjectYaml(): return flushLeft(""" --- !!__main__.SimpleObject x: 100 y: 20 z: 3 """) testDumpingDictionary() """ LOADING OBJECTS: > Of course, we would expect to be able to load that YAML right back into Python, and we can. You get back an object of the intended class, with all of the normal methods. Be aware, though, that if your class creates methods on the fly, or if it does other trickery, then you might get unexpected results. """ def testLoadingDictionary(): obj = yaml.load(simpleObjectYaml()).next() assertEquals(obj.xyz(), 123) testLoadingDictionary() """ CUSTOM DUMPING: > Some times you want more control over how you dump objects in YAML. You might not want to dump all members of the object, for example. Also, you may not want to export the module name. """ class Triangle: def __init__(self,x,y): self.x = x self.y = y self._hypotneuse = sqrt(x*x + y*y) def to_yaml(self): # hide the hypotneuse attribute, it's private; # also use inches instead of feet view = { 'x_inches': self.x * 12, 'y_inches': self.y * 12 } return (view, '!!triangle_in_inches') def testDumpTriangle(): triangle = Triangle(3,4) assertEquals(yaml.dump(triangle), triangleYaml()) def triangleYaml(): return flushLeft(""" --- !!triangle_in_inches x_inches: 36 y_inches: 48 """) testDumpTriangle() """ CUSTOM LOADING: > You have control over the YAML load process too. Normally YAML resolves private types for you automatically, but you can override its behavior. """ class MyResolver: def resolveType(self, data, typestring): if typestring == '!!triangle_in_inches': x = data['x_inches'] / 12 y = data['y_inches'] / 12 return Triangle(x,y) else: raise 'Private type %s not supported' % typestring def testCustomLoad(): obj = yaml.load(triangleYaml(),MyResolver()).next() assertEquals(obj._hypotneuse, 5.0) testCustomLoad() """ USING FROM_YAML(): > Another way to customize the YAML loading process is to supply a from_yaml() method. For example, you might want the loading of an object to have some kind of a side effect. Or, you may need to calculate some value that is not part of the attribute. """ class TestConfig: lastTester = None def from_yaml(self, args): self.tester = args['tester'] self.hitcount = args['hitcount'] + 1 TestConfig.lastTester = self.tester return self def testFromYaml(): yamlData = flushLeft(""" --- !!__main__.TestConfig tester: showell hitcount: 42 """) obj = yaml.load(yamlData).next() assertEquals(obj.hitcount, 43) assertEquals(TestConfig.lastTester, 'showell') testFromYaml() === Comments are welcome. -- Steve |