[CMF-checkins] SVN: CMF/trunk/C merged yuppie-collector467 branch:

Yvo Schubbe y.2007- at wcm-solutions.de
Fri Feb 23 12:29:53 EST 2007


Log message for revision 72785:
  merged yuppie-collector467 branch:
  - refactored path and registry key handling based on wichert's cmf-dirview-keying-2 patch
  - updated profiles

Changed:
  U   CMF/trunk/CHANGES.txt
  U   CMF/trunk/CMFActionIcons/profiles/actionicons/skins.xml
  U   CMF/trunk/CMFCalendar/profiles/default/skins.xml
  U   CMF/trunk/CMFCore/DirectoryView.py
  U   CMF/trunk/CMFCore/exportimport/tests/test_skins.py
  U   CMF/trunk/CMFCore/tests/__init__.py
  U   CMF/trunk/CMFCore/tests/base/testcase.py
  U   CMF/trunk/CMFCore/tests/test_DirectoryView.py
  U   CMF/trunk/CMFCore/tests/test_utils.py
  U   CMF/trunk/CMFCore/utils.py
  U   CMF/trunk/CMFDefault/profiles/default/skins.xml
  U   CMF/trunk/CMFTopic/profiles/default/skins.xml

-=-
Modified: CMF/trunk/CHANGES.txt
===================================================================
--- CMF/trunk/CHANGES.txt	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CHANGES.txt	2007-02-23 17:29:52 UTC (rev 72785)
@@ -2,6 +2,11 @@
 
   New Features
 
+    - DirectoryView: Added support for non-product packages.
+      This introduces new registry keys. Old registry keys stored in
+      persistent DirectoryView objects are updated on the fly.
+      (http://www.zope.org/Collectors/CMF/467)
+
     - Document: Added two new methods for safety belt handling.
 
     - setup handlers: Improved properties handler.
@@ -34,6 +39,8 @@
 
   Others
 
+    - CMFCore utils: Marked 'minimalpath' and 'expandpath' as deprecated.
+
     - The CMF now depends on Zope 2.10.2 or higher.
 
 

Modified: CMF/trunk/CMFActionIcons/profiles/actionicons/skins.xml
===================================================================
--- CMF/trunk/CMFActionIcons/profiles/actionicons/skins.xml	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFActionIcons/profiles/actionicons/skins.xml	2007-02-23 17:29:52 UTC (rev 72785)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <object name="portal_skins" meta_type="CMF Skins Tool">
  <object name="actionicons" meta_type="Filesystem Directory View"
-    directory="CMFActionIcons/skins/actionicons"/>
+    directory="Products.CMFActionIcons:skins/actionicons"/>
  <skin-path name="*">
   <layer name="actionicons" insert-before="zpt_content"/>
  </skin-path>

Modified: CMF/trunk/CMFCalendar/profiles/default/skins.xml
===================================================================
--- CMF/trunk/CMFCalendar/profiles/default/skins.xml	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCalendar/profiles/default/skins.xml	2007-02-23 17:29:52 UTC (rev 72785)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <object name="portal_skins" meta_type="CMF Skins Tool">
  <object name="zpt_calendar" meta_type="Filesystem Directory View"
-    directory="CMFCalendar/skins/zpt_calendar"/>
+    directory="Products.CMFCalendar:skins/zpt_calendar"/>
  <skin-path name="*">
   <layer name="zpt_calendar" insert-before="zpt_content"/>
  </skin-path>

Modified: CMF/trunk/CMFCore/DirectoryView.py
===================================================================
--- CMF/trunk/CMFCore/DirectoryView.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/DirectoryView.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -18,6 +18,7 @@
 import logging
 import re
 from os import path, listdir, stat
+from os.path import abspath
 from sys import platform
 from warnings import warn
 
@@ -27,7 +28,6 @@
 from Globals import DTMLFile
 from Globals import HTMLFile
 from Globals import InitializeClass
-from Globals import package_home
 from Globals import Persistent
 from OFS.Folder import Folder
 from OFS.ObjectManager import bad_id
@@ -39,8 +39,10 @@
 from permissions import AccessContentsInformation
 from permissions import ManagePortal
 from utils import _dtmldir
-from utils import minimalpath
 from utils import normalize
+from utils import getPackageName
+from utils import getPackageLocation
+from utils import ProductsPath
 
 logger = logging.getLogger('CMFCore.DirectoryView')
 
@@ -76,14 +78,40 @@
                     for name in names ]
         listdir.extend(results)
 
+
+def _generateKey(package, subdir):
+    """Generate a key for a path inside a package.
+
+    The key has the quality that keys for subdirectories can be derived by
+    simply appending to the key.
+    """
+    return ':'.join((package, subdir.replace('\\', '/')))
+
+def _findProductForPath(path, subdir=None):
+    # like minimalpath, but raises an error if path is not inside a product
+    p = abspath(path)
+    for ppath in ProductsPath:
+        if p.startswith(ppath):
+            dirpath = p[len(ppath)+1:]
+            parts = dirpath.replace('\\', '/').split('/', 1)
+            parts.append('')
+            if subdir:
+                subdir = '/'.join((parts[1], subdir))
+            else:
+                subdir = parts[1]
+            return ('Products.' + parts[0], subdir)
+
+    raise ValueError('Path is not inside a product')
+
+
 class DirectoryInformation:
     data = None
     _v_last_read = 0
     _v_last_filelist = [] # Only used on Win32
 
-    def __init__(self, filepath, minimal_fp, ignore=ignore):
+    def __init__(self, filepath, reg_key, ignore=ignore):
         self._filepath = filepath
-        self._minimal_fp = minimal_fp
+        self._reg_key = reg_key
         self.ignore=base_ignore + tuple(ignore)
         if platform == 'win32':
             self._walker = _walker(self.ignore)
@@ -182,12 +210,13 @@
             if path.isdir(entry_filepath):
                 # Add a subdirectory only if it was previously registered,
                 # unless register_subdirs is set.
-                entry_minimal_fp = '/'.join( (self._minimal_fp, entry) )
-                info = registry.getDirectoryInfo(entry_minimal_fp)
+                entry_reg_key = '/'.join((self._reg_key, entry))
+                info = registry.getDirectoryInfo(entry_reg_key)
                 if info is None and register_subdirs:
                     # Register unknown subdirs
-                    registry.registerDirectoryByPath(entry_filepath)
-                    info = registry.getDirectoryInfo(entry_minimal_fp)
+                    registry.registerDirectoryByKey(entry_filepath,
+                                                    entry_reg_key)
+                    info = registry.getDirectoryInfo(entry_reg_key)
                 if info is not None:
                     # Folders on the file system have no extension or
                     # meta_type, as a crutch to enable customizing what gets
@@ -203,7 +232,7 @@
                     metadata = FSMetadata(entry_filepath)
                     metadata.read()
                     ob = t( entry
-                          , entry_minimal_fp
+                          , entry_reg_key
                           , properties=metadata.getProperties()
                           )
                     ob_id = ob.getId()
@@ -303,44 +332,91 @@
         # This what is actually called to register a
         # file system directory to become a FSDV.
         if not isinstance(_prefix, basestring):
-            _prefix = package_home(_prefix)
-        filepath = path.join(_prefix, name)
-        self.registerDirectoryByPath(filepath, subdirs, ignore=ignore)
+            package = getPackageName(_prefix)
+            filepath = path.join(getPackageLocation(package), name)
+        else:
+            warn('registerDirectory() called with a path; should be called '
+                 'with globals', DeprecationWarning, stacklevel=2)
+            filepath = path.join(_prefix, name)
+            (package, name) = _findProductForPath(_prefix, name)
+        reg_key = _generateKey(package, name)
+        self.registerDirectoryByKey(filepath, reg_key, subdirs, ignore)
 
-    def registerDirectoryByPath(self, filepath, subdirs=1, ignore=ignore):
-        # This is indirectly called during registration of
-        # a directory. As you can see, minimalpath is called
-        # on the supplied path at this point.
-        # The idea is that the registry will only contain
-        # small paths that are likely to work across platforms
-        # and SOFTWARE_HOME, INSTANCE_HOME and PRODUCTS_PATH setups
-        minimal_fp = minimalpath(filepath)
-        info = DirectoryInformation(filepath, minimal_fp, ignore=ignore)
-        self._directories[minimal_fp] = info
+    def registerDirectoryByKey(self, filepath, reg_key, subdirs=1,
+                               ignore=ignore):
+        info = DirectoryInformation(filepath, reg_key, ignore)
+        self._directories[reg_key] = info
         if subdirs:
             for entry in info.getSubdirs():
                 entry_filepath = path.join(filepath, entry)
-                self.registerDirectoryByPath( entry_filepath
-                                            , subdirs
-                                            , ignore=ignore
-                                            )
+                entry_reg_key = '/'.join((reg_key, entry))
+                self.registerDirectoryByKey(entry_filepath, entry_reg_key,
+                                            subdirs, ignore)
 
-    def reloadDirectory(self, minimal_fp):
-        info = self.getDirectoryInfo(minimal_fp)
+    def registerDirectoryByPath(self, filepath, subdirs=1, ignore=ignore):
+        warn('registerDirectoryByPath() is deprecated and will be removed in '
+             'CMF 2.3. Please use registerDirectoryByKey() instead.',
+             DeprecationWarning, stacklevel=2)
+        (package, subdir) = _findProductForPath(filepath)
+        reg_key = _generateKey(package, subdir)
+        self.registerDirectoryByKey(filepath, reg_key, subdirs, ignore)
+
+    def reloadDirectory(self, reg_key):
+        info = self.getDirectoryInfo(reg_key)
         if info is not None:
             info.reload()
 
-    def getDirectoryInfo(self, minimal_fp):
+    def getDirectoryInfo(self, reg_key):
         # This is called when we need to get hold of the information
         # for a minimal path. Can return None.
-        return self._directories.get(minimal_fp, None)
+        return self._directories.get(reg_key, None)
 
     def listDirectories(self):
         dirs = self._directories.keys()
         dirs.sort()
         return dirs
 
+    def getCurrentKeyFormat(self, reg_key):
+        # BBB: method will be removed in CMF 2.3
 
+        if reg_key in self._directories:
+            return reg_key
+
+        # for DirectoryViews created with CMF versions before 2.1
+        # a path relative to Products/ was used
+        dirpath = reg_key.replace('\\', '/')
+        if dirpath.startswith('Products/'):
+            dirpath = dirpath[9:]
+        product = ['Products']
+        dirparts = dirpath.split('/')
+        while dirparts:
+            product.append(dirparts[0])
+            dirparts = dirparts[1:]
+            possible_key = _generateKey('.'.join(product), '/'.join(dirparts))
+            if possible_key in self._directories:
+                return possible_key
+
+        # for DirectoryViews created with CMF versions before 1.5
+        # this is basically the old minimalpath() code
+        dirpath = normalize(reg_key)
+        index = dirpath.rfind('Products')
+        if index == -1:
+            index = dirpath.rfind('products')
+        if index != -1:
+            dirpath = dirpath[index+len('products/'):]
+            product = ['Products']
+            dirparts = dirpath.split('/')
+            while dirparts:
+                product.append(dirparts[0])
+                dirparts = dirparts[1:]
+                possible_key = _generateKey('.'.join(product),
+                                            '/'.join(dirparts))
+                if possible_key in self._directories:
+                    return possible_key
+
+        raise ValueError('Unsupported key given: %s' % reg_key)
+
+
 _dirreg = DirectoryRegistry()
 registerDirectory = _dirreg.registerDirectory
 registerFileExtension = _dirreg.registerFileExtension
@@ -393,35 +469,29 @@
     _properties = None
     _objects = ()
 
-    def __init__(self, id, dirpath='', fullname=None, properties=None):
+    def __init__(self, id, reg_key='', fullname=None, properties=None):
         if properties:
             # Since props come from the filesystem, this should be
             # safe.
             self.__dict__.update(properties)
 
         self.id = id
-        self._dirpath = dirpath
+        self._dirpath = reg_key
         self._properties = properties
 
     def __of__(self, parent):
-        dirpath = self._dirpath
-        info = _dirreg.getDirectoryInfo(dirpath)
+        reg_key = self._dirpath
+        info = _dirreg.getDirectoryInfo(reg_key)
         if info is None:
-            # for DirectoryViews created with CMF versions before 1.5
-            # this is basically the old minimalpath() code
-            dirpath = normalize(dirpath)
-            index = dirpath.rfind('Products')
-            if index == -1:
-                index = dirpath.rfind('products')
-            if index != -1:
-                dirpath = dirpath[index+len('products/'):]
-            info = _dirreg.getDirectoryInfo(dirpath)
-            if info is not None:
-                # update the directory view with a corrected path
-                self._dirpath = dirpath
-            elif self._dirpath:
-                warn('DirectoryView %s refers to a non-existing path %s'
-                     % (self.id, dirpath), UserWarning)
+            try:
+                reg_key = self._dirpath = _dirreg.getCurrentKeyFormat(reg_key)
+                info = _dirreg.getDirectoryInfo(reg_key)
+            except ValueError:
+                # During GenericSetup a view will be created with an empty
+                # reg_key. This is expected behaviour, so do not warn about it.
+                if reg_key:
+                    warn('DirectoryView %s refers to a non-existing path %r' %
+                          (self.id, reg_key), UserWarning)
         if info is None:
             data = {}
             objects = ()
@@ -471,10 +541,10 @@
     manage_propertiesForm = DTMLFile( 'dirview_properties', _dtmldir )
 
     security.declareProtected(ManagePortal, 'manage_properties')
-    def manage_properties( self, dirpath, REQUEST=None ):
+    def manage_properties(self, reg_key, REQUEST=None):
         """ Update the directory path of the DirectoryView.
         """
-        self.__dict__['_real']._dirpath = dirpath
+        self.__dict__['_real']._dirpath = reg_key
         if REQUEST is not None:
             REQUEST['RESPONSE'].redirect( '%s/manage_propertiesForm'
                                         % self.absolute_url() )
@@ -509,17 +579,17 @@
 
 manage_addDirectoryViewForm = HTMLFile('dtml/addFSDirView', globals())
 
-def createDirectoryView(parent, minimal_fp, id=None):
+def createDirectoryView(parent, reg_key, id=None):
     """ Add either a DirectoryView or a derivative object.
     """
-    info = _dirreg.getDirectoryInfo(minimal_fp)
+    info = _dirreg.getDirectoryInfo(reg_key)
     if info is None:
-        raise ValueError('Not a registered directory: %s' % minimal_fp)
+        raise ValueError('Not a registered directory: %s' % reg_key)
     if not id:
-        id = minimal_fp.split('/')[-1]
+        id = reg_key.split('/')[-1]
     else:
         id = str(id)
-    ob = DirectoryView(id, minimal_fp)
+    ob = DirectoryView(id, reg_key)
     parent._setObject(id, ob)
 
 def addDirectoryViews(ob, name, _prefix):
@@ -530,20 +600,23 @@
     persistence demands.
     """
     if not isinstance(_prefix, basestring):
-        _prefix = package_home(_prefix)
-    filepath = path.join(_prefix, name)
-    minimal_fp = minimalpath(filepath)
-    info = _dirreg.getDirectoryInfo(minimal_fp)
+        package = getPackageName(_prefix)
+    else:
+        warn('addDirectoryViews() called with a path; should be called with '
+             'globals', DeprecationWarning, stacklevel=2)
+        (package, name) = _findProductForPath(_prefix, name)
+    reg_key = _generateKey(package, name)
+    info = _dirreg.getDirectoryInfo(reg_key)
     if info is None:
-        raise ValueError('Not a registered directory: %s' % minimal_fp)
+        raise ValueError('Not a registered directory: %s' % reg_key)
     for entry in info.getSubdirs():
-        entry_minimal_fp = '/'.join( (minimal_fp, entry) )
-        createDirectoryView(ob, entry_minimal_fp, entry)
+        entry_reg_key = '/'.join((reg_key, entry))
+        createDirectoryView(ob, entry_reg_key, entry)
 
-def manage_addDirectoryView(self, dirpath, id=None, REQUEST=None):
+def manage_addDirectoryView(self, reg_key, id=None, REQUEST=None):
     """ Add either a DirectoryView or a derivative object.
     """
-    createDirectoryView(self, dirpath, id)
+    createDirectoryView(self, reg_key, id)
     if REQUEST is not None:
         return self.manage_main(self, REQUEST)
 

Modified: CMF/trunk/CMFCore/exportimport/tests/test_skins.py
===================================================================
--- CMF/trunk/CMFCore/exportimport/tests/test_skins.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/exportimport/tests/test_skins.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -45,7 +45,7 @@
 <object name="portal_skins" meta_type="CMF Skins Tool" allow_any="False"
    cookie_persistence="False" default_skin="" request_varname="portal_skin">
  <object name="foo_directoryview" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/one"/>
+    directory="Products.CMFCore.exportimport.tests:one"/>
  <skin-path name="foo_path">
   <layer name="one"/>
  </skin-path>
@@ -64,11 +64,11 @@
 <object name="portal_skins" meta_type="Dummy Skins Tool" allow_any="True"
    cookie_persistence="True" default_skin="basic" request_varname="skin_var">
  <object name="one" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/one"/>
+    directory="Products.CMFCore.exportimport.tests:one"/>
  <object name="three" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/three"/>
+    directory="Products.CMFCore.exportimport.tests:three"/>
  <object name="two" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/two"/>
+    directory="Products.CMFCore.exportimport.tests:two"/>
  <skin-path name="basic">
   <layer name="one"/>
  </skin-path>
@@ -84,7 +84,7 @@
 <?xml version="1.0"?>
 <object name="portal_skins" meta_type="Dummy Skins Tool">
  <object name="three" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/three"/>
+    package="Products.CMFCore" path="exportimport/tests/three"/>
  <skin-path name="*">
   <layer name="three" insert-before="two"/>
  </skin-path>
@@ -95,7 +95,7 @@
 <?xml version="1.0"?>
 <object name="portal_skins" meta_type="Dummy Skins Tool">
  <object name="four" meta_type="Filesystem Directory View"
-    directory="CMFCore/exportimport/tests/four"/>
+    directory="Products.CMFCore.exportimport.tests:four"/>
  <skin-path name="*">
   <layer name="four" insert-after="three"/>
  </skin-path>
@@ -189,10 +189,10 @@
         self._olddirreg = DirectoryView._dirreg
         DirectoryView._dirreg = DirectoryView.DirectoryRegistry()
         self._dirreg = DirectoryView._dirreg
-        self._dirreg.registerDirectory('one', _TESTS_PATH)
-        self._dirreg.registerDirectory('two', _TESTS_PATH)
-        self._dirreg.registerDirectory('three', _TESTS_PATH)
-        self._dirreg.registerDirectory('four', _TESTS_PATH)
+        self._dirreg.registerDirectory('one', globals())
+        self._dirreg.registerDirectory('two', globals())
+        self._dirreg.registerDirectory('three', globals())
+        self._dirreg.registerDirectory('four', globals())
 
     def tearDown(self):
         from Products.CMFCore import DirectoryView
@@ -576,6 +576,16 @@
 
 
 def test_suite():
+    # reimport to make sure tests are run from Products
+    from Products.CMFCore.exportimport.tests.test_skins \
+            import DirectoryViewAdapterTests
+    from Products.CMFCore.exportimport.tests.test_skins \
+            import exportSkinsToolTests
+    from Products.CMFCore.exportimport.tests.test_skins \
+            import importSkinsToolTests
+    from Products.CMFCore.exportimport.tests.test_skins \
+            import SkinsToolXMLAdapterTests
+
     return unittest.TestSuite((
         unittest.makeSuite(DirectoryViewAdapterTests),
         unittest.makeSuite(SkinsToolXMLAdapterTests),

Modified: CMF/trunk/CMFCore/tests/__init__.py
===================================================================
--- CMF/trunk/CMFCore/tests/__init__.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/tests/__init__.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -4,3 +4,5 @@
 As test suites are added, they should be added to the
 mega-test-suite in Products.CMFCore.tests.test_all.py
 """
+
+_globals = globals()

Modified: CMF/trunk/CMFCore/tests/base/testcase.py
===================================================================
--- CMF/trunk/CMFCore/tests/base/testcase.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/tests/base/testcase.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -18,6 +18,7 @@
 from dummy import DummyFolder
 from security import AnonymousUser
 from security import PermissiveSecurityPolicy
+from Products.CMFCore.utils import getPackageLocation
 
 
 class LogInterceptor:
@@ -208,7 +209,7 @@
 
     def setUp(self):
         # store the place where the skin copy will be created
-        self.tempname = mktemp()
+        self.tempname = mktemp(dir=getPackageLocation('Products.CMFCore.tests'))
         # create the temporary folder
         mkdir(self.tempname)
         # copy the source fake skin to the new location

Modified: CMF/trunk/CMFCore/tests/test_DirectoryView.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_DirectoryView.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/tests/test_DirectoryView.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -1,14 +1,15 @@
 import unittest
 import Testing
 
+import sys
 from os import remove, mkdir, rmdir
 from os.path import join
 from tempfile import mktemp
 
 from Globals import DevelopmentMode
 
+from Products.CMFCore.tests import _globals
 from Products.CMFCore.tests.base.dummy import DummyFolder
-from Products.CMFCore.tests.base.testcase import _prefix
 from Products.CMFCore.tests.base.testcase import FSDVTest
 from Products.CMFCore.tests.base.testcase import WarningInterceptor
 from Products.CMFCore.tests.base.testcase import WritableFSDVTest
@@ -36,16 +37,36 @@
         self._trap_warning_output()
         from Products.CMFCore.DirectoryView import registerDirectory
         from Products.CMFCore.DirectoryView import addDirectoryViews
-        registerDirectory('fake_skins', _prefix)
+        registerDirectory('fake_skins', _globals)
         self.ob = DummyFolder()
-        addDirectoryViews(self.ob, 'fake_skins', _prefix)
+        addDirectoryViews(self.ob, 'fake_skins', _globals)
 
     def tearDown(self):
         self._free_warning_output()
 
+    def test__generateKey(self):
+        from Products.CMFCore.DirectoryView import _generateKey
+
+        key = _generateKey('Products.CMFCore', 'tests')
+        self.assertEqual(key.split(':')[0], 'Products.CMFCore')
+
+        subkey = _generateKey('Products.CMFCore', 'tests\foo')
+        self.failUnless(subkey.startswith(key))
+
+    def test__findProductForPath(self):
+        from Products.CMFCore.DirectoryView import _findProductForPath
+
+        cmfpath = sys.modules['Products.CMFCore'].__path__[0]
+        self.assertEqual(_findProductForPath(cmfpath),
+                         ('Products.CMFCore', ''))
+
+        cmfpath = join(cmfpath, 'tests')
+        self.assertEqual(_findProductForPath(cmfpath),
+                ('Products.CMFCore', 'tests'))
+
     def test_getDirectoryInfo(self):
         skin = self.ob.fake_skin
-        skin.manage_properties('CMFCore/tests/fake_skins/fake_skin')
+        skin.manage_properties('Products.CMFCore.tests:fake_skins/fake_skin')
         self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
                          self.ob.fake_skin.getDirPath() )
 
@@ -106,6 +127,14 @@
         self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
                          self.ob.fake_skin.getDirPath() )
 
+    # Test pre CMF 2.1 backwards compatibility code in DirectoryView's __of__
+    # method.
+    def test_getDirectoryInfo8(self):
+        skin = self.ob.fake_skin
+        skin.manage_properties('CMFCore/tests/fake_skins/fake_skin')
+        self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
+                         self.ob.fake_skin.getDirPath() )
+
     # Test we do nothing if given a really wacky path
     def test_UnhandleableExpandPath( self ):
         from tempfile import mktemp
@@ -116,8 +145,7 @@
         # Check that a warning was raised.
         from Products.CMFCore import DirectoryView
         warnings = [t[0] for t in DirectoryView.__warningregistry__]
-        text = 'DirectoryView fake_skin refers to a non-existing path %s' % file
-        text = text.replace('\\','/')
+        text = 'DirectoryView fake_skin refers to a non-existing path %r' % file
         self.assert_(text in warnings)
         self.failUnless(text in self._our_stderr_stream.getvalue())
 
@@ -129,16 +157,14 @@
         # normalize in this unit test.
         self.assertEqual( normalize(weirdpath), minimalpath(weirdpath) )
 
-    # this test tests that registerDirectory calls minimalpath correctly
-    # the only way to test this works under SOFTWARE_HOME,INSTANCE_HOME and
-    # PRODUCTS_PATH setups is to run the test in those environments
-    def test_registerDirectoryMinimalPath(self):
+    # this test tests that registerDirectory creates keys in the right format.
+    def test_registerDirectoryKeys(self):
         from Products.CMFCore.DirectoryView import _dirreg
         dirs = _dirreg._directories
-        self.failUnless( dirs.has_key('CMFCore/tests/fake_skins/fake_skin'),
+        self.failUnless( dirs.has_key('Products.CMFCore.tests:fake_skins/fake_skin'),
                          dirs.keys() )
         self.assertEqual( self.ob.fake_skin.getDirPath(),
-                          'CMFCore/tests/fake_skins/fake_skin' )
+                          'Products.CMFCore.tests:fake_skins/fake_skin' )
 
 
 class DirectoryViewTests( FSDVTest ):

Modified: CMF/trunk/CMFCore/tests/test_utils.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_utils.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/tests/test_utils.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -61,7 +61,24 @@
             self.assertEqual( contributorsplitter({'Contributors': x}), 
                               ['foo', 'bar', 'baz'] )
 
+    def test_getPackageName(self):
+        from Products.CMFCore.utils import getPackageName
+        from Products.CMFCore.utils import _globals
 
+        self.assertEqual(getPackageName(globals()), 'Products.CMFCore.tests')
+        self.assertEqual(getPackageName(_globals), 'Products.CMFCore')
+
+    def test_getContainingPackage(self):
+        from Products.CMFCore.utils import getContainingPackage
+
+        self.assertEqual(getContainingPackage('Products.CMFCore.exceptions'),
+                'Products.CMFCore')
+        self.assertEqual(getContainingPackage('Products.CMFCore'),
+                'Products.CMFCore')
+        self.assertEqual(getContainingPackage('zope.interface.verify'),
+                'zope.interface')
+
+
 class CoreUtilsSecurityTests(SecurityTest):
 
     def _makeSite(self):
@@ -130,6 +147,9 @@
 
 
 def test_suite():
+    # reimport to make sure tests are run from Products
+    from Products.CMFCore.tests.test_utils import CoreUtilsTests
+
     return unittest.TestSuite((
         unittest.makeSuite(CoreUtilsTests),
         unittest.makeSuite(CoreUtilsSecurityTests),

Modified: CMF/trunk/CMFCore/utils.py
===================================================================
--- CMF/trunk/CMFCore/utils.py	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFCore/utils.py	2007-02-23 17:29:52 UTC (rev 72785)
@@ -20,6 +20,7 @@
 from os import path as os_path
 from os.path import abspath
 from warnings import warn
+import sys
 
 from AccessControl import ClassSecurityInfo
 from AccessControl import getSecurityManager
@@ -55,6 +56,7 @@
 
 security = ModuleSecurityInfo( 'Products.CMFCore.utils' )
 
+_globals = globals()
 _dtmldir = os_path.join( package_home( globals() ), 'dtml' )
 _wwwdir = os_path.join( package_home( globals() ), 'www' )
 
@@ -263,7 +265,6 @@
         result.append(value)
     return apply(parse_etags,(text[l:],result))
 
-
 def _checkConditionalGET(obj, extra_context):
     """A conditional GET is done using one or both of the request
        headers:
@@ -272,7 +273,7 @@
        If-None-Match: list ETags (comma delimited, sometimes quoted)
 
        If both conditions are present, both must be satisfied.
-       
+
        This method checks the caching policy manager to see if
        a content object's Last-modified date and ETag satisfy
        the conditional GET headers.
@@ -310,14 +311,14 @@
     ret = manager.getModTimeAndETag(aq_parent(obj), obj.getId(), extra_context)
     if ret is None:
         # no appropriate policy or 304s not enabled
-        return  False 
+        return False
 
     (content_mod_time, content_etag, set_last_modified_header) = ret
     if content_mod_time:
         mod_time_secs = long(content_mod_time.timeTime())
     else:
         mod_time_secs = None
-    
+
     if if_modified_since:
         # from CMFCore/FSFile.py:
         if_modified_since = if_modified_since.split(';')[0]
@@ -331,7 +332,7 @@
             if_modified_since=long(DateTime(if_modified_since).timeTime())
         except:
             if_mod_since=None
-                
+
     client_etags = None
     if if_none_match:
         client_etags = parse_etags(if_none_match)
@@ -345,7 +346,7 @@
              mod_time_secs < 0 or 
              mod_time_secs > if_modified_since ):
             return False
-        
+
     if client_etags:
         if ( not content_etag or 
              (content_etag not in client_etags and '*' not in client_etags) ):
@@ -365,9 +366,8 @@
         response.setHeader('ETag', content_etag, literal=1)
     response.setStatus(304)
     delattr(REQUEST, SUBTEMPLATE)
-            
+
     return True
-   
 
 security.declarePrivate('_setCacheHeaders')
 def _setCacheHeaders(obj, extra_context):
@@ -728,6 +728,9 @@
     The (expanded) filepath is the valid absolute path on the current platform
     and setup.
     """
+    warn('expandpath() is deprecated and will be removed in CMF 2.3.',
+         DeprecationWarning, stacklevel=2)
+
     p = os_path.normpath(p)
     if os_path.isabs(p):
         return p
@@ -751,6 +754,9 @@
     Returns a slash-separated path relative to the Products path. If it can't
     be found, a normalized path is returned.
     """
+    warn('minimalpath() is deprecated and will be removed in CMF 2.3.',
+         DeprecationWarning, stacklevel=2)
+
     p = abspath(p)
     for ppath in ProductsPath:
         if p.startswith(ppath):
@@ -758,6 +764,33 @@
             break
     return p.replace('\\','/')
 
+security.declarePrivate('getContainingPackage')
+def getContainingPackage(module):
+    parts = module.split('.')
+    while parts:
+        name = '.'.join(parts)
+        mod = sys.modules[name]
+        if '__init__' in mod.__file__:
+            return name
+        parts = parts[:-1]
+
+    raise ValueError('Unable to find package for module %s' % module)
+
+security.declarePrivate('getPackageLocation')
+def getPackageLocation(module):
+    """ Return the filesystem location of a module.
+
+    This is a simple wrapper around the global package_home method which
+    tricks it into working with just a module name.
+    """
+    package = getContainingPackage(module)
+    return package_home({'__name__' : package})
+
+security.declarePrivate('getPackageName')
+def getPackageName(globals_):
+    module = globals_['__name__']
+    return getContainingPackage(module)
+
 def _OldCacheHeaders(obj):
     # Old-style checking of modified headers
 
@@ -782,7 +815,7 @@
             mod_since=long(mod_since.timeTime())
         except TypeError:
             mod_since=None
-               
+
         if mod_since is not None:
             if last_mod > 0 and last_mod <= mod_since:
                 RESPONSE.setStatus(304)
@@ -816,7 +849,7 @@
             mod_since=long(mod_since.timeTime())
         except TypeError:
             mod_since=None
-               
+
         if mod_since is not None:
             if last_mod > 0 and last_mod <= mod_since:
                 RESPONSE.setStatus(304)

Modified: CMF/trunk/CMFDefault/profiles/default/skins.xml
===================================================================
--- CMF/trunk/CMFDefault/profiles/default/skins.xml	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFDefault/profiles/default/skins.xml	2007-02-23 17:29:52 UTC (rev 72785)
@@ -3,14 +3,14 @@
    cookie_persistence="False" default_skin="Basic"
    request_varname="portal_skin">
  <object name="Images" meta_type="Filesystem Directory View"
-    directory="CMFDefault/skins/Images"/>
+    directory="Products.CMFDefault:skins/Images"/>
  <object name="custom" meta_type="Folder"/>
  <object name="zpt_content" meta_type="Filesystem Directory View"
-    directory="CMFDefault/skins/zpt_content"/>
+    directory="Products.CMFDefault:skins/zpt_content"/>
  <object name="zpt_control" meta_type="Filesystem Directory View"
-    directory="CMFDefault/skins/zpt_control"/>
+    directory="Products.CMFDefault:skins/zpt_control"/>
  <object name="zpt_generic" meta_type="Filesystem Directory View"
-    directory="CMFDefault/skins/zpt_generic"/>
+    directory="Products.CMFDefault:skins/zpt_generic"/>
  <skin-path name="Basic">
   <layer name="custom"/>
   <layer name="zpt_content"/>

Modified: CMF/trunk/CMFTopic/profiles/default/skins.xml
===================================================================
--- CMF/trunk/CMFTopic/profiles/default/skins.xml	2007-02-23 17:11:17 UTC (rev 72784)
+++ CMF/trunk/CMFTopic/profiles/default/skins.xml	2007-02-23 17:29:52 UTC (rev 72785)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <object name="portal_skins" meta_type="CMF Skins Tool">
  <object name="zpt_topic" meta_type="Filesystem Directory View"
-    directory="CMFTopic/skins/zpt_topic"/>
+    directory="Products.CMFTopic:skins/zpt_topic"/>
  <skin-path name="*">
   <layer name="zpt_topic" insert-before="zpt_content"/>
  </skin-path>



More information about the CMF-checkins mailing list