[CMF-checkins] SVN: CMF/branches/tseaver-pkg_resources/CMFCore/ -
Checkpoint.
Tres Seaver
tseaver at palladion.com
Tue Oct 25 18:38:06 EDT 2005
Log message for revision 39626:
- Checkpoint.
Changed:
U CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py
U CMF/branches/tseaver-pkg_resources/CMFCore/FSMetadata.py
U CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py
U CMF/branches/tseaver-pkg_resources/CMFCore/FSPageTemplate.py
U CMF/branches/tseaver-pkg_resources/CMFCore/tests/base/testcase.py
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/not_a_package/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/not_a_package/rotten.egg
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/__init__.py
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt.metadata
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/stinky.py
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/__init__.py
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/__init__.py
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/data.txt
A CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/setup.py
U CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py
U CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_FSMetadata.py
-=-
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -17,6 +17,9 @@
import re
from os import path, listdir, stat
+from pkg_resources import resource_listdir
+from pkg_resources import resource_isdir
+from pkg_resources import resource_string
from sys import exc_info
from sys import platform
@@ -31,6 +34,7 @@
from OFS.Folder import Folder
from OFS.ObjectManager import bad_id
from zLOG import LOG, ERROR
+from zope.interface import Interface
from FSMetadata import FSMetadata
from FSObject import BadFile
@@ -73,24 +77,29 @@
for name in names ]
listdir.extend(results)
-class DirectoryInformation:
+class IDirectoryInformation(Interface):
+
+ def getSubdirs():
+ """ Return a sequence of names of subdirs within this directory.
+
+ o Excludes subdirs which match 'ignore'.
+ """
+
+ def reload():
+ """ Remove all cached information about the directory.
+ """
+
+ def readFile(self, filename, mode='r'):
+ """ Return the data from the given file.
+
+ o Return None if the file does not exist.
+ """
+
+class DirectoryInformationBase:
+
data = None
- _v_last_read = 0
- _v_last_filelist = [] # Only used on Win32
+ subdirs = ()
- def __init__(self, filepath, minimal_fp, ignore=ignore):
- self._filepath = filepath
- self._minimal_fp = minimal_fp
- self.ignore=base_ignore + tuple(ignore)
- if platform == 'win32':
- self._walker = _walker(self.ignore)
- subdirs = []
- for entry in _filtered_listdir(self._filepath, ignore=self.ignore):
- entry_filepath = path.join(self._filepath, entry)
- if path.isdir(entry_filepath):
- subdirs.append(entry)
- self.subdirs = tuple(subdirs)
-
def getSubdirs(self):
return self.subdirs
@@ -108,14 +117,9 @@
""" Read the .objects file produced by FSDump.
"""
types = {}
- try:
- f = open( path.join(self._filepath, '.objects'), 'rt' )
- except IOError:
- pass
- else:
- lines = f.readlines()
- f.close()
- for line in lines:
+ data = self.readFile('.objects', 'rt')
+ if data is not None:
+ for line in data.splitlines():
try:
obname, meta_type = line.split(':')
except ValueError:
@@ -124,6 +128,56 @@
types[obname.strip()] = meta_type.strip()
return types
+ def _changed(self):
+ return False
+
+ def getContents(self, registry):
+ changed = self._changed()
+ if self.data is None or changed:
+ try:
+ self.data, self.objects = self.prepareContents(registry,
+ register_subdirs=changed)
+ except:
+ LOG('DirectoryView',
+ ERROR,
+ 'Error during prepareContents:',
+ error=exc_info())
+ self.data = {}
+ self.objects = ()
+
+ return self.data, self.objects
+
+class DirectoryInformation(DirectoryInformationBase):
+
+ _v_last_read = 0
+ _v_last_filelist = [] # Only used on Win32
+
+ def __init__(self, filepath, minimal_fp, ignore=ignore):
+ self._filepath = filepath
+ self._minimal_fp = minimal_fp
+ self.ignore = base_ignore + tuple(ignore)
+ if platform == 'win32':
+ self._walker = _walker(self.ignore)
+ subdirs = []
+ for entry in _filtered_listdir(self._filepath, ignore=self.ignore):
+ entry_filepath = path.join(self._filepath, entry)
+ if path.isdir(entry_filepath):
+ subdirs.append(entry)
+ self.subdirs = tuple(subdirs)
+
+ def readFile(self, filename, mode='r'):
+ data = None
+ try:
+ f = open( path.join(self._filepath, filename), mode )
+ except IOError:
+ pass
+ else:
+ try:
+ data = f.read()
+ finally:
+ f.close()
+ return data
+
if DevelopmentMode:
def _changed(self):
@@ -152,27 +206,6 @@
return 0
- else:
-
- def _changed(self):
- return 0
-
- def getContents(self, registry):
- changed = self._changed()
- if self.data is None or changed:
- try:
- self.data, self.objects = self.prepareContents(registry,
- register_subdirs=changed)
- except:
- LOG('DirectoryView',
- ERROR,
- 'Error during prepareContents:',
- error=exc_info())
- self.data = {}
- self.objects = ()
-
- return self.data, self.objects
-
def prepareContents(self, registry, register_subdirs=0):
# Creates objects for each file.
data = {}
@@ -203,7 +236,7 @@
t = registry.getTypeByMetaType(mt)
if t is None:
t = DirectoryView
- metadata = FSMetadata(entry_filepath)
+ metadata = FSMetadata(filename=entry_filepath)
metadata.read()
ob = t( entry
, entry_minimal_fp
@@ -237,7 +270,7 @@
t = registry.getTypeByExtension(ext)
if t is not None:
- metadata = FSMetadata(entry_filepath)
+ metadata = FSMetadata(filename=entry_filepath)
metadata.read()
try:
ob = t(name, entry_minimal_fp, fullname=entry,
@@ -288,7 +321,169 @@
return data, tuple(objects)
+class ResourceDirectoryInformation(DirectoryInformationBase):
+ """ DI for directories read using pkg_resources API.
+ """
+ def __init__(self, pname, name, ignore=ignore):
+ self._pname = pname
+ self._name = name
+ self.ignore = base_ignore + tuple(ignore)
+ subdirs = []
+ for entry in self._listEntries():
+ entry_subpath = self._getEntrySubpath(entry)
+ if resource_isdir(pname, entry_subpath):
+ subdirs.append(entry)
+ self.subdirs = tuple(subdirs)
+
+ def _listEntries(self):
+ for entry in resource_listdir(self._pname, self._name):
+ if entry not in self.ignore:
+ yield entry
+
+ def _getEntrySubpath(self, entry):
+ return '%s/%s' % (self._name, entry)
+
+ def readFile(self, filename, mode='ignored'):
+ try:
+ return resource_string(self._pname, '%s/%s' % (self._name,
+ filename))
+ except IOError:
+ return None
+
+ def prepareContents(self, registry, register_subdirs=0):
+ # Creates objects for each file.
+ data = {}
+ objects = []
+ pname = self._pname
+ types = self._readTypesFile()
+ faux_path_prefix = pname.split('.')
+
+ for entry in resource_listdir(self._pname, self._name):
+
+ if not self._isAllowableFilename(entry):
+ continue
+
+ entry_subpath = self._getEntrySubpath(entry)
+ faux_path_elements = faux_path_prefix + [entry]
+ faux_path = '/'.join(faux_path_elements)
+
+ if entry in self.subdirs:
+ # Add a subdirectory only if it was previously registered,
+ # unless register_subdirs is set.
+ info = registry.getDirectoryInfo(faux_path)
+ if info is None and register_subdirs:
+ # Register unknown subdirs
+ registry.registerDirectoryByGlobals(entry_subpath,
+ {'__name__' :
+ self._pname },
+ ignore=self.ignore,
+ )
+ info = registry.getDirectoryInfo(faux_path)
+ if info is not None:
+ # Folders on the file system have no extension or
+ # meta_type, as a crutch to enable customizing what gets
+ # created to represent a filesystem folder in a
+ # DirectoryView we use a fake type "FOLDER". That way
+ # other implementations can register for that type and
+ # circumvent the hardcoded assumption that all filesystem
+ # directories will turn into DirectoryViews.
+ mt = types.get(entry) or 'FOLDER'
+ t = registry.getTypeByMetaType(mt)
+ if t is None:
+ t = DirectoryView
+ metadata = FSMetadata(package=pname,
+ entry_subpath=entry_subpath)
+ metadata.read()
+ ob = t( entry
+ , entry_minimal_fp
+ , properties=metadata.getProperties()
+ )
+ ob_id = ob.getId()
+ data[ob_id] = ob
+ objects.append({'id': ob_id, 'meta_type': ob.meta_type})
+ else:
+ pos = entry.rfind('.')
+ if pos >= 0:
+ name = entry[:pos]
+ ext = path.normcase(entry[pos + 1:])
+ else:
+ name = entry
+ ext = ''
+ if not name or name == 'REQUEST':
+ # Not an allowable id.
+ continue
+ mo = bad_id(name)
+ if mo is not None and mo != -1: # Both re and regex formats
+ # Not an allowable id.
+ continue
+ t = None
+ mt = types.get(entry, None)
+ if mt is None:
+ mt = types.get(name, None)
+ if mt is not None:
+ t = registry.getTypeByMetaType(mt)
+ if t is None:
+ t = registry.getTypeByExtension(ext)
+
+ if t is not None:
+ metadata = FSMetadata(package=pname,
+ entry_subpath=entry_subpath)
+ metadata.read()
+ try:
+ ob = t(name,
+ package=pname,
+ entry_subpath=entry_subpath,
+ fullname=entry,
+ properties=metadata.getProperties(),
+ )
+ except:
+ import traceback
+ typ, val, tb = exc_info()
+ try:
+ exc_lines = traceback.format_exception( typ,
+ val,
+ tb )
+ LOG( 'DirectoryView', ERROR,
+ '\n'.join(exc_lines) )
+
+ ob = BadFile( name,
+ entry_minimal_fp,
+ exc_str='\r\n'.join(exc_lines),
+ fullname=entry )
+ finally:
+ tb = None # Avoid leaking frame!
+
+ # FS-based security
+ permissions = metadata.getSecurity()
+ if permissions is not None:
+ for name in permissions.keys():
+ acquire, roles = permissions[name]
+ try:
+ ob.manage_permission(name,roles,acquire)
+ except ValueError:
+ LOG('DirectoryView',
+ ERROR,
+ 'Error setting permissions',
+ error=exc_info())
+
+ # only DTML Methods and Python Scripts can have proxy roles
+ if hasattr(ob, '_proxy_roles'):
+ try:
+ ob._proxy_roles = tuple(metadata.getProxyRoles())
+ except:
+ LOG('DirectoryView',
+ ERROR,
+ 'Error setting proxy role',
+ error=exc_info())
+
+ ob_id = ob.getId()
+ data[ob_id] = ob
+ objects.append({'id': ob_id, 'meta_type': ob.meta_type})
+
+ return data, tuple(objects)
+
+
class DirectoryRegistry:
def __init__(self):
@@ -311,11 +506,32 @@
def registerDirectory(self, name, _prefix, subdirs=1, ignore=ignore):
# 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)
+ if isinstance(_prefix, basestring):
+ filepath = path.join(_prefix, name)
+ self.registerDirectoryByPath(filepath, subdirs, ignore=ignore)
+ else:
+ self.registerDirectoryByGlobals(name, _prefix, subdirs, ignore)
+ def registerDirectoryByGlobals(self, name, pglobals,
+ subdirs=1, ignore=ignore):
+ pname = pglobals['__name__']
+ faux_path_elements = pname.split('.')
+ faux_path_elements.append(name)
+ faux_path = '/'.join(faux_path_elements)
+ info = ResourceDirectoryInformation(pname, name, ignore=ignore)
+ self._directories[faux_path] = info
+ if subdirs:
+ for entry in resource_listdir(pname, name):
+ if entry in ignore:
+ continue
+ sub_name = '%s/%s' % (name, entry)
+ if resource_isdir(pname, sub_name):
+ self.registerDirectoryByGlobals( sub_name
+ , pglobals
+ , subdirs
+ , ignore=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
@@ -532,16 +748,22 @@
still needs to be called by product initialization code to satisfy
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)
+ if isinstance(_prefix, basestring):
+ filepath = path.join(_prefix, name)
+ adjusted = minimalpath(filepath)
+ else:
+ pname = _prefix['__name__']
+ elements = pname.split('.') + [name]
+ adjusted = '/'.join(elements)
+
+ info = _dirreg.getDirectoryInfo(adjusted)
+
if info is None:
raise ValueError('Not a registered directory: %s' % minimal_fp)
+
for entry in info.getSubdirs():
- entry_minimal_fp = '/'.join( (minimal_fp, entry) )
- createDirectoryView(ob, entry_minimal_fp, entry)
+ entry_subname = '%s/%s' % (adjusted, entry)
+ createDirectoryView(ob, entry_subname, entry)
def manage_addDirectoryView(self, dirpath, id=None, REQUEST=None):
""" Add either a DirectoryView or a derivative object.
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/FSMetadata.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/FSMetadata.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/FSMetadata.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -15,13 +15,13 @@
$Id$
"""
-from zLOG import LOG, ERROR
-from sys import exc_info
-from os.path import exists
from ConfigParser import ConfigParser
+from pkg_resources import resource_stream
+import re
+import sys
from warnings import warn
-import re
+from zLOG import LOG, ERROR
class CMFConfigParser(ConfigParser):
""" This our wrapper around ConfigParser to
@@ -44,20 +44,30 @@
class FSMetadata:
# public API
- def __init__(self, filename):
- self._filename = filename
+ _package = None
+ _entry_subpath = None
+ _filename = None
+ def __init__(self, package=None, entry_subpath=None, filename=None):
+ MESSAGE = ("Either 'filename' or 'package' + 'entry_subpath' must "
+ "be supplied.")
+ if filename is None:
+ if package is None or entry_subpath is None:
+ raise ValueError(MESSAGE)
+ self._package = package
+ self._entry_subpath = entry_subpath
+ else:
+ if package is not None or entry_subpath is not None:
+ raise ValueError(MESSAGE)
+ self._filename = filename
def read(self):
- """ Find the files to read, either the old security and
- properties type or the new metadata type """
- filename = self._filename + '.metadata'
- if exists(filename):
- # found the new type, lets use that
- self._readMetadata()
- else:
- # not found so try the old ones
- self._properties = self._old_readProperties()
- self._security = self._old_readSecurity()
+ """ Find the file(s) and read them.
+
+ o Prefer new '.metdata' file.
+
+ o Fall back to '.properties' and '.security' files.
+ """
+ self._readMetadata()
def getProxyRoles(self):
""" Returns the proxy roles """
@@ -82,24 +92,46 @@
self._security = {}
try:
+ stream = self._getStream()
+ if stream is None:
+ return
+
cfg = CMFConfigParser()
- cfg.read(self._filename + '.metadata')
+ cfg.readfp(stream)
# the two sections we care about
- self._properties = self._getSectionDict(cfg, 'default')
- self._security = self._getSectionDict(cfg, 'security',
+ self._properties = self._getSectionDict(cfg, 'Default')
+ self._security = self._getSectionDict(cfg, 'Security',
self._securityParser)
except:
LOG('FSMetadata',
ERROR,
'Error parsing .metadata file',
- error=exc_info())
+ error=sys.exc_info())
# to add in a new value such as proxy roles,
# just add in the section, call it using getSectionDict
# if you need a special parser for some whacky
# config, then just pass through a special parser
+
+ def _getStream(self):
+ """ Return a stream opened against our .metadata file
+
+ o File may be found either via 'pkg_resoruces' or via direct
+ file access.
+ """
+ if self._package is not None:
+ try:
+ filename = '%s%s' % (self._entry_subpath, '.metadata')
+ return resource_stream(self._package, filename)
+ except IOError:
+ return None
+ try:
+ return open(self._filename + '.metadata', 'r')
+ except IOError:
+ return None
+
def _nullParser(self, data):
"""
This is the standard rather boring null parser that does very little
@@ -145,72 +177,3 @@
# we need to return None if we have none to be compatible
# with existing API
return None
-
- def _old_readProperties(self):
- """
- Reads the properties file next to an object.
-
- Moved from DirectoryView.py to here with only minor
- modifications. Old and deprecated in favour of .metadata now
- """
- fp = self._filename + '.properties'
- try:
- f = open(fp, 'rt')
- except IOError:
- return None
- else:
- warn('.properties objects will disappear in CMF 1.7 - Use '
- '.metadata objects instead.', DeprecationWarning)
- lines = f.readlines()
- f.close()
- props = {}
- for line in lines:
- kv = line.split('=', 1)
- if len(kv) == 2:
- props[kv[0].strip()] = kv[1].strip()
- else:
- LOG('FSMetadata',
- ERROR,
- 'Error parsing .properties file',
- error=exc_info())
-
- return props
-
- def _old_readSecurity(self):
- """
- Reads the security file next to an object.
-
- Moved from DirectoryView.py to here with only minor
- modifications. Old and deprecated in favour of .metadata now
- """
- fp = self._filename + '.security'
- try:
- f = open(fp, 'rt')
- except IOError:
- return None
- else:
- warn('.security objects will disappear in CMF 1.7 - Use '
- '.metadata objects instead.', DeprecationWarning)
- lines = f.readlines()
- f.close()
- prm = {}
- for line in lines:
- try:
- c1 = line.index(':')+1
- c2 = line.index(':',c1)
- permission = line[:c1-1]
- acquire = bool(line[c1:c2])
- proles = line[c2+1:].split(',')
- roles=[]
- for role in proles:
- role = role.strip()
- if role:
- roles.append(role)
- except:
- LOG('DirectoryView',
- ERROR,
- 'Error reading permission from .security file',
- error=exc_info())
- # warning use of exc_info is deprecated
- prm[permission]=(acquire,roles)
- return prm
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -51,10 +51,31 @@
security = ClassSecurityInfo()
security.declareObjectProtected(View)
+ _filepath = None
+ _package = None
+ _entry_subpath = None
_file_mod_time = 0
_parsed = 0
- def __init__(self, id, filepath, fullname=None, properties=None):
+ def __init__(self, id, filepath=None, package=None, entry_subpath=None,
+ fullname=None, properties=None):
+ MESSAGE = ("Either 'filepath' or 'package' + 'entry_subpath' must "
+ "be supplied.")
+ if filepath is None:
+ if package is None or entry_subpath is None:
+ raise ValueError(MESSAGE)
+ self._package = package
+ self._entry_subpath = entry_subpath
+ else:
+ if package is not None or entry_subpath is not None:
+ raise ValueError(MESSAGE)
+ self._filepath = filepath
+ fp = expandpath(self._filepath)
+ try:
+ self._file_mod_time = stat(fp)[8]
+ except:
+ pass
+
if properties:
# Since props come from the filesystem, this should be
# safe.
@@ -68,11 +89,6 @@
self.id = id
self.__name__ = id # __name__ is used in traceback reporting
- self._filepath = filepath
- fp = expandpath(self._filepath)
-
- try: self._file_mod_time = stat(fp)[8]
- except: pass
self._readFile(0)
security.declareProtected(ViewManagementScreens, 'manage_doCustomize')
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/FSPageTemplate.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/FSPageTemplate.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/FSPageTemplate.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -15,6 +15,7 @@
$Id$
"""
+from pkg_resources import resource_string
import re
import Globals
@@ -63,8 +64,10 @@
# Declare security for unprotected PageTemplate methods.
security.declarePrivate('pt_edit', 'write')
- def __init__(self, id, filepath, fullname=None, properties=None):
- FSObject.__init__(self, id, filepath, fullname, properties)
+ def __init__(self, id, filepath=None, package=None, entry_subpath=None,
+ fullname=None, properties=None):
+ FSObject.__init__(self, id, filepath, package, entry_subpath,
+ fullname, properties)
self.ZBindings_edit(self._default_bindings)
def _createZODBClone(self):
@@ -78,12 +81,15 @@
# return 0
def _readFile(self, reparse):
- fp = expandpath(self._filepath)
- file = open(fp, 'r') # not 'rb', as this is a text file!
- try:
- data = file.read()
- finally:
- file.close()
+ if self._filepath is None:
+ data = resource_string(self._package, self._entry_subpath)
+ else:
+ fp = expandpath(self._filepath)
+ file = open(fp, 'r') # not 'rb', as this is a text file!
+ try:
+ data = file.read()
+ finally:
+ file.close()
if reparse:
# If we already have a content_type set it must come from a
@@ -100,7 +106,7 @@
encoding = xml_info.group(1) or 'utf-8'
self.content_type = 'text/xml; charset=%s' % encoding
- self.write(data)
+ self.write(data)
security.declarePrivate('read')
def read(self):
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/tests/base/testcase.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/base/testcase.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/base/testcase.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -227,3 +227,50 @@
# kill the copy
self._free_warning_output()
rmtree(self.tempname)
+
+class EggTestsBase( FSDVTest ):
+ """ Base class for tests of skins inside .egg files.
+ """
+ _skinname = 'not_a_package'
+
+ def setUp(self):
+ import os
+ from pkg_resources import working_set
+ import sys
+ import Products
+ FSDVTest.setUp(self)
+ self._entry_name = os.path.join(self.tempname, self._skinname)
+ self._oldpath = sys.path[:]
+ self._oldmodules = {}
+ self._oldmodules.update(sys.modules)
+ self._saveWorkingSet()
+ self._products_path = Products.__path__[:]
+ working_set.entries.insert(0, self._entry_name)
+ sys.path.insert(0, os.path.join(self.tempname,
+ self._skinname,
+ ))
+
+ def tearDown(self):
+ import sys
+ from pkg_resources import working_set
+ import Products
+ sys.path[:] = self._oldpath
+ sys.modules.clear()
+ sys.modules.update(self._oldmodules)
+ Products.__path__[:] = self._products_path
+ self._restoreWorkingSet()
+ FSDVTest.tearDown(self)
+
+ def _saveWorkingSet(self):
+ from pkg_resources import working_set
+ self._ws_entries = working_set.entries[:]
+ self._ws_entry_keys = dict(working_set.entry_keys)
+ self._ws_by_key = dict(working_set.by_key)
+
+ def _restoreWorkingSet(self):
+ from pkg_resources import working_set
+ working_set.entries[:] = self._ws_entries
+ working_set.entry_keys.clear()
+ working_set.entry_keys.update(self._ws_entry_keys)
+ working_set.by_key.clear()
+ working_set.by_key.update(self._ws_by_key)
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/not_a_package/rotten.egg
===================================================================
(Binary files differ)
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/not_a_package/rotten.egg
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/__init__.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/__init__.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/__init__.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1,7 @@
+""" Rotten product (demo CMF eggification)
+
+$Id$
+"""
+
+def initialize(context):
+ pass
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1,5 @@
+<html>
+<body>
+<h1> Rotten to the Core </h1>
+</body>
+</html>
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt.metadata
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt.metadata 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/skins/rotten/rotten.pt.metadata 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1,7 @@
+[Default]
+title=Rotten Template
+proxy=Foo
+
+[Security]
+Access contents information = 1:Manager,Anonymous
+View management screens = 0:Manager
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/stinky.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/stinky.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/stinky.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1,26 @@
+""" Rotten content object.
+
+$Id$
+"""
+from pkg_resources import resource_string
+
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Globals import InitializeClass
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+
+from Products.CMFCore.URLTool import URLTool
+
+class Stinky(URLTool):
+ """
+ """
+ security = ClassSecurityInfo()
+
+ manage_tabs = ({'label' : 'Stench', 'action' : 'manage_stench'},
+ ) + URLTool.manage_options
+
+ manage_stench = ZopePageTemplate('manage_stench',
+ resource_string(__name__,
+ 'zmi/stench.pt'),
+ )
+
+InitializeClass(Stinky)
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/Rotten/stinky.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/__init__.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/__init__.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/__init__.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1 @@
+# Namespace package
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/Products/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/__init__.py
===================================================================
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/data.txt
===================================================================
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/aargh/data.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/setup.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/setup.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/setup.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -0,0 +1,14 @@
+from setuptools import find_packages
+from setuptools import setup
+
+setup(
+ name='rotten',
+ version='0.1',
+ packages=find_packages(),
+ namespace_packages=['Products'],
+ package_data={'': ['*.txt'],
+ 'Products.Rotten': ['skins/rotten/*',
+ 'profiles/rotten/*',
+ ],
+ },
+)
Property changes on: CMF/branches/tseaver-pkg_resources/CMFCore/tests/rotten.egg/setup.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -11,6 +11,7 @@
from Products.CMFCore.tests.base.dummy import DummyFolder
from Products.CMFCore.tests.base.testcase import _prefix
+from Products.CMFCore.tests.base.testcase import EggTestsBase
from Products.CMFCore.tests.base.testcase import FSDVTest
from Products.CMFCore.tests.base.testcase import WarningInterceptor
@@ -259,7 +260,35 @@
testfolder = self.ob.fake_skin.test_directory
self.failUnless(isinstance(testfolder, DummyDirectoryViewSurrogate))
+class DirectoryViewEggTests( EggTestsBase ):
+ def test_resource_listdir_works_with_egg(self):
+ from pkg_resources import Requirement
+ from pkg_resources import require
+ from pkg_resources import resource_listdir
+
+ require('rotten')
+ import Products.Rotten
+ found = resource_listdir('Products.Rotten', 'skins/rotten')
+ self.assertEqual(len(found), 1, found)
+ self.assertEqual(found[0], 'rotten.pt')
+
+ def test_registerDirectory_in_egg(self):
+ from pkg_resources import require
+ require('rotten')
+ from Products.CMFCore.DirectoryView import registerDirectory
+ from Products.CMFCore.DirectoryView import _dirreg
+
+ before = _dirreg._directories.copy()
+ registerDirectory('skins', {'__name__': 'Products.Rotten'})
+ after = _dirreg._directories.copy()
+
+ added = [x for x in after.keys() if x not in before]
+ self.assertEqual(len(added), 2)
+ self.failUnless('Products/Rotten/skins' in added)
+ self.failUnless('Products/Rotten/skins/rotten' in added)
+
+
if DevelopmentMode:
class DebugModeTests( FSDVTest ):
@@ -337,6 +366,7 @@
makeSuite(DirectoryViewTests),
makeSuite(DirectoryViewIgnoreTests),
makeSuite(DirectoryViewFolderTests),
+ makeSuite(DirectoryViewEggTests),
makeSuite(DebugModeTests),
))
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_FSMetadata.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_FSMetadata.py 2005-10-25 22:08:56 UTC (rev 39625)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_FSMetadata.py 2005-10-25 22:38:06 UTC (rev 39626)
@@ -20,9 +20,11 @@
Zope2.startup()
from test_FSSecurity import FSSecurityBase
+from base.testcase import EggTestsBase
+from base.dummy import DummyFolder
-class FSMetadata(FSSecurityBase):
+class FSMetadataDirectoryTests(FSSecurityBase):
def _checkProxyRoles(self, obj, roles):
# Test proxy roles on the object
@@ -84,9 +86,30 @@
self._checkProxyRoles(ob, ['Manager', 'Anonymous'])
+class FSMetadataEggTests(EggTestsBase):
+
+ def test_fsmetadata_from_egg(self):
+ from pkg_resources import require
+ from Products.CMFCore.DirectoryView import addDirectoryViews
+ from Products.CMFCore.DirectoryView import registerDirectory
+
+ faux_globals = {'__name__': 'Products.Rotten'}
+ require('rotten')
+ registerDirectory('skins', faux_globals)
+
+ ob = DummyFolder()
+ self.failIf('rotten' in ob.__dict__)
+ addDirectoryViews(ob, 'skins', faux_globals)
+ self.failUnless('rotten' in ob.__dict__)
+
+ rotten = ob.rotten
+ template = rotten._getOb('rotten')
+ self.assertEqual(template.title, 'Rotten Template')
+
def test_suite():
return TestSuite((
- makeSuite(FSMetadata),
+ makeSuite(FSMetadataDirectoryTests),
+ makeSuite(FSMetadataEggTests),
))
if __name__ == '__main__':
More information about the CMF-checkins
mailing list