[CMF-checkins] SVN: CMF/trunk/ merged yuppie-catalog_setup-redo branch:

Yvo Schubbe y.2005- at wcm-solutions.de
Thu Sep 29 13:56:15 EDT 2005


Log message for revision 38690:
  merged yuppie-catalog_setup-redo branch:
  - added DOM node based sub-framework for XML im- and export
  - added catalog tool setup handlers
  - updated existing profiles
  - removed obsolete code from GenericSetup utils

Changed:
  U   CMF/trunk/CHANGES.txt
  A   CMF/trunk/CMFCalendar/profiles/default/catalog.xml
  U   CMF/trunk/CMFCalendar/setuphandlers.py
  A   CMF/trunk/CMFDefault/profiles/default/catalog.xml
  U   CMF/trunk/CMFDefault/profiles/default/export_steps.xml
  U   CMF/trunk/CMFDefault/profiles/default/import_steps.xml
  A   CMF/trunk/CMFSetup/catalog.py
  A   CMF/trunk/CMFSetup/tests/test_catalog.py
  A   CMF/trunk/GenericSetup/PluginIndexes/
  A   CMF/trunk/GenericSetup/ZCTextIndex/
  A   CMF/trunk/GenericSetup/ZCatalog/
  A   CMF/trunk/GenericSetup/configure.zcml
  U   CMF/trunk/GenericSetup/interfaces.py
  A   CMF/trunk/GenericSetup/testing.py
  U   CMF/trunk/GenericSetup/tests/test_utils.py
  U   CMF/trunk/GenericSetup/utils.py
  D   CMF/trunk/GenericSetup/xml/object_nodes.xml
  D   CMF/trunk/GenericSetup/xml/property_nodes.xml

-=-
Modified: CMF/trunk/CHANGES.txt
===================================================================
--- CMF/trunk/CHANGES.txt	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/CHANGES.txt	2005-09-29 17:56:14 UTC (rev 38690)
@@ -2,6 +2,18 @@
 
   New Features
 
+    - CMFSetup and GenericSetup: Added catalog tool setup handlers.
+      This includes node adapters for PluginIndexes, ZCTextIndex and ZCatalog.
+      Support for additional indexes can be added by providing INodeExporter
+      and INodeImporter adapters. All indexes are cleared by this handler, so
+      please make sure to re-catalog existing content if necessary.
+
+    - GenericSetup.utils: Added new sub-framework for XML im- and export.
+      Instead of using ConfiguratorBase configurators should now implement
+      INodeExporter and INodeImporter. These node adapters should subclass
+      from NodeAdapterBase and mix in ObjectManagerHelpers and / or
+      PropertyManagerHelpers if needed.
+
     - CMFCore.exportimport:  Added framework and interfaces for exporting
       and importing content using the export / import contexts provided by
       GenericSetup.

Copied: CMF/trunk/CMFCalendar/profiles/default/catalog.xml (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/CMFCalendar/profiles/default/catalog.xml)

Modified: CMF/trunk/CMFCalendar/setuphandlers.py
===================================================================
--- CMF/trunk/CMFCalendar/setuphandlers.py	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/CMFCalendar/setuphandlers.py	2005-09-29 17:56:14 UTC (rev 38690)
@@ -17,7 +17,6 @@
 
 from Products.CMFCore.utils import getToolByName
 
-from exceptions import CatalogError
 from exceptions import MetadataError
 
 
@@ -28,27 +27,8 @@
     are implemented for these steps.
     """
     site = context.getSite()
-    ctool = getToolByName(site, 'portal_catalog')
     mdtool = getToolByName(site, 'portal_metadata')
 
-    # Set up a catalog indexes and metadata
-    try:
-        ctool.addIndex('start', 'DateIndex')
-    except CatalogError:
-        pass
-    try:
-        ctool.addIndex('end', 'DateIndex')
-    except CatalogError:
-        pass
-    try:
-        ctool.addColumn('start')
-    except CatalogError:
-        pass
-    try:
-        ctool.addColumn('end')
-    except CatalogError:
-        pass
-
     # Set up a MetadataTool element policy for events
     try:
         _ = str # MetadataTool ist not aware of MessageIDs

Copied: CMF/trunk/CMFDefault/profiles/default/catalog.xml (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/CMFDefault/profiles/default/catalog.xml)

Modified: CMF/trunk/CMFDefault/profiles/default/export_steps.xml
===================================================================
--- CMF/trunk/CMFDefault/profiles/default/export_steps.xml	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/CMFDefault/profiles/default/export_steps.xml	2005-09-29 17:56:14 UTC (rev 38690)
@@ -11,6 +11,17 @@
  
  
  </export-step>
+ <export-step id="catalog"
+              handler="Products.CMFSetup.catalog.exportCatalogTool"
+              title="Catalog Tool">
+  
+  
+  
+  Export catalog tool's sub-objects, indexes and columns.
+ 
+ 
+ 
+ </export-step>
  <export-step id="cookieauth"
               handler="Products.CMFSetup.cookieauth.exportCookieCrumbler"
               title="Cookie Authentication">

Modified: CMF/trunk/CMFDefault/profiles/default/import_steps.xml
===================================================================
--- CMF/trunk/CMFDefault/profiles/default/import_steps.xml	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/CMFDefault/profiles/default/import_steps.xml	2005-09-29 17:56:14 UTC (rev 38690)
@@ -13,6 +13,19 @@
   
  
  </import-step>
+ <import-step id="catalog" version="20050929-01"
+              handler="Products.CMFSetup.catalog.importCatalogTool"
+              title="Catalog Tool">
+  <dependency step="toolset"/>
+  
+  
+  
+  Import catalog tool's sub-objects, indexes and columns.
+ 
+ 
+  
+ 
+ </import-step>
  <import-step id="cookie_authentication"
               version="20050903-01"
               handler="Products.CMFSetup.cookieauth.importCookieCrumbler"

Copied: CMF/trunk/CMFSetup/catalog.py (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/CMFSetup/catalog.py)

Copied: CMF/trunk/CMFSetup/tests/test_catalog.py (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/CMFSetup/tests/test_catalog.py)

Copied: CMF/trunk/GenericSetup/PluginIndexes (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/GenericSetup/PluginIndexes)

Copied: CMF/trunk/GenericSetup/ZCTextIndex (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/GenericSetup/ZCTextIndex)

Copied: CMF/trunk/GenericSetup/ZCatalog (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/GenericSetup/ZCatalog)

Copied: CMF/trunk/GenericSetup/configure.zcml (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/GenericSetup/configure.zcml)

Modified: CMF/trunk/GenericSetup/interfaces.py
===================================================================
--- CMF/trunk/GenericSetup/interfaces.py	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/GenericSetup/interfaces.py	2005-09-29 17:56:14 UTC (rev 38690)
@@ -18,7 +18,8 @@
 from zope.interface import Interface
 
 
-BASE, EXTENSION = range(2)
+BASE, EXTENSION = range(1, 3)
+PURGE, UPDATE = range(1, 3)
 
 
 class IPseudoInterface( Interface ):
@@ -523,3 +524,23 @@
         o If 'ignore_whitespace', then suppress diffs due only to whitespace
           (c.f:  'diff -wbB')
         """
+
+
+class INodeExporter(Interface):
+
+    """Node exporter.
+    """
+
+    def exportNode(doc):
+        """Export the object as a DOM node.
+        """
+
+
+class INodeImporter(Interface):
+
+    """Node importer.
+    """
+
+    def importNode(node, mode=PURGE):
+        """Import the object from the DOM node.
+        """

Copied: CMF/trunk/GenericSetup/testing.py (from rev 38669, CMF/branches/yuppie-catalog_setup-redo/GenericSetup/testing.py)

Modified: CMF/trunk/GenericSetup/tests/test_utils.py
===================================================================
--- CMF/trunk/GenericSetup/tests/test_utils.py	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/GenericSetup/tests/test_utils.py	2005-09-29 17:56:14 UTC (rev 38690)
@@ -17,155 +17,100 @@
 
 import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
-from DateTime.DateTime import DateTime
-from OFS.Folder import Folder
+from xml.dom.minidom import parseString
 
-from common import BaseRegistryTests
+from Products.GenericSetup.interfaces import PURGE, UPDATE
+from Products.GenericSetup.utils import PrettyDocument
 
 
-_NORMAL_PROPERTY_NODES = """\
-  <property name="foo_boolean" type="boolean">True</property>
-  <property name="foo_date" type="date">2000/01/01</property>
-  <property name="foo_float" type="float">1.1</property>
-  <property name="foo_int" type="int">1</property>
-  <property name="foo_lines" type="lines">
-   <element value="Foo"/>
-   <element value="Lines"/></property>
-  <property name="foo_long" type="long">1</property>
-  <property name="foo_string" type="string">Foo String</property>
-  <property name="foo_text" type="text">Foo
-Text</property>
-  <property name="foo_tokens" type="tokens">
-   <element value="Foo"/>
-   <element value="Tokens"/></property>
-  <property name="foo_selection" type="selection"
-            select_variable="foobarbaz">Foo</property>
-  <property name="foo_mselection" type="multiple selection"
-            select_variable="foobarbaz">
-   <element value="Foo"/>
-   <element value="Baz"/></property>
-  <property name="foo_boolean0" type="boolean">0</property>
+_EMPTY_PROPERTY_EXPORT = """\
+<?xml version="1.0"?>
+<dummy>
+ <property name="foo_boolean" type="boolean">False</property>
+ <property name="foo_date" type="date"></property>
+ <property name="foo_float" type="float"></property>
+ <property name="foo_int" type="int"></property>
+ <property name="foo_lines" type="lines"></property>
+ <property name="foo_long" type="long"></property>
+ <property name="foo_string" type="string"></property>
+ <property name="foo_text" type="text"></property>
+ <property name="foo_tokens" type="tokens"/>
+ <property name="foo_selection" select_variable="foobarbaz" \
+type="selection"></property>
+ <property name="foo_mselection" select_variable="foobarbaz" \
+type="multiple selection"/>
+ <property name="foo_boolean0" type="boolean">False</property>
+</dummy>
 """
 
-_FIXED_PROPERTY_NODES = """\
-  <property name="foo_boolean">True</property>
-  <property name="foo_date">2000/01/01</property>
-  <property name="foo_float">1.1</property>
-  <property name="foo_int">1</property>
-  <property name="foo_lines">
-   <element value="Foo"/>
-   <element value="Lines"/></property>
-  <property name="foo_long">1</property>
-  <property name="foo_string">Foo String</property>
-  <property name="foo_text">Foo
-Text</property>
-  <property name="foo_tokens">
-   <element value="Foo"/>
-   <element value="Tokens"/></property>
-  <property name="foo_selection" type="selection"
-            select_variable="foobarbaz">Foo</property>
-  <property name="foo_mselection">
-   <element value="Foo"/>
-   <element value="Baz"/></property>
-  <property name="foo_boolean0">0</property>
-"""
-
-_NORMAL_PROPERTY_INFO = ( { 'id': 'foo_boolean',
-                            'value': True,
-                            'elements': (),
-                            'type': 'boolean',
-                            'select_variable': None },
-                          { 'id': 'foo_date',
-                            'value': DateTime('2000/01/01'),
-                            'elements': (),
-                            'type': 'date',
-                            'select_variable': None },
-                          { 'id': 'foo_float',
-                            'value': 1.1,
-                            'elements': (),
-                            'type': 'float',
-                            'select_variable': None },
-                          { 'id': 'foo_int',
-                            'value': 1,
-                            'elements': (),
-                            'type': 'int',
-                            'select_variable': None },
-                          { 'id': 'foo_lines',
-                            'value': '',
-                            'elements': ('Foo', 'Lines'),
-                            'type': 'lines',
-                            'select_variable': None },
-                          { 'id': 'foo_long',
-                            'value': 1,
-                            'elements': (),
-                            'type': 'long',
-                            'select_variable': None },
-                          { 'id': 'foo_string',
-                            'value': 'Foo String',
-                            'elements': (),
-                            'type': 'string',
-                            'select_variable': None },
-                          { 'id': 'foo_text',
-                            'value': 'Foo\nText',
-                            'elements': (),
-                            'type': 'text',
-                            'select_variable': None },
-                          { 'id': 'foo_tokens',
-                            'value': '',
-                            'elements': ('Foo', 'Tokens'),
-                            'type': 'tokens',
-                            'select_variable': None },
-                          { 'id': 'foo_selection',
-                            'value': 'Foo',
-                            'elements': (),
-                            'type': 'selection',
-                            'select_variable': 'foobarbaz' },
-                          { 'id': 'foo_mselection',
-                            'value': '',
-                            'elements': ('Foo', 'Baz'),
-                            'type': 'multiple selection',
-                            'select_variable': 'foobarbaz' },
-                          { 'id': 'foo_boolean0',
-                            'value': False, # 0 imports as False
-                            'elements': (),
-                            'type': 'boolean',
-                            'select_variable': None },
-                          )
-
 _NORMAL_PROPERTY_EXPORT = """\
 <?xml version="1.0"?>
 <dummy>
-%s
+ <property name="foo_boolean" type="boolean">True</property>
+ <property name="foo_date" type="date">2000/01/01</property>
+ <property name="foo_float" type="float">1.1</property>
+ <property name="foo_int" type="int">1</property>
+ <property name="foo_lines" type="lines">
+  <element value="Foo"/>
+  <element value="Lines"/>
+ </property>
+ <property name="foo_long" type="long">1</property>
+ <property name="foo_string" type="string">Foo String</property>
+ <property name="foo_text" type="text">Foo
+Text</property>
+ <property name="foo_tokens" type="tokens">
+  <element value="Foo"/>
+  <element value="Tokens"/>
+ </property>
+ <property name="foo_selection" select_variable="foobarbaz" \
+type="selection">Foo</property>
+ <property name="foo_mselection" select_variable="foobarbaz" \
+type="multiple selection">
+  <element value="Foo"/>
+  <element value="Baz"/>
+ </property>
+ <property name="foo_boolean0" type="boolean">False</property>
 </dummy>
-""" % _NORMAL_PROPERTY_NODES
+"""
 
 _FIXED_PROPERTY_EXPORT = """\
 <?xml version="1.0"?>
 <dummy>
-%s
+ <property name="foo_boolean">True</property>
+ <property name="foo_date">2000/01/01</property>
+ <property name="foo_float">1.1</property>
+ <property name="foo_int">1</property>
+ <property name="foo_lines">
+  <element value="Foo"/>
+  <element value="Lines"/>
+ </property>
+ <property name="foo_long">1</property>
+ <property name="foo_string">Foo String</property>
+ <property name="foo_text">Foo
+Text</property>
+ <property name="foo_tokens">
+  <element value="Foo"/>
+  <element value="Tokens"/></property>
+ <property name="foo_selection" type="selection" \
+select_variable="foobarbaz">Foo</property>
+ <property name="foo_mselection">
+  <element value="Foo"/>
+  <element value="Baz"/>
+ </property>
+ <property name="foo_boolean0">False</property>
 </dummy>
-""" % _FIXED_PROPERTY_NODES
+"""
 
-_NORMAL_OBJECT_EXPORT = """\
-<?xml version="1.0"?>
-<dummy>
- <object meta_type="Dummy Type" name="dummy">
-%s
- </object>
-</dummy>
-""" % _NORMAL_PROPERTY_NODES
-
 _SPECIAL_IMPORT = """\
 <?xml version="1.0"?>
 <dummy>
- <!-- ignore comment, allow empty description -->
- <description></description>
+ <!-- ignore comment, import 0 as False -->
+ <property name="foo_boolean0" type="boolean">0</property>
 </dummy>
 """
 
+
 def _testFunc( *args, **kw ):
 
     """ This is a test.
@@ -231,292 +176,114 @@
         self.assertRaises( ValueError, _getDottedName, doh )
 
 
-class DummyObject(Folder):
+class PropertyManagerHelpersTests(unittest.TestCase):
 
-    meta_type = 'Dummy Type'
-    _properties = ()
-
-
-class _ConfiguratorBaseTests(BaseRegistryTests):
-
-    def _initSite(self, foo=2):
-
-        self.root.site = Folder(id='site')
-        site = self.root.site
-
-        site.dummy = DummyObject(id='dummy')
-        site.dummy.foobarbaz = ('Foo', 'Bar', 'Baz')
-
-        if foo > 0:
-            site.dummy._setProperty('foo_boolean', '', 'boolean')
-            site.dummy._setProperty('foo_date', '', 'date')
-            site.dummy._setProperty('foo_float', '', 'float')
-            site.dummy._setProperty('foo_int', '', 'int')
-            site.dummy._setProperty('foo_lines', '', 'lines')
-            site.dummy._setProperty('foo_long', '', 'long')
-            site.dummy._setProperty('foo_string', '', 'string')
-            site.dummy._setProperty('foo_text', '', 'text')
-            site.dummy._setProperty('foo_tokens', (), 'tokens')
-            site.dummy._setProperty('foo_selection', 'foobarbaz', 'selection')
-            site.dummy._setProperty('foo_mselection', 'foobarbaz',
-                                    'multiple selection')
-            site.dummy._setProperty('foo_boolean0', '', 'boolean')
-
-        if foo > 1:
-            site.dummy._updateProperty('foo_boolean', 'True')
-            site.dummy._updateProperty('foo_date', '2000/01/01')
-            site.dummy._updateProperty('foo_float', '1.1')
-            site.dummy._updateProperty('foo_int', '1')
-            site.dummy._updateProperty('foo_lines', 'Foo\nLines')
-            site.dummy._updateProperty('foo_long', '1')
-            site.dummy._updateProperty('foo_string', 'Foo String')
-            site.dummy._updateProperty('foo_text', 'Foo\nText')
-            site.dummy._updateProperty( 'foo_tokens', ('Foo', 'Tokens') )
-            site.dummy._updateProperty('foo_selection', 'Foo')
-            site.dummy._updateProperty( 'foo_mselection', ('Foo', 'Baz') )
-            site.dummy.foo_boolean0 = 0
-
-        return site
-
-
-class ExportConfiguratorBaseTests(_ConfiguratorBaseTests):
-
     def _getTargetClass(self):
+        from Products.GenericSetup.utils import PropertyManagerHelpers
 
-        from Products.GenericSetup.utils import ExportConfiguratorBase
+        return PropertyManagerHelpers
 
-        class Configurator(ExportConfiguratorBase):
-            def _getExportTemplate(self):
-                return None
+    def _makeOne(self, *args, **kw):
+        from Products.GenericSetup.utils import NodeAdapterBase
 
-        return Configurator
+        class Foo(self._getTargetClass(), NodeAdapterBase):
 
-    def test__extractProperty_normal(self):
+            pass
 
-        site = self._initSite()
+        return Foo(*args, **kw)
 
-        EXPECTED = _NORMAL_PROPERTY_INFO
+    def setUp(self):
+        from OFS.PropertyManager import PropertyManager
 
-        configurator = self._makeOne(site)
-        prop_infos = [ configurator._extractProperty(site.dummy, prop_def)
-                       for prop_def in site.dummy._propertyMap() ]
+        obj = PropertyManager('obj')
+        obj.foobarbaz = ('Foo', 'Bar', 'Baz')
+        obj._properties = ()
+        obj._setProperty('foo_boolean', '', 'boolean')
+        obj._setProperty('foo_date', '', 'date')
+        obj._setProperty('foo_float', '', 'float')
+        obj._setProperty('foo_int', '', 'int')
+        obj._setProperty('foo_lines', '', 'lines')
+        obj._setProperty('foo_long', '', 'long')
+        obj._setProperty('foo_string', '', 'string')
+        obj._setProperty('foo_text', '', 'text')
+        obj._setProperty('foo_tokens', (), 'tokens')
+        obj._setProperty('foo_selection', 'foobarbaz', 'selection')
+        obj._setProperty('foo_mselection', 'foobarbaz', 'multiple selection')
+        obj._setProperty('foo_boolean0', '', 'boolean')
+        self.helpers = self._makeOne(obj)
 
-        self.assertEqual( len(prop_infos), len(EXPECTED) )
+    def _populate(self, obj):
+        obj._updateProperty('foo_boolean', 'True')
+        obj._updateProperty('foo_date', '2000/01/01')
+        obj._updateProperty('foo_float', '1.1')
+        obj._updateProperty('foo_int', '1')
+        obj._updateProperty('foo_lines', 'Foo\nLines')
+        obj._updateProperty('foo_long', '1')
+        obj._updateProperty('foo_string', 'Foo String')
+        obj._updateProperty('foo_text', 'Foo\nText')
+        obj._updateProperty( 'foo_tokens', ('Foo', 'Tokens') )
+        obj._updateProperty('foo_selection', 'Foo')
+        obj._updateProperty( 'foo_mselection', ('Foo', 'Baz') )
+        obj.foo_boolean0 = 0
 
-        for found, expected in zip(prop_infos, EXPECTED):
-            self.assertEqual(found, expected)
+    def test__extractProperties_empty(self):
+        doc = self.helpers._doc = PrettyDocument()
+        node = doc.createElement('dummy')
+        node.appendChild(self.helpers._extractProperties())
+        doc.appendChild(node)
 
-    def test__extractObject_normal(self):
+        self.assertEqual(doc.toprettyxml(' '), _EMPTY_PROPERTY_EXPORT)
 
-        site = self._initSite()
+    def test__extractProperties_normal(self):
+        self._populate(self.helpers.context)
+        doc = self.helpers._doc = PrettyDocument()
+        node = doc.createElement('dummy')
+        node.appendChild(self.helpers._extractProperties())
+        doc.appendChild(node)
 
-        EXPECTED = { 'id': 'dummy',
-                     'meta_type': 'Dummy Type',
-                     'properties': _NORMAL_PROPERTY_INFO,
-                     'subobjects': (),
-                     'i18n_domain' : None,
-                   }
+        self.assertEqual(doc.toprettyxml(' '), _NORMAL_PROPERTY_EXPORT)
 
-        configurator = self._makeOne(site)
-        obj_info = configurator._extractObject(site.dummy)
+    def test__initProperties_normal(self):
+        node = parseString(_NORMAL_PROPERTY_EXPORT).documentElement
+        self.helpers._initProperties(node, PURGE)
 
-        self.assertEqual( len(obj_info), len(EXPECTED) )
-        self.assertEqual(obj_info, EXPECTED)
+        doc = self.helpers._doc = PrettyDocument()
+        node = doc.createElement('dummy')
+        node.appendChild(self.helpers._extractProperties())
+        doc.appendChild(node)
 
-    def test_generatePropertyNodes_normal(self):
+        self.assertEqual(doc.toprettyxml(' '), _NORMAL_PROPERTY_EXPORT)
 
-        site = self._initSite()
-        configurator = self._makeOne(site).__of__(site)
-        prop_infos = [ configurator._extractProperty(site.dummy, prop_def)
-                       for prop_def in site.dummy._propertyMap() ]
-        nodes = configurator.generatePropertyNodes(prop_infos)
-        xml = '<?xml version="1.0"?><dummy>%s\n</dummy>' % nodes
+    def test__initProperties_fixed(self):
+        node = parseString(_FIXED_PROPERTY_EXPORT).documentElement
+        self.helpers._initProperties(node, PURGE)
 
-        self._compareDOM(xml, _NORMAL_PROPERTY_EXPORT)
+        doc = self.helpers._doc = PrettyDocument()
+        node = doc.createElement('dummy')
+        node.appendChild(self.helpers._extractProperties())
+        doc.appendChild(node)
 
-    def test_generateObjectNodes_normal(self):
+        self.assertEqual(doc.toprettyxml(' '), _NORMAL_PROPERTY_EXPORT)
 
-        site = self._initSite()
-        configurator = self._makeOne(site).__of__(site)
-        obj_infos = ( configurator._extractObject(site.dummy), )
-        nodes = configurator.generateObjectNodes(obj_infos)
-        xml = '<?xml version="1.0"?><dummy>%s\n</dummy>' % nodes
+    def test__initProperties_special(self):
+        node = parseString(_SPECIAL_IMPORT).documentElement
+        self.helpers._initProperties(node, UPDATE)
 
-        self._compareDOM(xml, _NORMAL_OBJECT_EXPORT)
+        doc = self.helpers._doc = PrettyDocument()
+        node = doc.createElement('dummy')
+        node.appendChild(self.helpers._extractProperties())
+        doc.appendChild(node)
 
+        self.assertEqual(doc.toprettyxml(' '), _EMPTY_PROPERTY_EXPORT)
 
-class ImportConfiguratorBaseTests(_ConfiguratorBaseTests):
 
-    def _getTargetClass(self):
-
-        from Products.GenericSetup.utils import ImportConfiguratorBase
-        from Products.GenericSetup.utils import CONVERTER, DEFAULT, KEY
-
-        class Configurator(ImportConfiguratorBase):
-            def _getImportMapping(self):
-                return {
-                  'dummy':
-                    { 'property':    {KEY: 'properties', DEFAULT: ()},
-                      'description': {CONVERTER: self._convertToUnique} } }
-
-        return Configurator
-
-
-    def test_parseXML_normal(self):
-
-        site = self._initSite()
-        configurator = self._makeOne(site)
-        site_info = configurator.parseXML(_NORMAL_PROPERTY_EXPORT)
-
-        self.assertEqual( len( site_info['properties'] ), 12 )
-
-        info = site_info['properties'][0]
-        self.assertEqual( info['id'], 'foo_boolean' )
-        self.assertEqual( info['value'], 'True' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'boolean' )
-
-        info = site_info['properties'][1]
-        self.assertEqual( info['id'], 'foo_date' )
-        self.assertEqual( info['value'], '2000/01/01' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'date' )
-
-        info = site_info['properties'][2]
-        self.assertEqual( info['id'], 'foo_float' )
-        self.assertEqual( info['value'], '1.1' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'float' )
-
-        info = site_info['properties'][3]
-        self.assertEqual( info['id'], 'foo_int' )
-        self.assertEqual( info['value'], '1' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'int' )
-
-        info = site_info['properties'][4]
-        self.assertEqual( info['id'], 'foo_lines' )
-        self.assertEqual( info['value'], '' )
-        self.assertEqual( len( info['elements'] ), 2 )
-        self.assertEqual( info['elements'][0], 'Foo' )
-        self.assertEqual( info['elements'][1], 'Lines' )
-        self.assertEqual( info['type'], 'lines' )
-
-        info = site_info['properties'][5]
-        self.assertEqual( info['id'], 'foo_long' )
-        self.assertEqual( info['value'], '1' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'long' )
-
-        info = site_info['properties'][6]
-        self.assertEqual( info['id'], 'foo_string' )
-        self.assertEqual( info['value'], 'Foo String' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'string' )
-
-        info = site_info['properties'][7]
-        self.assertEqual( info['id'], 'foo_text' )
-        self.assertEqual( info['value'], 'Foo\nText' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'text' )
-
-        info = site_info['properties'][8]
-        self.assertEqual( info['id'], 'foo_tokens' )
-        self.assertEqual( info['value'], '' )
-        self.assertEqual( len( info['elements'] ), 2 )
-        self.assertEqual( info['elements'][0], 'Foo' )
-        self.assertEqual( info['elements'][1], 'Tokens' )
-        self.assertEqual( info['type'], 'tokens' )
-
-        info = site_info['properties'][9]
-        self.assertEqual( info['id'], 'foo_selection' )
-        self.assertEqual( info['value'], 'Foo' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'selection' )
-        self.assertEqual( info['select_variable'], 'foobarbaz' )
-
-        info = site_info['properties'][10]
-        self.assertEqual( info['id'], 'foo_mselection' )
-        self.assertEqual( info['value'], '' )
-        self.assertEqual( len( info['elements'] ), 2 )
-        self.assertEqual( info['elements'][0], 'Foo' )
-        self.assertEqual( info['elements'][1], 'Baz' )
-        self.assertEqual( info['type'], 'multiple selection' )
-        self.assertEqual( info['select_variable'], 'foobarbaz' )
-
-        info = site_info['properties'][11]
-        self.assertEqual( info['id'], 'foo_boolean0' )
-        self.assertEqual( info['value'], '0' )
-        self.assertEqual( len( info['elements'] ), 0 )
-        self.assertEqual( info['type'], 'boolean' )
-
-    def test_parseXML_special(self):
-
-        site = self._initSite()
-        configurator = self._makeOne(site)
-        try:
-            site_info = configurator.parseXML(_SPECIAL_IMPORT)
-        except KeyError:
-            self.fail('CMF Collector issue #352 (comment or empty '
-                      'description bug): KeyError raised')
-
-        self.assertEqual( len(site_info), 2 )
-        self.assertEqual( site_info['description'], '' )
-        self.assertEqual( len(site_info['properties']), 0 )
-
-    def test_initProperty_normal(self):
-
-        EXPECTED = _NORMAL_PROPERTY_INFO
-
-        site = self._initSite(0)
-        dummy = site.dummy
-        configurator = self._makeOne(site)
-        site_info = configurator.parseXML(_NORMAL_PROPERTY_EXPORT)
-
-        self.assertEqual( len( dummy.propertyIds() ), 0 )
-
-        for prop_info in site_info['properties']:
-            configurator.initProperty(dummy, prop_info)
-
-        self.assertEqual( len( dummy.propertyIds() ), len(EXPECTED) )
-
-        for exp_info in EXPECTED:
-            exp_id = exp_info['id']
-            exp_value = exp_info['elements'] or exp_info['value']
-            self.failUnless( exp_id in dummy.propertyIds() )
-            self.assertEqual( dummy.getProperty(exp_id), exp_value )
-
-    def test_initProperty_fixed(self):
-
-        EXPECTED = _NORMAL_PROPERTY_INFO
-
-        site = self._initSite(1)
-        dummy = site.dummy
-        configurator = self._makeOne(site)
-        site_info = configurator.parseXML(_FIXED_PROPERTY_EXPORT)
-
-        self.assertEqual( len( dummy.propertyIds() ), 12 )
-
-        for prop_info in site_info['properties']:
-            configurator.initProperty(dummy, prop_info)
-
-        self.assertEqual( len( dummy.propertyIds() ), len(EXPECTED) )
-
-        for exp_info in EXPECTED:
-            exp_id = exp_info['id']
-            exp_value = exp_info['elements'] or exp_info['value']
-            self.failUnless( exp_id in dummy.propertyIds() )
-            self.assertEqual( dummy.getProperty(exp_id), exp_value )
-
-
 def test_suite():
     # reimport to make sure tests are run from Products
     from Products.GenericSetup.tests.test_utils import UtilsTests
 
     return unittest.TestSuite((
-        unittest.makeSuite( UtilsTests ),
-        unittest.makeSuite( ImportConfiguratorBaseTests ),
-        unittest.makeSuite( ExportConfiguratorBaseTests ),
+        unittest.makeSuite(UtilsTests),
+        unittest.makeSuite(PropertyManagerHelpersTests),
         ))
 
 if __name__ == '__main__':

Modified: CMF/trunk/GenericSetup/utils.py
===================================================================
--- CMF/trunk/GenericSetup/utils.py	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/GenericSetup/utils.py	2005-09-29 17:56:14 UTC (rev 38690)
@@ -17,27 +17,34 @@
 
 import os
 from inspect import getdoc
+from xml.dom.minidom import _nssplit
+from xml.dom.minidom import _write_data
+from xml.dom.minidom import Document
+from xml.dom.minidom import Element
+from xml.dom.minidom import Node
 from xml.dom.minidom import parseString as domParseString
 from xml.sax.handler import ContentHandler
 
 import Products
 from AccessControl import ClassSecurityInfo
-from Acquisition import aq_base
 from Acquisition import Implicit
 from Globals import InitializeClass
 from Globals import package_home
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from zope.interface import implements
 
 from exceptions import BadRequest
+from interfaces import INodeExporter
+from interfaces import INodeImporter
+from interfaces import PURGE
 from permissions import ManagePortal
 
 
 _pkgdir = package_home( globals() )
 _wwwdir = os.path.join( _pkgdir, 'www' )
-_datadir = os.path.join( _pkgdir, 'data' )
 _xmldir = os.path.join( _pkgdir, 'xml' )
 
 CONVERTER, DEFAULT, KEY = range(3)
+I18NURI = 'http://xml.zope.org/namespaces/i18n'
 
 
 def _getDottedName( named ):
@@ -241,78 +248,6 @@
         assert len(val) == 1
         return val[0]
 
-    security.declareProtected(ManagePortal, 'initObject')
-    def initObject(self, parent, o_info):
-
-        obj_id = str(o_info['id'])
-        if obj_id not in parent.objectIds():
-            meta_type = o_info['meta_type']
-            for mt_info in Products.meta_types:
-                if mt_info['name'] == meta_type:
-                    parent._setObject( obj_id, mt_info['instance'](obj_id) )
-                    break
-            else:
-                raise ValueError('unknown meta_type \'%s\'' % obj_id)
-        obj = parent._getOb(obj_id)
-
-        if 'insert-before' in o_info:
-            if o_info['insert-before'] == '*':
-                parent.moveObjectsToTop(obj_id)
-            else:
-                try:
-                    position = parent.getObjectPosition(o_info['insert-before'])
-                    parent.moveObjectToPosition(obj_id, position)
-                except ValueError:
-                    pass
-        elif 'insert-after' in o_info:
-            if o_info['insert-after'] == '*':
-                parent.moveObjectsToBottom(obj_id)
-            else:
-                try:
-                    position = parent.getObjectPosition(o_info['insert-after'])
-                    parent.moveObjectToPosition(obj_id, position+1)
-                except ValueError:
-                    pass
-
-        [ self.initObject(obj, info) for info in o_info['objects'] ]
-
-        if 'i18n:domain' in o_info:
-            obj.i18n_domain = o_info['i18n:domain']
-
-        [ self.initProperty(obj, info) for info in o_info['properties'] ]
-
-    security.declareProtected(ManagePortal, 'initProperty')
-    def initProperty(self, obj, p_info):
-
-        prop_id = p_info['id']
-        prop_map = obj.propdict().get(prop_id, None)
-
-        if prop_map is None:
-            type = p_info.get('type', None)
-            if type:
-                val = p_info.get('select_variable', '')
-                obj._setProperty(prop_id, val, type)
-                prop_map = obj.propdict().get(prop_id, None)
-            else:
-                raise ValueError('undefined property \'%s\'' % prop_id)
-
-        if not 'w' in prop_map.get('mode', 'wd'):
-            raise BadRequest('%s cannot be changed' % prop_id)
-
-        if prop_map.get('type') == 'multiple selection':
-            prop_value = p_info['elements'] or ()
-        elif prop_map.get('type') == 'boolean':
-            # Make sure '0' is imported as False
-            prop_value = str(p_info['value'])
-            if prop_value == '0':
-                prop_value = ''
-        else:
-            # if we pass a *string* to _updateProperty, all other values
-            # are converted to the right type
-            prop_value = p_info['elements'] or str( p_info['value'] )
-
-        obj._updateProperty(prop_id, prop_value)
-
 InitializeClass(ImportConfiguratorBase)
 
 
@@ -334,181 +269,281 @@
         """
         return self._template(**kw)
 
-    #
-    #   generic object and property support
-    #
-    _ob_nodes = PageTemplateFile('object_nodes.xml', _xmldir)
-    _prop_nodes = PageTemplateFile('property_nodes.xml', _xmldir)
+InitializeClass(ExportConfiguratorBase)
 
-    security.declareProtected(ManagePortal, 'generateObjectNodes')
-    def generateObjectNodes(self, obj_infos):
-        """ Pseudo API.
-        """
-        lines = self._ob_nodes(objects=obj_infos).splitlines()
-        return '\n'.join(lines)
 
-    security.declareProtected(ManagePortal, 'generatePropertyNodes')
-    def generatePropertyNodes(self, prop_infos):
-        """ Pseudo API.
-        """
-        lines = self._prop_nodes(properties=prop_infos).splitlines()
-        return '\n'.join(lines)
+# BBB: old class mixing the two, will be removed in CMF 2.1
+class ConfiguratorBase(ImportConfiguratorBase, ExportConfiguratorBase):
+    """ Synthesize XML description.
+    """
+    security = ClassSecurityInfo()
+    security.setDefaultAccess('allow')
 
-    def _extractObject(self, obj):
+    def __init__(self, site, encoding=None):
+        ImportConfiguratorBase.__init__(self, site, encoding)
+        ExportConfiguratorBase.__init__(self, site, encoding)
 
-        properties = []
-        subobjects = []
-        i18n_domain = getattr(obj, 'i18n_domain', None)
+InitializeClass(ConfiguratorBase)
 
-        if getattr( aq_base(obj), '_propertyMap' ):
-            for prop_map in obj._propertyMap():
-                prop_info = self._extractProperty(obj, prop_map)
-                if i18n_domain and prop_info['id'] in ('title', 'description'):
-                    prop_info['i18ned'] = ''
-                if prop_info['id'] != 'i18n_domain':
-                    properties.append(prop_info)
 
-        if getattr( aq_base(obj), 'objectValues' ):
-            for sub in obj.objectValues():
-                subobjects.append( self._extractObject(sub) )
+# XXX: Is there any code available in Zope that generates pretty XML? If not,
+#      this code has to be improved.
+class _Element(Element):
 
-        return { 'id': obj.getId(),
-                 'meta_type': obj.meta_type,
-                 'i18n_domain': i18n_domain or None,
-                 'properties': tuple(properties),
-                 'subobjects': tuple(subobjects) }
+    """minidom element with 'pretty' XML output.
+    """
 
-    def _extractProperty(self, obj, prop_map):
+    def writexml(self, writer, indent="", addindent="", newl=""):
+        # indent = current indentation
+        # addindent = indentation to add to higher levels
+        # newl = newline string
+        writer.write(indent+"<" + self.tagName)
 
-        prop_id = prop_map['id']
-        prop = obj.getProperty(prop_id)
+        attrs = self._get_attributes()
+        a_names = attrs.keys()
+        a_names.sort()
+        if 'title' in a_names:
+            a_names.remove('title')
+            a_names.insert(0, 'title')
+        if 'meta_type' in a_names:
+            a_names.remove('meta_type')
+            a_names.insert(0, 'meta_type')
+        if 'name' in a_names:
+            a_names.remove('name')
+            a_names.insert(0, 'name')
 
-        if isinstance(prop, tuple):
-            prop_value = ''
-            prop_elements = prop
-        elif isinstance(prop, list):
-            # Backward compat for old instances that stored
-            # properties as list.
-            prop_value = ''
-            prop_elements = tuple(prop)
+        for a_name in a_names:
+            writer.write(" %s=\"" % a_name)
+            _write_data(writer, attrs[a_name].value)
+            writer.write("\"")
+        if self.childNodes:
+            if self.firstChild.nodeType == Node.TEXT_NODE:
+                writer.write(">")
+            else:
+                writer.write(">%s"%(newl))
+            for node in self.childNodes:
+                if node.nodeType == Node.TEXT_NODE:
+                    writer.write(node.data)
+                else:
+                    node.writexml(writer,indent+addindent,addindent,newl)
+            if self.lastChild.nodeType == Node.TEXT_NODE:
+                writer.write("</%s>%s" % (self.tagName,newl))
+            else:
+                writer.write("%s</%s>%s" % (indent,self.tagName,newl))
         else:
-            prop_value = prop
-            prop_elements = ()
+            writer.write("/>%s"%(newl))
 
-        if 'd' in prop_map.get('mode', 'wd') and not prop_id == 'title':
-            type = prop_map.get('type', 'string')
-            select_variable = prop_map.get('select_variable', None)
-        else:
-            type = None
-            select_variable = None
 
-        return { 'id': prop_id,
-                 'value': prop_value,
-                 'elements': prop_elements,
-                 'type': type,
-                 'select_variable': select_variable }
+class PrettyDocument(Document):
 
-InitializeClass(ExportConfiguratorBase)
+    """minidom document with 'pretty' XML output.
+    """
 
+    def createElement(self, tagName):
+        e = _Element(tagName)
+        e.ownerDocument = self
+        return e
 
-# BBB: old class mixing the two, will be removed in CMF 2.1
-class ConfiguratorBase(ImportConfiguratorBase, ExportConfiguratorBase):
-    """ Synthesize XML description.
-    """
-    security = ClassSecurityInfo()
-    security.setDefaultAccess('allow')
+    def createElementNS(self, namespaceURI, qualifiedName):
+        prefix, localName = _nssplit(qualifiedName)
+        e = _Element(qualifiedName, namespaceURI, prefix)
+        e.ownerDocument = self
+        return e
 
-    def __init__(self, site, encoding=None):
-        ImportConfiguratorBase.__init__(self, site, encoding)
-        ExportConfiguratorBase.__init__(self, site, encoding)
+    def writexml(self, writer, indent="", addindent="", newl="",
+                 encoding = None):
+        if encoding is None:
+            writer.write('<?xml version="1.0"?>\n')
+        else:
+            writer.write('<?xml version="1.0" encoding="%s"?>\n' % encoding)
+        for node in self.childNodes:
+            node.writexml(writer, indent, addindent, newl)
 
-InitializeClass(ConfiguratorBase)
 
+class NodeAdapterBase(object):
 
-#
-#   deprecated DOM parsing utilities
-#
-_marker = object()
+    """Node im- and exporter base.
+    """
 
-def _queryNodeAttribute( node, attr_name, default, encoding=None ):
+    implements(INodeExporter, INodeImporter)
 
-    """ Extract a string-valued attribute from node.
+    def __init__(self, context):
+        self.context = context
 
-    o Return 'default' if the attribute is not present.
-    """
-    attr_node = node.attributes.get( attr_name, _marker )
+    def exportNode(self, doc):
+        """Export the object as a DOM node.
+        """
+        self._doc = doc
+        return self._getObjectNode('object')
 
-    if attr_node is _marker:
-        return default
+    def importNode(self, node, mode=PURGE):
+        """Import the object from the DOM node.
+        """
 
-    value = attr_node.nodeValue
+    def _getObjectNode(self, name):
+        node = self._doc.createElement(name)
+        node.setAttribute('name', self.context.getId())
+        node.setAttribute('meta_type', self.context.meta_type)
+        i18n_domain = getattr(self.context, 'i18n_domain', None)
+        if i18n_domain:
+            node.setAttributeNS(I18NURI, 'i18n:domain', i18n_domain)
+            self._i18n_props = ('title', 'description')
+        return node
 
-    if encoding is not None:
-        value = value.encode( encoding )
+    def _getNodeText(self, node):
+        text = ''
+        for child in node.childNodes:
+            if child.nodeName != '#text':
+                continue
+            text += child.nodeValue.lstrip()
+        return text
 
-    return value
+    def _getNodeTextBoolean(self, node):
+        text = self._getNodeText(node)
+        return text.lower() in ('true', 'yes', '1')
 
-def _getNodeAttribute( node, attr_name, encoding=None ):
 
-    """ Extract a string-valued attribute from node.
+class ObjectManagerHelpers(object):
+
+    """ObjectManager im- and export helpers.
     """
-    value = _queryNodeAttribute( node, attr_name, _marker, encoding )
 
-    if value is _marker:
-        raise ValueError, 'Invaid attribute: %s' % attr_name
+    def _extractObjects(self):
+        fragment = self._doc.createDocumentFragment()
+        for obj in self.context.objectValues():
+            exporter = INodeExporter(obj, None)
+            if exporter is None:
+                continue
+            fragment.appendChild(exporter.exportNode(self._doc))
+        return fragment
 
-    return value
+    def _purgeObjects(self):
+        for obj_id in self.context.objectIds():
+            self.context._delObject(obj_id)
 
-def _queryNodeAttributeBoolean( node, attr_name, default ):
+    def _initObjects(self, node, mode):
+        for child in node.childNodes:
+            if child.nodeName != 'object':
+                continue
+            if child.hasAttribute('deprecated'):
+                continue
+            parent = self.context
 
-    """ Extract a string-valued attribute from node.
+            obj_id = str(child.getAttribute('name'))
+            if obj_id not in parent.objectIds():
+                meta_type = str(child.getAttribute('meta_type'))
+                for mt_info in Products.meta_types:
+                    if mt_info['name'] == meta_type:
+                        parent._setObject(obj_id, mt_info['instance'](obj_id))
+                        break
+                else:
+                    raise ValueError('unknown meta_type \'%s\'' % obj_id)
 
-    o Return 'default' if the attribute is not present.
+            if child.hasAttribute('insert-before'):
+                insert_before = child.getAttribute('insert-before')
+                if insert_before == '*':
+                    parent.moveObjectsToTop(obj_id)
+                else:
+                    try:
+                        position = parent.getObjectPosition(insert_before)
+                        parent.moveObjectToPosition(obj_id, position)
+                    except ValueError:
+                        pass
+            elif child.hasAttribute('insert-after'):
+                insert_after = child.getAttribute('insert-after')
+                if insert_after == '*':
+                    parent.moveObjectsToBottom(obj_id)
+                else:
+                    try:
+                        position = parent.getObjectPosition(insert_after)
+                        parent.moveObjectToPosition(obj_id, position+1)
+                    except ValueError:
+                        pass
+
+            obj = getattr(self.context, obj_id)
+            INodeImporter(obj).importNode(child, mode)
+
+
+class PropertyManagerHelpers(object):
+
+    """PropertyManager im- and export helpers.
     """
-    attr_node = node.attributes.get( attr_name, _marker )
 
-    if attr_node is _marker:
-        return default
+    def _extractProperties(self):
+        fragment = self._doc.createDocumentFragment()
 
-    value = node.attributes[ attr_name ].nodeValue.lower()
+        for prop_map in self.context._propertyMap():
+            if prop_map['id'] == 'i18n_domain':
+                continue
+            node = self._doc.createElement('property')
 
-    return value in ( 'true', 'yes', '1' )
+            prop_id = prop_map['id']
+            node.setAttribute('name', prop_id)
 
-def _getNodeAttributeBoolean( node, attr_name ):
+            prop = self.context.getProperty(prop_id)
+            if isinstance(prop, (tuple, list)):
+                for value in prop:
+                    child = self._doc.createElement('element')
+                    child.setAttribute('value', value)
+                    node.appendChild(child)
+            else:
+                if prop_map.get('type') == 'boolean':
+                    prop = str(bool(prop))
+                elif not isinstance(prop, basestring):
+                    prop = str(prop)
+                child = self._doc.createTextNode(prop)
+                node.appendChild(child)
 
-    """ Extract a string-valued attribute from node.
-    """
-    value = node.attributes[ attr_name ].nodeValue.lower()
+            if 'd' in prop_map.get('mode', 'wd') and not prop_id == 'title':
+                type = prop_map.get('type', 'string')
+                node.setAttribute('type', type)
+                select_variable = prop_map.get('select_variable', None)
+                if select_variable is not None:
+                    node.setAttribute('select_variable', select_variable)
 
-    return value in ( 'true', 'yes', '1' )
+            if hasattr(self, '_i18n_props') and prop_id in self._i18n_props:
+                node.setAttribute('i18n:translate', '')
 
-def _coalesceTextNodeChildren( node, encoding=None ):
+            fragment.appendChild(node)
 
-    """ Concatenate all childe text nodes into a single string.
-    """
-    from xml.dom import Node
-    fragments = []
-    node.normalize()
-    child = node.firstChild
+        return fragment
 
-    while child is not None:
+    def _purgeProperties(self):
+        #XXX: not implemented
+        pass
 
-        if child.nodeType == Node.TEXT_NODE:
-            fragments.append( child.nodeValue )
+    def _initProperties(self, node, mode):
+        self.context.i18n_domain = node.getAttribute('i18n:domain')
+        for child in node.childNodes:
+            if child.nodeName != 'property':
+                continue
+            obj = self.context
+            prop_id = str(child.getAttribute('name'))
+            prop_map = obj.propdict().get(prop_id, None)
 
-        child = child.nextSibling
+            if prop_map is None:
+                if child.hasAttribute('type'):
+                    val = child.getAttribute('select_variable')
+                    obj._setProperty(prop_id, val, child.getAttribute('type'))
+                    prop_map = obj.propdict().get(prop_id, None)
+                else:
+                    raise ValueError('undefined property \'%s\'' % prop_id)
 
-    joined = ''.join( fragments )
+            if not 'w' in prop_map.get('mode', 'wd'):
+                raise BadRequest('%s cannot be changed' % prop_id)
 
-    if encoding is not None:
-        joined = joined.encode( encoding )
+            elements = []
+            for sub in child.childNodes:
+                if sub.nodeName == 'element':
+                    elements.append(sub.getAttribute('value'))
 
-    return ''.join( [ line.lstrip() for line in joined.splitlines(True) ] )
+            if elements or prop_map.get('type') == 'multiple selection':
+                prop_value = tuple(elements) or ()
+            elif prop_map.get('type') == 'boolean':
+                prop_value = self._getNodeTextBoolean(child)
+            else:
+                # if we pass a *string* to _updateProperty, all other values
+                # are converted to the right type
+                prop_value = self._getNodeText(child)
 
-def _extractDescriptionNode(parent, encoding=None):
-
-    d_nodes = parent.getElementsByTagName('description')
-    if d_nodes:
-        return _coalesceTextNodeChildren(d_nodes[0], encoding)
-    else:
-        return ''
+            obj._updateProperty(prop_id, prop_value)

Deleted: CMF/trunk/GenericSetup/xml/object_nodes.xml
===================================================================
--- CMF/trunk/GenericSetup/xml/object_nodes.xml	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/GenericSetup/xml/object_nodes.xml	2005-09-29 17:56:14 UTC (rev 38690)
@@ -1,11 +0,0 @@
-<tal:loop xmlns:tal="http://xml.zope.org/namespaces/tal"
-   tal:repeat="obj_info options/objects">
- <object name="ID" meta_type="META TYPE"
-    tal:attributes="name obj_info/id;
-                    meta_type obj_info/meta_type"
- ><tal:span tal:define="prop_infos obj_info/properties"
-     tal:replace="structure python: context.generatePropertyNodes(prop_infos)"
-/><tal:span tal:define="sub_infos obj_info/subobjects"
-     tal:condition="sub_infos"
-     tal:replace="structure python: context.generateObjectNodes(sub_infos)"/>
- </object></tal:loop>

Deleted: CMF/trunk/GenericSetup/xml/property_nodes.xml
===================================================================
--- CMF/trunk/GenericSetup/xml/property_nodes.xml	2005-09-29 17:07:04 UTC (rev 38689)
+++ CMF/trunk/GenericSetup/xml/property_nodes.xml	2005-09-29 17:56:14 UTC (rev 38690)
@@ -1,10 +0,0 @@
-<tal:loop xmlns:tal="http://xml.zope.org/namespaces/tal"
-   tal:repeat="prop_info options/properties">
-  <property name="ID"
-     tal:attributes="name prop_info/id;
-                     type prop_info/type;
-                     select_variable prop_info/select_variable"
-  ><tal:span tal:content="prop_info/value"
- /><tal:loop tal:repeat="element prop_info/elements">
-   <element value="VALUE"
-      tal:attributes="value element"/></tal:loop></property></tal:loop>



More information about the CMF-checkins mailing list