[Zope-CVS] SVN: PluginRegistry/trunk/ Added support for exporting /
importing registry via GenericSetup.
Tres Seaver
tseaver at palladion.com
Fri Nov 4 16:34:10 EST 2005
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
More information about the Zope-CVS
mailing list