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> _______________________________________________ CMF-checkins mailing list [email protected] http://mail.zope.org/mailman/listinfo/cmf-checkins
