[CMF-checkins] SVN: CMF/trunk/CMFTopic/ Add beginnings of support
for export/import of topic criteria.
Tres Seaver
tseaver at palladion.com
Sun Nov 20 15:44:35 EST 2005
Log message for revision 40278:
Add beginnings of support for export/import of topic criteria.
Changed:
A CMF/trunk/CMFTopic/exportimport.py
A CMF/trunk/CMFTopic/tests/test_exportimport.py
A CMF/trunk/CMFTopic/xml/
A CMF/trunk/CMFTopic/xml/criteria.xml
-=-
Added: CMF/trunk/CMFTopic/exportimport.py
===================================================================
--- CMF/trunk/CMFTopic/exportimport.py 2005-11-20 18:34:48 UTC (rev 40277)
+++ CMF/trunk/CMFTopic/exportimport.py 2005-11-20 20:44:35 UTC (rev 40278)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup export / import support for topics / criteria.
+
+$Id$
+"""
+from xml.dom.minidom import parseString
+
+from Acquisition import Implicit
+from zope.interface import implements
+
+from Products.GenericSetup.interfaces import IFilesystemExporter
+from Products.GenericSetup.interfaces import IFilesystemImporter
+from Products.GenericSetup.content import FolderishExporterImporter
+
+try:
+ from Products.GenericSetup.utils import PageTemplateResource
+except ImportError: # BBB: no egg support
+ from Products.PageTemplates.PageTemplateFile \
+ import PageTemplateFile as PageTemplateResource
+
+
+class TopicExportImport(FolderishExporterImporter):
+ """ Dump topic criteria to / from an XML file.
+ """
+ implements(IFilesystemExporter, IFilesystemImporter)
+
+ encoding = None
+ _FILENAME = 'criteria.xml'
+ _ROOT_TAGNAME = 'criteria'
+
+ def __init__(self, context):
+ self.context = context
+
+ def listExportableItems(self):
+ """ See IFilesystemExporter.
+ """
+ criteria_metatypes = self.context._criteria_metatype_ids()
+ return [x for x in FolderishExporterImporter.listExportableItems(self)
+ if x[1].meta_type not in criteria_metatypes]
+
+ def export(self, export_context, subdir, root=False):
+ """ See IFilesystemExporter.
+ """
+ FolderishExporterImporter.export(self, export_context, subdir, root)
+ template = PageTemplateResource('xml/%s' % self._FILENAME,
+ globals()).__of__(self.context)
+ export_context.writeDataFile('%s/criteria.xml' % self.context.getId(),
+ template(info=self._getExportInfo()),
+ 'text/xml',
+ subdir,
+ )
+
+ def import_(self, import_context, subdir, root=False):
+ """ See IFilesystemImporter
+ """
+ return
+ FolderishExporterImporter.import_(self, import_context, subdir, root)
+
+ self.encoding = import_context.getEncoding()
+
+ if import_context.shouldPurge():
+ self._purgeContext()
+
+ data = import_context.readDataFile('%s/criteria.xml'
+ % self.context.getId(),
+ subdir)
+
+ if data is not None:
+
+ dom = parseString(data)
+ root = dom.firstChild
+ assert root.tagName == self._ROOT_TAGNAME
+
+ self.context.title = self._getNodeAttr(root, 'title', None)
+ self._updateFromDOM(root)
+
+ def _getNodeAttr(self, node, attrname, default=None):
+ attr = node.attributes.get(attrname)
+ if attr is None:
+ return default
+ value = attr.value
+ if isinstance(value, unicode) and self.encoding is not None:
+ value = value.encode(self.encoding)
+ return value
+
+ def _purgeContext(self):
+ return
+ context = self.context
+ criterion_ids = context.objectIds(context._criteria_metatype_ids())
+ for criterion_id in criterion_ids:
+ self.context._delObject(criterion_id)
+
+ def _updateFromDOM(self, root):
+ return
+ for group in root.getElementsByTagName('group'):
+ group_id = self._getNodeAttr(group, 'group_id', None)
+ predicate = self._getNodeAttr(group, 'predicate', None)
+ title = self._getNodeAttr(group, 'title', None)
+ description = self._getNodeAttr(group, 'description', None)
+ active = self._getNodeAttr(group, 'active', None)
+
+ self.context.addGroup(group_id,
+ predicate,
+ title,
+ description,
+ active == 'True',
+ )
+ def _getExportInfo(self):
+ context = self.context
+ criterion_info = []
+
+ for criterion_id, criterion in context.objectItems(
+ context._criteria_metatype_ids()):
+
+ # SortCriterion stashes the 'field' as 'index'.
+ field = getattr(criterion, 'index', criterion.field)
+
+ info = {'criterion_id': criterion_id,
+ 'type': criterion.meta_type,
+ 'field': field,
+ 'attributes': []
+ }
+
+ attributes = info['attributes']
+ for attrname in criterion.editableAttributes():
+ attributes.append((attrname, getattr(criterion, attrname)))
+
+ criterion_info.append(info)
+
+ return {'criteria': criterion_info,
+ }
+
Property changes on: CMF/trunk/CMFTopic/exportimport.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFTopic/tests/test_exportimport.py
===================================================================
--- CMF/trunk/CMFTopic/tests/test_exportimport.py 2005-11-20 18:34:48 UTC (rev 40277)
+++ CMF/trunk/CMFTopic/tests/test_exportimport.py 2005-11-20 20:44:35 UTC (rev 40278)
@@ -0,0 +1,164 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Unit tests for GenericSetup export / import support for topics / criteria.
+
+$Id$
+"""
+import unittest
+
+from DateTime.DateTime import DateTime
+
+from Products.GenericSetup.tests.conformance \
+ import ConformsToIFilesystemExporter
+from Products.GenericSetup.tests.conformance \
+ import ConformsToIFilesystemImporter
+from Products.GenericSetup.tests.common import SecurityRequestTest
+from Products.GenericSetup.tests.common import DOMComparator
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
+
+_DATE_STR = '2005-11-20T12:00:00Z'
+_CRITERIA_DATA = (
+ ('a', 'String Criterion', {'value': 'A'}),
+ ('b', 'List Criterion', {'value': ('B', 'b'), 'operator': 'or'}),
+ ('c', 'Integer Criterion', {'value': 3, 'direction': 'min'}),
+ ('d', 'Friendly Date Criterion', {'value': DateTime(_DATE_STR),
+ 'operation': 'min', 'daterange': 'old'}),
+ ('e', 'Sort Criterion', {'reversed': 0}),
+)
+
+class TopicExportImportTests(SecurityRequestTest,
+ DOMComparator,
+ ConformsToIFilesystemExporter,
+ ConformsToIFilesystemImporter,
+ ):
+
+ def _getTargetClass(self):
+ from Products.CMFTopic.exportimport import TopicExportImport
+ return TopicExportImport
+
+ def _makeOne(self, context, *args, **kw):
+ return self._getTargetClass()(context, *args, **kw)
+
+ def _makeTopic(self, id, with_criteria=False):
+ from Products.CMFTopic.Topic import Topic
+ topic = Topic(id)
+
+ if with_criteria:
+ for field, c_type, attrs in _CRITERIA_DATA:
+ topic.addCriterion(field, c_type)
+ criterion = topic.getCriterion(field)
+ criterion.edit(**attrs)
+
+ return topic
+
+ def test_listExportableItems(self):
+ topic = self._makeTopic('lEI', False).__of__(self.root)
+ adapter = self._makeOne(topic)
+
+ self.assertEqual(len(adapter.listExportableItems()), 0)
+ topic.addCriterion('field_a', 'String Criterion')
+ self.assertEqual(len(adapter.listExportableItems()), 0)
+
+ def test__getExportInfo_empty(self):
+ topic = self._makeTopic('empty', False).__of__(self.root)
+ adapter = self._makeOne(topic)
+
+ info = adapter._getExportInfo()
+ self.assertEqual(len(info['criteria']), 0)
+
+ def test_export_empty(self):
+ topic = self._makeTopic('empty', False).__of__(self.root)
+ adapter = self._makeOne(topic)
+
+ context = DummyExportContext(topic)
+ adapter.export(context, 'test', False)
+
+ self.assertEqual( len( context._wrote ), 2 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'test/empty/.objects' )
+ self.assertEqual( text, '' )
+ self.assertEqual( content_type, 'text/comma-separated-values' )
+
+ filename, text, content_type = context._wrote[ 1 ]
+ self.assertEqual( filename, 'test/empty/criteria.xml' )
+ self._compareDOM( text, _EMPTY_TOPIC_CRITERIA )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test__getExportInfo_with_criteria(self):
+ topic = self._makeTopic('with_criteria', True).__of__(self.root)
+ adapter = self._makeOne(topic)
+
+ info = adapter._getExportInfo()
+ self.assertEqual(len(info['criteria']), len(_CRITERIA_DATA))
+
+ for found, expected in zip(info['criteria'], _CRITERIA_DATA):
+ self.assertEqual(found['criterion_id'], 'crit__%s' % expected[0])
+ self.assertEqual(found['type'], expected[1])
+
+ if 0 and expected[0] == 'e': # field is None for SortCriterion
+ self.assertEqual(found['field'], None)
+ expected_attributes = expected[2].copy()
+ expected_attributes['index'] = expected[0]
+ self.assertEqual(dict(found['attributes']), expected_attributes)
+ else:
+ self.assertEqual(found['field'], expected[0])
+ self.assertEqual(dict(found['attributes']), expected[2])
+
+ def test_export_with_string_criterion(self):
+ topic = self._makeTopic('with_string', False).__of__(self.root)
+ data = _CRITERIA_DATA[0]
+ topic.addCriterion(data[0], data[1])
+ topic.getCriterion(data[0]).edit(**data[2])
+ adapter = self._makeOne(topic)
+
+ context = DummyExportContext(topic)
+ adapter.export(context, 'test', False)
+
+ self.assertEqual( len( context._wrote ), 2 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'test/with_string/.objects' )
+ self.assertEqual( text, '' )
+ self.assertEqual( content_type, 'text/comma-separated-values' )
+
+ filename, text, content_type = context._wrote[ 1 ]
+ self.assertEqual( filename, 'test/with_string/criteria.xml' )
+ self._compareDOM( text, _STRING_TOPIC_CRITERIA )
+ self.assertEqual( content_type, 'text/xml' )
+
+_EMPTY_TOPIC_CRITERIA = """\
+<?xml version="1.0" ?>
+<criteria>
+</criteria>
+"""
+
+_STRING_TOPIC_CRITERIA = """\
+<?xml version="1.0" ?>
+<criteria>
+ <criterion
+ criterion_id="crit__a"
+ type="String Criterion"
+ field="a">
+ <attribute name="value" value="A" />
+ </criterion>
+</criteria>
+"""
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(TopicExportImportTests),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Property changes on: CMF/trunk/CMFTopic/tests/test_exportimport.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFTopic/xml/criteria.xml
===================================================================
--- CMF/trunk/CMFTopic/xml/criteria.xml 2005-11-20 18:34:48 UTC (rev 40277)
+++ CMF/trunk/CMFTopic/xml/criteria.xml 2005-11-20 20:44:35 UTC (rev 40278)
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<criteria xmlns:tal="http://xml.zope.org/namespaces/tal"
+ tal:define="info options/info;
+ "
+>
+ <criterion criterion_id="GROUP_ID"
+ type="PREDICATE"
+ field="TITLE"
+ tal:repeat="criterion info/criteria"
+ tal:attributes="criterion_id criterion/criterion_id;
+ type criterion/type;
+ field criterion/field;
+ ">
+ <attribute name="NAME" value="VALUE"
+ tal:repeat="attr criterion/attributes"
+ tal:attributes="name python:attr[0];
+ value python:attr[1];
+ " />
+ </criterion>
+</criteria>
Property changes on: CMF/trunk/CMFTopic/xml/criteria.xml
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the CMF-checkins
mailing list