SVN: PluginRegistry/trunk/ Added support for exporting / importing registry via GenericSetup.

Tres Seaver <[email protected]>
Newsgroups gmane.comp.web.zope.public-cvs
Message-ID <[email protected]>
Log message for revision 39896:
  Added support for exporting / importing registry via GenericSetup.
  
  

Changed:
  U   PluginRegistry/trunk/CHANGES.txt
  A   PluginRegistry/trunk/exportimport.py
  A   PluginRegistry/trunk/tests/test_exportimport.py
  A   PluginRegistry/trunk/xml/
  A   PluginRegistry/trunk/xml/pirExport.xml

-=-
Modified: PluginRegistry/trunk/CHANGES.txt
===================================================================
--- PluginRegistry/trunk/CHANGES.txt	2005-11-04 21:09:13 UTC (rev 39895)
+++ PluginRegistry/trunk/CHANGES.txt	2005-11-04 21:34:09 UTC (rev 39896)
@@ -3,6 +3,8 @@
 
   After PluginRegistry-1.0.2
 
+    - Added support for exporting / importing registry via GenericSetup.
+      
     - Saner version name
 
     - Added a new ZMI tab offering a simple overview over active/available

Added: PluginRegistry/trunk/exportimport.py
===================================================================
--- PluginRegistry/trunk/exportimport.py	2005-11-04 21:09:13 UTC (rev 39895)
+++ PluginRegistry/trunk/exportimport.py	2005-11-04 21:34:09 UTC (rev 39896)
@@ -0,0 +1,116 @@
+""" GenericSetup export / import support for PluginRegistry.
+
+$Id$
+"""
+from Persistence import PersistentMapping
+
+from Products.GenericSetup.utils import ExportConfiguratorBase
+from Products.GenericSetup.utils import ImportConfiguratorBase
+from Products.GenericSetup.utils import _getDottedName
+from Products.GenericSetup.utils import _resolveDottedName
+from Products.GenericSetup.utils import CONVERTER
+from Products.GenericSetup.utils import DEFAULT
+from Products.GenericSetup.utils import KEY
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from interfaces.plugins import IPluginRegistry
+
+def _providedBy(obj, iface):
+    try:
+        return iface.providedBy(obj)
+    except AttributeError:
+        return iface.isImplementedBy(obj) # Z2 interfaces
+
+_FILENAME = 'pluginregistry.xml'
+
+def _getRegistry(site):
+    registries = [x for x in site.objectValues()
+                    if _providedBy(x, IPluginRegistry)]
+
+    if len(registries) < 1:
+        raise ValueError, 'No plugin registries'
+
+    if len(registries) > 1:
+        raise ValueError, 'Too many plugin registries'
+
+    return registries[0]
+
+def exportPluginRegistry(context):
+    """ Export plugin registry as an XML file.
+    """
+    registry = _getRegistry(context.getSite())
+    pre = PluginRegistryExporter(registry).__of__(registry)
+    xml = pre.generateXML()
+    context.writeDataFile(_FILENAME, xml, 'text/xml')
+
+    return 'Plugin registry exported.'
+
+def importPluginRegistry(context):
+    """ Import plugin registry from an XML file.
+    """
+    registry = _getRegistry(context.getSite())
+    encoding = context.getEncoding()
+
+    xml = context.readDataFile(_FILENAME)
+    if xml is None:
+        return 'Site properties: Nothing to import.'
+
+    if context.shouldPurge():
+
+        registry._plugin_types = []
+        registry._plugin_type_info = PersistentMapping()
+        registry._plugins = PersistentMapping()
+
+    pir = PluginRegistryImporter(registry, encoding)
+    reg_info = pir.parseXML(xml)
+
+    for info in reg_info['plugin_types']:
+        iface = _resolveDottedName(info['interface'])
+        registry._plugin_types.append(iface)
+        registry._plugin_type_info[iface] = {'id': info['id'],
+                                             'title': info['title'],
+                                             'description': info['description'],
+                                            }
+        registry._plugins[iface] = tuple([x['id'] for x in info['plugins']])
+
+    return 'Plugin registry imported.'
+
+class PluginRegistryExporter(ExportConfiguratorBase):
+
+    def __init__(self, context, encoding=None):
+        ExportConfiguratorBase.__init__(self, None, encoding)
+        self.context = context
+
+    def _getExportTemplate(self):
+        return PageTemplateFile('xml/pirExport.xml', globals())
+
+    def listPluginTypes(self):
+        for info in self.context.listPluginTypeInfo():
+            iface = info['interface']
+            info['interface'] = _getDottedName(iface)
+            info['plugins'] = self.context.listPluginIds(iface)
+            yield info
+
+class PluginRegistryImporter(ImportConfiguratorBase):
+
+    def __init__(self, context, encoding=None):
+        ImportConfiguratorBase.__init__(self, None, encoding)
+        self.context = context
+
+    def _getImportMapping(self):
+
+        return {
+          'plugin-registry':
+            {'plugin-type': {KEY: 'plugin_types', DEFAULT: ()},
+            },
+          'plugin-type':
+            {'id':          {KEY: 'id'},
+             'interface':   {KEY: 'interface'},
+             'title':       {KEY: 'title'},
+             'description': {KEY: 'description'},
+             'plugin':      {KEY: 'plugins', DEFAULT: ()}
+            },
+          'plugin':
+            {'id':          {KEY: 'id'},
+            },
+         }


Property changes on: PluginRegistry/trunk/exportimport.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: PluginRegistry/trunk/tests/test_exportimport.py
===================================================================
--- PluginRegistry/trunk/tests/test_exportimport.py	2005-11-04 21:09:13 UTC (rev 39895)
+++ PluginRegistry/trunk/tests/test_exportimport.py	2005-11-04 21:34:09 UTC (rev 39896)
@@ -0,0 +1,405 @@
+""" Unit tests for GenericSetup-based export / import of PluginRegistry.
+
+$Id$
+"""
+import unittest
+
+try:
+    import Products.GenericSetup
+except ImportError:  # No GenericSetup, so no tests
+
+    print 'XXXX:  No GenericSetup!'
+    def test_suite():
+        return unittest.TestSuite()
+
+else:
+    from Products.GenericSetup.tests.common import BaseRegistryTests
+    from Products.GenericSetup.tests.common import DummyExportContext
+    from Products.GenericSetup.tests.common import DummyImportContext
+    from Products.GenericSetup.utils import _getDottedName
+
+    from zope.interface import Interface
+    from zope.app.tests.placelesssetup import PlacelessSetup
+
+    class IFoo(Interface):
+        pass
+
+    class IBar(Interface):
+        pass
+
+    _EMPTY_PLUGINREGISTRY_EXPORT = """\
+<?xml version="1.0"?>
+<plugin-registry>
+</plugin-registry>
+"""
+
+    _PLUGIN_TYPE_INFO = (
+      ( IFoo
+      , 'IFoo'
+      , 'foo'
+      , "Some plugin interface"
+      )
+    , ( IBar
+      , 'IBar'
+      , 'bar'
+      , "Another plugin interface"
+      )
+    )
+
+    _NO_PLUGINS_PLUGINREGISTRY_EXPORT = """\
+<?xml version="1.0"?>
+<plugin-registry>
+ <plugin-type
+    id="IFoo"
+    interface="%s"
+    title="foo"
+    description="Some plugin interface">
+ </plugin-type>
+ <plugin-type
+    id="IBar"
+    interface="%s"
+    title="bar"
+    description="Another plugin interface">
+ </plugin-type>
+</plugin-registry>
+""" % (_getDottedName(IFoo), _getDottedName(IBar))
+
+    _NORMAL_PLUGINREGISTRY_EXPORT = """\
+<?xml version="1.0"?>
+<plugin-registry>
+ <plugin-type
+    id="IFoo"
+    interface="%s"
+    title="foo"
+    description="Some plugin interface">
+  <plugin id="foo_plugin_1" />
+  <plugin id="foo_plugin_2" />
+ </plugin-type>
+ <plugin-type
+    id="IBar"
+    interface="%s"
+    title="bar"
+    description="Another plugin interface">
+ </plugin-type>
+</plugin-registry>
+""" % (_getDottedName(IFoo), _getDottedName(IBar))
+
+    class _TestBase(PlacelessSetup, BaseRegistryTests):
+
+        def _initRegistry(self, plugin_type_info=(), plugins={}):
+            from OFS.Folder import Folder
+            from OFS.SimpleItem import SimpleItem
+            from Products.PluginRegistry.PluginRegistry import PluginRegistry
+
+            app = Folder()
+            app.getPhysicalPath = lambda: ()
+            app.getPhysicalRoot = lambda: app
+
+            app._setObject('foo_plugin_1', SimpleItem())
+            app._setObject('foo_plugin_2', SimpleItem())
+
+            registry = PluginRegistry(plugin_type_info)
+            registry._plugins = {} # it is usually lazy
+
+            for plugin_type, registered in plugins.items():
+                registry._plugins[plugin_type] = registered
+
+            app._setObject('plugin_registry', registry)
+            registry = app._getOb('plugin_registry')
+            return app, registry
+
+    class PluginRegistryExporterTests(_TestBase):
+
+        def _getTargetClass(self):
+            from Products.PluginRegistry.exportimport \
+                import PluginRegistryExporter
+            return PluginRegistryExporter
+
+        def test_empty(self):
+
+            app, registry = self._initRegistry()
+            exporter = self._makeOne(registry).__of__(registry)
+            xml = exporter.generateXML()
+
+            self._compareDOM(xml, _EMPTY_PLUGINREGISTRY_EXPORT)
+
+        def test_normal_no_plugins(self):
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO)
+            exporter = self._makeOne(registry).__of__(registry)
+            xml = exporter.generateXML()
+
+            self._compareDOM(xml, _NO_PLUGINS_PLUGINREGISTRY_EXPORT)
+
+        def test_normal_with_plugins(self):
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO,
+                                    plugins={IFoo: ('foo_plugin_1',
+                                                    'foo_plugin_2')},
+                                        )
+            exporter = self._makeOne(registry).__of__(registry)
+            xml = exporter.generateXML()
+
+            self._compareDOM(xml, _NORMAL_PLUGINREGISTRY_EXPORT)
+
+    class Test_exportPluginRegistry(_TestBase):
+
+        def test_empty(self):
+            from Products.PluginRegistry.exportimport \
+                import exportPluginRegistry
+
+            app, registry = self._initRegistry()
+            context = DummyExportContext(app)
+            exportPluginRegistry(context)
+
+            self.assertEqual( len(context._wrote), 1 )
+            filename, text, content_type = context._wrote[0]
+            self.assertEqual(filename, 'pluginregistry.xml')
+            self._compareDOM(text, _EMPTY_PLUGINREGISTRY_EXPORT)
+            self.assertEqual(content_type, 'text/xml')
+
+        def test_normal_no_plugins(self):
+            from Products.PluginRegistry.exportimport \
+                import exportPluginRegistry
+
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO)
+            context = DummyExportContext(app)
+            exportPluginRegistry(context)
+
+            self.assertEqual( len(context._wrote), 1 )
+            filename, text, content_type = context._wrote[0]
+            self.assertEqual(filename, 'pluginregistry.xml')
+            self._compareDOM(text, _NO_PLUGINS_PLUGINREGISTRY_EXPORT)
+            self.assertEqual(content_type, 'text/xml')
+
+        def test_normal_with_plugins(self):
+            from Products.PluginRegistry.exportimport \
+                import exportPluginRegistry
+
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO,
+                                    plugins={IFoo: ('foo_plugin_1',
+                                                    'foo_plugin_2')},
+                                        )
+            context = DummyExportContext(app)
+            exportPluginRegistry(context)
+
+            self.assertEqual( len(context._wrote), 1 )
+            filename, text, content_type = context._wrote[0]
+            self.assertEqual(filename, 'pluginregistry.xml')
+            self._compareDOM(text, _NORMAL_PLUGINREGISTRY_EXPORT)
+            self.assertEqual(content_type, 'text/xml')
+
+    class PluginRegistryImporterTests(_TestBase):
+
+        def _getTargetClass(self):
+            from Products.PluginRegistry.exportimport \
+                import PluginRegistryImporter
+            return PluginRegistryImporter
+
+        def test_parseXML_empty(self):
+
+            app, registry = self._initRegistry()
+            importer = self._makeOne(registry).__of__(registry)
+            reg_info = importer.parseXML(_EMPTY_PLUGINREGISTRY_EXPORT)
+
+            self.assertEqual( len( reg_info['plugin_types'] ), 0 )
+
+        def test_parseXML_normal_no_plugins(self):
+
+            app, registry = self._initRegistry()
+            importer = self._makeOne(registry).__of__(registry)
+            reg_info = importer.parseXML(_NO_PLUGINS_PLUGINREGISTRY_EXPORT)
+
+            self.assertEqual( len( reg_info['plugin_types'] ), 2 )
+
+            info = reg_info['plugin_types'][0]
+            self.assertEqual(info['id'], 'IFoo')
+            self.assertEqual(info['interface'], _getDottedName(IFoo))
+            self.assertEqual(info['title'], 'foo')
+            self.assertEqual(info['description'], 'Some plugin interface')
+            self.assertEqual(len( info['plugins'] ), 0)
+
+            info = reg_info['plugin_types'][1]
+            self.assertEqual(info['id'], 'IBar')
+            self.assertEqual(info['interface'], _getDottedName(IBar))
+            self.assertEqual(info['title'], 'bar')
+            self.assertEqual(info['description'], 'Another plugin interface')
+            self.assertEqual(len( info['plugins'] ), 0 )
+
+        def test_parseXML_normal_with_plugins(self):
+
+            app, registry = self._initRegistry()
+            importer = self._makeOne(registry).__of__(registry)
+            reg_info = importer.parseXML(_NORMAL_PLUGINREGISTRY_EXPORT)
+
+            self.assertEqual(len(reg_info['plugin_types'] ), 2 )
+
+            info = reg_info['plugin_types'][0]
+            self.assertEqual(info['id'], 'IFoo')
+            self.assertEqual(info['interface'], _getDottedName(IFoo))
+            self.assertEqual(info['title'], 'foo')
+            self.assertEqual(info['description'], 'Some plugin interface')
+            plugins = info['plugins']
+            self.assertEqual(len(plugins), 2)
+            self.assertEqual(plugins[0]['id'], 'foo_plugin_1')
+            self.assertEqual(plugins[1]['id'], 'foo_plugin_2')
+
+            info = reg_info['plugin_types'][1]
+            self.assertEqual(info['id'], 'IBar')
+            self.assertEqual(info['interface'], _getDottedName(IBar))
+            self.assertEqual(info['title'], 'bar')
+            self.assertEqual(info['description'], 'Another plugin interface')
+            self.assertEqual(len(info['plugins']), 0 )
+
+    class Test_importPluginRegistry(_TestBase):
+
+        def test_empty_default_purge(self):
+            from Products.PluginRegistry.exportimport \
+                import importPluginRegistry
+
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO,
+                                    plugins={IFoo: ('foo_plugin_1',
+                                                    'foo_plugin_2')},
+                                   )
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+            context = DummyImportContext(app)
+            context._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
+
+            importPluginRegistry(context)
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
+            self.assertRaises(KeyError, registry.listPlugins, IFoo)
+            self.assertRaises(KeyError, registry.listPlugins, IBar)
+
+        def test_empty_explicit_purge(self):
+            from Products.PluginRegistry.exportimport \
+                import importPluginRegistry
+
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO,
+                                    plugins={IFoo: ('foo_plugin_1',
+                                                    'foo_plugin_2')},
+                                   )
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+            context = DummyImportContext(app, True)
+            context._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
+
+            importPluginRegistry(context)
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
+            self.assertRaises(KeyError, registry.listPlugins, IFoo)
+            self.assertRaises(KeyError, registry.listPlugins, IBar)
+
+        def test_empty_skip_purge(self):
+            from Products.PluginRegistry.exportimport \
+                import importPluginRegistry
+
+            app, registry = self._initRegistry(
+                                    plugin_type_info=_PLUGIN_TYPE_INFO,
+                                    plugins={IFoo: ('foo_plugin_1',
+                                                    'foo_plugin_2')},
+                                   )
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+            context = DummyImportContext(app, False)
+            context._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
+
+            importPluginRegistry(context)
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+        def test_normal_no_plugins(self):
+            from Products.PluginRegistry.exportimport \
+                import importPluginRegistry
+
+            app, registry = self._initRegistry()
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
+            self.assertRaises(KeyError, registry.listPlugins, IFoo)
+            self.assertRaises(KeyError, registry.listPlugins, IBar)
+
+            context = DummyImportContext(app, False)
+            context._files['pluginregistry.xml'
+                          ] = _NO_PLUGINS_PLUGINREGISTRY_EXPORT
+
+            importPluginRegistry(context)
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+
+            info = registry.listPluginTypeInfo()[0]
+            self.assertEqual(info['id'], 'IFoo')
+            self.assertEqual(info['title'], 'foo')
+            self.assertEqual(info['description'], 'Some plugin interface')
+
+            info = registry.listPluginTypeInfo()[1]
+            self.assertEqual(info['id'], 'IBar')
+            self.assertEqual(info['title'], 'bar')
+            self.assertEqual(info['description'], 'Another plugin interface')
+
+            self.assertEqual(len(registry.listPlugins(IFoo)), 0)
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+        def test_normal_with_plugins(self):
+            from Products.PluginRegistry.exportimport \
+                import importPluginRegistry
+
+            app, registry = self._initRegistry()
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
+            self.assertRaises(KeyError, registry.listPlugins, IFoo)
+            self.assertRaises(KeyError, registry.listPlugins, IBar)
+
+            context = DummyImportContext(app, False)
+            context._files['pluginregistry.xml'
+                          ] = _NORMAL_PLUGINREGISTRY_EXPORT
+
+            importPluginRegistry(context)
+
+            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
+
+            info = registry.listPluginTypeInfo()[0]
+            self.assertEqual(info['id'], 'IFoo')
+            self.assertEqual(info['title'], 'foo')
+            self.assertEqual(info['description'], 'Some plugin interface')
+
+            info = registry.listPluginTypeInfo()[1]
+            self.assertEqual(info['id'], 'IBar')
+            self.assertEqual(info['title'], 'bar')
+            self.assertEqual(info['description'], 'Another plugin interface')
+
+            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
+            plugins = registry.listPlugins(IFoo)
+            self.assertEqual(plugins[0][0], 'foo_plugin_1')
+            self.assertEqual(plugins[0][1], app._getOb('foo_plugin_1'))
+            self.assertEqual(plugins[1][0], 'foo_plugin_2')
+            self.assertEqual(plugins[1][1], app._getOb('foo_plugin_2'))
+
+            self.assertEqual(len(registry.listPlugins(IBar)), 0)
+
+    def test_suite():
+        return unittest.TestSuite((
+            unittest.makeSuite( PluginRegistryExporterTests ),
+            unittest.makeSuite( PluginRegistryImporterTests ),
+            unittest.makeSuite( Test_exportPluginRegistry ),
+            unittest.makeSuite( Test_importPluginRegistry ),
+           ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: PluginRegistry/trunk/tests/test_exportimport.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: PluginRegistry/trunk/xml/pirExport.xml
===================================================================
--- PluginRegistry/trunk/xml/pirExport.xml	2005-11-04 21:09:13 UTC (rev 39895)
+++ PluginRegistry/trunk/xml/pirExport.xml	2005-11-04 21:34:09 UTC (rev 39896)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<plugin-registry xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <plugin-type
+    id="PLUGIN_TYPE_ID"
+    title="PLUGIN_TYPE_TITLE"
+    description="PLUGIN_TYPE_DESCRIPTION"
+    interface="PLUGIN_TYPE_INTERFACE"
+    tal:repeat="pt context/listPluginTypes"
+    tal:attributes="id pt/id;
+                    title pt/title;
+                    description pt/description;
+                    interface pt/interface;
+                   "
+    >
+  <plugin
+    id="PLUGIN_ID"
+    tal:repeat="plugin_id pt/plugins"
+    tal:attributes="id plugin_id" />
+ </plugin-type>
+</plugin-registry>


Property changes on: PluginRegistry/trunk/xml/pirExport.xml
___________________________________________________________________
Name: svn:eol-style
   + native

_______________________________________________
Zope-CVS maillist  -  [email protected]
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.