[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