Hi all,

I currently have a product by the name of pythonproducts
(http://codespeak.net/svn/z3/pythonproducts/) that does its best to
patch Zope/Five and CMF so that regular python packages can be treated
as first-class Zope 2 products.  The underlying problem being that
certain portions of Zope/CMF code assumes all assumes products found in
the control panel live at the toplevel package 'Products' when this
should not be necessity.  A practical example of what this means is that
today usually when you need to import things you do "from
Products.product1 import foo" but since products can be regular packages
with the fixes, you can now do "from product1 import foo" as long as
your product is on PYTHONPATH (often this is $INSTANCE_HOME/lib/python).

As of Five 1.4, the Five specific functionality has been merged into
Five itself.  As of Zope 2.10, the Zope specific functionality has been
merged into Zope itself.  So all that remains now is CMF.  The biggest
problem with CMF was CMFCore.TypesTool.listDefaultTypeInformation.  As I
know this is no longer used in CMF2 this *should* mean CMF2 is safe
(although I'd have to do further tests to confirm this).

What I would like to do is get CMF1.6's listDefaultTypeInformation fixed
so that people stuck on CMF1.6 can reap all of these benefits without
having to include pythonproducts.  One large beneficiary of this work
will be the Zope2.10 based Plone 2.5 combination which will be able to
do all of this without the need for pythonrproducts *if* CMF1.6 is
fixed.

Anyhow, I've included a patch that demonstrates what would need to be
done including some extra test logic that fails before my changes and of
course passes afterwards.

What do you all think?  Something we can include in time for CMF1.6.1
beta2 ?

Regards,
Rocky


-- 
Rocky Burt
ServerZen Software -- http://www.serverzen.com
News About The Server (blog) -- http://www.serverzen.net

Index: CHANGES.txt
===================================================================
--- CHANGES.txt	(revision 68481)
+++ CHANGES.txt	(working copy)
@@ -1,3 +1,12 @@
+CMF 1.6.1-beta2 (unreleased)
+
+  Others
+
+    - TypesTool is now capable of understanding types that don't 
+      necessarily live in product pkgs beneath the toplevel Products/*
+      package.  This makes productsless packages work with CMF.
+
+
 CMF 1.6.1-beta (2006/06/03)
 
   Bug Fixes
Index: CMFCore/TypesTool.py
===================================================================
--- CMFCore/TypesTool.py	(revision 68481)
+++ CMFCore/TypesTool.py	(working copy)
@@ -16,6 +16,7 @@
 """
 
 from sys import exc_info
+import types
 from warnings import warn
 
 from AccessControl import ClassSecurityInfo
@@ -55,7 +56,6 @@
 
 _marker = []  # Create a new marker.
 
-
 class TypeInformation(SimpleItemWithProperties, ActionProviderBase):
     """
     Base class for information about a content type.
@@ -693,6 +693,40 @@
                    if mt['name'] in allowedTypes ]
         return tuple(all) + tuple(others)
 
+    def _product_packages(self):
+        """Returns all product packages including the regularly defined
+        zope2 packages and those without the Products namespace package.
+        """
+        
+        old_product_packages = {}
+        for x in dir(Products):
+            m = getattr(Products, x)
+            if isinstance(m, types.ModuleType):
+                old_product_packages[x] = m
+        
+        packages = {}
+        app = self
+        while hasattr(app, 'aq_parent'):
+            app = app.aq_parent
+        products = app.Control_Panel.Products
+        
+        for product_id in products.objectIds():
+            product = products[product_id]
+            if hasattr(product, 'package_name'):
+                pos = product.package_name.rfind('.')
+                if pos > -1:
+                    packages[product_id] = __import__(product.package_name, 
+                                                      globals(), {}, 
+                                                      product.package_name[pos+1:])
+                else:
+                    packages[product_id] = __import__(product.package_name)
+            elif old_product_packages.has_key(product_id):
+                packages[product_id] = old_product_packages[product_id]
+        
+        return packages
+
+
+
     #
     #   other methods
     #
@@ -702,13 +736,14 @@
         # of all products and factory dispatchers within products.
         res = []
         products = self.aq_acquire('_getProducts')()
+        product_pkgs = self._product_packages()
         for product in products.objectValues():
             product_id = product.getId()
 
             if hasattr(aq_base(product), 'factory_type_information'):
                 ftis = product.factory_type_information
             else:
-                package = getattr(Products, product_id, None)
+                package = product_pkgs.get(product_id, None)
                 dispatcher = getattr(package, '__FactoryDispatcher__', None)
                 ftis = getattr(dispatcher, 'factory_type_information', None)
 
Index: CMFCore/tests/test_TypesTool.py
===================================================================
--- CMFCore/tests/test_TypesTool.py	(revision 68481)
+++ CMFCore/tests/test_TypesTool.py	(working copy)
@@ -179,15 +179,8 @@
             self.fail('CMF Collector issue #165 (Ownership bug): '
                       'Unauthorized raised' )
 
-    def test_CMFCollector_49(self):
-        #http://www.zope.org/Collectors/CMF/49
+    def test_listDefaultTypeInformation(self):
 
-        #If you have two FTIs on the file system, both with the same meta_type
-        #but with different id values, the way listDefaultTypeInformation
-        #listed them in the dropdown list made it impossible to distinguish
-        #the two because the identifier string only contained the CMF package
-        #name and the meta_type
-
         # Extreme nastiness: Fake out a /Control_Panel/Products registry
         # inside the fake site by putting dummy objects with a
         # factory_type_information attribute on them...
@@ -205,6 +198,15 @@
         self.ttool._getProducts = fakeGetProducts
         self.site.objectValues = fakeObjectValues
 
+        
+        #http://www.zope.org/Collectors/CMF/49
+
+        #If you have two FTIs on the file system, both with the same meta_type
+        #but with different id values, the way listDefaultTypeInformation
+        #listed them in the dropdown list made it impossible to distinguish
+        #the two because the identifier string only contained the CMF package
+        #name and the meta_type
+
         types = self.ttool.listDefaultTypeInformation()
         dropdown_representation = [x[0] for x in types]
         self.failIf(dropdown_representation[0]==dropdown_representation[1])
@@ -227,8 +229,18 @@
         self.failUnless('NewType2' in self.ttool.objectIds())
         self.failUnless('DeprecationWarning' in
                             self._our_stderr_stream.getvalue())
+        
+        # Make sure that if our product doesn't have factory type info
+        # then listDefaultTypeInformation() is still able to get to
+        # the appropriate fti from the product's "home" package (which
+        # normally would live in Product.product1).
+        del product1.factory_type_information
+        product1.package_name = 'Products.CMFCore.tests.base.factorydispatcher'
+        self.site.Control_Panel.Products._setObject('product1', product1)
+        types = self.ttool.listDefaultTypeInformation()
+        self.failUnless(len(types) == 1)
+        self.failUnless(types[0][0] == 'product1: Dummy Content (Dummy)')
 
-
 class TypeInfoTests(unittest.TestCase, WarningInterceptor):
 
     def _makeTypesTool(self):
@@ -507,7 +519,6 @@
         ti.getMethodAliases()
         self._checkContentTI(ti)
 
-
 class FTIDataTests( TypeInfoTests ):
 
     def _makeInstance(self, id, **kw):
Index: CMFCore/tests/base/factorydispatcher.py
===================================================================
--- CMFCore/tests/base/factorydispatcher.py	(revision 0)
+++ CMFCore/tests/base/factorydispatcher.py	(revision 0)
@@ -0,0 +1,7 @@
+from Products.CMFCore.tests.base.tidata import FTIDATA_DUMMY
+
+class MockFactoryDispatcher:
+    def __init__(self):
+        self.factory_type_information = FTIDATA_DUMMY
+
+__FactoryDispatcher__ = MockFactoryDispatcher()

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
Zope-CMF maillist  -  Zope-CMF@lists.zope.org
http://mail.zope.org/mailman/listinfo/zope-cmf

See http://collector.zope.org/CMF for bug reports and feature requests

Reply via email to