Download Shareware and Freeware Software for Windows, Linux, Macintosh, PDA

line Home  |  About Us  |  Link To Us  |  FAQ  |  Contact

Serving Software Downloads in 956 Categories, Downloaded 49.601.249 Times

zope.fssync 3.5.2

Company: Zope Corporation and Contributors
Date Added: August 28, 2013  |  Visits: 513

zope.fssync

Report Broken Link
Printer Friendly Version


Product Homepage
Download (33 downloads)



This package provides filesystem synchronization utilities for Zope 3. It is used by the zope.app.fssync package.<br />Filesystem Synchronization<br /><br />This package provides an API for the synchronization of Python objects with a serialized filesystem representation. This API does not address security issues. (See zope.app.fssync for a protected web-based API). This API is Zope and ZODB independent.<br /><br />The main use cases are<br /><br /> * data export / import (e.g. moving data from one place to another)<br /> * content management (e.g. managing a wiki or other collections of documents offline)<br /><br />The target representation depends on your use case. In the use case of data export/import, for instance, it is crucial that all data are exported as completely as possible. Since the data need not be read by humans in most circumstances a pickle format may be the most complete and easy one to use. In the use case of content management it may be more important that all metadata are readable by humans. In this case another format, e.g. RDFa, may be more appropriate.<br />Main components<br /><br />A synchronizer serializes content objects and stores the serialized data in a repository in an application specific format. It uses deserializers to read the object back into the content space. The serialization format must be rich enough to preserve various forms of references which should be reestablished on deserialization.<br /><br />All these components should be replaceable. Application may use different serialization formats with different references for different purposes (e.g. backup vs. content management) and different target systems (e.g. a zip archive vs. a svn repository).<br /><br />The main components are:<br /><br /> * ISyncTasks like Checkout, Check, and Commit which synchronize a content space with a repository. These tasks uses serializers to produce serialized data for a repository in an application specific format. They use deserializers to read the data back. The default implementation uses xmlpickle for python objects, data streams for file contents, and special directories for extras and metadata. Alternative implementations may use standard pickles, a human readable format like RDFa, or application specific formats.<br /> * ISynchronizer: Synchronizers produce serialized pieces of a Python object (the ISerializer part of a synchronizer) and consume serialized data to (re-)create Python objects (the IDeserializer part of a synchronizer).<br /> * IPickler: An adapter that determines the pickle format.<br /> * IRepository: represents a target system that can be used to read and write serialized data.<br /><br />Let's take some samples:<br /><br /> >>> from StringIO import StringIO<br /> >>> from zope import interface<br /> >>> from zope import component<br /> >>> from zope.fssync import interfaces<br /> >>> from zope.fssync import task<br /> >>> from zope.fssync import synchronizer<br /> >>> from zope.fssync import repository<br /> >>> from zope.fssync import pickle<br /><br /> >>> class A(object):<br /> ... data = 'data of a'<br /> >>> class B(A):<br /> ... pass<br /> >>> a = A()<br /> >>> b = B()<br /> >>> b.data = 'data of b'<br /> >>> b.extra = 'extra of b'<br /> >>> root = dict(a=a, b=b)<br /><br />Persistent References<br /><br />Many applications use more than one system of persistent references. Zope, for instance, uses p_oids, int ids, key references, traversal paths, dotted names, named utilities, etc.<br /><br />Other systems might use generic reference systems like global unique ids or primary keys together with domain specific references, like emails, URI, postal addresses, code numbers, etc. All these references are candidates for exportable references as long as they can be resolved on import or reimport.<br /><br />In our example we use simple integer ids:<br /><br /> >>> class GlobalIds(object):<br /> ... ids = dict()<br /> ... count = 0<br /> ... def getId(self, obj):<br /> ... for k, v in self.ids.iteritems():<br /> ... if obj == v:<br /> ... return k<br /> ... def register(self, obj):<br /> ... uid = self.getId(obj)<br /> ... if uid is not None:<br /> ... return uid<br /> ... self.count += 1<br /> ... self.ids[self.count] = obj<br /> ... return self.count<br /> ... def resolve(self, uid):<br /> ... return self.ids.get(int(uid), None)<br /><br /> >>> globalIds = GlobalIds()<br /> >>> globalIds.register(a)<br /> 1<br /> >>> globalIds.register(b)<br /> 2<br /> >>> globalIds.register(root)<br /> 3<br /><br />In our example we use the int ids as a substitute for the default path references which are the most common references in Zope.<br /><br />In our examples we use a SnarfRepository which can easily be examined:<br /><br />>>> snarf = repository.SnarfRepository(StringIO())<br />>>> checkout = task.Checkout(synchronizer.getSynchronizer, snarf)<br /><br />Snarf is a Zope3 specific archive format where the key need is for simple software. The format is dead simple: each file is represented by the string<br /><br /> '<size> <pathname>n'<br /><br />followed by exactly <size> bytes. Directories are not represented explicitly.<br />Entry Ids<br /><br />Persistent ids are also used in the metadata files of fssync. The references are generated by an IEntryId adapter which must have a string representation in order to be saveable in a text file. Typically these object ids correspond to the persistent pickle ids, but this is not necessarily the case.<br /><br />Since we do not have paths we use our integer ids:<br /><br /> >>> @component.adapter(interface.Interface)<br /> ... @interface.implementer(interfaces.IEntryId)<br /> ... def entryId(obj):<br /> ... global globalIds<br /> ... return globalIds.getId(obj)<br /> >>> component.provideAdapter(entryId)<br /><br />Synchronizer<br /><br />In the use case of data export / import it is crucial that fssync is able to serialize "all" object data. Note that it isn't always obvious what data is intrinsic to an object. Therefore we must provide special serialization / de-serialization tools which take care of writing and reading "all" data.<br /><br />An obvious solution would be to use inheriting synchronization adapters. But this solution bears a risk. If someone created a subclass and forgot to create an adapter, then their data would be serialized incompletely. To give an example: What happens if someone has a serialization adapter for class Person which serializes every aspect of Person instances and defines a subclass Employee(Person) later on? If the Employee class has some extra aspects (for example additional attributes like insurance id, wage, etc.) these would never be serialized as long as there is no special serialization adapter for Employees which handles this extra aspects. The behavior is different if the adapters are looked up by their dotted class name (i.e. the most specific class) and not their class or interface (which might led to adapters written for super classes). If no specific adapter exists a default serializer (e.g a xmlpickler) can serialize the object completely. So even if you forget to provide special serializers for all your classes you can be sure that your data are complete.<br /><br />Since the component architecture doesn't support adapters that work one class only (not their subclasses), we register the adapter classes as named ISynchronizerFactory utilities and use the dotted name of the class as lookup key. The default synchronizer is registered as a unnamed ISynchronizerFactory utility. This synchronizer ensures that all data are pickled to the target repository.<br /><br /> >>> component.provideUtility(synchronizer.DefaultSynchronizer,<br /> ... provides=interfaces.ISynchronizerFactory)<br /><br />All special synchronizers are registered for a specific content class and not an abstract interface. The class is represented by the dotted class name in the factory registration:<br /><br /> >>> class AFileSynchronizer(synchronizer.Synchronizer):<br /> ... interface.implements(interfaces.IFileSynchronizer)<br /> ... def dump(self, writeable):<br /> ... writeable.write(self.context.data)<br /> ... def load(self, readable):<br /> ... self.context.data = readable.read()<br /><br /> >>> component.provideUtility(AFileSynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(A))<br /><br />The lookup of the utilities by the dotted class name is handled by the getSynchronizer function, which first tries to find a named utility. The IDefaultSynchronizer utility is used as a fallback:<br /><br /> >>> synchronizer.getSynchronizer(a)<br /> <zope.fssync.doctest.AFileSynchronizer object at ...><br /><br />If no named adapter is registered it returns the registered unnamed default adapter (as long as the permissions allow this):<br /><br /> >>> synchronizer.getSynchronizer(b)<br /> <zope.fssync.synchronizer.DefaultSynchronizer object at ...><br /><br />This default serializer typically uses a pickle format, which is determined by the IPickler adapter. Here we use Zope's xmlpickle.<br /><br /> >>> component.provideAdapter(pickle.XMLPickler)<br /> >>> component.provideAdapter(pickle.XMLUnpickler)<br /><br />For container like objects we must provide an adapter that maps the container to a directory. In our example we use the buildin dict class:<br /><br /> >>> component.provideUtility(synchronizer.DirectorySynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(dict))<br /><br />Now we can export the object to the snarf archive:<br /><br /> >>> checkout.perform(root, 'test')<br /> >>> print snarf.stream.getvalue()<br /> 00000213 @@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="__builtin__.dict"<br /> factory="__builtin__.dict"<br /> id="3"<br /> /><br /> </entries><br /> 00000339 test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="a"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.A"<br /> factory="zope.fssync.doctest.A"<br /> id="1"<br /> /><br /> <entry name="b"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.B"<br /> id="2"<br /> /><br /> </entries><br /> 00000009 test/a<br /> data of a00000370 test/b<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <object><br /> <klass><br /> <global name="B" module="zope.fssync.doctest"/><br /> </klass><br /> <attributes><br /> <attribute name="data"><br /> <string>data of b</string><br /> </attribute><br /> <attribute name="extra"><br /> <string>extra of b</string><br /> </attribute><br /> </attributes><br /> </object><br /> </pickle><br /> <BLANKLINE><br /><br />After the registration of the necessary generators we can reimport the serialized data from the repository:<br /><br /> >>> component.provideUtility(synchronizer.FileGenerator(),<br /> ... provides=interfaces.IFileGenerator)<br /><br /> >>> target = {}<br /> >>> commit = task.Commit(synchronizer.getSynchronizer, snarf)<br /> >>> commit.perform(target, 'root', 'test')<br /> >>> sorted(target.keys())<br /> ['root']<br /> >>> sorted(target['root'].keys())<br /> ['a', 'b']<br /><br /> >>> target['root']['a'].data<br /> 'data of a'<br /><br /> >>> target['root']['b'].extra<br /> 'extra of b'<br /><br />If we want to commit the data back into the original place we must check whether the repository is still consistent with the original content. We modify the objects in place to see what happens:<br /><br /> >>> check = task.Check(synchronizer.getSynchronizer, snarf)<br /> >>> check.check(root, '', 'test')<br /> >>> check.errors()<br /> []<br /><br /> >>> root['a'].data = 'overwritten'<br /> >>> root['b'].extra = 'overwritten'<br /><br /> >>> check = task.Check(synchronizer.getSynchronizer, snarf)<br /> >>> check.check(root, '', 'test')<br /> >>> check.errors()<br /> ['test/a', 'test/b']<br /><br /> >>> commit.perform(root, '', 'test')<br /> >>> sorted(root.keys())<br /> ['a', 'b']<br /> >>> root['a'].data<br /> 'data of a'<br /> >>> root['b'].extra<br /> 'extra of b'<br /><br /> >>> del root['a']<br /> >>> commit.perform(root, '', 'test')<br /> >>> sorted(root.keys())<br /> ['a', 'b']<br /><br /> >>> del root['b']<br /> >>> commit.perform(root, '', 'test')<br /> >>> sorted(root.keys())<br /> ['a', 'b']<br /><br /> >>> del root['a']<br /> >>> del root['b']<br /> >>> commit.perform(root, '', 'test')<br /> >>> sorted(root.keys())<br /> ['a', 'b']<br /><br />Pickling<br /><br />In many data structures, large, complex objects are composed of smaller objects. These objects are typically stored in one of two ways:<br /><br /> 1. The smaller objects are stored inside the larger object.<br /> 2. The smaller objects are allocated in their own location, and the larger object stores references to them.<br /><br />In case 1 the object is self-contained and can be pickled completely. This is the default behavior of the fssync pickler:<br /><br /> >>> pickler = interfaces.IPickler([42])<br /> >>> pickler<br /> <zope.fssync.pickle.XMLPickler object at ...><br /> >>> print pickler.dumps()<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <list><br /> <int>42</int><br /> </list><br /> </pickle><br /> <BLANKLINE><br /><br />Case 2 is more complex since the pickler has to take persistent references into account.<br /><br /> >>> class Complex(object):<br /> ... def __init__(self, part1, part2):<br /> ... self.part1 = part1<br /> ... self.part2 = part2<br /><br />Everthing here depends on the definition of what we consider to be an intrinsic reference. In the examples above we simply considered all objects as intrinsic.<br /><br /> >>> from zope.fssync import pickle<br /> >>> c = root['c'] = Complex(a, b)<br /> >>> stream = StringIO()<br /> >>> print interfaces.IPickler(c).dumps()<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <initialized_object><br /> <klass><br /> <global id="o0" name="_reconstructor" module="copy_reg"/><br /> </klass><br /> <arguments><br /> <tuple><br /> <global name="Complex" module="zope.fssync.doctest"/><br /> <global id="o1" name="object" module="__builtin__"/><br /> <none/><br /> </tuple><br /> </arguments><br /> <state><br /> <dictionary><br /> <item key="part1"><br /> <object><br /> <klass><br /> <global name="A" module="zope.fssync.doctest"/><br /> </klass><br /> <attributes><br /> <attribute name="data"><br /> <string>data of a</string><br /> </attribute><br /> </attributes><br /> </object><br /> </item><br /> <item key="part2"><br /> <object><br /> <klass><br /> <global name="B" module="zope.fssync.doctest"/><br /> </klass><br /> <attributes><br /> <attribute name="data"><br /> <string>data of b</string><br /> </attribute><br /> <attribute name="extra"><br /> <string>overwritten</string><br /> </attribute><br /> </attributes><br /> </object><br /> </item><br /> </dictionary><br /> </state><br /> </initialized_object><br /> </pickle><br /> <BLANKLINE><br /><br />In order to use persistent references we must define a PersistentIdGenerator for our pickler, which determines whether an object should be pickled completely or only by reference:<br /><br /> >>> class PersistentIdGenerator(object):<br /> ... interface.implements(interfaces.IPersistentIdGenerator)<br /> ... component.adapts(interfaces.IPickler)<br /> ... def __init__(self, pickler):<br /> ... self.pickler = pickler<br /> ... def id(self, obj):<br /> ... if isinstance(obj, Complex):<br /> ... return None<br /> ... return globalIds.getId(obj)<br /><br /> >>> component.provideAdapter(PersistentIdGenerator)<br /><br /> >>> globalIds.register(a)<br /> 1<br /> >>> globalIds.register(b)<br /> 2<br /> >>> globalIds.register(root)<br /> 3<br /><br /> >>> xml = interfaces.IPickler(c).dumps()<br /> >>> print xml<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <object><br /> <klass><br /> <global name="Complex" module="zope.fssync.doctest"/><br /> </klass><br /> <attributes><br /> <attribute name="part1"><br /> <persistent> <string>1</string> </persistent><br /> </attribute><br /> <attribute name="part2"><br /> <persistent> <string>2</string> </persistent><br /> </attribute><br /> </attributes><br /> </object><br /> </pickle><br /> <BLANKLINE><br /><br />The persistent ids can be loaded if we define and register a IPersistentIdLoader adapter first:<br /><br /> >>> class PersistentIdLoader(object):<br /> ... interface.implements(interfaces.IPersistentIdLoader)<br /> ... component.adapts(interfaces.IUnpickler)<br /> ... def __init__(self, unpickler):<br /> ... self.unpickler = unpickler<br /> ... def load(self, id):<br /> ... global globalIds<br /> ... return globalIds.resolve(id)<br /><br /> >>> component.provideAdapter(PersistentIdLoader)<br /> >>> c2 = interfaces.IUnpickler(None).loads(xml)<br /> >>> c2.part1 == a<br /> True<br /><br />Annotations, Extras, and Metadata<br /><br />Complex objects often combine metadata and content data in various ways. The fssync package allows to distinguish between file content, extras, annotations, and fssync specific metadata:<br /><br /> * The file content or body is directly stored in a corresponding file.<br /> * The extras are object attributes which are part of the object but not part of the file content. They are typically store in extra files.<br /> * Annotations are content related metadata which can be stored as attribute annotations or outside the object itself. They are typically stored in seperate pickles for each annotation namespace.<br /> * Metadata directly related to fssync are stored in Entries.xml files.<br /><br />Where exactly these aspects are stored is defined in the synchronization format. The default format uses a @@Zope directory with subdirectories for object extras and annotations. These @@Zope directories also contain an Entries.xml metadata file which defines the following attributes:<br /><br /> *<br /><br /> id: the system id of the object, in Zope typically a traversal path<br /> *<br /><br /> name: the filename of the serialized object<br /> *<br /><br /> factory: the factory of the object, typically a dotted name of a class<br /> *<br /><br /> type: a type identifier for pickled objects without factory<br /> *<br /><br /> provides: directly provided interfaces of the object<br /> *<br /><br /> key: the original name in the content space which is used<br /><br /> in cases where the repository is not able to store this key unambigously<br /><br /> *<br /><br /> binary: a flag that prevents merging of binary data<br /> *<br /><br /> flag: a status flag with the values 'added' or 'removed'<br /><br />In part the metadata have to be delivered by the synchronizer. The base synchronizer, for instance, returns the directly provided interfaces of an object as part of it's metadata:<br /><br /> >>> class IMarkerInterface(interface.Interface):<br /> ... pass<br /> >>> interface.directlyProvides(a, IMarkerInterface)<br /> >>> pprint(synchronizer.Synchronizer(a).metadata())<br /> {'factory': 'zope.fssync.doctest.A',<br /> 'provides': 'zope.fssync.doctest.IMarkerInterface'}<br /><br />The setmetadata method can be used to write metadata back to an object. Which metadata are consumed is up to the synchronizer:<br /><br /> >>> metadata = {'provides': 'zope.fssync.doctest.IMarkerInterface'}<br /> >>> synchronizer.Synchronizer(b).setmetadata(metadata)<br /> >>> [x for x in interface.directlyProvidedBy(b)]<br /> [<InterfaceClass zope.fssync.doctest.IMarkerInterface>]<br /><br />In order to serialize annotations we must first provide a ISynchronizableAnnotations adapter:<br /><br /> >>> snarf = repository.SnarfRepository(StringIO())<br /> >>> checkout = task.Checkout(synchronizer.getSynchronizer, snarf)<br /><br /> >>> from zope import annotation<br /> >>> from zope.annotation.attribute import AttributeAnnotations<br /> >>> component.provideAdapter(AttributeAnnotations)<br /> >>> class IAnnotatableSample(interface.Interface):<br /> ... pass<br /> >>> class AnnotatableSample(object):<br /> ... interface.implements(IAnnotatableSample,<br /> ... annotation.interfaces.IAttributeAnnotatable)<br /> ... data = 'Main file content'<br /> ... extra = None<br /> >>> sample = AnnotatableSample()<br /><br /> >>> class ITestAnnotations(interface.Interface):<br /> ... a = interface.Attribute('A')<br /> ... b = interface.Attribute('B')<br /> >>> import persistent<br /> >>> class TestAnnotations(persistent.Persistent):<br /> ... interface.implements(ITestAnnotations,<br /> ... annotation.interfaces.IAnnotations)<br /> ... component.adapts(IAnnotatableSample)<br /> ... def __init__(self):<br /> ... self.a = None<br /> ... self.b = None<br /><br /> >>> component.provideAdapter(synchronizer.SynchronizableAnnotations)<br /><br /> >>> from zope.annotation.factory import factory<br /> >>> component.provideAdapter(factory(TestAnnotations))<br /> >>> ITestAnnotations(sample).a = 'annotation a'<br /> >>> ITestAnnotations(sample).a<br /> 'annotation a'<br /> >>> sample.extra = 'extra'<br /><br />Without a special serializer the annotations are pickled since the annotations are stored in the __annotions__ attribute:<br /><br /> >>> root = dict()<br /> >>> root['test'] = sample<br /> >>> checkout.perform(root, 'test')<br /> >>> print snarf.stream.getvalue()<br /> 00000197 @@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="__builtin__.dict"<br /> factory="__builtin__.dict"<br /> /><br /> </entries><br /> 00000182 test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.AnnotatableSample"<br /> /><br /> </entries><br /> 00001929 test/test<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <object><br /> <klass><br /> <global name="AnnotatableSample" module="zope.fssync.doctest"/><br /> </klass><br /> ...<br /> </attributes><br /> </object><br /> </pickle><br /> <BLANKLINE><br /><br />If we provide a directory serializer for annotations and extras we get a file for each extra attribute and annotation namespace.<br /><br /> >>> component.provideUtility(<br /> ... synchronizer.DirectorySynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(synchronizer.Extras))<br /><br /> >>> component.provideUtility(<br /> ... synchronizer.DirectorySynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(<br /> ... synchronizer.SynchronizableAnnotations))<br /><br />Since the annotations are already handled by the Synchronizer base class we only need to specify the extra attribute here:<br /><br /> >>> class SampleFileSynchronizer(synchronizer.Synchronizer):<br /> ... interface.implements(interfaces.IFileSynchronizer)<br /> ... def dump(self, writeable):<br /> ... writeable.write(self.context.data)<br /> ... def extras(self):<br /> ... return synchronizer.Extras(extra=self.context.extra)<br /> ... def load(self, readable):<br /> ... self.context.data = readable.read()<br /> >>> component.provideUtility(SampleFileSynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(AnnotatableSample))<br /><br /> >>> interface.directlyProvides(sample, IMarkerInterface)<br /> >>> root['test'] = sample<br /> >>> checkout.perform(root, 'test')<br /> >>> print snarf.stream.getvalue()<br /> 00000197 @@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="__builtin__.dict"<br /> factory="__builtin__.dict"<br /> /><br /> </entries><br /> 00000182 test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.AnnotatableSample"<br /> /><br /> </entries><br /> 00001929 test/test<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> <object><br /> <klass><br /> <global name="AnnotatableSample" module="zope.fssync.doctest"/><br /> </klass><br /> <attributes><br /> <attribute name="__annotations__"><br /> ...<br /> </attribute><br /> <attribute name="extra"><br /> <string>extra</string><br /> </attribute><br /> </attributes><br /> </object><br /> </pickle><br /> 00000197 @@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="__builtin__.dict"<br /> factory="__builtin__.dict"<br /> /><br /> </entries><br /> 00000296 test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="test"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.AnnotatableSample"<br /> factory="zope.fssync.doctest.AnnotatableSample"<br /> provides="zope.fssync.doctest.IMarkerInterface"<br /> /><br /> </entries><br /> 00000211 test/@@Zope/Annotations/test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="zope.fssync.doctest.TestAnnotations"<br /> keytype="__builtin__.str"<br /> type="zope.fssync.doctest.TestAnnotations"<br /> /><br /> </entries><br /> 00000617 test/@@Zope/Annotations/test/zope.fssync.doctest.TestAnnotations<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle><br /> ...<br /> </pickle><br /> 00000161 test/@@Zope/Extra/test/@@Zope/Entries.xml<br /> <?xml version='1.0' encoding='utf-8'?><br /> <entries><br /> <entry name="extra"<br /> keytype="__builtin__.str"<br /> type="__builtin__.str"<br /> /><br /> </entries><br /> 00000082 test/@@Zope/Extra/test/extra<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <pickle> <string>extra</string> </pickle><br /> 00000017 test/test<br /> Main file content<br /><br />The annotations and extras can of course also be deserialized. The default deserializer handles both cases:<br /><br /> >>> target = {}<br /> >>> commit = task.Commit(synchronizer.getSynchronizer, snarf)<br /> >>> commit.perform(target, 'root', 'test')<br /> >>> result = target['root']['test']<br /> >>> result.extra<br /> 'extra'<br /> >>> ITestAnnotations(result).a<br /> 'annotation a'<br /><br />Since we use an IDirectorySynchronizer each extra attribute and annotation namespace get's it's own file:<br /><br /> >>> for path in sorted(snarf.iterPaths()):<br /> ... print path<br /> @@Zope/Entries.xml<br /> test/@@Zope/Annotations/test/@@Zope/Entries.xml<br /> test/@@Zope/Annotations/test/zope.fssync.doctest.TestAnnotations<br /> test/@@Zope/Entries.xml<br /> test/@@Zope/Extra/test/@@Zope/Entries.xml<br /> test/@@Zope/Extra/test/extra<br /> test/test<br /><br />The number of files can be reduced if we provide the default synchronizer which uses a single file for all annotations and a single file for all extras:<br /><br /> >>> component.provideUtility(<br /> ... synchronizer.DefaultSynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(synchronizer.Extras))<br /><br /> >>> component.provideUtility(<br /> ... synchronizer.DefaultSynchronizer,<br /> ... interfaces.ISynchronizerFactory,<br /> ... name=synchronizer.dottedname(<br /> ... synchronizer.SynchronizableAnnotations))<br /><br /> >>> root['test'] = sample<br /> >>> snarf = repository.SnarfRepository(StringIO())<br /> >>> checkout.repository = snarf<br /> >>> checkout.perform(root, 'test')<br /> >>> for path in sorted(snarf.iterPaths()):<br /> ... print path<br /> @@Zope/Entries.xml<br /> test/@@Zope/Annotations/test<br /> test/@@Zope/Entries.xml<br /> test/@@Zope/Extra/test<br /> test/test<br /><br />The annotations and extras can of course also be deserialized. The default deserializer handles both<br /><br /> >>> target = {}<br /> >>> commit = task.Commit(synchronizer.getSynchronizer, snarf)<br /> >>> commit.perform(target, 'root', 'test')<br /> >>> result = target['root']['test']<br /> >>> result.extra<br /> 'extra'<br /> >>> ITestAnnotations(result).a<br /> 'annotation a'<br /> >>> [x for x in interface.directlyProvidedBy(result)]<br /> [<InterfaceClass zope.fssync.doctest.IMarkerInterface>]<br /><br />#md5=014745b4405685649ddfa547ba6569e7

Requirements: No special requirements
Platforms: *nix, Linux
Keyword: Adapter Annotations Class Content Default Format Fxml Gtgtgt Import Ltattributesgt Ltentriesgt Ltklassgt Ltobjectgt Ltpicklegt Metadata Object Objects References Test
Users rating: 0/10

License: Freeware Size: 71.68 KB
USER REVIEWS
More Reviews or Write Review


ZOPE.FSSYNC RELATED
Miscellaneous  -  Class with default method handler 1.0
This script is a class whose objects can handle undefined method calls, passing them on to a default handler.
 
Development Tools  -  get_non_default_value 1.0
get_non_default_value - get the list of which have different values than the default format: [fields,values,ui_type] = get_non_default_value( ui_handle ) input: ui_handle - a graphic handle of any type output: fields,values - pairs of field name...
10 KB  
Modules  -  Better Formats 6.x-1.2
Better formats is a module to add more flexibility to Drupal's core input format system.Features * Set the default format per role. * Set the default format per content type. * Control allowed formats per content type. * Hide format tips. * Hide...
20.48 KB  
Modules  -  Create related content 6.x-1.1
I am planning an extended world trip, so I am looking for co-maintainers or a new maintainer to help out. No upgrade path to Drupal 7 has been started yet. If no response to a request is given after a few weeks, guide the web masters here to...
30.72 KB  
Network & Internet  -  Bricolage 1.10.3
Bricolage, an open-source enterprise-class content management system, greatly simplifies the complex tasks of creating, publishing, and managing the vast libraries of content essential to any organization. With advanced features such as...
2.7 MB  
Libraries  -  Class::Std::Utils 0.0.2
Class::Std::Utils is a Perl module for utility subroutines for building "inside-out" objects. SYNOPSIS use Class::Std::Utils; # Constructor for anonymous scalars... my $new_object = bless anon_scalar(), $class; # Convert an object...
5.12 KB  
Libraries  -  PD4ML. HTML to PDF converter for Java 3.8.0
PD4ML is a powerful PDF generating tool uses HTML and CSS as page layout and content definition format. Written in 100% pure Java, it allows users to easily add PDF generation functionality to end products. PD4ML is encapsulated in an...
 
Registry Tools  -  ScreenMat 1.0
ScreenMat... This application allows users to change the default format that screen shots are saved in. ScreenMat allows you to change your default screen shot format to PDF, PNG, JPG or GIF.
 
Unit Conversion Tools  -  Free EZdo Word to Pdf Converter 4.9
EZdo Word to Pdf Converter allows you to convert hundreds of windows printable documents, such as word (doc,docx,docm), rtf to searchable pdf (as default format, as text format)document. The converter can be used as a PDF writer or PDF creator...
9.88 MB  
Utilities  -  EZ Word to Pdf Converter Free 6.1
EZ Word to Pdf Converter Free allows you to convert hundreds of windows printable documents, such as word (doc,docx,docm), rtf to searchable pdf (as default format, as text format)document. The converter can be used as a PDF writer or PDF creator...
3.21 MB  
NEW DOWNLOADS IN LINUX SOFTWARE, PROGRAMMING
Linux Software  -  EasyEDA PCB Designer for Linux 2.0.0
EasyEDA, a great web based EDA(Electronics Design Automation) tool, online PCB tool, online PCB software for electronics engineers, educators, students, makers and enthusiasts. Theres no need to install any software. Just open EasyEDA in any...
34.4 MB  
Linux Software  -  wpCache® WordPress HTTP Cache 1.9
wpCache® is a high-performance, distributed object, caching system application, generic in nature, but intended for use in speeding up dynamic web applications, by decreasing database load time. wpCache® decreases dramatically the page...
3.51 MB  
Linux Software  -  Polling Autodialer Software 3.4
ICTBroadcast Auto Dialer software has a survey campaign for telephone surveys and polls. This auto dialer software automatically dials a list of numbers and asks them a set of questions that they can respond to, by using their telephone keypad....
488 B  
Linux Software  -  Total Video Converter Mac Free 3.5.5
Total Video Converter Mac Free developed by EffectMatrix Ltd is the official legal version of Total Video Converter which was a globally recognized brand since 2006. Total Video Converter Mac Free is a free but powerful all-in-one video...
17.7 MB  
Linux Software  -  Skeith mod_log_sql Analyzer 2.10beta2
Skeith is a php based front end for analyzing logs for Apache using mod_log_sql.
47.5 KB  
Programming  -  Cedalion for Linux 0.2.6
Cedalion is a programming language that allows its users to add new abstractions and define (and use) internal DSLs. Its innovation is in the fact that it uses projectional editing to allow the new abstractions to have no syntactic limitations.
471.04 KB  
Programming  -  Math::GMPf 0.29
Math::GMPf - perl interface to the GMP library's floating point (mpf) functions.
30.72 KB  
Programming  -  Net::Wire10 1.08
Net::Wire10 is a Pure Perl connector that talks to Sphinx, MySQL and Drizzle servers. Net::Wire10 implements the low-level network protocol, alias the MySQL wire protocol version 10, necessary for talking to one of the aforementioned...
30.72 KB  
Programming  -  logilab-common 0.56.2
a bunch of modules providing low level functionnalities shared among some python projects devel Please note that some of the modules have some extra dependencies. For instance, logilab.common.db will require a db-api 2.0 compliant...
174.08 KB  
Programming  -  OpenSSL for linux 1.0.0a
The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well as a...
3.83 MB